cloudapi: validate input
Validate incoming requests with openapi3. Remove unsupported uuid format from the openapi spec. Similarly, change url to uri as uri is a supported format and url is not. Co-authored-by: Ondřej Budai <obudai@redhat.com> Signed-off-by: Ondřej Budai <ondrej@budai.cz>
This commit is contained in:
parent
f616becf39
commit
13c79294b6
83 changed files with 4942 additions and 549 deletions
3
go.mod
3
go.mod
|
|
@ -19,7 +19,8 @@ require (
|
|||
github.com/coreos/go-semver v0.3.0
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
|
||||
github.com/deepmap/oapi-codegen v1.8.2
|
||||
github.com/getkin/kin-openapi v0.61.0
|
||||
github.com/getkin/kin-openapi v0.93.0
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
|
|
|
|||
14
go.sum
14
go.sum
|
|
@ -200,8 +200,9 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2
|
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/getkin/kin-openapi v0.61.0 h1:6awGqF5nG5zkVpMsAih1QH4VgzS8phTxECUWIFo7zko=
|
||||
github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
|
||||
github.com/getkin/kin-openapi v0.93.0 h1:fc9z+9VADQla6bEb7V+dtZmr9Gj4qB6ZsD8c3pqEK0E=
|
||||
github.com/getkin/kin-openapi v0.93.0/go.mod h1:LWZfzOd7PRy8GJ1dJ6mCU6tNdSfOwRac1BUPam4aw6Q=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||
|
|
@ -217,8 +218,9 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
|||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
|
||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
|
|
@ -337,6 +339,7 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
|||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
|
|
@ -449,6 +452,8 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW
|
|||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
|
|
@ -496,8 +501,9 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
|
|||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
|
|
@ -549,6 +555,7 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE
|
|||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
|
|
@ -1224,6 +1231,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ const (
|
|||
ErrorInvalidOSTreeParams ServiceErrorCode = 27
|
||||
ErrorTenantNotFound ServiceErrorCode = 28
|
||||
ErrorNoGPGKey ServiceErrorCode = 29
|
||||
ErrorInvalidRequest ServiceErrorCode = 30
|
||||
|
||||
// Internal errors, these are bugs
|
||||
ErrorFailedToInitializeBlueprint ServiceErrorCode = 1000
|
||||
|
|
@ -110,6 +111,7 @@ func getServiceErrors() serviceErrors {
|
|||
serviceError{ErrorInvalidOSTreeParams, http.StatusBadRequest, "Invalid OSTree parameters or parameter combination"},
|
||||
serviceError{ErrorTenantNotFound, http.StatusBadRequest, "Tenant not found in JWT claims"},
|
||||
serviceError{ErrorNoGPGKey, http.StatusBadRequest, "Invalid repository, when check_gpg is set, gpgkey must be specified"},
|
||||
serviceError{ErrorInvalidRequest, http.StatusBadRequest, "Request could not be validated"},
|
||||
|
||||
serviceError{ErrorFailedToInitializeBlueprint, http.StatusInternalServerError, "Failed to initialize blueprint"},
|
||||
serviceError{ErrorFailedToGenerateManifestSeed, http.StatusInternalServerError, "Failed to generate manifest seed"},
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ type List struct {
|
|||
|
||||
// OSTree defines model for OSTree.
|
||||
type OSTree struct {
|
||||
// Can be either a commit (example: 02604b2da6e954bd34b8b82a835e5a77d2b60ffa), or a branch-like reference (example: rhel/8/x86_64/edge)
|
||||
Parent *string `json:"parent,omitempty"`
|
||||
Ref *string `json:"ref,omitempty"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
|
|
@ -661,108 +662,109 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
|||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"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",
|
||||
"fGs+VHoj0q5NBlp+9lC7Mbp9PsyfdmCdlJpe9mbmVZoNmmmixsMw++rWb26rsK2NW1d537QKdR9N+cmg",
|
||||
"PyLzu8cBqncW/nOndNN9oje37fmse2cuxlb26bwy85+1tphk9Our3AL62sLlVf/0quWh6ezmtrdwRmT5",
|
||||
"KibLZ5PRB4wult782ZrdzQUh3UrG6jf8TOthwIZaMec27gfluj4uF6b61cXgwuxOHTK9zIyIZt4Xqj1Y",
|
||||
"1ApX+cVEm4oxys/a+u0Tvb3x27UHftWfadr95bC6vEX+8qRS1u8zw4bdLU/z/Yf2ZERKqPlsLXH3Rps7",
|
||||
"2eHlea+t+858yk+rJ74ztbJ0MC7w/Jv7PLvVypd0sHgs5CawXXzsn1zbzwiNSKWkPdEHe6xn217/ZGI+",
|
||||
"0wlnDfFcuR3fP58MZxeVnseMxyqbXI1b01zL67Wri4G94HdVXrMvsyOidfxF7hF2a5qVaxZv9a7Ryuiv",
|
||||
"E6pVdJ1Nak8+XjwyXMT+affJq7wOMmb/7drlRtMilczrc3tEcOXOd0y/XPZf7cfMXOTGgmBh9fjrxF50",
|
||||
"/cnwvvA8LthTcVGx2/eZp6dyIfdqd4rtebVXvavWRkScX1w+P/Zmutuw2ufdbLtfrTy7D9NxvmV3Bt1s",
|
||||
"56m2hI9ZWydONXquX7Vm0H2YGPXibER0Vz/Bd62bWq1bq1erhQvcaKCrksvsi6uy/8DvOt1uThsW9Web",
|
||||
"LIaVi6qrdKh+Oa9c1OfT5ojU5s3Lizvaqld5vVYb1qvzRv3KatQvCtVq3ZrerWefXA+rmXJt6FnOsl99",
|
||||
"Hl7Zk2XbHpHMiVl6uzUfZuOrnNZ4zU+b5ZuL2rVGOk8ntfus68/6J68Dv59/7LBa3s1f+o7w2r1Gq90R",
|
||||
"brFxPiJZdvn2VKWD7NI7HTYrneq50a3Xb5aT6oTTx/tKeXjv108yYzJhA9TLdXo3dXN5Wy+XHk8rRXzz",
|
||||
"MCJusX8y5nfn83I912GOUe0Wuuc+XT5n+1hcwudC+67zIE4GDZgtYD7sX9Ynb7R8O6w85Fs306I2Itbr",
|
||||
"o1XJXWfGbq7x1i8PKvnHxvk468wmhaYzW1jN1zaystm3p+HCZcP+c6tVN2dv5olz3S/5C+tqRCaLTEtb",
|
||||
"Os+5Dh5fstJltbq8Ob1/ZNXn/rzf1Rr6ZFCZN+pkMe2f+8tX93H+MLuuPfmN5kPlBuWHI9LF91mzdV3h",
|
||||
"Rvnc4xeLYvfkySBdctc/uWKTwW37PO8+MqdqkMbANoYPlcnz1Hu0z5c8nzk9RTcjYk811iFLbXI9n0Lf",
|
||||
"zOD7yo1eepp1p5NOr9uyivenD+1ly398FG/zJzLpXhcfexe113aBP1O32x0RU4wHV9mT4nLce8xU87Pa",
|
||||
"GC56jzlRvn+7nuhvaNp/bmDYuT7tZK70Vr3Zy95dVEqV3LlRdRoXp8aITHPWHR7276oQtrRWq/p2NetN",
|
||||
"e61Ox2rnhndDfHX9sMyJfGt5YXIG3eK8X3+8Me1b1Fx2aoPn1ojMmHft3I6RyQenxfLAzNWum7719szq",
|
||||
"xYfFeb89fbZ6dvbhctZv3pH68m16tyw17nOvtx5+LJ5KG2XfNp+eWZvq7Xy70z/N4LfW3aDniEm3+ueI",
|
||||
"/HlrDsojorxL4/r8I9cTmyhRZc4Xzp14V+kiAR1MpvH+28XykM9jjl3RvL9Lb/ln8D6Vz418TcuVZATx",
|
||||
"5yp585kzD5A44Rlim4gVDfJ1WkdEUK7w/z2MV/6spLhgCLobmKH8v1QInij65BH1pn8ELZs15NgKFiZW",
|
||||
"FDGAoNCswvd1zAAgl2EFB1gVE9aJblW/HpE/POwhBxP0PbaWvZfqVG8TyQT9YqMAs7kbrMCEviMSZyZ0",
|
||||
"OErurOgcCcRcTBAHcxuFh5mg0rDVhKvCoiCIVKtSaZS4cGlXwuKOCP2dUvlODK4LPAtKvmEQt32pAekM",
|
||||
"iZR8tbGdHuR8TpkRt6cysnyJDVH3I9RYFSIcW/bOrQ3BfJSM0SfKLEjCXordzEdBy+cKh9Me+zRubkFa",
|
||||
"bugGqZ8K807cv0VYcpfLWzRssGxj9XEHqr1KMCTLI8rvcRdt3pOfztm9tfHZlL1S9ac49i9PvP9I7tU+",
|
||||
"MY/avRmCTtATQwm6McHYF2CfUKk9UOkTEoCaIxKz/jRQcF0ESVgfgo4DYgaCgPt8RCBDADqchvq6hxeu",
|
||||
"xoYV6Bmm6oqBsjqK4BFhvoOCnh+GTMpQEswRsOFsVSVXOwpUgVeubowAnAf1RihUUzsn38SIeJRzPHbU",
|
||||
"NBcvVK3XhUK3gUsZAiGHgaCWsjLSzK3k51BOaiNFrqj9klytGumOFqsjZ+wWZ74gVNGMH0dnzTfnrdLm",
|
||||
"x5Q9golh3eNQQ2CYC4j4/GNnR76YPmc+IYdy5JvkxCXJ0zy/SmAHufBYKBzF9COqyt12dWZtQtXL2Ht5",
|
||||
"e42au86GczuFjFyxmD0F1Wq1Ws9fv8F61nk+b2avB42ifNa8ZpftBusO8Um3ez/3r2Cv2nJ7Hdp865m5",
|
||||
"1/OccV5802qDRaa0iCNiP7Xuc8Q+zzQfKLUpX6L7DItlXwpCwKAagixg3Fh9uoj8RutxEF2PVG4sGLeC",
|
||||
"Kl1kcEkSE5Puh0P9sHIuaBjDqA6WoNQQFHa5DAkcrCMSJMLCe5lVD+o2AjlVBFBebxVxzufzNFSvVZgX",
|
||||
"zuWZTrPeuO43Urm0lraF66gdxEKx7KZfU+jD8hQDqkUEQA9vZLjOErmwUY3IF2eJfFpLZ1WqWNiKTZmw",
|
||||
"sUZJGOVxWV+GoEAAAoLmIBydBB4ViAisPIFOCQ9bm6gJOJohBiNeKPaEvT7qdmvQa4IZMJCcEvatbDa9",
|
||||
"NY3EWeKWchEuLRFIAeKiRo1l0JGnUmrK93qeg4O+lMwkbLZbX309oq636vzeljYZ6gT3yTxKws7onJb9",
|
||||
"1dibRoB4h+XBS2BDDriATCBDbmNB034Z/rCQuY+7SQLPGu50dGcxwJ/99+Ov+kIKyRSp+BsH1ATY8/9+",
|
||||
"7PcE+sKmDL8FMb+HmAw4wUo4A0oK/wlKpoTOyWofAiYU/xMicE/QwkO6QAZQFXJAdd1nUi02ba0KTCIr",
|
||||
"+9cPGTNy33UhW66NRmRc5LzI0vDMT2y8Kx8W1zB5iUTQjKa8sWqdBKGTBZQpiA6SpIXgVEOdkhTd8Y2N",
|
||||
"Ix1lqr1Gwop4qFw5MpCxb28ukdi+npHc+v2Av+LvRq4AB8QKCizVoqnu5Usbu76WH/b8b9qXzUv6v/yq",
|
||||
"3I8946X9auO1akvYk6BtvvzXbFdkOH6brd9m6yizNdgxPIftV8YJWxb+GSNmYoK5vWHDwIcmDIu15Uqq",
|
||||
"gEqdgF0kIJBBqjQEmBIAx9QX0dV23xEfWTnVcfHbxn1q48J7t+/JmGZwKQKrhvrg5yBW8TEmgFCV/cS6",
|
||||
"70AWdhCDP4RNfcsO0xet/s3193S8fRRoITKeA/EO0TE/53KcFSz8KgRxOv6+qUaXqlvcivLEkZTHqdHW",
|
||||
"HeIPdWk18gh16iHhM8LVz2tE8xQx6ggStt+Szd/kSAPVIr4arFOlWDzqjQ+3z0AmJsgAUIDNwxvl6iwY",
|
||||
"FAkgyYTfUxG4dPEDVVzfzf6tj5/q45pZB5Rya7v3FPP/T13bVo8jlG6jF+hjnQsHBiq3p2fBXRa0gLrY",
|
||||
"ckRMqR8ygIE8RAyph5u6Fv24TnDD4iPNiOj8rRifK8bq+v8BvYi28it68TtG/x2j/78Wo+/Zpjh7p4Bv",
|
||||
"xhR7JmZ9gXbPuMStbD0ko9psDxVANsapPtx/q+qv1xAn7cGPilAThMz4rWb/HTULBP1/T8ngSoCg44BV",
|
||||
"rTOSprWafZ7QgyQokRB99etrAWXru77jJVCuM15Rj4sAVnD/Va+f/w/78INbqV6AzWe/tfi3Fn9Fi9G+",
|
||||
"BEnNXZUED3vIm3BIvNxvExuCU/osT9aSB+GZ+X8xtvhwOe+r5qU4S9QNLx5Tw9eD2/KrC1LbRV/o4bTE",
|
||||
"w20c/vIh9HAmuLqmsgeIpaJfPcjMciri2ClFC2hhYn2EgAtooX8RjWIiiS5Gr9B8BufH+/8NAAD///0e",
|
||||
"w1eRWQAA",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
|
|
|||
|
|
@ -279,6 +279,7 @@ paths:
|
|||
description: ID of the error
|
||||
responses:
|
||||
'200':
|
||||
description: Error description
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
|
|
@ -445,6 +446,9 @@ components:
|
|||
properties:
|
||||
image_builds:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
x-go-type: interface{}
|
||||
koji:
|
||||
$ref: '#/components/schemas/KojiLogs'
|
||||
KojiLogs:
|
||||
|
|
@ -464,6 +468,9 @@ components:
|
|||
properties:
|
||||
manifests:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
x-go-type: interface{}
|
||||
ImageStatus:
|
||||
required:
|
||||
- status
|
||||
|
|
@ -659,15 +666,15 @@ components:
|
|||
description: 'Determines whether a valid subscription is required to access this repository.'
|
||||
baseurl:
|
||||
type: string
|
||||
format: url
|
||||
format: uri
|
||||
example: 'https://cdn.redhat.com/content/dist/rhel8/8/x86_64/baseos/os/'
|
||||
mirrorlist:
|
||||
type: string
|
||||
format: url
|
||||
format: uri
|
||||
example: 'http://mirrorlist.centos.org/?release=8-stream&arch=aarch64&repo=BaseOS'
|
||||
metalink:
|
||||
type: string
|
||||
format: url
|
||||
format: uri
|
||||
example: 'https://mirrors.fedoraproject.org/metalink?repo=fedora-32&arch=x86_64'
|
||||
gpgkey:
|
||||
type: string
|
||||
|
|
@ -865,13 +872,11 @@ components:
|
|||
example: 'rhel/8/x86_64/edge'
|
||||
parent:
|
||||
type: string
|
||||
examples:
|
||||
commit_id:
|
||||
value: '02604b2da6e954bd34b8b82a835e5a77d2b60ffa'
|
||||
summary: A commit ID
|
||||
ref:
|
||||
value: 'rhel/8/x86_64/edge'
|
||||
summary: A branch-like ref
|
||||
description: >
|
||||
Can be either a commit (example:
|
||||
02604b2da6e954bd34b8b82a835e5a77d2b60ffa), or a branch-like
|
||||
reference (example: rhel/8/x86_64/edge)
|
||||
example: 'rhel/8/x86_64/edge'
|
||||
Subscription:
|
||||
type: object
|
||||
required:
|
||||
|
|
@ -890,10 +895,10 @@ components:
|
|||
example: 'my-secret-key'
|
||||
server_url:
|
||||
type: string
|
||||
format: uri
|
||||
example: 'subscription.rhsm.redhat.com'
|
||||
base_url:
|
||||
type: string
|
||||
format: url
|
||||
example: 'http://cdn.redhat.com/'
|
||||
insights:
|
||||
type: boolean
|
||||
|
|
@ -925,7 +930,7 @@ components:
|
|||
properties:
|
||||
server:
|
||||
type: string
|
||||
format: url
|
||||
format: uri
|
||||
example: 'https://koji.fedoraproject.org/kojihub'
|
||||
task_id:
|
||||
type: integer
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/getkin/kin-openapi/openapi3filter"
|
||||
"github.com/getkin/kin-openapi/routers"
|
||||
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"
|
||||
"github.com/google/uuid"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
|
|
@ -30,6 +34,7 @@ type Server struct {
|
|||
workers *worker.Server
|
||||
distros *distroregistry.Registry
|
||||
config ServerConfig
|
||||
router routers.Router
|
||||
|
||||
goroutinesCtx context.Context
|
||||
goroutinesCtxCancel context.CancelFunc
|
||||
|
|
@ -44,10 +49,26 @@ type ServerConfig struct {
|
|||
|
||||
func NewServer(workers *worker.Server, distros *distroregistry.Registry, config ServerConfig) *Server {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
spec, err := GetSwagger()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
loader := openapi3.NewLoader()
|
||||
if err := spec.Validate(loader.Context); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
router, err := legacyrouter.NewRouter(spec)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
server := &Server{
|
||||
workers: workers,
|
||||
distros: distros,
|
||||
config: config,
|
||||
router: router,
|
||||
|
||||
goroutinesCtx: ctx,
|
||||
goroutinesCtxCancel: cancel,
|
||||
|
|
@ -66,11 +87,39 @@ func (s *Server) Handler(path string) http.Handler {
|
|||
handler := apiHandlers{
|
||||
server: s,
|
||||
}
|
||||
RegisterHandlers(e.Group(path, prometheus.MetricsMiddleware), &handler)
|
||||
RegisterHandlers(e.Group(path, prometheus.MetricsMiddleware, s.ValidateRequest), &handler)
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func (s *Server) ValidateRequest(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
request := c.Request()
|
||||
|
||||
// extract route and parameters from request
|
||||
route, params, err := s.router.FindRoute(request)
|
||||
if err != nil {
|
||||
return HTTPErrorWithInternal(ErrorResourceNotFound, err)
|
||||
}
|
||||
|
||||
input := &openapi3filter.RequestValidationInput{
|
||||
Request: request,
|
||||
PathParams: params,
|
||||
Route: route,
|
||||
Options: &openapi3filter.Options{
|
||||
AuthenticationFunc: openapi3filter.NoopAuthenticationFunc,
|
||||
},
|
||||
}
|
||||
|
||||
ctx := request.Context()
|
||||
if err := openapi3filter.ValidateRequest(ctx, input); err != nil {
|
||||
return HTTPErrorWithInternal(ErrorInvalidRequest, err)
|
||||
}
|
||||
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Shutdown() {
|
||||
s.goroutinesCtxCancel()
|
||||
s.goroutinesGroup.Wait()
|
||||
|
|
|
|||
|
|
@ -159,11 +159,11 @@ func TestCompose(t *testing.T) {
|
|||
}
|
||||
}`, test_distro.TestArch3Name), http.StatusBadRequest, `
|
||||
{
|
||||
"href": "/api/image-builder-composer/v2/errors/4",
|
||||
"id": "4",
|
||||
"href": "/api/image-builder-composer/v2/errors/30",
|
||||
"id": "30",
|
||||
"kind": "Error",
|
||||
"code": "IMAGE-BUILDER-COMPOSER-4",
|
||||
"reason": "Unsupported distribution"
|
||||
"code": "IMAGE-BUILDER-COMPOSER-30",
|
||||
"reason": "Request could not be validated"
|
||||
}`, "operation_id")
|
||||
|
||||
// unsupported architecture
|
||||
|
|
@ -207,11 +207,11 @@ func TestCompose(t *testing.T) {
|
|||
}
|
||||
}`, test_distro.TestDistroName, test_distro.TestArch3Name), http.StatusBadRequest, `
|
||||
{
|
||||
"href": "/api/image-builder-composer/v2/errors/6",
|
||||
"id": "6",
|
||||
"href": "/api/image-builder-composer/v2/errors/30",
|
||||
"id": "30",
|
||||
"kind": "Error",
|
||||
"code": "IMAGE-BUILDER-COMPOSER-6",
|
||||
"reason": "Unsupported image type"
|
||||
"code": "IMAGE-BUILDER-COMPOSER-30",
|
||||
"reason": "Request could not be validated"
|
||||
}`, "operation_id")
|
||||
|
||||
// Returns 404, but should be 405; see https://github.com/labstack/echo/issues/1981
|
||||
|
|
@ -945,7 +945,9 @@ func TestImageTypes(t *testing.T) {
|
|||
"rhsm": false
|
||||
}],
|
||||
"upload_options": {
|
||||
"region": "eu-central-1"
|
||||
"region": "eu-central-1",
|
||||
"snapshot_name": "name",
|
||||
"share_with_accounts": ["123456789012","234567890123"]
|
||||
}
|
||||
}
|
||||
}`, test_distro.TestDistroName, test_distro.TestArch3Name, string(v2.ImageTypesAws)), http.StatusCreated, `
|
||||
|
|
|
|||
3
vendor/github.com/getkin/kin-openapi/jsoninfo/field_info.go
generated
vendored
3
vendor/github.com/getkin/kin-openapi/jsoninfo/field_info.go
generated
vendored
|
|
@ -21,6 +21,9 @@ type FieldInfo struct {
|
|||
}
|
||||
|
||||
func AppendFields(fields []FieldInfo, parentIndex []int, t reflect.Type) []FieldInfo {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
// For each field
|
||||
numField := t.NumField()
|
||||
iteration:
|
||||
|
|
|
|||
6
vendor/github.com/getkin/kin-openapi/jsoninfo/marshal_ref.go
generated
vendored
6
vendor/github.com/getkin/kin-openapi/jsoninfo/marshal_ref.go
generated
vendored
|
|
@ -5,7 +5,7 @@ import (
|
|||
)
|
||||
|
||||
func MarshalRef(value string, otherwise interface{}) ([]byte, error) {
|
||||
if len(value) > 0 {
|
||||
if value != "" {
|
||||
return json.Marshal(&refProps{
|
||||
Ref: value,
|
||||
})
|
||||
|
|
@ -17,7 +17,7 @@ func UnmarshalRef(data []byte, destRef *string, destOtherwise interface{}) error
|
|||
refProps := &refProps{}
|
||||
if err := json.Unmarshal(data, refProps); err == nil {
|
||||
ref := refProps.Ref
|
||||
if len(ref) > 0 {
|
||||
if ref != "" {
|
||||
*destRef = ref
|
||||
return nil
|
||||
}
|
||||
|
|
@ -26,5 +26,5 @@ func UnmarshalRef(data []byte, destRef *string, destOtherwise interface{}) error
|
|||
}
|
||||
|
||||
type refProps struct {
|
||||
Ref string `json:"$ref,omitempty"`
|
||||
Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
|
||||
}
|
||||
|
|
|
|||
3
vendor/github.com/getkin/kin-openapi/openapi3/callback.go
generated
vendored
3
vendor/github.com/getkin/kin-openapi/openapi3/callback.go
generated
vendored
|
|
@ -23,7 +23,8 @@ func (c Callbacks) JSONLookup(token string) (interface{}, error) {
|
|||
return ref.Value, nil
|
||||
}
|
||||
|
||||
// Callback is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// Callback is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#callbackObject
|
||||
type Callback map[string]*PathItem
|
||||
|
||||
func (value Callback) Validate(ctx context.Context) error {
|
||||
|
|
|
|||
4
vendor/github.com/getkin/kin-openapi/openapi3/components.go
generated
vendored
4
vendor/github.com/getkin/kin-openapi/openapi3/components.go
generated
vendored
|
|
@ -8,9 +8,11 @@ import (
|
|||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// Components is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// Components is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#componentsObject
|
||||
type Components struct {
|
||||
ExtensionProps
|
||||
|
||||
Schemas Schemas `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
Parameters ParametersMap `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
|
|
|
|||
4
vendor/github.com/getkin/kin-openapi/openapi3/discriminator.go
generated
vendored
4
vendor/github.com/getkin/kin-openapi/openapi3/discriminator.go
generated
vendored
|
|
@ -6,9 +6,11 @@ import (
|
|||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// Discriminator is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// Discriminator is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#discriminatorObject
|
||||
type Discriminator struct {
|
||||
ExtensionProps
|
||||
|
||||
PropertyName string `json:"propertyName" yaml:"propertyName"`
|
||||
Mapping map[string]string `json:"mapping,omitempty" yaml:"mapping,omitempty"`
|
||||
}
|
||||
|
|
|
|||
1
vendor/github.com/getkin/kin-openapi/openapi3/encoding.go
generated
vendored
1
vendor/github.com/getkin/kin-openapi/openapi3/encoding.go
generated
vendored
|
|
@ -8,6 +8,7 @@ import (
|
|||
)
|
||||
|
||||
// Encoding is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#encodingObject
|
||||
type Encoding struct {
|
||||
ExtensionProps
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ func (e Examples) JSONLookup(token string) (interface{}, error) {
|
|||
}
|
||||
|
||||
// Example is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#exampleObject
|
||||
type Example struct {
|
||||
ExtensionProps
|
||||
|
||||
22
vendor/github.com/getkin/kin-openapi/openapi3/external_docs.go
generated
vendored
22
vendor/github.com/getkin/kin-openapi/openapi3/external_docs.go
generated
vendored
|
|
@ -1,15 +1,21 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// ExternalDocs is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// ExternalDocs is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#external-documentation-object
|
||||
type ExternalDocs struct {
|
||||
ExtensionProps
|
||||
|
||||
Description string `json:"description,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
}
|
||||
|
||||
func (e *ExternalDocs) MarshalJSON() ([]byte, error) {
|
||||
|
|
@ -19,3 +25,13 @@ func (e *ExternalDocs) MarshalJSON() ([]byte, error) {
|
|||
func (e *ExternalDocs) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, e)
|
||||
}
|
||||
|
||||
func (e *ExternalDocs) Validate(ctx context.Context) error {
|
||||
if e.URL == "" {
|
||||
return errors.New("url is required")
|
||||
}
|
||||
if _, err := url.Parse(e.URL); err != nil {
|
||||
return fmt.Errorf("url is incorrect: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
74
vendor/github.com/getkin/kin-openapi/openapi3/header.go
generated
vendored
74
vendor/github.com/getkin/kin-openapi/openapi3/header.go
generated
vendored
|
|
@ -2,6 +2,7 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
|
|
@ -24,17 +25,10 @@ func (h Headers) JSONLookup(token string) (interface{}, error) {
|
|||
return ref.Value, nil
|
||||
}
|
||||
|
||||
// Header is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#headerObject
|
||||
type Header struct {
|
||||
ExtensionProps
|
||||
|
||||
// Optional description. Should use CommonMark syntax.
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
|
||||
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
Parameter
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Header)(nil)
|
||||
|
|
@ -43,10 +37,52 @@ func (value *Header) UnmarshalJSON(data []byte) error {
|
|||
return jsoninfo.UnmarshalStrictStruct(data, value)
|
||||
}
|
||||
|
||||
// SerializationMethod returns a header's serialization method.
|
||||
func (value *Header) SerializationMethod() (*SerializationMethod, error) {
|
||||
style := value.Style
|
||||
if style == "" {
|
||||
style = SerializationSimple
|
||||
}
|
||||
explode := false
|
||||
if value.Explode != nil {
|
||||
explode = *value.Explode
|
||||
}
|
||||
return &SerializationMethod{Style: style, Explode: explode}, nil
|
||||
}
|
||||
|
||||
func (value *Header) Validate(ctx context.Context) error {
|
||||
if v := value.Schema; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
if value.Name != "" {
|
||||
return errors.New("header 'name' MUST NOT be specified, it is given in the corresponding headers map")
|
||||
}
|
||||
if value.In != "" {
|
||||
return errors.New("header 'in' MUST NOT be specified, it is implicitly in header")
|
||||
}
|
||||
|
||||
// Validate a parameter's serialization method.
|
||||
sm, err := value.SerializationMethod()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if smSupported := false ||
|
||||
sm.Style == SerializationSimple && !sm.Explode ||
|
||||
sm.Style == SerializationSimple && sm.Explode; !smSupported {
|
||||
e := fmt.Errorf("serialization method with style=%q and explode=%v is not supported by a header parameter", sm.Style, sm.Explode)
|
||||
return fmt.Errorf("header schema is invalid: %v", e)
|
||||
}
|
||||
|
||||
if (value.Schema == nil) == (value.Content == nil) {
|
||||
e := fmt.Errorf("parameter must contain exactly one of content and schema: %v", value)
|
||||
return fmt.Errorf("header schema is invalid: %v", e)
|
||||
}
|
||||
if schema := value.Schema; schema != nil {
|
||||
if err := schema.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("header schema is invalid: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if content := value.Content; content != nil {
|
||||
if err := content.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("header content is invalid: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
@ -61,8 +97,20 @@ func (value Header) JSONLookup(token string) (interface{}, error) {
|
|||
}
|
||||
return value.Schema.Value, nil
|
||||
}
|
||||
case "name":
|
||||
return value.Name, nil
|
||||
case "in":
|
||||
return value.In, nil
|
||||
case "description":
|
||||
return value.Description, nil
|
||||
case "style":
|
||||
return value.Style, nil
|
||||
case "explode":
|
||||
return value.Explode, nil
|
||||
case "allowEmptyValue":
|
||||
return value.AllowEmptyValue, nil
|
||||
case "allowReserved":
|
||||
return value.AllowReserved, nil
|
||||
case "deprecated":
|
||||
return value.Deprecated, nil
|
||||
case "required":
|
||||
|
|
|
|||
12
vendor/github.com/getkin/kin-openapi/openapi3/info.go
generated
vendored
12
vendor/github.com/getkin/kin-openapi/openapi3/info.go
generated
vendored
|
|
@ -7,9 +7,11 @@ import (
|
|||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// Info is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// Info is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#infoObject
|
||||
type Info struct {
|
||||
ExtensionProps
|
||||
|
||||
Title string `json:"title" yaml:"title"` // Required
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"`
|
||||
|
|
@ -50,9 +52,11 @@ func (value *Info) Validate(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Contact is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// Contact is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#contactObject
|
||||
type Contact struct {
|
||||
ExtensionProps
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
Email string `json:"email,omitempty" yaml:"email,omitempty"`
|
||||
|
|
@ -70,9 +74,11 @@ func (value *Contact) Validate(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// License is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// License is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#licenseObject
|
||||
type License struct {
|
||||
ExtensionProps
|
||||
|
||||
Name string `json:"name" yaml:"name"` // Required
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
}
|
||||
|
|
|
|||
369
vendor/github.com/getkin/kin-openapi/openapi3/internalize_refs.go
generated
vendored
Normal file
369
vendor/github.com/getkin/kin-openapi/openapi3/internalize_refs.go
generated
vendored
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RefNameResolver func(string) string
|
||||
|
||||
// DefaultRefResolver is a default implementation of refNameResolver for the
|
||||
// InternalizeRefs function.
|
||||
//
|
||||
// If a reference points to an element inside a document, it returns the last
|
||||
// element in the reference using filepath.Base. Otherwise if the reference points
|
||||
// to a file, it returns the file name trimmed of all extensions.
|
||||
func DefaultRefNameResolver(ref string) string {
|
||||
if ref == "" {
|
||||
return ""
|
||||
}
|
||||
split := strings.SplitN(ref, "#", 2)
|
||||
if len(split) == 2 {
|
||||
return filepath.Base(split[1])
|
||||
}
|
||||
ref = split[0]
|
||||
for ext := filepath.Ext(ref); len(ext) > 0; ext = filepath.Ext(ref) {
|
||||
ref = strings.TrimSuffix(ref, ext)
|
||||
}
|
||||
return filepath.Base(ref)
|
||||
}
|
||||
|
||||
func schemaNames(s Schemas) []string {
|
||||
out := make([]string, 0, len(s))
|
||||
for i := range s {
|
||||
out = append(out, i)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func parametersMapNames(s ParametersMap) []string {
|
||||
out := make([]string, 0, len(s))
|
||||
for i := range s {
|
||||
out = append(out, i)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func isExternalRef(ref string) bool {
|
||||
return ref != "" && !strings.HasPrefix(ref, "#/components/")
|
||||
}
|
||||
|
||||
func (doc *T) addSchemaToSpec(s *SchemaRef, refNameResolver RefNameResolver) {
|
||||
if s == nil || !isExternalRef(s.Ref) {
|
||||
return
|
||||
}
|
||||
|
||||
name := refNameResolver(s.Ref)
|
||||
if _, ok := doc.Components.Schemas[name]; ok {
|
||||
s.Ref = "#/components/schemas/" + name
|
||||
return
|
||||
}
|
||||
|
||||
if doc.Components.Schemas == nil {
|
||||
doc.Components.Schemas = make(Schemas)
|
||||
}
|
||||
doc.Components.Schemas[name] = s.Value.NewRef()
|
||||
s.Ref = "#/components/schemas/" + name
|
||||
}
|
||||
|
||||
func (doc *T) addParameterToSpec(p *ParameterRef, refNameResolver RefNameResolver) {
|
||||
if p == nil || !isExternalRef(p.Ref) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(p.Ref)
|
||||
if _, ok := doc.Components.Parameters[name]; ok {
|
||||
p.Ref = "#/components/parameters/" + name
|
||||
return
|
||||
}
|
||||
|
||||
if doc.Components.Parameters == nil {
|
||||
doc.Components.Parameters = make(ParametersMap)
|
||||
}
|
||||
doc.Components.Parameters[name] = &ParameterRef{Value: p.Value}
|
||||
p.Ref = "#/components/parameters/" + name
|
||||
}
|
||||
|
||||
func (doc *T) addHeaderToSpec(h *HeaderRef, refNameResolver RefNameResolver) {
|
||||
if h == nil || !isExternalRef(h.Ref) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(h.Ref)
|
||||
if _, ok := doc.Components.Headers[name]; ok {
|
||||
h.Ref = "#/components/headers/" + name
|
||||
return
|
||||
}
|
||||
if doc.Components.Headers == nil {
|
||||
doc.Components.Headers = make(Headers)
|
||||
}
|
||||
doc.Components.Headers[name] = &HeaderRef{Value: h.Value}
|
||||
h.Ref = "#/components/headers/" + name
|
||||
}
|
||||
|
||||
func (doc *T) addRequestBodyToSpec(r *RequestBodyRef, refNameResolver RefNameResolver) {
|
||||
if r == nil || !isExternalRef(r.Ref) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(r.Ref)
|
||||
if _, ok := doc.Components.RequestBodies[name]; ok {
|
||||
r.Ref = "#/components/requestBodies/" + name
|
||||
return
|
||||
}
|
||||
if doc.Components.RequestBodies == nil {
|
||||
doc.Components.RequestBodies = make(RequestBodies)
|
||||
}
|
||||
doc.Components.RequestBodies[name] = &RequestBodyRef{Value: r.Value}
|
||||
r.Ref = "#/components/requestBodies/" + name
|
||||
}
|
||||
|
||||
func (doc *T) addResponseToSpec(r *ResponseRef, refNameResolver RefNameResolver) {
|
||||
if r == nil || !isExternalRef(r.Ref) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(r.Ref)
|
||||
if _, ok := doc.Components.Responses[name]; ok {
|
||||
r.Ref = "#/components/responses/" + name
|
||||
return
|
||||
}
|
||||
if doc.Components.Responses == nil {
|
||||
doc.Components.Responses = make(Responses)
|
||||
}
|
||||
doc.Components.Responses[name] = &ResponseRef{Value: r.Value}
|
||||
r.Ref = "#/components/responses/" + name
|
||||
|
||||
}
|
||||
|
||||
func (doc *T) addSecuritySchemeToSpec(ss *SecuritySchemeRef, refNameResolver RefNameResolver) {
|
||||
if ss == nil || !isExternalRef(ss.Ref) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(ss.Ref)
|
||||
if _, ok := doc.Components.SecuritySchemes[name]; ok {
|
||||
ss.Ref = "#/components/securitySchemes/" + name
|
||||
return
|
||||
}
|
||||
if doc.Components.SecuritySchemes == nil {
|
||||
doc.Components.SecuritySchemes = make(SecuritySchemes)
|
||||
}
|
||||
doc.Components.SecuritySchemes[name] = &SecuritySchemeRef{Value: ss.Value}
|
||||
ss.Ref = "#/components/securitySchemes/" + name
|
||||
|
||||
}
|
||||
|
||||
func (doc *T) addExampleToSpec(e *ExampleRef, refNameResolver RefNameResolver) {
|
||||
if e == nil || !isExternalRef(e.Ref) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(e.Ref)
|
||||
if _, ok := doc.Components.Examples[name]; ok {
|
||||
e.Ref = "#/components/examples/" + name
|
||||
return
|
||||
}
|
||||
if doc.Components.Examples == nil {
|
||||
doc.Components.Examples = make(Examples)
|
||||
}
|
||||
doc.Components.Examples[name] = &ExampleRef{Value: e.Value}
|
||||
e.Ref = "#/components/examples/" + name
|
||||
|
||||
}
|
||||
|
||||
func (doc *T) addLinkToSpec(l *LinkRef, refNameResolver RefNameResolver) {
|
||||
if l == nil || !isExternalRef(l.Ref) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(l.Ref)
|
||||
if _, ok := doc.Components.Links[name]; ok {
|
||||
l.Ref = "#/components/links/" + name
|
||||
return
|
||||
}
|
||||
if doc.Components.Links == nil {
|
||||
doc.Components.Links = make(Links)
|
||||
}
|
||||
doc.Components.Links[name] = &LinkRef{Value: l.Value}
|
||||
l.Ref = "#/components/links/" + name
|
||||
|
||||
}
|
||||
|
||||
func (doc *T) addCallbackToSpec(c *CallbackRef, refNameResolver RefNameResolver) {
|
||||
if c == nil || !isExternalRef(c.Ref) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(c.Ref)
|
||||
if _, ok := doc.Components.Callbacks[name]; ok {
|
||||
c.Ref = "#/components/callbacks/" + name
|
||||
}
|
||||
if doc.Components.Callbacks == nil {
|
||||
doc.Components.Callbacks = make(Callbacks)
|
||||
}
|
||||
doc.Components.Callbacks[name] = &CallbackRef{Value: c.Value}
|
||||
c.Ref = "#/components/callbacks/" + name
|
||||
}
|
||||
|
||||
func (doc *T) derefSchema(s *Schema, refNameResolver RefNameResolver) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, list := range []SchemaRefs{s.AllOf, s.AnyOf, s.OneOf} {
|
||||
for _, s2 := range list {
|
||||
doc.addSchemaToSpec(s2, refNameResolver)
|
||||
if s2 != nil {
|
||||
doc.derefSchema(s2.Value, refNameResolver)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, s2 := range s.Properties {
|
||||
doc.addSchemaToSpec(s2, refNameResolver)
|
||||
if s2 != nil {
|
||||
doc.derefSchema(s2.Value, refNameResolver)
|
||||
}
|
||||
}
|
||||
for _, ref := range []*SchemaRef{s.Not, s.AdditionalProperties, s.Items} {
|
||||
doc.addSchemaToSpec(ref, refNameResolver)
|
||||
if ref != nil {
|
||||
doc.derefSchema(ref.Value, refNameResolver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefHeaders(hs Headers, refNameResolver RefNameResolver) {
|
||||
for _, h := range hs {
|
||||
doc.addHeaderToSpec(h, refNameResolver)
|
||||
doc.derefParameter(h.Value.Parameter, refNameResolver)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefExamples(es Examples, refNameResolver RefNameResolver) {
|
||||
for _, e := range es {
|
||||
doc.addExampleToSpec(e, refNameResolver)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefContent(c Content, refNameResolver RefNameResolver) {
|
||||
for _, mediatype := range c {
|
||||
doc.addSchemaToSpec(mediatype.Schema, refNameResolver)
|
||||
if mediatype.Schema != nil {
|
||||
doc.derefSchema(mediatype.Schema.Value, refNameResolver)
|
||||
}
|
||||
doc.derefExamples(mediatype.Examples, refNameResolver)
|
||||
for _, e := range mediatype.Encoding {
|
||||
doc.derefHeaders(e.Headers, refNameResolver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefLinks(ls Links, refNameResolver RefNameResolver) {
|
||||
for _, l := range ls {
|
||||
doc.addLinkToSpec(l, refNameResolver)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefResponses(es Responses, refNameResolver RefNameResolver) {
|
||||
for _, e := range es {
|
||||
doc.addResponseToSpec(e, refNameResolver)
|
||||
if e.Value != nil {
|
||||
doc.derefHeaders(e.Value.Headers, refNameResolver)
|
||||
doc.derefContent(e.Value.Content, refNameResolver)
|
||||
doc.derefLinks(e.Value.Links, refNameResolver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefParameter(p Parameter, refNameResolver RefNameResolver) {
|
||||
doc.addSchemaToSpec(p.Schema, refNameResolver)
|
||||
doc.derefContent(p.Content, refNameResolver)
|
||||
if p.Schema != nil {
|
||||
doc.derefSchema(p.Schema.Value, refNameResolver)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefRequestBody(r RequestBody, refNameResolver RefNameResolver) {
|
||||
doc.derefContent(r.Content, refNameResolver)
|
||||
}
|
||||
|
||||
func (doc *T) derefPaths(paths map[string]*PathItem, refNameResolver RefNameResolver) {
|
||||
for _, ops := range paths {
|
||||
// inline full operations
|
||||
ops.Ref = ""
|
||||
|
||||
for _, op := range ops.Operations() {
|
||||
doc.addRequestBodyToSpec(op.RequestBody, refNameResolver)
|
||||
if op.RequestBody != nil && op.RequestBody.Value != nil {
|
||||
doc.derefRequestBody(*op.RequestBody.Value, refNameResolver)
|
||||
}
|
||||
for _, cb := range op.Callbacks {
|
||||
doc.addCallbackToSpec(cb, refNameResolver)
|
||||
if cb.Value != nil {
|
||||
doc.derefPaths(*cb.Value, refNameResolver)
|
||||
}
|
||||
}
|
||||
doc.derefResponses(op.Responses, refNameResolver)
|
||||
for _, param := range op.Parameters {
|
||||
doc.addParameterToSpec(param, refNameResolver)
|
||||
if param.Value != nil {
|
||||
doc.derefParameter(*param.Value, refNameResolver)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InternalizeRefs removes all references to external files from the spec and moves them
|
||||
// to the components section.
|
||||
//
|
||||
// refNameResolver takes in references to returns a name to store the reference under locally.
|
||||
// It MUST return a unique name for each reference type.
|
||||
// A default implementation is provided that will suffice for most use cases. See the function
|
||||
// documention for more details.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// doc.InternalizeRefs(context.Background(), nil)
|
||||
func (doc *T) InternalizeRefs(ctx context.Context, refNameResolver func(ref string) string) {
|
||||
if refNameResolver == nil {
|
||||
refNameResolver = DefaultRefNameResolver
|
||||
}
|
||||
|
||||
// Handle components section
|
||||
names := schemaNames(doc.Components.Schemas)
|
||||
for _, name := range names {
|
||||
schema := doc.Components.Schemas[name]
|
||||
doc.addSchemaToSpec(schema, refNameResolver)
|
||||
if schema != nil {
|
||||
schema.Ref = "" // always dereference the top level
|
||||
doc.derefSchema(schema.Value, refNameResolver)
|
||||
}
|
||||
}
|
||||
names = parametersMapNames(doc.Components.Parameters)
|
||||
for _, name := range names {
|
||||
p := doc.Components.Parameters[name]
|
||||
doc.addParameterToSpec(p, refNameResolver)
|
||||
if p != nil && p.Value != nil {
|
||||
p.Ref = "" // always dereference the top level
|
||||
doc.derefParameter(*p.Value, refNameResolver)
|
||||
}
|
||||
}
|
||||
doc.derefHeaders(doc.Components.Headers, refNameResolver)
|
||||
for _, req := range doc.Components.RequestBodies {
|
||||
doc.addRequestBodyToSpec(req, refNameResolver)
|
||||
if req != nil && req.Value != nil {
|
||||
req.Ref = "" // always dereference the top level
|
||||
doc.derefRequestBody(*req.Value, refNameResolver)
|
||||
}
|
||||
}
|
||||
doc.derefResponses(doc.Components.Responses, refNameResolver)
|
||||
for _, ss := range doc.Components.SecuritySchemes {
|
||||
doc.addSecuritySchemeToSpec(ss, refNameResolver)
|
||||
}
|
||||
doc.derefExamples(doc.Components.Examples, refNameResolver)
|
||||
doc.derefLinks(doc.Components.Links, refNameResolver)
|
||||
for _, cb := range doc.Components.Callbacks {
|
||||
doc.addCallbackToSpec(cb, refNameResolver)
|
||||
if cb != nil && cb.Value != nil {
|
||||
cb.Ref = "" // always dereference the top level
|
||||
doc.derefPaths(*cb.Value, refNameResolver)
|
||||
}
|
||||
}
|
||||
|
||||
doc.derefPaths(doc.Paths, refNameResolver)
|
||||
}
|
||||
6
vendor/github.com/getkin/kin-openapi/openapi3/link.go
generated
vendored
6
vendor/github.com/getkin/kin-openapi/openapi3/link.go
generated
vendored
|
|
@ -25,11 +25,13 @@ func (l Links) JSONLookup(token string) (interface{}, error) {
|
|||
|
||||
var _ jsonpointer.JSONPointable = (*Links)(nil)
|
||||
|
||||
// Link is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// Link is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#linkObject
|
||||
type Link struct {
|
||||
ExtensionProps
|
||||
OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
||||
|
||||
OperationRef string `json:"operationRef,omitempty" yaml:"operationRef,omitempty"`
|
||||
OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Parameters map[string]interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
Server *Server `json:"server,omitempty" yaml:"server,omitempty"`
|
||||
|
|
|
|||
62
vendor/github.com/getkin/kin-openapi/openapi3/loader.go
generated
vendored
62
vendor/github.com/getkin/kin-openapi/openapi3/loader.go
generated
vendored
|
|
@ -5,8 +5,6 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
|
@ -31,10 +29,12 @@ type Loader struct {
|
|||
IsExternalRefsAllowed bool
|
||||
|
||||
// ReadFromURIFunc allows overriding the any file/URL reading func
|
||||
ReadFromURIFunc func(loader *Loader, url *url.URL) ([]byte, error)
|
||||
ReadFromURIFunc ReadFromURIFunc
|
||||
|
||||
Context context.Context
|
||||
|
||||
rootDir string
|
||||
|
||||
visitedPathItemRefs map[string]struct{}
|
||||
|
||||
visitedDocuments map[string]*T
|
||||
|
|
@ -66,6 +66,7 @@ func (loader *Loader) LoadFromURI(location *url.URL) (*T, error) {
|
|||
|
||||
// LoadFromFile loads a spec from a local file path
|
||||
func (loader *Loader) LoadFromFile(location string) (*T, error) {
|
||||
loader.rootDir = path.Dir(location)
|
||||
return loader.LoadFromURI(&url.URL{Path: filepath.ToSlash(location)})
|
||||
}
|
||||
|
||||
|
|
@ -118,22 +119,7 @@ func (loader *Loader) readURL(location *url.URL) ([]byte, error) {
|
|||
if f := loader.ReadFromURIFunc; f != nil {
|
||||
return f(loader, location)
|
||||
}
|
||||
|
||||
if location.Scheme != "" && location.Host != "" {
|
||||
resp, err := http.Get(location.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode > 399 {
|
||||
return nil, fmt.Errorf("error loading %q: request returned status code %d", location.String(), resp.StatusCode)
|
||||
}
|
||||
return ioutil.ReadAll(resp.Body)
|
||||
}
|
||||
if location.Scheme != "" || location.Host != "" || location.RawQuery != "" {
|
||||
return nil, fmt.Errorf("unsupported URI: %q", location.String())
|
||||
}
|
||||
return ioutil.ReadFile(location.Path)
|
||||
return DefaultReadFromURI(loader, location)
|
||||
}
|
||||
|
||||
// LoadFromData loads a spec from a byte array
|
||||
|
|
@ -305,6 +291,9 @@ func (loader *Loader) resolveComponent(
|
|||
}
|
||||
var cursor interface{}
|
||||
if cursor, err = drill(doc); err != nil {
|
||||
if path == nil {
|
||||
return nil, err
|
||||
}
|
||||
var err2 error
|
||||
data, err2 := loader.readURL(path)
|
||||
if err2 != nil {
|
||||
|
|
@ -346,6 +335,14 @@ func (loader *Loader) resolveComponent(
|
|||
}
|
||||
|
||||
func drillIntoField(cursor interface{}, fieldName string) (interface{}, error) {
|
||||
// Special case due to multijson
|
||||
if s, ok := cursor.(*SchemaRef); ok && fieldName == "additionalProperties" {
|
||||
if ap := s.Value.AdditionalPropertiesAllowed; ap != nil {
|
||||
return *ap, nil
|
||||
}
|
||||
return s.Value.AdditionalProperties, nil
|
||||
}
|
||||
|
||||
switch val := reflect.Indirect(reflect.ValueOf(cursor)); val.Kind() {
|
||||
case reflect.Map:
|
||||
elementValue := val.MapIndex(reflect.ValueOf(fieldName))
|
||||
|
|
@ -372,6 +369,10 @@ func drillIntoField(cursor interface{}, fieldName string) (interface{}, error) {
|
|||
field := val.Type().Field(i)
|
||||
tagValue := field.Tag.Get("yaml")
|
||||
yamlKey := strings.Split(tagValue, ",")[0]
|
||||
if yamlKey == "-" {
|
||||
tagValue := field.Tag.Get("multijson")
|
||||
yamlKey = strings.Split(tagValue, ",")[0]
|
||||
}
|
||||
if yamlKey == fieldName {
|
||||
return val.Field(i).Interface(), nil
|
||||
}
|
||||
|
|
@ -400,6 +401,14 @@ func drillIntoField(cursor interface{}, fieldName string) (interface{}, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (loader *Loader) documentPathForRecursiveRef(current *url.URL, resolvedRef string) *url.URL {
|
||||
if loader.rootDir == "" {
|
||||
return current
|
||||
}
|
||||
return &url.URL{Path: path.Join(loader.rootDir, resolvedRef)}
|
||||
|
||||
}
|
||||
|
||||
func (loader *Loader) resolveRef(doc *T, ref string, path *url.URL) (*T, string, *url.URL, error) {
|
||||
if ref != "" && ref[0] == '#' {
|
||||
return doc, ref, path, nil
|
||||
|
|
@ -459,6 +468,7 @@ func (loader *Loader) resolveHeaderRef(doc *T, component *HeaderRef, documentPat
|
|||
return err
|
||||
}
|
||||
component.Value = resolved.Value
|
||||
documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref)
|
||||
}
|
||||
}
|
||||
value := component.Value
|
||||
|
|
@ -506,6 +516,7 @@ func (loader *Loader) resolveParameterRef(doc *T, component *ParameterRef, docum
|
|||
return err
|
||||
}
|
||||
component.Value = resolved.Value
|
||||
documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref)
|
||||
}
|
||||
}
|
||||
value := component.Value
|
||||
|
|
@ -562,6 +573,7 @@ func (loader *Loader) resolveRequestBodyRef(doc *T, component *RequestBodyRef, d
|
|||
return err
|
||||
}
|
||||
component.Value = resolved.Value
|
||||
documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref)
|
||||
}
|
||||
}
|
||||
value := component.Value
|
||||
|
|
@ -617,6 +629,7 @@ func (loader *Loader) resolveResponseRef(doc *T, component *ResponseRef, documen
|
|||
return err
|
||||
}
|
||||
component.Value = resolved.Value
|
||||
documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref)
|
||||
}
|
||||
}
|
||||
value := component.Value
|
||||
|
|
@ -686,6 +699,7 @@ func (loader *Loader) resolveSchemaRef(doc *T, component *SchemaRef, documentPat
|
|||
return err
|
||||
}
|
||||
component.Value = resolved.Value
|
||||
documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref)
|
||||
}
|
||||
}
|
||||
value := component.Value
|
||||
|
|
@ -749,7 +763,7 @@ func (loader *Loader) resolveSecuritySchemeRef(doc *T, component *SecurityScheme
|
|||
if ref := component.Ref; ref != "" {
|
||||
if isSingleRefElement(ref) {
|
||||
var scheme SecurityScheme
|
||||
if documentPath, err = loader.loadSingleElementFromURI(ref, documentPath, &scheme); err != nil {
|
||||
if _, err = loader.loadSingleElementFromURI(ref, documentPath, &scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
component.Value = &scheme
|
||||
|
|
@ -763,6 +777,7 @@ func (loader *Loader) resolveSecuritySchemeRef(doc *T, component *SecurityScheme
|
|||
return err
|
||||
}
|
||||
component.Value = resolved.Value
|
||||
_ = loader.documentPathForRecursiveRef(documentPath, resolved.Ref)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
@ -785,7 +800,7 @@ func (loader *Loader) resolveExampleRef(doc *T, component *ExampleRef, documentP
|
|||
if ref := component.Ref; ref != "" {
|
||||
if isSingleRefElement(ref) {
|
||||
var example Example
|
||||
if documentPath, err = loader.loadSingleElementFromURI(ref, documentPath, &example); err != nil {
|
||||
if _, err = loader.loadSingleElementFromURI(ref, documentPath, &example); err != nil {
|
||||
return err
|
||||
}
|
||||
component.Value = &example
|
||||
|
|
@ -799,6 +814,7 @@ func (loader *Loader) resolveExampleRef(doc *T, component *ExampleRef, documentP
|
|||
return err
|
||||
}
|
||||
component.Value = resolved.Value
|
||||
_ = loader.documentPathForRecursiveRef(documentPath, resolved.Ref)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
@ -826,6 +842,7 @@ func (loader *Loader) resolveCallbackRef(doc *T, component *CallbackRef, documen
|
|||
return err
|
||||
}
|
||||
component.Value = resolved.Value
|
||||
documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref)
|
||||
}
|
||||
}
|
||||
value := component.Value
|
||||
|
|
@ -909,7 +926,7 @@ func (loader *Loader) resolveLinkRef(doc *T, component *LinkRef, documentPath *u
|
|||
if ref := component.Ref; ref != "" {
|
||||
if isSingleRefElement(ref) {
|
||||
var link Link
|
||||
if documentPath, err = loader.loadSingleElementFromURI(ref, documentPath, &link); err != nil {
|
||||
if _, err = loader.loadSingleElementFromURI(ref, documentPath, &link); err != nil {
|
||||
return err
|
||||
}
|
||||
component.Value = &link
|
||||
|
|
@ -923,6 +940,7 @@ func (loader *Loader) resolveLinkRef(doc *T, component *LinkRef, documentPath *u
|
|||
return err
|
||||
}
|
||||
component.Value = resolved.Value
|
||||
_ = loader.documentPathForRecursiveRef(documentPath, resolved.Ref)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
104
vendor/github.com/getkin/kin-openapi/openapi3/loader_uri_reader.go
generated
vendored
Normal file
104
vendor/github.com/getkin/kin-openapi/openapi3/loader_uri_reader.go
generated
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// ReadFromURIFunc defines a function which reads the contents of a resource
|
||||
// located at a URI.
|
||||
type ReadFromURIFunc func(loader *Loader, url *url.URL) ([]byte, error)
|
||||
|
||||
// ErrURINotSupported indicates the ReadFromURIFunc does not know how to handle a
|
||||
// given URI.
|
||||
var ErrURINotSupported = errors.New("unsupported URI")
|
||||
|
||||
// ReadFromURIs returns a ReadFromURIFunc which tries to read a URI using the
|
||||
// given reader functions, in the same order. If a reader function does not
|
||||
// support the URI and returns ErrURINotSupported, the next function is checked
|
||||
// until a match is found, or the URI is not supported by any.
|
||||
func ReadFromURIs(readers ...ReadFromURIFunc) ReadFromURIFunc {
|
||||
return func(loader *Loader, url *url.URL) ([]byte, error) {
|
||||
for i := range readers {
|
||||
buf, err := readers[i](loader, url)
|
||||
if err == ErrURINotSupported {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
return nil, ErrURINotSupported
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultReadFromURI returns a caching ReadFromURIFunc which can read remote
|
||||
// HTTP URIs and local file URIs.
|
||||
var DefaultReadFromURI = URIMapCache(ReadFromURIs(ReadFromHTTP(http.DefaultClient), ReadFromFile))
|
||||
|
||||
// ReadFromHTTP returns a ReadFromURIFunc which uses the given http.Client to
|
||||
// read the contents from a remote HTTP URI. This client may be customized to
|
||||
// implement timeouts, RFC 7234 caching, etc.
|
||||
func ReadFromHTTP(cl *http.Client) ReadFromURIFunc {
|
||||
return func(loader *Loader, location *url.URL) ([]byte, error) {
|
||||
if location.Scheme == "" || location.Host == "" {
|
||||
return nil, ErrURINotSupported
|
||||
}
|
||||
req, err := http.NewRequest("GET", location.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := cl.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode > 399 {
|
||||
return nil, fmt.Errorf("error loading %q: request returned status code %d", location.String(), resp.StatusCode)
|
||||
}
|
||||
return ioutil.ReadAll(resp.Body)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadFromFile is a ReadFromURIFunc which reads local file URIs.
|
||||
func ReadFromFile(loader *Loader, location *url.URL) ([]byte, error) {
|
||||
if location.Host != "" {
|
||||
return nil, ErrURINotSupported
|
||||
}
|
||||
if location.Scheme != "" && location.Scheme != "file" {
|
||||
return nil, ErrURINotSupported
|
||||
}
|
||||
return ioutil.ReadFile(location.Path)
|
||||
}
|
||||
|
||||
// URIMapCache returns a ReadFromURIFunc that caches the contents read from URI
|
||||
// locations in a simple map. This cache implementation is suitable for
|
||||
// short-lived processes such as command-line tools which process OpenAPI
|
||||
// documents.
|
||||
func URIMapCache(reader ReadFromURIFunc) ReadFromURIFunc {
|
||||
cache := map[string][]byte{}
|
||||
return func(loader *Loader, location *url.URL) (buf []byte, err error) {
|
||||
if location.Scheme == "" || location.Scheme == "file" {
|
||||
if !filepath.IsAbs(location.Path) {
|
||||
// Do not cache relative file paths; this can cause trouble if
|
||||
// the current working directory changes when processing
|
||||
// multiple top-level documents.
|
||||
return reader(loader, location)
|
||||
}
|
||||
}
|
||||
uri := location.String()
|
||||
var ok bool
|
||||
if buf, ok = cache[uri]; ok {
|
||||
return
|
||||
}
|
||||
if buf, err = reader(loader, location); err != nil {
|
||||
return
|
||||
}
|
||||
cache[uri] = buf
|
||||
return
|
||||
}
|
||||
}
|
||||
1
vendor/github.com/getkin/kin-openapi/openapi3/media_type.go
generated
vendored
1
vendor/github.com/getkin/kin-openapi/openapi3/media_type.go
generated
vendored
|
|
@ -8,6 +8,7 @@ import (
|
|||
)
|
||||
|
||||
// MediaType is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#mediaTypeObject
|
||||
type MediaType struct {
|
||||
ExtensionProps
|
||||
|
||||
|
|
|
|||
20
vendor/github.com/getkin/kin-openapi/openapi3/openapi3.go
generated
vendored
20
vendor/github.com/getkin/kin-openapi/openapi3/openapi3.go
generated
vendored
|
|
@ -9,8 +9,10 @@ import (
|
|||
)
|
||||
|
||||
// T is the root of an OpenAPI v3 document
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oasObject
|
||||
type T struct {
|
||||
ExtensionProps
|
||||
|
||||
OpenAPI string `json:"openapi" yaml:"openapi"` // Required
|
||||
Components Components `json:"components,omitempty" yaml:"components,omitempty"`
|
||||
Info *Info `json:"info" yaml:"info"` // Required
|
||||
|
|
@ -101,5 +103,23 @@ func (value *T) Validate(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
wrap := func(e error) error { return fmt.Errorf("invalid tags: %w", e) }
|
||||
if v := value.Tags; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
wrap := func(e error) error { return fmt.Errorf("invalid external docs: %w", e) }
|
||||
if v := value.ExternalDocs; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
7
vendor/github.com/getkin/kin-openapi/openapi3/operation.go
generated
vendored
7
vendor/github.com/getkin/kin-openapi/openapi3/operation.go
generated
vendored
|
|
@ -3,6 +3,7 @@ package openapi3
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
|
|
@ -10,6 +11,7 @@ import (
|
|||
)
|
||||
|
||||
// Operation represents "operation" specified by" OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object
|
||||
type Operation struct {
|
||||
ExtensionProps
|
||||
|
||||
|
|
@ -138,5 +140,10 @@ func (value *Operation) Validate(ctx context.Context) error {
|
|||
} else {
|
||||
return errors.New("value of responses must be an object")
|
||||
}
|
||||
if v := value.ExternalDocs; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("invalid external docs: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
43
vendor/github.com/getkin/kin-openapi/openapi3/parameter.go
generated
vendored
43
vendor/github.com/getkin/kin-openapi/openapi3/parameter.go
generated
vendored
|
|
@ -83,8 +83,10 @@ func (value Parameters) Validate(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// Parameter is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#parameterObject
|
||||
type Parameter struct {
|
||||
ExtensionProps
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
In string `json:"in,omitempty" yaml:"in,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
|
|
@ -167,42 +169,42 @@ func (parameter *Parameter) UnmarshalJSON(data []byte) error {
|
|||
return jsoninfo.UnmarshalStrictStruct(data, parameter)
|
||||
}
|
||||
|
||||
func (parameter Parameter) JSONLookup(token string) (interface{}, error) {
|
||||
func (value Parameter) JSONLookup(token string) (interface{}, error) {
|
||||
switch token {
|
||||
case "schema":
|
||||
if parameter.Schema != nil {
|
||||
if parameter.Schema.Ref != "" {
|
||||
return &Ref{Ref: parameter.Schema.Ref}, nil
|
||||
if value.Schema != nil {
|
||||
if value.Schema.Ref != "" {
|
||||
return &Ref{Ref: value.Schema.Ref}, nil
|
||||
}
|
||||
return parameter.Schema.Value, nil
|
||||
return value.Schema.Value, nil
|
||||
}
|
||||
case "name":
|
||||
return parameter.Name, nil
|
||||
return value.Name, nil
|
||||
case "in":
|
||||
return parameter.In, nil
|
||||
return value.In, nil
|
||||
case "description":
|
||||
return parameter.Description, nil
|
||||
return value.Description, nil
|
||||
case "style":
|
||||
return parameter.Style, nil
|
||||
return value.Style, nil
|
||||
case "explode":
|
||||
return parameter.Explode, nil
|
||||
return value.Explode, nil
|
||||
case "allowEmptyValue":
|
||||
return parameter.AllowEmptyValue, nil
|
||||
return value.AllowEmptyValue, nil
|
||||
case "allowReserved":
|
||||
return parameter.AllowReserved, nil
|
||||
return value.AllowReserved, nil
|
||||
case "deprecated":
|
||||
return parameter.Deprecated, nil
|
||||
return value.Deprecated, nil
|
||||
case "required":
|
||||
return parameter.Required, nil
|
||||
return value.Required, nil
|
||||
case "example":
|
||||
return parameter.Example, nil
|
||||
return value.Example, nil
|
||||
case "examples":
|
||||
return parameter.Examples, nil
|
||||
return value.Examples, nil
|
||||
case "content":
|
||||
return parameter.Content, nil
|
||||
return value.Content, nil
|
||||
}
|
||||
|
||||
v, _, err := jsonpointer.GetForToken(parameter.ExtensionProps, token)
|
||||
v, _, err := jsonpointer.GetForToken(value.ExtensionProps, token)
|
||||
return v, err
|
||||
}
|
||||
|
||||
|
|
@ -251,6 +253,10 @@ func (value *Parameter) Validate(ctx context.Context) error {
|
|||
return fmt.Errorf("parameter can't have 'in' value %q", value.In)
|
||||
}
|
||||
|
||||
if in == ParameterInPath && !value.Required {
|
||||
return fmt.Errorf("path parameter %q must be required", value.Name)
|
||||
}
|
||||
|
||||
// Validate a parameter's serialization method.
|
||||
sm, err := value.SerializationMethod()
|
||||
if err != nil {
|
||||
|
|
@ -294,6 +300,7 @@ func (value *Parameter) Validate(ctx context.Context) error {
|
|||
return fmt.Errorf("parameter %q schema is invalid: %v", value.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
if content := value.Content; content != nil {
|
||||
if err := content.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("parameter %q content is invalid: %v", value.Name, err)
|
||||
|
|
|
|||
3
vendor/github.com/getkin/kin-openapi/openapi3/path_item.go
generated
vendored
3
vendor/github.com/getkin/kin-openapi/openapi3/path_item.go
generated
vendored
|
|
@ -8,8 +8,11 @@ import (
|
|||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// PathItem is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#pathItemObject
|
||||
type PathItem struct {
|
||||
ExtensionProps
|
||||
|
||||
Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
|
||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
|
|
|
|||
109
vendor/github.com/getkin/kin-openapi/openapi3/paths.go
generated
vendored
109
vendor/github.com/getkin/kin-openapi/openapi3/paths.go
generated
vendored
|
|
@ -6,7 +6,8 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// Paths is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// Paths is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#paths-object
|
||||
type Paths map[string]*PathItem
|
||||
|
||||
func (value Paths) Validate(ctx context.Context) error {
|
||||
|
|
@ -21,31 +22,60 @@ func (value Paths) Validate(ctx context.Context) error {
|
|||
pathItem = value[path]
|
||||
}
|
||||
|
||||
normalizedPath, pathParamsCount := normalizeTemplatedPath(path)
|
||||
normalizedPath, _, varsInPath := normalizeTemplatedPath(path)
|
||||
if oldPath, ok := normalizedPaths[normalizedPath]; ok {
|
||||
return fmt.Errorf("conflicting paths %q and %q", path, oldPath)
|
||||
}
|
||||
normalizedPaths[path] = path
|
||||
|
||||
var globalCount uint
|
||||
var commonParams []string
|
||||
for _, parameterRef := range pathItem.Parameters {
|
||||
if parameterRef != nil {
|
||||
if parameter := parameterRef.Value; parameter != nil && parameter.In == ParameterInPath {
|
||||
globalCount++
|
||||
commonParams = append(commonParams, parameter.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
for method, operation := range pathItem.Operations() {
|
||||
var count uint
|
||||
var setParams []string
|
||||
for _, parameterRef := range operation.Parameters {
|
||||
if parameterRef != nil {
|
||||
if parameter := parameterRef.Value; parameter != nil && parameter.In == ParameterInPath {
|
||||
count++
|
||||
setParams = append(setParams, parameter.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if count+globalCount != pathParamsCount {
|
||||
return fmt.Errorf("operation %s %s must define exactly all path parameters", method, path)
|
||||
if expected := len(setParams) + len(commonParams); expected != len(varsInPath) {
|
||||
expected -= len(varsInPath)
|
||||
if expected < 0 {
|
||||
expected *= -1
|
||||
}
|
||||
missing := make(map[string]struct{}, expected)
|
||||
definedParams := append(setParams, commonParams...)
|
||||
for _, name := range definedParams {
|
||||
if _, ok := varsInPath[name]; !ok {
|
||||
missing[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
for name := range varsInPath {
|
||||
got := false
|
||||
for _, othername := range definedParams {
|
||||
if othername == name {
|
||||
got = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !got {
|
||||
missing[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
if len(missing) != 0 {
|
||||
missings := make([]string, 0, len(missing))
|
||||
for name := range missing {
|
||||
missings = append(missings, name)
|
||||
}
|
||||
return fmt.Errorf("operation %s %s must define exactly all path parameters (missing: %v)", method, path, missings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -53,6 +83,11 @@ func (value Paths) Validate(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := value.validateUniqueOperationIDs(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -75,9 +110,9 @@ func (paths Paths) Find(key string) *PathItem {
|
|||
return pathItem
|
||||
}
|
||||
|
||||
normalizedPath, expected := normalizeTemplatedPath(key)
|
||||
normalizedPath, expected, _ := normalizeTemplatedPath(key)
|
||||
for path, pathItem := range paths {
|
||||
pathNormalized, got := normalizeTemplatedPath(path)
|
||||
pathNormalized, got, _ := normalizeTemplatedPath(path)
|
||||
if got == expected && pathNormalized == normalizedPath {
|
||||
return pathItem
|
||||
}
|
||||
|
|
@ -85,43 +120,75 @@ func (paths Paths) Find(key string) *PathItem {
|
|||
return nil
|
||||
}
|
||||
|
||||
func normalizeTemplatedPath(path string) (string, uint) {
|
||||
func (value Paths) validateUniqueOperationIDs() error {
|
||||
operationIDs := make(map[string]string)
|
||||
for urlPath, pathItem := range value {
|
||||
if pathItem == nil {
|
||||
continue
|
||||
}
|
||||
for httpMethod, operation := range pathItem.Operations() {
|
||||
if operation == nil || operation.OperationID == "" {
|
||||
continue
|
||||
}
|
||||
endpoint := httpMethod + " " + urlPath
|
||||
if endpointDup, ok := operationIDs[operation.OperationID]; ok {
|
||||
if endpoint > endpointDup { // For make error message a bit more deterministic. May be useful for tests.
|
||||
endpoint, endpointDup = endpointDup, endpoint
|
||||
}
|
||||
return fmt.Errorf("operations %q and %q have the same operation id %q",
|
||||
endpoint, endpointDup, operation.OperationID)
|
||||
}
|
||||
operationIDs[operation.OperationID] = endpoint
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeTemplatedPath(path string) (string, uint, map[string]struct{}) {
|
||||
if strings.IndexByte(path, '{') < 0 {
|
||||
return path, 0
|
||||
return path, 0, nil
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
buf.Grow(len(path))
|
||||
var buffTpl strings.Builder
|
||||
buffTpl.Grow(len(path))
|
||||
|
||||
var (
|
||||
cc rune
|
||||
count uint
|
||||
isVariable bool
|
||||
vars = make(map[string]struct{})
|
||||
buffVar strings.Builder
|
||||
)
|
||||
for i, c := range path {
|
||||
if isVariable {
|
||||
if c == '}' {
|
||||
// End path variables
|
||||
// End path variable
|
||||
isVariable = false
|
||||
|
||||
vars[buffVar.String()] = struct{}{}
|
||||
buffVar = strings.Builder{}
|
||||
|
||||
// First append possible '*' before this character
|
||||
// The character '}' will be appended
|
||||
if i > 0 && cc == '*' {
|
||||
buf.WriteRune(cc)
|
||||
buffTpl.WriteRune(cc)
|
||||
}
|
||||
isVariable = false
|
||||
} else {
|
||||
// Skip this character
|
||||
buffVar.WriteRune(c)
|
||||
continue
|
||||
}
|
||||
|
||||
} else if c == '{' {
|
||||
// Begin path variable
|
||||
// The character '{' will be appended
|
||||
isVariable = true
|
||||
|
||||
// The character '{' will be appended
|
||||
count++
|
||||
}
|
||||
|
||||
// Append the character
|
||||
buf.WriteRune(c)
|
||||
buffTpl.WriteRune(c)
|
||||
cc = c
|
||||
}
|
||||
return buf.String(), count
|
||||
return buffTpl.String(), count, vars
|
||||
}
|
||||
|
|
|
|||
19
vendor/github.com/getkin/kin-openapi/openapi3/refs.go
generated
vendored
19
vendor/github.com/getkin/kin-openapi/openapi3/refs.go
generated
vendored
|
|
@ -8,10 +8,13 @@ import (
|
|||
)
|
||||
|
||||
// Ref is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#referenceObject
|
||||
type Ref struct {
|
||||
Ref string `json:"$ref" yaml:"$ref"`
|
||||
}
|
||||
|
||||
// CallbackRef represents either a Callback or a $ref to a Callback.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type CallbackRef struct {
|
||||
Ref string
|
||||
Value *Callback
|
||||
|
|
@ -43,6 +46,8 @@ func (value CallbackRef) JSONLookup(token string) (interface{}, error) {
|
|||
return ptr, err
|
||||
}
|
||||
|
||||
// ExampleRef represents either a Example or a $ref to a Example.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type ExampleRef struct {
|
||||
Ref string
|
||||
Value *Example
|
||||
|
|
@ -74,6 +79,8 @@ func (value ExampleRef) JSONLookup(token string) (interface{}, error) {
|
|||
return ptr, err
|
||||
}
|
||||
|
||||
// HeaderRef represents either a Header or a $ref to a Header.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type HeaderRef struct {
|
||||
Ref string
|
||||
Value *Header
|
||||
|
|
@ -105,6 +112,8 @@ func (value HeaderRef) JSONLookup(token string) (interface{}, error) {
|
|||
return ptr, err
|
||||
}
|
||||
|
||||
// LinkRef represents either a Link or a $ref to a Link.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type LinkRef struct {
|
||||
Ref string
|
||||
Value *Link
|
||||
|
|
@ -125,6 +134,8 @@ func (value *LinkRef) Validate(ctx context.Context) error {
|
|||
return foundUnresolvedRef(value.Ref)
|
||||
}
|
||||
|
||||
// ParameterRef represents either a Parameter or a $ref to a Parameter.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type ParameterRef struct {
|
||||
Ref string
|
||||
Value *Parameter
|
||||
|
|
@ -156,6 +167,8 @@ func (value ParameterRef) JSONLookup(token string) (interface{}, error) {
|
|||
return ptr, err
|
||||
}
|
||||
|
||||
// ResponseRef represents either a Response or a $ref to a Response.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type ResponseRef struct {
|
||||
Ref string
|
||||
Value *Response
|
||||
|
|
@ -187,6 +200,8 @@ func (value ResponseRef) JSONLookup(token string) (interface{}, error) {
|
|||
return ptr, err
|
||||
}
|
||||
|
||||
// RequestBodyRef represents either a RequestBody or a $ref to a RequestBody.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type RequestBodyRef struct {
|
||||
Ref string
|
||||
Value *RequestBody
|
||||
|
|
@ -218,6 +233,8 @@ func (value RequestBodyRef) JSONLookup(token string) (interface{}, error) {
|
|||
return ptr, err
|
||||
}
|
||||
|
||||
// SchemaRef represents either a Schema or a $ref to a Schema.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type SchemaRef struct {
|
||||
Ref string
|
||||
Value *Schema
|
||||
|
|
@ -256,6 +273,8 @@ func (value SchemaRef) JSONLookup(token string) (interface{}, error) {
|
|||
return ptr, err
|
||||
}
|
||||
|
||||
// SecuritySchemeRef represents either a SecurityScheme or a $ref to a SecurityScheme.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type SecuritySchemeRef struct {
|
||||
Ref string
|
||||
Value *SecurityScheme
|
||||
|
|
|
|||
13
vendor/github.com/getkin/kin-openapi/openapi3/request_body.go
generated
vendored
13
vendor/github.com/getkin/kin-openapi/openapi3/request_body.go
generated
vendored
|
|
@ -2,6 +2,7 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
|
|
@ -25,11 +26,13 @@ func (r RequestBodies) JSONLookup(token string) (interface{}, error) {
|
|||
}
|
||||
|
||||
// RequestBody is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#requestBodyObject
|
||||
type RequestBody struct {
|
||||
ExtensionProps
|
||||
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
Content Content `json:"content" yaml:"content"`
|
||||
}
|
||||
|
||||
func NewRequestBody() *RequestBody {
|
||||
|
|
@ -98,10 +101,8 @@ func (requestBody *RequestBody) UnmarshalJSON(data []byte) error {
|
|||
}
|
||||
|
||||
func (value *RequestBody) Validate(ctx context.Context) error {
|
||||
if v := value.Content; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if value.Content == nil {
|
||||
return errors.New("content of the request body is required")
|
||||
}
|
||||
return nil
|
||||
return value.Content.Validate(ctx)
|
||||
}
|
||||
|
|
|
|||
14
vendor/github.com/getkin/kin-openapi/openapi3/response.go
generated
vendored
14
vendor/github.com/getkin/kin-openapi/openapi3/response.go
generated
vendored
|
|
@ -11,6 +11,7 @@ import (
|
|||
)
|
||||
|
||||
// Responses is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#responsesObject
|
||||
type Responses map[string]*ResponseRef
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Responses)(nil)
|
||||
|
|
@ -54,8 +55,10 @@ func (responses Responses) JSONLookup(token string) (interface{}, error) {
|
|||
}
|
||||
|
||||
// Response is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#responseObject
|
||||
type Response struct {
|
||||
ExtensionProps
|
||||
|
||||
Description *string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
|
|
@ -104,5 +107,16 @@ func (value *Response) Validate(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
for _, header := range value.Headers {
|
||||
if err := header.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, link := range value.Links {
|
||||
if err := link.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
263
vendor/github.com/getkin/kin-openapi/openapi3/schema.go
generated
vendored
263
vendor/github.com/getkin/kin-openapi/openapi3/schema.go
generated
vendored
|
|
@ -16,6 +16,15 @@ import (
|
|||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
const (
|
||||
TypeArray = "array"
|
||||
TypeBoolean = "boolean"
|
||||
TypeInteger = "integer"
|
||||
TypeNumber = "number"
|
||||
TypeObject = "object"
|
||||
TypeString = "string"
|
||||
)
|
||||
|
||||
var (
|
||||
// SchemaErrorDetailsDisabled disables printing of details about schema errors.
|
||||
SchemaErrorDetailsDisabled = false
|
||||
|
|
@ -93,6 +102,7 @@ func (s SchemaRefs) JSONLookup(token string) (interface{}, error) {
|
|||
}
|
||||
|
||||
// Schema is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#schemaObject
|
||||
type Schema struct {
|
||||
ExtensionProps
|
||||
|
||||
|
|
@ -109,20 +119,18 @@ type Schema struct {
|
|||
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
|
||||
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||
|
||||
// Object-related, here for struct compactness
|
||||
AdditionalPropertiesAllowed *bool `json:"-" multijson:"additionalProperties,omitempty" yaml:"-"`
|
||||
// Array-related, here for struct compactness
|
||||
UniqueItems bool `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"`
|
||||
// Number-related, here for struct compactness
|
||||
ExclusiveMin bool `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"`
|
||||
ExclusiveMax bool `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"`
|
||||
// Properties
|
||||
Nullable bool `json:"nullable,omitempty" yaml:"nullable,omitempty"`
|
||||
ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"`
|
||||
WriteOnly bool `json:"writeOnly,omitempty" yaml:"writeOnly,omitempty"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
|
||||
XML interface{} `json:"xml,omitempty" yaml:"xml,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||
Nullable bool `json:"nullable,omitempty" yaml:"nullable,omitempty"`
|
||||
ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"`
|
||||
WriteOnly bool `json:"writeOnly,omitempty" yaml:"writeOnly,omitempty"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||
XML *XML `json:"xml,omitempty" yaml:"xml,omitempty"`
|
||||
|
||||
// Number
|
||||
Min *float64 `json:"minimum,omitempty" yaml:"minimum,omitempty"`
|
||||
|
|
@ -141,12 +149,13 @@ type Schema struct {
|
|||
Items *SchemaRef `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
|
||||
// Object
|
||||
Required []string `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
Properties Schemas `json:"properties,omitempty" yaml:"properties,omitempty"`
|
||||
MinProps uint64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"`
|
||||
MaxProps *uint64 `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"`
|
||||
AdditionalProperties *SchemaRef `json:"-" multijson:"additionalProperties,omitempty" yaml:"-"`
|
||||
Discriminator *Discriminator `json:"discriminator,omitempty" yaml:"discriminator,omitempty"`
|
||||
Required []string `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
Properties Schemas `json:"properties,omitempty" yaml:"properties,omitempty"`
|
||||
MinProps uint64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"`
|
||||
MaxProps *uint64 `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"`
|
||||
AdditionalPropertiesAllowed *bool `multijson:"additionalProperties,omitempty" json:"-" yaml:"-"` // In this order...
|
||||
AdditionalProperties *SchemaRef `multijson:"additionalProperties,omitempty" json:"-" yaml:"-"` // ...for multijson
|
||||
Discriminator *Discriminator `json:"discriminator,omitempty" yaml:"discriminator,omitempty"`
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Schema)(nil)
|
||||
|
|
@ -298,73 +307,73 @@ func NewAllOfSchema(schemas ...*Schema) *Schema {
|
|||
|
||||
func NewBoolSchema() *Schema {
|
||||
return &Schema{
|
||||
Type: "boolean",
|
||||
Type: TypeBoolean,
|
||||
}
|
||||
}
|
||||
|
||||
func NewFloat64Schema() *Schema {
|
||||
return &Schema{
|
||||
Type: "number",
|
||||
Type: TypeNumber,
|
||||
}
|
||||
}
|
||||
|
||||
func NewIntegerSchema() *Schema {
|
||||
return &Schema{
|
||||
Type: "integer",
|
||||
Type: TypeInteger,
|
||||
}
|
||||
}
|
||||
|
||||
func NewInt32Schema() *Schema {
|
||||
return &Schema{
|
||||
Type: "integer",
|
||||
Type: TypeInteger,
|
||||
Format: "int32",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInt64Schema() *Schema {
|
||||
return &Schema{
|
||||
Type: "integer",
|
||||
Type: TypeInteger,
|
||||
Format: "int64",
|
||||
}
|
||||
}
|
||||
|
||||
func NewStringSchema() *Schema {
|
||||
return &Schema{
|
||||
Type: "string",
|
||||
Type: TypeString,
|
||||
}
|
||||
}
|
||||
|
||||
func NewDateTimeSchema() *Schema {
|
||||
return &Schema{
|
||||
Type: "string",
|
||||
Type: TypeString,
|
||||
Format: "date-time",
|
||||
}
|
||||
}
|
||||
|
||||
func NewUUIDSchema() *Schema {
|
||||
return &Schema{
|
||||
Type: "string",
|
||||
Type: TypeString,
|
||||
Format: "uuid",
|
||||
}
|
||||
}
|
||||
|
||||
func NewBytesSchema() *Schema {
|
||||
return &Schema{
|
||||
Type: "string",
|
||||
Type: TypeString,
|
||||
Format: "byte",
|
||||
}
|
||||
}
|
||||
|
||||
func NewArraySchema() *Schema {
|
||||
return &Schema{
|
||||
Type: "array",
|
||||
Type: TypeArray,
|
||||
}
|
||||
}
|
||||
|
||||
func NewObjectSchema() *Schema {
|
||||
return &Schema{
|
||||
Type: "object",
|
||||
Properties: make(map[string]*SchemaRef),
|
||||
Type: TypeObject,
|
||||
Properties: make(Schemas),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -485,7 +494,7 @@ func (schema *Schema) WithProperty(name string, propertySchema *Schema) *Schema
|
|||
func (schema *Schema) WithPropertyRef(name string, ref *SchemaRef) *Schema {
|
||||
properties := schema.Properties
|
||||
if properties == nil {
|
||||
properties = make(map[string]*SchemaRef)
|
||||
properties = make(Schemas)
|
||||
schema.Properties = properties
|
||||
}
|
||||
properties[name] = ref
|
||||
|
|
@ -493,7 +502,7 @@ func (schema *Schema) WithPropertyRef(name string, ref *SchemaRef) *Schema {
|
|||
}
|
||||
|
||||
func (schema *Schema) WithProperties(properties map[string]*Schema) *Schema {
|
||||
result := make(map[string]*SchemaRef, len(properties))
|
||||
result := make(Schemas, len(properties))
|
||||
for k, v := range properties {
|
||||
result[k] = &SchemaRef{
|
||||
Value: v,
|
||||
|
|
@ -638,8 +647,8 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error)
|
|||
schemaType := schema.Type
|
||||
switch schemaType {
|
||||
case "":
|
||||
case "boolean":
|
||||
case "number":
|
||||
case TypeBoolean:
|
||||
case TypeNumber:
|
||||
if format := schema.Format; len(format) > 0 {
|
||||
switch format {
|
||||
case "float", "double":
|
||||
|
|
@ -649,7 +658,7 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error)
|
|||
}
|
||||
}
|
||||
}
|
||||
case "integer":
|
||||
case TypeInteger:
|
||||
if format := schema.Format; len(format) > 0 {
|
||||
switch format {
|
||||
case "int32", "int64":
|
||||
|
|
@ -659,17 +668,21 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error)
|
|||
}
|
||||
}
|
||||
}
|
||||
case "string":
|
||||
case TypeString:
|
||||
if format := schema.Format; len(format) > 0 {
|
||||
switch format {
|
||||
// Supported by OpenAPIv3.0.1:
|
||||
// Supported by OpenAPIv3.0.3:
|
||||
// https://spec.openapis.org/oas/v3.0.3
|
||||
case "byte", "binary", "date", "date-time", "password":
|
||||
// In JSON Draft-07 (not validated yet though):
|
||||
case "regex":
|
||||
case "time", "email", "idn-email":
|
||||
case "hostname", "idn-hostname", "ipv4", "ipv6":
|
||||
case "uri", "uri-reference", "iri", "iri-reference", "uri-template":
|
||||
case "json-pointer", "relative-json-pointer":
|
||||
// In JSON Draft-07 (not validated yet though):
|
||||
// https://json-schema.org/draft-07/json-schema-release-notes.html#formats
|
||||
case "iri", "iri-reference", "uri-template", "idn-email", "idn-hostname":
|
||||
case "json-pointer", "relative-json-pointer", "regex", "time":
|
||||
// In JSON Draft 2019-09 (not validated yet though):
|
||||
// https://json-schema.org/draft/2019-09/release-notes.html#format-vocabulary
|
||||
case "duration", "uuid":
|
||||
// Defined in some other specification
|
||||
case "email", "hostname", "ipv4", "ipv6", "uri", "uri-reference":
|
||||
default:
|
||||
// Try to check for custom defined formats
|
||||
if _, ok := SchemaStringFormats[format]; !ok && !SchemaFormatValidationDisabled {
|
||||
|
|
@ -677,11 +690,16 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error)
|
|||
}
|
||||
}
|
||||
}
|
||||
case "array":
|
||||
if schema.Pattern != "" {
|
||||
if err = schema.compilePattern(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case TypeArray:
|
||||
if schema.Items == nil {
|
||||
return errors.New("when schema type is 'array', schema 'items' must be non-null")
|
||||
}
|
||||
case "object":
|
||||
case TypeObject:
|
||||
default:
|
||||
return fmt.Errorf("unsupported 'type' value %q", schemaType)
|
||||
}
|
||||
|
|
@ -716,6 +734,12 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error)
|
|||
}
|
||||
}
|
||||
|
||||
if v := schema.ExternalDocs; v != nil {
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("invalid external docs: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -775,8 +799,6 @@ func (schema *Schema) visitJSON(settings *schemaValidationSettings, value interf
|
|||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case nil:
|
||||
return schema.visitJSONNull(settings)
|
||||
case bool:
|
||||
return schema.visitJSONBoolean(settings, value)
|
||||
case float64:
|
||||
|
|
@ -787,13 +809,22 @@ func (schema *Schema) visitJSON(settings *schemaValidationSettings, value interf
|
|||
return schema.visitJSONArray(settings, value)
|
||||
case map[string]interface{}:
|
||||
return schema.visitJSONObject(settings, value)
|
||||
default:
|
||||
return &SchemaError{
|
||||
Value: value,
|
||||
Schema: schema,
|
||||
SchemaField: "type",
|
||||
Reason: fmt.Sprintf("unhandled value of type %T", value),
|
||||
case map[interface{}]interface{}: // for YAML cf. issue #444
|
||||
values := make(map[string]interface{}, len(value))
|
||||
for key, v := range value {
|
||||
if k, ok := key.(string); ok {
|
||||
values[k] = v
|
||||
}
|
||||
}
|
||||
if len(value) == len(values) {
|
||||
return schema.visitJSONObject(settings, values)
|
||||
}
|
||||
}
|
||||
return &SchemaError{
|
||||
Value: value,
|
||||
Schema: schema,
|
||||
SchemaField: "type",
|
||||
Reason: fmt.Sprintf("unhandled value of type %T", value),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -820,11 +851,7 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val
|
|||
if v == nil {
|
||||
return foundUnresolvedRef(ref.Ref)
|
||||
}
|
||||
var oldfailfast bool
|
||||
oldfailfast, settings.failfast = settings.failfast, true
|
||||
err := v.visitJSON(settings, value)
|
||||
settings.failfast = oldfailfast
|
||||
if err == nil {
|
||||
if err := v.visitJSON(settings, value); err == nil {
|
||||
if settings.failfast {
|
||||
return errSchema
|
||||
}
|
||||
|
|
@ -837,33 +864,57 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val
|
|||
}
|
||||
|
||||
if v := schema.OneOf; len(v) > 0 {
|
||||
var discriminatorRef string
|
||||
if schema.Discriminator != nil {
|
||||
pn := schema.Discriminator.PropertyName
|
||||
if valuemap, okcheck := value.(map[string]interface{}); okcheck {
|
||||
discriminatorVal, okcheck := valuemap[pn]
|
||||
if !okcheck {
|
||||
return errors.New("input does not contain the discriminator property")
|
||||
}
|
||||
|
||||
discriminatorValString, okcheck := discriminatorVal.(string)
|
||||
if !okcheck {
|
||||
return errors.New("descriminator value is not a string")
|
||||
}
|
||||
|
||||
if discriminatorRef, okcheck = schema.Discriminator.Mapping[discriminatorValString]; len(schema.Discriminator.Mapping) > 0 && !okcheck {
|
||||
return errors.New("input does not contain a valid discriminator value")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok := 0
|
||||
validationErrors := []error{}
|
||||
for _, item := range v {
|
||||
v := item.Value
|
||||
if v == nil {
|
||||
return foundUnresolvedRef(item.Ref)
|
||||
}
|
||||
var oldfailfast bool
|
||||
oldfailfast, settings.failfast = settings.failfast, true
|
||||
err := v.visitJSON(settings, value)
|
||||
settings.failfast = oldfailfast
|
||||
if err == nil {
|
||||
if schema.Discriminator != nil {
|
||||
pn := schema.Discriminator.PropertyName
|
||||
if valuemap, okcheck := value.(map[string]interface{}); okcheck {
|
||||
if discriminatorVal, okcheck := valuemap[pn]; okcheck == true {
|
||||
mapref, okcheck := schema.Discriminator.Mapping[discriminatorVal.(string)]
|
||||
if okcheck && mapref == item.Ref {
|
||||
ok++
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ok++
|
||||
}
|
||||
|
||||
if discriminatorRef != "" && discriminatorRef != item.Ref {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := v.visitJSON(settings, value); err != nil {
|
||||
validationErrors = append(validationErrors, err)
|
||||
continue
|
||||
}
|
||||
|
||||
ok++
|
||||
}
|
||||
|
||||
if ok != 1 {
|
||||
if len(validationErrors) > 1 {
|
||||
errorMessage := ""
|
||||
for _, err := range validationErrors {
|
||||
if errorMessage != "" {
|
||||
errorMessage += " Or "
|
||||
}
|
||||
errorMessage += err.Error()
|
||||
}
|
||||
return errors.New("doesn't match schema due to: " + errorMessage)
|
||||
}
|
||||
if settings.failfast {
|
||||
return errSchema
|
||||
}
|
||||
|
|
@ -874,7 +925,10 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val
|
|||
}
|
||||
if ok > 1 {
|
||||
e.Origin = ErrOneOfConflict
|
||||
} else if len(validationErrors) == 1 {
|
||||
e.Origin = validationErrors[0]
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
|
@ -886,11 +940,7 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val
|
|||
if v == nil {
|
||||
return foundUnresolvedRef(item.Ref)
|
||||
}
|
||||
var oldfailfast bool
|
||||
oldfailfast, settings.failfast = settings.failfast, true
|
||||
err := v.visitJSON(settings, value)
|
||||
settings.failfast = oldfailfast
|
||||
if err == nil {
|
||||
if err := v.visitJSON(settings, value); err == nil {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
|
|
@ -912,11 +962,7 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val
|
|||
if v == nil {
|
||||
return foundUnresolvedRef(item.Ref)
|
||||
}
|
||||
var oldfailfast bool
|
||||
oldfailfast, settings.failfast = settings.failfast, false
|
||||
err := v.visitJSON(settings, value)
|
||||
settings.failfast = oldfailfast
|
||||
if err != nil {
|
||||
if err := v.visitJSON(settings, value); err != nil {
|
||||
if settings.failfast {
|
||||
return errSchema
|
||||
}
|
||||
|
|
@ -952,8 +998,8 @@ func (schema *Schema) VisitJSONBoolean(value bool) error {
|
|||
}
|
||||
|
||||
func (schema *Schema) visitJSONBoolean(settings *schemaValidationSettings, value bool) (err error) {
|
||||
if schemaType := schema.Type; schemaType != "" && schemaType != "boolean" {
|
||||
return schema.expectedType(settings, "boolean")
|
||||
if schemaType := schema.Type; schemaType != "" && schemaType != TypeBoolean {
|
||||
return schema.expectedType(settings, TypeBoolean)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -982,7 +1028,7 @@ func (schema *Schema) visitJSONNumber(settings *schemaValidationSettings, value
|
|||
}
|
||||
me = append(me, err)
|
||||
}
|
||||
} else if schemaType != "" && schemaType != "number" {
|
||||
} else if schemaType != "" && schemaType != TypeNumber {
|
||||
return schema.expectedType(settings, "number, integer")
|
||||
}
|
||||
|
||||
|
|
@ -1046,7 +1092,7 @@ func (schema *Schema) visitJSONNumber(settings *schemaValidationSettings, value
|
|||
Value: value,
|
||||
Schema: schema,
|
||||
SchemaField: "maximum",
|
||||
Reason: fmt.Sprintf("number must be most %g", *v),
|
||||
Reason: fmt.Sprintf("number must be at most %g", *v),
|
||||
}
|
||||
if !settings.multiError {
|
||||
return err
|
||||
|
|
@ -1087,8 +1133,8 @@ func (schema *Schema) VisitJSONString(value string) error {
|
|||
}
|
||||
|
||||
func (schema *Schema) visitJSONString(settings *schemaValidationSettings, value string) error {
|
||||
if schemaType := schema.Type; schemaType != "" && schemaType != "string" {
|
||||
return schema.expectedType(settings, "string")
|
||||
if schemaType := schema.Type; schemaType != "" && schemaType != TypeString {
|
||||
return schema.expectedType(settings, TypeString)
|
||||
}
|
||||
|
||||
var me MultiError
|
||||
|
|
@ -1139,15 +1185,9 @@ func (schema *Schema) visitJSONString(settings *schemaValidationSettings, value
|
|||
}
|
||||
|
||||
// "pattern"
|
||||
if pattern := schema.Pattern; pattern != "" && schema.compiledPattern == nil {
|
||||
if schema.Pattern != "" && schema.compiledPattern == nil {
|
||||
var err error
|
||||
if schema.compiledPattern, err = regexp.Compile(pattern); err != nil {
|
||||
err = &SchemaError{
|
||||
Value: value,
|
||||
Schema: schema,
|
||||
SchemaField: "pattern",
|
||||
Reason: fmt.Sprintf("cannot compile pattern %q: %v", pattern, err),
|
||||
}
|
||||
if err = schema.compilePattern(); err != nil {
|
||||
if !settings.multiError {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1159,7 +1199,7 @@ func (schema *Schema) visitJSONString(settings *schemaValidationSettings, value
|
|||
Value: value,
|
||||
Schema: schema,
|
||||
SchemaField: "pattern",
|
||||
Reason: fmt.Sprintf("string doesn't match the regular expression %q", schema.Pattern),
|
||||
Reason: fmt.Sprintf(`string doesn't match the regular expression "%s"`, schema.Pattern),
|
||||
}
|
||||
if !settings.multiError {
|
||||
return err
|
||||
|
|
@ -1174,7 +1214,7 @@ func (schema *Schema) visitJSONString(settings *schemaValidationSettings, value
|
|||
switch {
|
||||
case f.regexp != nil && f.callback == nil:
|
||||
if cp := f.regexp; !cp.MatchString(value) {
|
||||
formatErr = fmt.Sprintf("string doesn't match the format %q (regular expression %q)", format, cp.String())
|
||||
formatErr = fmt.Sprintf(`string doesn't match the format %q (regular expression "%s")`, format, cp.String())
|
||||
}
|
||||
case f.regexp == nil && f.callback != nil:
|
||||
if err := f.callback(value); err != nil {
|
||||
|
|
@ -1212,8 +1252,8 @@ func (schema *Schema) VisitJSONArray(value []interface{}) error {
|
|||
}
|
||||
|
||||
func (schema *Schema) visitJSONArray(settings *schemaValidationSettings, value []interface{}) error {
|
||||
if schemaType := schema.Type; schemaType != "" && schemaType != "array" {
|
||||
return schema.expectedType(settings, "array")
|
||||
if schemaType := schema.Type; schemaType != "" && schemaType != TypeArray {
|
||||
return schema.expectedType(settings, TypeArray)
|
||||
}
|
||||
|
||||
var me MultiError
|
||||
|
|
@ -1308,8 +1348,8 @@ func (schema *Schema) VisitJSONObject(value map[string]interface{}) error {
|
|||
}
|
||||
|
||||
func (schema *Schema) visitJSONObject(settings *schemaValidationSettings, value map[string]interface{}) error {
|
||||
if schemaType := schema.Type; schemaType != "" && schemaType != "object" {
|
||||
return schema.expectedType(settings, "object")
|
||||
if schemaType := schema.Type; schemaType != "" && schemaType != TypeObject {
|
||||
return schema.expectedType(settings, TypeObject)
|
||||
}
|
||||
|
||||
var me MultiError
|
||||
|
|
@ -1383,7 +1423,7 @@ func (schema *Schema) visitJSONObject(settings *schemaValidationSettings, value
|
|||
}
|
||||
}
|
||||
allowed := schema.AdditionalPropertiesAllowed
|
||||
if additionalProperties != nil || allowed == nil || (allowed != nil && *allowed) {
|
||||
if additionalProperties != nil || allowed == nil || *allowed {
|
||||
if additionalProperties != nil {
|
||||
if err := additionalProperties.visitJSON(settings, v); err != nil {
|
||||
if settings.failfast {
|
||||
|
|
@ -1461,6 +1501,17 @@ func (schema *Schema) expectedType(settings *schemaValidationSettings, typ strin
|
|||
}
|
||||
}
|
||||
|
||||
func (schema *Schema) compilePattern() (err error) {
|
||||
if schema.compiledPattern, err = regexp.Compile(schema.Pattern); err != nil {
|
||||
return &SchemaError{
|
||||
Schema: schema,
|
||||
SchemaField: "pattern",
|
||||
Reason: fmt.Sprintf("cannot compile pattern %q: %v", schema.Pattern, err),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SchemaError struct {
|
||||
Value interface{}
|
||||
reversePath []string
|
||||
|
|
@ -1470,6 +1521,8 @@ type SchemaError struct {
|
|||
Origin error
|
||||
}
|
||||
|
||||
var _ interface{ Unwrap() error } = SchemaError{}
|
||||
|
||||
func markSchemaErrorKey(err error, key string) error {
|
||||
if v, ok := err.(*SchemaError); ok {
|
||||
v.reversePath = append(v.reversePath, key)
|
||||
|
|
@ -1545,6 +1598,10 @@ func (err *SchemaError) Error() string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
func (err SchemaError) Unwrap() error {
|
||||
return err.Origin
|
||||
}
|
||||
|
||||
func isSliceOfUniqueItems(xs []interface{}) bool {
|
||||
s := len(xs)
|
||||
m := make(map[string]struct{}, s)
|
||||
|
|
|
|||
22
vendor/github.com/getkin/kin-openapi/openapi3/schema_formats.go
generated
vendored
22
vendor/github.com/getkin/kin-openapi/openapi3/schema_formats.go
generated
vendored
|
|
@ -4,11 +4,12 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// FormatOfStringForUUIDOfRFC4122 is an optional predefined format for UUID v1-v5 as specified by RFC4122
|
||||
FormatOfStringForUUIDOfRFC4122 = `^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`
|
||||
FormatOfStringForUUIDOfRFC4122 = `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$`
|
||||
)
|
||||
|
||||
//FormatCallback custom check on exotic formats
|
||||
|
|
@ -37,24 +38,23 @@ func DefineStringFormatCallback(name string, callback FormatCallback) {
|
|||
SchemaStringFormats[name] = Format{callback: callback}
|
||||
}
|
||||
|
||||
func validateIP(ip string) (*net.IP, error) {
|
||||
func validateIP(ip string) error {
|
||||
parsed := net.ParseIP(ip)
|
||||
if parsed == nil {
|
||||
return nil, &SchemaError{
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IP address",
|
||||
}
|
||||
}
|
||||
return &parsed, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateIPv4(ip string) error {
|
||||
parsed, err := validateIP(ip)
|
||||
if err != nil {
|
||||
if err := validateIP(ip); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if parsed.To4() == nil {
|
||||
if !(strings.Count(ip, ":") < 2) {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IPv4 address (it's IPv6)",
|
||||
|
|
@ -62,13 +62,13 @@ func validateIPv4(ip string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateIPv6(ip string) error {
|
||||
parsed, err := validateIP(ip)
|
||||
if err != nil {
|
||||
if err := validateIP(ip); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if parsed.To4() != nil {
|
||||
if !(strings.Count(ip, ":") >= 2) {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IPv6 address (it's IPv4)",
|
||||
|
|
@ -90,7 +90,7 @@ func init() {
|
|||
DefineStringFormat("date", `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)$`)
|
||||
|
||||
// date-time
|
||||
DefineStringFormat("date-time", `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)T[0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`)
|
||||
DefineStringFormat("date-time", `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
2
vendor/github.com/getkin/kin-openapi/openapi3/security_requirements.go
generated
vendored
2
vendor/github.com/getkin/kin-openapi/openapi3/security_requirements.go
generated
vendored
|
|
@ -24,6 +24,8 @@ func (value SecurityRequirements) Validate(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SecurityRequirement is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#securityRequirementObject
|
||||
type SecurityRequirement map[string][]string
|
||||
|
||||
func NewSecurityRequirement() SecurityRequirement {
|
||||
|
|
|
|||
8
vendor/github.com/getkin/kin-openapi/openapi3/security_scheme.go
generated
vendored
8
vendor/github.com/getkin/kin-openapi/openapi3/security_scheme.go
generated
vendored
|
|
@ -25,6 +25,8 @@ func (s SecuritySchemes) JSONLookup(token string) (interface{}, error) {
|
|||
|
||||
var _ jsonpointer.JSONPointable = (*SecuritySchemes)(nil)
|
||||
|
||||
// SecurityScheme is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#securitySchemeObject
|
||||
type SecurityScheme struct {
|
||||
ExtensionProps
|
||||
|
||||
|
|
@ -166,8 +168,11 @@ func (value *SecurityScheme) Validate(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// OAuthFlows is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauthFlowsObject
|
||||
type OAuthFlows struct {
|
||||
ExtensionProps
|
||||
|
||||
Implicit *OAuthFlow `json:"implicit,omitempty" yaml:"implicit,omitempty"`
|
||||
Password *OAuthFlow `json:"password,omitempty" yaml:"password,omitempty"`
|
||||
ClientCredentials *OAuthFlow `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"`
|
||||
|
|
@ -207,8 +212,11 @@ func (flows *OAuthFlows) Validate(ctx context.Context) error {
|
|||
return errors.New("no OAuth flow is defined")
|
||||
}
|
||||
|
||||
// OAuthFlow is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauthFlowObject
|
||||
type OAuthFlow struct {
|
||||
ExtensionProps
|
||||
|
||||
AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
|
||||
TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
|
||||
RefreshURL string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
|
||||
|
|
|
|||
10
vendor/github.com/getkin/kin-openapi/openapi3/server.go
generated
vendored
10
vendor/github.com/getkin/kin-openapi/openapi3/server.go
generated
vendored
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// Servers is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// Servers is specified by OpenAPI/Swagger standard version 3.
|
||||
type Servers []*Server
|
||||
|
||||
// Validate ensures servers are per the OpenAPIv3 specification.
|
||||
|
|
@ -38,9 +38,11 @@ func (servers Servers) MatchURL(parsedURL *url.URL) (*Server, []string, string)
|
|||
return nil, nil, ""
|
||||
}
|
||||
|
||||
// Server is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// Server is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#serverObject
|
||||
type Server struct {
|
||||
ExtensionProps
|
||||
|
||||
URL string `json:"url" yaml:"url"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Variables map[string]*ServerVariable `json:"variables,omitempty" yaml:"variables,omitempty"`
|
||||
|
|
@ -147,9 +149,11 @@ func (value *Server) Validate(ctx context.Context) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// ServerVariable is specified by OpenAPI/Swagger standard version 3.0.
|
||||
// ServerVariable is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#server-variable-object
|
||||
type ServerVariable struct {
|
||||
ExtensionProps
|
||||
|
||||
Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"`
|
||||
Default string `json:"default,omitempty" yaml:"default,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
|
|
|
|||
27
vendor/github.com/getkin/kin-openapi/openapi3/tag.go
generated
vendored
27
vendor/github.com/getkin/kin-openapi/openapi3/tag.go
generated
vendored
|
|
@ -1,6 +1,11 @@
|
|||
package openapi3
|
||||
|
||||
import "github.com/getkin/kin-openapi/jsoninfo"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// Tags is specified by OpenAPI/Swagger 3.0 standard.
|
||||
type Tags []*Tag
|
||||
|
|
@ -14,9 +19,20 @@ func (tags Tags) Get(name string) *Tag {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (tags Tags) Validate(ctx context.Context) error {
|
||||
for _, v := range tags {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tag is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#tagObject
|
||||
type Tag struct {
|
||||
ExtensionProps
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||
|
|
@ -29,3 +45,12 @@ func (t *Tag) MarshalJSON() ([]byte, error) {
|
|||
func (t *Tag) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, t)
|
||||
}
|
||||
|
||||
func (t *Tag) Validate(ctx context.Context) error {
|
||||
if v := t.ExternalDocs; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("invalid external docs: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/getkin/kin-openapi/openapi3/testdata/recursiveRef/components/Bar.yml
generated
vendored
Normal file
2
vendor/github.com/getkin/kin-openapi/openapi3/testdata/recursiveRef/components/Bar.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
type: string
|
||||
example: bar
|
||||
4
vendor/github.com/getkin/kin-openapi/openapi3/testdata/recursiveRef/components/Foo.yml
generated
vendored
Normal file
4
vendor/github.com/getkin/kin-openapi/openapi3/testdata/recursiveRef/components/Foo.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
type: object
|
||||
properties:
|
||||
bar:
|
||||
$ref: ../openapi.yml#/components/schemas/Bar
|
||||
4
vendor/github.com/getkin/kin-openapi/openapi3/testdata/recursiveRef/components/Foo/Foo2.yml
generated
vendored
Normal file
4
vendor/github.com/getkin/kin-openapi/openapi3/testdata/recursiveRef/components/Foo/Foo2.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
type: object
|
||||
properties:
|
||||
foo:
|
||||
$ref: ../../openapi.yml#/components/schemas/Foo
|
||||
15
vendor/github.com/getkin/kin-openapi/openapi3/testdata/recursiveRef/openapi.yml
generated
vendored
Normal file
15
vendor/github.com/getkin/kin-openapi/openapi3/testdata/recursiveRef/openapi.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
openapi: "3.0.3"
|
||||
info:
|
||||
title: Recursive refs example
|
||||
version: "1.0"
|
||||
paths:
|
||||
/foo:
|
||||
$ref: ./paths/foo.yml
|
||||
components:
|
||||
schemas:
|
||||
Foo:
|
||||
$ref: ./components/Foo.yml
|
||||
Foo2:
|
||||
$ref: ./components/Foo/Foo2.yml
|
||||
Bar:
|
||||
$ref: ./components/Bar.yml
|
||||
11
vendor/github.com/getkin/kin-openapi/openapi3/testdata/recursiveRef/paths/foo.yml
generated
vendored
Normal file
11
vendor/github.com/getkin/kin-openapi/openapi3/testdata/recursiveRef/paths/foo.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
foo2:
|
||||
$ref: ../openapi.yml#/components/schemas/Foo2
|
||||
31
vendor/github.com/getkin/kin-openapi/openapi3/xml.go
generated
vendored
Normal file
31
vendor/github.com/getkin/kin-openapi/openapi3/xml.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// XML is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#xmlObject
|
||||
type XML struct {
|
||||
ExtensionProps
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
||||
Attribute bool `json:"attribute,omitempty" yaml:"attribute,omitempty"`
|
||||
Wrapped bool `json:"wrapped,omitempty" yaml:"wrapped,omitempty"`
|
||||
}
|
||||
|
||||
func (value *XML) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(value)
|
||||
}
|
||||
|
||||
func (value *XML) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, value)
|
||||
}
|
||||
|
||||
func (value *XML) Validate(ctx context.Context) error {
|
||||
return nil // TODO
|
||||
}
|
||||
29
vendor/github.com/getkin/kin-openapi/openapi3filter/authentication_input.go
generated
vendored
Normal file
29
vendor/github.com/getkin/kin-openapi/openapi3filter/authentication_input.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
)
|
||||
|
||||
type AuthenticationInput struct {
|
||||
RequestValidationInput *RequestValidationInput
|
||||
SecuritySchemeName string
|
||||
SecurityScheme *openapi3.SecurityScheme
|
||||
Scopes []string
|
||||
}
|
||||
|
||||
func (input *AuthenticationInput) NewError(err error) error {
|
||||
if err == nil {
|
||||
if len(input.Scopes) == 0 {
|
||||
err = fmt.Errorf("security requirement %q failed", input.SecuritySchemeName)
|
||||
} else {
|
||||
err = fmt.Errorf("security requirement %q (scopes: %+v) failed", input.SecuritySchemeName, input.Scopes)
|
||||
}
|
||||
}
|
||||
return &RequestError{
|
||||
Input: input.RequestValidationInput,
|
||||
Reason: "authorization failed",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
82
vendor/github.com/getkin/kin-openapi/openapi3filter/errors.go
generated
vendored
Normal file
82
vendor/github.com/getkin/kin-openapi/openapi3filter/errors.go
generated
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
)
|
||||
|
||||
var _ error = &RequestError{}
|
||||
|
||||
// RequestError is returned by ValidateRequest when request does not match OpenAPI spec
|
||||
type RequestError struct {
|
||||
Input *RequestValidationInput
|
||||
Parameter *openapi3.Parameter
|
||||
RequestBody *openapi3.RequestBody
|
||||
Reason string
|
||||
Err error
|
||||
}
|
||||
|
||||
var _ interface{ Unwrap() error } = RequestError{}
|
||||
|
||||
func (err *RequestError) Error() string {
|
||||
reason := err.Reason
|
||||
if e := err.Err; e != nil {
|
||||
if len(reason) == 0 {
|
||||
reason = e.Error()
|
||||
} else {
|
||||
reason += ": " + e.Error()
|
||||
}
|
||||
}
|
||||
if v := err.Parameter; v != nil {
|
||||
return fmt.Sprintf("parameter %q in %s has an error: %s", v.Name, v.In, reason)
|
||||
} else if v := err.RequestBody; v != nil {
|
||||
return fmt.Sprintf("request body has an error: %s", reason)
|
||||
} else {
|
||||
return reason
|
||||
}
|
||||
}
|
||||
|
||||
func (err RequestError) Unwrap() error {
|
||||
return err.Err
|
||||
}
|
||||
|
||||
var _ error = &ResponseError{}
|
||||
|
||||
// ResponseError is returned by ValidateResponse when response does not match OpenAPI spec
|
||||
type ResponseError struct {
|
||||
Input *ResponseValidationInput
|
||||
Reason string
|
||||
Err error
|
||||
}
|
||||
|
||||
var _ interface{ Unwrap() error } = ResponseError{}
|
||||
|
||||
func (err *ResponseError) Error() string {
|
||||
reason := err.Reason
|
||||
if e := err.Err; e != nil {
|
||||
if len(reason) == 0 {
|
||||
reason = e.Error()
|
||||
} else {
|
||||
reason += ": " + e.Error()
|
||||
}
|
||||
}
|
||||
return reason
|
||||
}
|
||||
|
||||
func (err ResponseError) Unwrap() error {
|
||||
return err.Err
|
||||
}
|
||||
|
||||
var _ error = &SecurityRequirementsError{}
|
||||
|
||||
// SecurityRequirementsError is returned by ValidateSecurityRequirements
|
||||
// when no requirement is met.
|
||||
type SecurityRequirementsError struct {
|
||||
SecurityRequirements openapi3.SecurityRequirements
|
||||
Errors []error
|
||||
}
|
||||
|
||||
func (err *SecurityRequirementsError) Error() string {
|
||||
return "Security requirements failed"
|
||||
}
|
||||
25
vendor/github.com/getkin/kin-openapi/openapi3filter/internal.go
generated
vendored
Normal file
25
vendor/github.com/getkin/kin-openapi/openapi3filter/internal.go
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parseMediaType(contentType string) string {
|
||||
i := strings.IndexByte(contentType, ';')
|
||||
if i < 0 {
|
||||
return contentType
|
||||
}
|
||||
return contentType[:i]
|
||||
}
|
||||
|
||||
func isNilValue(value interface{}) bool {
|
||||
if value == nil {
|
||||
return true
|
||||
}
|
||||
switch reflect.TypeOf(value).Kind() {
|
||||
case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice:
|
||||
return reflect.ValueOf(value).IsNil()
|
||||
}
|
||||
return false
|
||||
}
|
||||
273
vendor/github.com/getkin/kin-openapi/openapi3filter/middleware.go
generated
vendored
Normal file
273
vendor/github.com/getkin/kin-openapi/openapi3filter/middleware.go
generated
vendored
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/getkin/kin-openapi/routers"
|
||||
)
|
||||
|
||||
// Validator provides HTTP request and response validation middleware.
|
||||
type Validator struct {
|
||||
router routers.Router
|
||||
errFunc ErrFunc
|
||||
logFunc LogFunc
|
||||
strict bool
|
||||
}
|
||||
|
||||
// ErrFunc handles errors that may occur during validation.
|
||||
type ErrFunc func(w http.ResponseWriter, status int, code ErrCode, err error)
|
||||
|
||||
// LogFunc handles log messages that may occur during validation.
|
||||
type LogFunc func(message string, err error)
|
||||
|
||||
// ErrCode is used for classification of different types of errors that may
|
||||
// occur during validation. These may be used to write an appropriate response
|
||||
// in ErrFunc.
|
||||
type ErrCode int
|
||||
|
||||
const (
|
||||
// ErrCodeOK indicates no error. It is also the default value.
|
||||
ErrCodeOK = 0
|
||||
// ErrCodeCannotFindRoute happens when the validator fails to resolve the
|
||||
// request to a defined OpenAPI route.
|
||||
ErrCodeCannotFindRoute = iota
|
||||
// ErrCodeRequestInvalid happens when the inbound request does not conform
|
||||
// to the OpenAPI 3 specification.
|
||||
ErrCodeRequestInvalid = iota
|
||||
// ErrCodeResponseInvalid happens when the wrapped handler response does
|
||||
// not conform to the OpenAPI 3 specification.
|
||||
ErrCodeResponseInvalid = iota
|
||||
)
|
||||
|
||||
func (e ErrCode) responseText() string {
|
||||
switch e {
|
||||
case ErrCodeOK:
|
||||
return "OK"
|
||||
case ErrCodeCannotFindRoute:
|
||||
return "not found"
|
||||
case ErrCodeRequestInvalid:
|
||||
return "bad request"
|
||||
default:
|
||||
return "server error"
|
||||
}
|
||||
}
|
||||
|
||||
// NewValidator returns a new response validation middlware, using the given
|
||||
// routes from an OpenAPI 3 specification.
|
||||
func NewValidator(router routers.Router, options ...ValidatorOption) *Validator {
|
||||
v := &Validator{
|
||||
router: router,
|
||||
errFunc: func(w http.ResponseWriter, status int, code ErrCode, _ error) {
|
||||
http.Error(w, code.responseText(), status)
|
||||
},
|
||||
logFunc: func(message string, err error) {
|
||||
log.Printf("%s: %v", message, err)
|
||||
},
|
||||
}
|
||||
for i := range options {
|
||||
options[i](v)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// ValidatorOption defines an option that may be specified when creating a
|
||||
// Validator.
|
||||
type ValidatorOption func(*Validator)
|
||||
|
||||
// OnErr provides a callback that handles writing an HTTP response on a
|
||||
// validation error. This allows customization of error responses without
|
||||
// prescribing a particular form. This callback is only called on response
|
||||
// validator errors in Strict mode.
|
||||
func OnErr(f ErrFunc) ValidatorOption {
|
||||
return func(v *Validator) {
|
||||
v.errFunc = f
|
||||
}
|
||||
}
|
||||
|
||||
// OnLog provides a callback that handles logging in the Validator. This allows
|
||||
// the validator to integrate with a services' existing logging system without
|
||||
// prescribing a particular one.
|
||||
func OnLog(f LogFunc) ValidatorOption {
|
||||
return func(v *Validator) {
|
||||
v.logFunc = f
|
||||
}
|
||||
}
|
||||
|
||||
// Strict, if set, causes an internal server error to be sent if the wrapped
|
||||
// handler response fails response validation. If not set, the response is sent
|
||||
// and the error is only logged.
|
||||
func Strict(strict bool) ValidatorOption {
|
||||
return func(v *Validator) {
|
||||
v.strict = strict
|
||||
}
|
||||
}
|
||||
|
||||
// Middleware returns an http.Handler which wraps the given handler with
|
||||
// request and response validation.
|
||||
func (v *Validator) Middleware(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
route, pathParams, err := v.router.FindRoute(r)
|
||||
if err != nil {
|
||||
v.logFunc("validation error: failed to find route for "+r.URL.String(), err)
|
||||
v.errFunc(w, http.StatusNotFound, ErrCodeCannotFindRoute, err)
|
||||
return
|
||||
}
|
||||
requestValidationInput := &RequestValidationInput{
|
||||
Request: r,
|
||||
PathParams: pathParams,
|
||||
Route: route,
|
||||
}
|
||||
if err = ValidateRequest(r.Context(), requestValidationInput); err != nil {
|
||||
v.logFunc("invalid request", err)
|
||||
v.errFunc(w, http.StatusBadRequest, ErrCodeRequestInvalid, err)
|
||||
return
|
||||
}
|
||||
|
||||
var wr responseWrapper
|
||||
if v.strict {
|
||||
wr = &strictResponseWrapper{w: w}
|
||||
} else {
|
||||
wr = newWarnResponseWrapper(w)
|
||||
}
|
||||
|
||||
h.ServeHTTP(wr, r)
|
||||
|
||||
if err = ValidateResponse(r.Context(), &ResponseValidationInput{
|
||||
RequestValidationInput: requestValidationInput,
|
||||
Status: wr.statusCode(),
|
||||
Header: wr.Header(),
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer(wr.bodyContents())),
|
||||
}); err != nil {
|
||||
v.logFunc("invalid response", err)
|
||||
if v.strict {
|
||||
v.errFunc(w, http.StatusInternalServerError, ErrCodeResponseInvalid, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err = wr.flushBodyContents(); err != nil {
|
||||
v.logFunc("failed to write response", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type responseWrapper interface {
|
||||
http.ResponseWriter
|
||||
|
||||
// flushBodyContents writes the buffered response to the client, if it has
|
||||
// not yet been written.
|
||||
flushBodyContents() error
|
||||
|
||||
// statusCode returns the response status code, 0 if not set yet.
|
||||
statusCode() int
|
||||
|
||||
// bodyContents returns the buffered
|
||||
bodyContents() []byte
|
||||
}
|
||||
|
||||
type warnResponseWrapper struct {
|
||||
w http.ResponseWriter
|
||||
headerWritten bool
|
||||
status int
|
||||
body bytes.Buffer
|
||||
tee io.Writer
|
||||
}
|
||||
|
||||
func newWarnResponseWrapper(w http.ResponseWriter) *warnResponseWrapper {
|
||||
wr := &warnResponseWrapper{
|
||||
w: w,
|
||||
}
|
||||
wr.tee = io.MultiWriter(w, &wr.body)
|
||||
return wr
|
||||
}
|
||||
|
||||
// Write implements http.ResponseWriter.
|
||||
func (wr *warnResponseWrapper) Write(b []byte) (int, error) {
|
||||
if !wr.headerWritten {
|
||||
wr.WriteHeader(http.StatusOK)
|
||||
}
|
||||
return wr.tee.Write(b)
|
||||
}
|
||||
|
||||
// WriteHeader implements http.ResponseWriter.
|
||||
func (wr *warnResponseWrapper) WriteHeader(status int) {
|
||||
if !wr.headerWritten {
|
||||
// If the header hasn't been written, record the status for response
|
||||
// validation.
|
||||
wr.status = status
|
||||
wr.headerWritten = true
|
||||
}
|
||||
wr.w.WriteHeader(wr.status)
|
||||
}
|
||||
|
||||
// Header implements http.ResponseWriter.
|
||||
func (wr *warnResponseWrapper) Header() http.Header {
|
||||
return wr.w.Header()
|
||||
}
|
||||
|
||||
// Flush implements the optional http.Flusher interface.
|
||||
func (wr *warnResponseWrapper) Flush() {
|
||||
// If the wrapped http.ResponseWriter implements optional http.Flusher,
|
||||
// pass through.
|
||||
if fl, ok := wr.w.(http.Flusher); ok {
|
||||
fl.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
func (wr *warnResponseWrapper) flushBodyContents() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wr *warnResponseWrapper) statusCode() int {
|
||||
return wr.status
|
||||
}
|
||||
|
||||
func (wr *warnResponseWrapper) bodyContents() []byte {
|
||||
return wr.body.Bytes()
|
||||
}
|
||||
|
||||
type strictResponseWrapper struct {
|
||||
w http.ResponseWriter
|
||||
headerWritten bool
|
||||
status int
|
||||
body bytes.Buffer
|
||||
}
|
||||
|
||||
// Write implements http.ResponseWriter.
|
||||
func (wr *strictResponseWrapper) Write(b []byte) (int, error) {
|
||||
if !wr.headerWritten {
|
||||
wr.WriteHeader(http.StatusOK)
|
||||
}
|
||||
return wr.body.Write(b)
|
||||
}
|
||||
|
||||
// WriteHeader implements http.ResponseWriter.
|
||||
func (wr *strictResponseWrapper) WriteHeader(status int) {
|
||||
if !wr.headerWritten {
|
||||
wr.status = status
|
||||
wr.headerWritten = true
|
||||
}
|
||||
}
|
||||
|
||||
// Header implements http.ResponseWriter.
|
||||
func (wr *strictResponseWrapper) Header() http.Header {
|
||||
return wr.w.Header()
|
||||
}
|
||||
|
||||
func (wr *strictResponseWrapper) flushBodyContents() error {
|
||||
wr.w.WriteHeader(wr.status)
|
||||
_, err := wr.w.Write(wr.body.Bytes())
|
||||
return err
|
||||
}
|
||||
|
||||
func (wr *strictResponseWrapper) statusCode() int {
|
||||
return wr.status
|
||||
}
|
||||
|
||||
func (wr *strictResponseWrapper) bodyContents() []byte {
|
||||
return wr.body.Bytes()
|
||||
}
|
||||
24
vendor/github.com/getkin/kin-openapi/openapi3filter/options.go
generated
vendored
Normal file
24
vendor/github.com/getkin/kin-openapi/openapi3filter/options.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package openapi3filter
|
||||
|
||||
// DefaultOptions do not set an AuthenticationFunc.
|
||||
// A spec with security schemes defined will not pass validation
|
||||
// unless an AuthenticationFunc is defined.
|
||||
var DefaultOptions = &Options{}
|
||||
|
||||
// Options used by ValidateRequest and ValidateResponse
|
||||
type Options struct {
|
||||
// Set ExcludeRequestBody so ValidateRequest skips request body validation
|
||||
ExcludeRequestBody bool
|
||||
|
||||
// Set ExcludeResponseBody so ValidateResponse skips response body validation
|
||||
ExcludeResponseBody bool
|
||||
|
||||
// Set IncludeResponseStatus so ValidateResponse fails on response
|
||||
// status not defined in OpenAPI spec
|
||||
IncludeResponseStatus bool
|
||||
|
||||
MultiError bool
|
||||
|
||||
// See NoopAuthenticationFunc
|
||||
AuthenticationFunc AuthenticationFunc
|
||||
}
|
||||
1081
vendor/github.com/getkin/kin-openapi/openapi3filter/req_resp_decoder.go
generated
vendored
Normal file
1081
vendor/github.com/getkin/kin-openapi/openapi3filter/req_resp_decoder.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
332
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_request.go
generated
vendored
Normal file
332
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_request.go
generated
vendored
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
)
|
||||
|
||||
// ErrAuthenticationServiceMissing is returned when no authentication service
|
||||
// is defined for the request validator
|
||||
var ErrAuthenticationServiceMissing = errors.New("missing AuthenticationFunc")
|
||||
|
||||
// ErrInvalidRequired is returned when a required value of a parameter or request body is not defined.
|
||||
var ErrInvalidRequired = errors.New("value is required but missing")
|
||||
|
||||
// ErrInvalidEmptyValue is returned when a value of a parameter or request body is empty while it's not allowed.
|
||||
var ErrInvalidEmptyValue = errors.New("empty value is not allowed")
|
||||
|
||||
// ValidateRequest is used to validate the given input according to previous
|
||||
// loaded OpenAPIv3 spec. If the input does not match the OpenAPIv3 spec, a
|
||||
// non-nil error will be returned.
|
||||
//
|
||||
// Note: One can tune the behavior of uniqueItems: true verification
|
||||
// by registering a custom function with openapi3.RegisterArrayUniqueItemsChecker
|
||||
func ValidateRequest(ctx context.Context, input *RequestValidationInput) error {
|
||||
var (
|
||||
err error
|
||||
me openapi3.MultiError
|
||||
)
|
||||
|
||||
options := input.Options
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
}
|
||||
route := input.Route
|
||||
operation := route.Operation
|
||||
operationParameters := operation.Parameters
|
||||
pathItemParameters := route.PathItem.Parameters
|
||||
|
||||
// Security
|
||||
security := operation.Security
|
||||
// If there aren't any security requirements for the operation
|
||||
if security == nil {
|
||||
// Use the global security requirements.
|
||||
security = &route.Spec.Security
|
||||
}
|
||||
if security != nil {
|
||||
if err = ValidateSecurityRequirements(ctx, input, *security); err != nil && !options.MultiError {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
me = append(me, err)
|
||||
}
|
||||
}
|
||||
|
||||
// For each parameter of the PathItem
|
||||
for _, parameterRef := range pathItemParameters {
|
||||
parameter := parameterRef.Value
|
||||
if operationParameters != nil {
|
||||
if override := operationParameters.GetByInAndName(parameter.In, parameter.Name); override != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err = ValidateParameter(ctx, input, parameter); err != nil && !options.MultiError {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
me = append(me, err)
|
||||
}
|
||||
}
|
||||
|
||||
// For each parameter of the Operation
|
||||
for _, parameter := range operationParameters {
|
||||
if err = ValidateParameter(ctx, input, parameter.Value); err != nil && !options.MultiError {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
me = append(me, err)
|
||||
}
|
||||
}
|
||||
|
||||
// RequestBody
|
||||
requestBody := operation.RequestBody
|
||||
if requestBody != nil && !options.ExcludeRequestBody {
|
||||
if err = ValidateRequestBody(ctx, input, requestBody.Value); err != nil && !options.MultiError {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
me = append(me, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(me) > 0 {
|
||||
return me
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateParameter validates a parameter's value by JSON schema.
|
||||
// The function returns RequestError with a ParseError cause when unable to parse a value.
|
||||
// The function returns RequestError with ErrInvalidRequired cause when a value of a required parameter is not defined.
|
||||
// The function returns RequestError with ErrInvalidEmptyValue cause when a value of a required parameter is not defined.
|
||||
// The function returns RequestError with a openapi3.SchemaError cause when a value is invalid by JSON schema.
|
||||
func ValidateParameter(ctx context.Context, input *RequestValidationInput, parameter *openapi3.Parameter) error {
|
||||
if parameter.Schema == nil && parameter.Content == nil {
|
||||
// We have no schema for the parameter. Assume that everything passes
|
||||
// a schema-less check, but this could also be an error. The OpenAPI
|
||||
// validation allows this to happen.
|
||||
return nil
|
||||
}
|
||||
|
||||
options := input.Options
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
}
|
||||
|
||||
var value interface{}
|
||||
var err error
|
||||
var found bool
|
||||
var schema *openapi3.Schema
|
||||
|
||||
// Validation will ensure that we either have content or schema.
|
||||
if parameter.Content != nil {
|
||||
if value, schema, found, err = decodeContentParameter(parameter, input); err != nil {
|
||||
return &RequestError{Input: input, Parameter: parameter, Err: err}
|
||||
}
|
||||
} else {
|
||||
if value, found, err = decodeStyledParameter(parameter, input); err != nil {
|
||||
return &RequestError{Input: input, Parameter: parameter, Err: err}
|
||||
}
|
||||
schema = parameter.Schema.Value
|
||||
}
|
||||
// Validate a parameter's value and presence.
|
||||
if parameter.Required && !found {
|
||||
return &RequestError{Input: input, Parameter: parameter, Reason: ErrInvalidRequired.Error(), Err: ErrInvalidRequired}
|
||||
}
|
||||
|
||||
if isNilValue(value) {
|
||||
if !parameter.AllowEmptyValue && found {
|
||||
return &RequestError{Input: input, Parameter: parameter, Reason: ErrInvalidEmptyValue.Error(), Err: ErrInvalidEmptyValue}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if schema == nil {
|
||||
// A parameter's schema is not defined so skip validation of a parameter's value.
|
||||
return nil
|
||||
}
|
||||
|
||||
var opts []openapi3.SchemaValidationOption
|
||||
if options.MultiError {
|
||||
opts = make([]openapi3.SchemaValidationOption, 0, 1)
|
||||
opts = append(opts, openapi3.MultiErrors())
|
||||
}
|
||||
if err = schema.VisitJSON(value, opts...); err != nil {
|
||||
return &RequestError{Input: input, Parameter: parameter, Err: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const prefixInvalidCT = "header Content-Type has unexpected value"
|
||||
|
||||
// ValidateRequestBody validates data of a request's body.
|
||||
//
|
||||
// The function returns RequestError with ErrInvalidRequired cause when a value is required but not defined.
|
||||
// The function returns RequestError with a openapi3.SchemaError cause when a value is invalid by JSON schema.
|
||||
func ValidateRequestBody(ctx context.Context, input *RequestValidationInput, requestBody *openapi3.RequestBody) error {
|
||||
var (
|
||||
req = input.Request
|
||||
data []byte
|
||||
)
|
||||
|
||||
options := input.Options
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
}
|
||||
|
||||
if req.Body != http.NoBody && req.Body != nil {
|
||||
defer req.Body.Close()
|
||||
var err error
|
||||
if data, err = ioutil.ReadAll(req.Body); err != nil {
|
||||
return &RequestError{
|
||||
Input: input,
|
||||
RequestBody: requestBody,
|
||||
Reason: "reading failed",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
// Put the data back into the input
|
||||
req.Body = ioutil.NopCloser(bytes.NewReader(data))
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
if requestBody.Required {
|
||||
return &RequestError{Input: input, RequestBody: requestBody, Err: ErrInvalidRequired}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
content := requestBody.Content
|
||||
if len(content) == 0 {
|
||||
// A request's body does not have declared content, so skip validation.
|
||||
return nil
|
||||
}
|
||||
|
||||
inputMIME := req.Header.Get(headerCT)
|
||||
contentType := requestBody.Content.Get(inputMIME)
|
||||
if contentType == nil {
|
||||
return &RequestError{
|
||||
Input: input,
|
||||
RequestBody: requestBody,
|
||||
Reason: fmt.Sprintf("%s %q", prefixInvalidCT, inputMIME),
|
||||
}
|
||||
}
|
||||
|
||||
if contentType.Schema == nil {
|
||||
// A JSON schema that describes the received data is not declared, so skip validation.
|
||||
return nil
|
||||
}
|
||||
|
||||
encFn := func(name string) *openapi3.Encoding { return contentType.Encoding[name] }
|
||||
value, err := decodeBody(bytes.NewReader(data), req.Header, contentType.Schema, encFn)
|
||||
if err != nil {
|
||||
return &RequestError{
|
||||
Input: input,
|
||||
RequestBody: requestBody,
|
||||
Reason: "failed to decode request body",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
opts := make([]openapi3.SchemaValidationOption, 0, 2) // 2 potential opts here
|
||||
opts = append(opts, openapi3.VisitAsRequest())
|
||||
if options.MultiError {
|
||||
opts = append(opts, openapi3.MultiErrors())
|
||||
}
|
||||
|
||||
// Validate JSON with the schema
|
||||
if err := contentType.Schema.Value.VisitJSON(value, opts...); err != nil {
|
||||
return &RequestError{
|
||||
Input: input,
|
||||
RequestBody: requestBody,
|
||||
Reason: "doesn't match the schema",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateSecurityRequirements goes through multiple OpenAPI 3 security
|
||||
// requirements in order and returns nil on the first valid requirement.
|
||||
// If no requirement is met, errors are returned in order.
|
||||
func ValidateSecurityRequirements(ctx context.Context, input *RequestValidationInput, srs openapi3.SecurityRequirements) error {
|
||||
if len(srs) == 0 {
|
||||
return nil
|
||||
}
|
||||
var errs []error
|
||||
for _, sr := range srs {
|
||||
if err := validateSecurityRequirement(ctx, input, sr); err != nil {
|
||||
if len(errs) == 0 {
|
||||
errs = make([]error, 0, len(srs))
|
||||
}
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return &SecurityRequirementsError{
|
||||
SecurityRequirements: srs,
|
||||
Errors: errs,
|
||||
}
|
||||
}
|
||||
|
||||
// validateSecurityRequirement validates a single OpenAPI 3 security requirement
|
||||
func validateSecurityRequirement(ctx context.Context, input *RequestValidationInput, securityRequirement openapi3.SecurityRequirement) error {
|
||||
doc := input.Route.Spec
|
||||
securitySchemes := doc.Components.SecuritySchemes
|
||||
|
||||
// Ensure deterministic order
|
||||
names := make([]string, 0, len(securityRequirement))
|
||||
for name := range securityRequirement {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
// Get authentication function
|
||||
options := input.Options
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
}
|
||||
f := options.AuthenticationFunc
|
||||
if f == nil {
|
||||
return ErrAuthenticationServiceMissing
|
||||
}
|
||||
|
||||
// For each scheme for the requirement
|
||||
for _, name := range names {
|
||||
var securityScheme *openapi3.SecurityScheme
|
||||
if securitySchemes != nil {
|
||||
if ref := securitySchemes[name]; ref != nil {
|
||||
securityScheme = ref.Value
|
||||
}
|
||||
}
|
||||
if securityScheme == nil {
|
||||
return &RequestError{
|
||||
Input: input,
|
||||
Err: fmt.Errorf("security scheme %q is not declared", name),
|
||||
}
|
||||
}
|
||||
scopes := securityRequirement[name]
|
||||
if err := f(ctx, &AuthenticationInput{
|
||||
RequestValidationInput: input,
|
||||
SecuritySchemeName: name,
|
||||
SecurityScheme: securityScheme,
|
||||
Scopes: scopes,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
38
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_request_input.go
generated
vendored
Normal file
38
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_request_input.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/getkin/kin-openapi/routers"
|
||||
)
|
||||
|
||||
// A ContentParameterDecoder takes a parameter definition from the OpenAPI spec,
|
||||
// and the value which we received for it. It is expected to return the
|
||||
// value unmarshaled into an interface which can be traversed for
|
||||
// validation, it should also return the schema to be used for validating the
|
||||
// object, since there can be more than one in the content spec.
|
||||
//
|
||||
// If a query parameter appears multiple times, values[] will have more
|
||||
// than one value, but for all other parameter types it should have just
|
||||
// one.
|
||||
type ContentParameterDecoder func(param *openapi3.Parameter, values []string) (interface{}, *openapi3.Schema, error)
|
||||
|
||||
type RequestValidationInput struct {
|
||||
Request *http.Request
|
||||
PathParams map[string]string
|
||||
QueryParams url.Values
|
||||
Route *routers.Route
|
||||
Options *Options
|
||||
ParamDecoder ContentParameterDecoder
|
||||
}
|
||||
|
||||
func (input *RequestValidationInput) GetQueryParams() url.Values {
|
||||
q := input.QueryParams
|
||||
if q == nil {
|
||||
q = input.Request.URL.Query()
|
||||
input.QueryParams = q
|
||||
}
|
||||
return q
|
||||
}
|
||||
138
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_response.go
generated
vendored
Normal file
138
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_response.go
generated
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
// Package openapi3filter validates that requests and inputs request an OpenAPI 3 specification file.
|
||||
package openapi3filter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
)
|
||||
|
||||
// ValidateResponse is used to validate the given input according to previous
|
||||
// loaded OpenAPIv3 spec. If the input does not match the OpenAPIv3 spec, a
|
||||
// non-nil error will be returned.
|
||||
//
|
||||
// Note: One can tune the behavior of uniqueItems: true verification
|
||||
// by registering a custom function with openapi3.RegisterArrayUniqueItemsChecker
|
||||
func ValidateResponse(ctx context.Context, input *ResponseValidationInput) error {
|
||||
req := input.RequestValidationInput.Request
|
||||
switch req.Method {
|
||||
case "HEAD":
|
||||
return nil
|
||||
}
|
||||
status := input.Status
|
||||
|
||||
// These status codes will never be validated.
|
||||
// TODO: The list is probably missing some.
|
||||
switch status {
|
||||
case http.StatusNotModified,
|
||||
http.StatusPermanentRedirect,
|
||||
http.StatusTemporaryRedirect,
|
||||
http.StatusMovedPermanently:
|
||||
return nil
|
||||
}
|
||||
route := input.RequestValidationInput.Route
|
||||
options := input.Options
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
}
|
||||
|
||||
// Find input for the current status
|
||||
responses := route.Operation.Responses
|
||||
if len(responses) == 0 {
|
||||
return nil
|
||||
}
|
||||
responseRef := responses.Get(status) // Response
|
||||
if responseRef == nil {
|
||||
responseRef = responses.Default() // Default input
|
||||
}
|
||||
if responseRef == nil {
|
||||
// By default, status that is not documented is allowed.
|
||||
if !options.IncludeResponseStatus {
|
||||
return nil
|
||||
}
|
||||
return &ResponseError{Input: input, Reason: "status is not supported"}
|
||||
}
|
||||
response := responseRef.Value
|
||||
if response == nil {
|
||||
return &ResponseError{Input: input, Reason: "response has not been resolved"}
|
||||
}
|
||||
|
||||
if options.ExcludeResponseBody {
|
||||
// A user turned off validation of a response's body.
|
||||
return nil
|
||||
}
|
||||
|
||||
content := response.Content
|
||||
if len(content) == 0 || options.ExcludeResponseBody {
|
||||
// An operation does not contains a validation schema for responses with this status code.
|
||||
return nil
|
||||
}
|
||||
|
||||
inputMIME := input.Header.Get(headerCT)
|
||||
contentType := content.Get(inputMIME)
|
||||
if contentType == nil {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
Reason: fmt.Sprintf("response header Content-Type has unexpected value: %q", inputMIME),
|
||||
}
|
||||
}
|
||||
|
||||
if contentType.Schema == nil {
|
||||
// An operation does not contains a validation schema for responses with this status code.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read response's body.
|
||||
body := input.Body
|
||||
|
||||
// Response would contain partial or empty input body
|
||||
// after we begin reading.
|
||||
// Ensure that this doesn't happen.
|
||||
input.Body = nil
|
||||
|
||||
// Ensure we close the reader
|
||||
defer body.Close()
|
||||
|
||||
// Read all
|
||||
data, err := ioutil.ReadAll(body)
|
||||
if err != nil {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
Reason: "failed to read response body",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// Put the data back into the response.
|
||||
input.SetBodyBytes(data)
|
||||
|
||||
encFn := func(name string) *openapi3.Encoding { return contentType.Encoding[name] }
|
||||
value, err := decodeBody(bytes.NewBuffer(data), input.Header, contentType.Schema, encFn)
|
||||
if err != nil {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
Reason: "failed to decode response body",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
opts := make([]openapi3.SchemaValidationOption, 0, 2) // 2 potential opts here
|
||||
opts = append(opts, openapi3.VisitAsRequest())
|
||||
if options.MultiError {
|
||||
opts = append(opts, openapi3.MultiErrors())
|
||||
}
|
||||
|
||||
// Validate data with the schema.
|
||||
if err := contentType.Schema.Value.VisitJSON(value, opts...); err != nil {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
Reason: "response body doesn't match the schema",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
42
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_response_input.go
generated
vendored
Normal file
42
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_response_input.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ResponseValidationInput struct {
|
||||
RequestValidationInput *RequestValidationInput
|
||||
Status int
|
||||
Header http.Header
|
||||
Body io.ReadCloser
|
||||
Options *Options
|
||||
}
|
||||
|
||||
func (input *ResponseValidationInput) SetBodyBytes(value []byte) *ResponseValidationInput {
|
||||
input.Body = ioutil.NopCloser(bytes.NewReader(value))
|
||||
return input
|
||||
}
|
||||
|
||||
var JSONPrefixes = []string{
|
||||
")]}',\n",
|
||||
}
|
||||
|
||||
// TrimJSONPrefix trims one of the possible prefixes
|
||||
func TrimJSONPrefix(data []byte) []byte {
|
||||
search:
|
||||
for _, prefix := range JSONPrefixes {
|
||||
if len(data) < len(prefix) {
|
||||
continue
|
||||
}
|
||||
for i, b := range data[:len(prefix)] {
|
||||
if b != prefix[i] {
|
||||
continue search
|
||||
}
|
||||
}
|
||||
return data[len(prefix):]
|
||||
}
|
||||
return data
|
||||
}
|
||||
85
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_error.go
generated
vendored
Normal file
85
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_error.go
generated
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ValidationError struct provides granular error information
|
||||
// useful for communicating issues back to end user and developer.
|
||||
// Based on https://jsonapi.org/format/#error-objects
|
||||
type ValidationError struct {
|
||||
// A unique identifier for this particular occurrence of the problem.
|
||||
Id string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
// The HTTP status code applicable to this problem.
|
||||
Status int `json:"status,omitempty" yaml:"status,omitempty"`
|
||||
// An application-specific error code, expressed as a string value.
|
||||
Code string `json:"code,omitempty" yaml:"code,omitempty"`
|
||||
// A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.
|
||||
Title string `json:"title,omitempty" yaml:"title,omitempty"`
|
||||
// A human-readable explanation specific to this occurrence of the problem.
|
||||
Detail string `json:"detail,omitempty" yaml:"detail,omitempty"`
|
||||
// An object containing references to the source of the error
|
||||
Source *ValidationErrorSource `json:"source,omitempty" yaml:"source,omitempty"`
|
||||
}
|
||||
|
||||
// ValidationErrorSource struct
|
||||
type ValidationErrorSource struct {
|
||||
// A JSON Pointer [RFC6901] to the associated entity in the request document [e.g. \"/data\" for a primary data object, or \"/data/attributes/title\" for a specific attribute].
|
||||
Pointer string `json:"pointer,omitempty" yaml:"pointer,omitempty"`
|
||||
// A string indicating which query parameter caused the error.
|
||||
Parameter string `json:"parameter,omitempty" yaml:"parameter,omitempty"`
|
||||
}
|
||||
|
||||
var _ error = &ValidationError{}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e *ValidationError) Error() string {
|
||||
b := new(bytes.Buffer)
|
||||
b.WriteString("[")
|
||||
if e.Status != 0 {
|
||||
b.WriteString(strconv.Itoa(e.Status))
|
||||
}
|
||||
b.WriteString("]")
|
||||
b.WriteString("[")
|
||||
if e.Code != "" {
|
||||
b.WriteString(e.Code)
|
||||
}
|
||||
b.WriteString("]")
|
||||
b.WriteString("[")
|
||||
if e.Id != "" {
|
||||
b.WriteString(e.Id)
|
||||
}
|
||||
b.WriteString("]")
|
||||
b.WriteString(" ")
|
||||
if e.Title != "" {
|
||||
b.WriteString(e.Title)
|
||||
b.WriteString(" ")
|
||||
}
|
||||
if e.Detail != "" {
|
||||
b.WriteString("| ")
|
||||
b.WriteString(e.Detail)
|
||||
b.WriteString(" ")
|
||||
}
|
||||
if e.Source != nil {
|
||||
b.WriteString("[source ")
|
||||
if e.Source.Parameter != "" {
|
||||
b.WriteString("parameter=")
|
||||
b.WriteString(e.Source.Parameter)
|
||||
} else if e.Source.Pointer != "" {
|
||||
b.WriteString("pointer=")
|
||||
b.WriteString(e.Source.Pointer)
|
||||
}
|
||||
b.WriteString("]")
|
||||
}
|
||||
|
||||
if b.Len() == 0 {
|
||||
return "no error"
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// StatusCode implements the StatusCoder interface for DefaultErrorEncoder
|
||||
func (e *ValidationError) StatusCode() int {
|
||||
return e.Status
|
||||
}
|
||||
185
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_error_encoder.go
generated
vendored
Normal file
185
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_error_encoder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/getkin/kin-openapi/routers"
|
||||
)
|
||||
|
||||
// ValidationErrorEncoder wraps a base ErrorEncoder to handle ValidationErrors
|
||||
type ValidationErrorEncoder struct {
|
||||
Encoder ErrorEncoder
|
||||
}
|
||||
|
||||
// Encode implements the ErrorEncoder interface for encoding ValidationErrors
|
||||
func (enc *ValidationErrorEncoder) Encode(ctx context.Context, err error, w http.ResponseWriter) {
|
||||
if e, ok := err.(*routers.RouteError); ok {
|
||||
cErr := convertRouteError(e)
|
||||
enc.Encoder(ctx, cErr, w)
|
||||
return
|
||||
}
|
||||
|
||||
e, ok := err.(*RequestError)
|
||||
if !ok {
|
||||
enc.Encoder(ctx, err, w)
|
||||
return
|
||||
}
|
||||
|
||||
var cErr *ValidationError
|
||||
if e.Err == nil {
|
||||
cErr = convertBasicRequestError(e)
|
||||
} else if e.Err == ErrInvalidRequired {
|
||||
cErr = convertErrInvalidRequired(e)
|
||||
} else if e.Err == ErrInvalidEmptyValue {
|
||||
cErr = convertErrInvalidEmptyValue(e)
|
||||
} else if innerErr, ok := e.Err.(*ParseError); ok {
|
||||
cErr = convertParseError(e, innerErr)
|
||||
} else if innerErr, ok := e.Err.(*openapi3.SchemaError); ok {
|
||||
cErr = convertSchemaError(e, innerErr)
|
||||
}
|
||||
|
||||
if cErr != nil {
|
||||
enc.Encoder(ctx, cErr, w)
|
||||
return
|
||||
}
|
||||
enc.Encoder(ctx, err, w)
|
||||
}
|
||||
|
||||
func convertRouteError(e *routers.RouteError) *ValidationError {
|
||||
status := http.StatusNotFound
|
||||
if e.Error() == routers.ErrMethodNotAllowed.Error() {
|
||||
status = http.StatusMethodNotAllowed
|
||||
}
|
||||
return &ValidationError{Status: status, Title: e.Error()}
|
||||
}
|
||||
|
||||
func convertBasicRequestError(e *RequestError) *ValidationError {
|
||||
if strings.HasPrefix(e.Reason, prefixInvalidCT) {
|
||||
if strings.HasSuffix(e.Reason, `""`) {
|
||||
return &ValidationError{
|
||||
Status: http.StatusUnsupportedMediaType,
|
||||
Title: "header Content-Type is required",
|
||||
}
|
||||
}
|
||||
return &ValidationError{
|
||||
Status: http.StatusUnsupportedMediaType,
|
||||
Title: prefixUnsupportedCT + strings.TrimPrefix(e.Reason, prefixInvalidCT),
|
||||
}
|
||||
}
|
||||
return &ValidationError{
|
||||
Status: http.StatusBadRequest,
|
||||
Title: e.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
func convertErrInvalidRequired(e *RequestError) *ValidationError {
|
||||
if e.Err == ErrInvalidRequired && e.Parameter != nil {
|
||||
return &ValidationError{
|
||||
Status: http.StatusBadRequest,
|
||||
Title: fmt.Sprintf("parameter %q in %s is required", e.Parameter.Name, e.Parameter.In),
|
||||
}
|
||||
}
|
||||
return &ValidationError{
|
||||
Status: http.StatusBadRequest,
|
||||
Title: e.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
func convertErrInvalidEmptyValue(e *RequestError) *ValidationError {
|
||||
if e.Err == ErrInvalidEmptyValue && e.Parameter != nil {
|
||||
return &ValidationError{
|
||||
Status: http.StatusBadRequest,
|
||||
Title: fmt.Sprintf("parameter %q in %s is not allowed to be empty", e.Parameter.Name, e.Parameter.In),
|
||||
}
|
||||
}
|
||||
return &ValidationError{
|
||||
Status: http.StatusBadRequest,
|
||||
Title: e.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
func convertParseError(e *RequestError, innerErr *ParseError) *ValidationError {
|
||||
// We treat path params of the wrong type like a 404 instead of a 400
|
||||
if innerErr.Kind == KindInvalidFormat && e.Parameter != nil && e.Parameter.In == "path" {
|
||||
return &ValidationError{
|
||||
Status: http.StatusNotFound,
|
||||
Title: fmt.Sprintf("resource not found with %q value: %v", e.Parameter.Name, innerErr.Value),
|
||||
}
|
||||
} else if strings.HasPrefix(innerErr.Reason, prefixUnsupportedCT) {
|
||||
return &ValidationError{
|
||||
Status: http.StatusUnsupportedMediaType,
|
||||
Title: innerErr.Reason,
|
||||
}
|
||||
} else if innerErr.RootCause() != nil {
|
||||
if rootErr, ok := innerErr.Cause.(*ParseError); ok &&
|
||||
rootErr.Kind == KindInvalidFormat && e.Parameter.In == "query" {
|
||||
return &ValidationError{
|
||||
Status: http.StatusBadRequest,
|
||||
Title: fmt.Sprintf("parameter %q in %s is invalid: %v is %s",
|
||||
e.Parameter.Name, e.Parameter.In, rootErr.Value, rootErr.Reason),
|
||||
}
|
||||
}
|
||||
return &ValidationError{
|
||||
Status: http.StatusBadRequest,
|
||||
Title: innerErr.Reason,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertSchemaError(e *RequestError, innerErr *openapi3.SchemaError) *ValidationError {
|
||||
cErr := &ValidationError{Title: innerErr.Reason}
|
||||
|
||||
// Handle "Origin" error
|
||||
if originErr, ok := innerErr.Origin.(*openapi3.SchemaError); ok {
|
||||
cErr = convertSchemaError(e, originErr)
|
||||
}
|
||||
|
||||
// Add http status code
|
||||
if e.Parameter != nil {
|
||||
cErr.Status = http.StatusBadRequest
|
||||
} else if e.RequestBody != nil {
|
||||
cErr.Status = http.StatusUnprocessableEntity
|
||||
}
|
||||
|
||||
// Add error source
|
||||
if e.Parameter != nil {
|
||||
// We have a JSONPointer in the query param too so need to
|
||||
// make sure 'Parameter' check takes priority over 'Pointer'
|
||||
cErr.Source = &ValidationErrorSource{Parameter: e.Parameter.Name}
|
||||
} else if ptr := innerErr.JSONPointer(); ptr != nil {
|
||||
cErr.Source = &ValidationErrorSource{Pointer: toJSONPointer(ptr)}
|
||||
}
|
||||
|
||||
// Add details on allowed values for enums
|
||||
if innerErr.SchemaField == "enum" {
|
||||
enums := make([]string, 0, len(innerErr.Schema.Enum))
|
||||
for _, enum := range innerErr.Schema.Enum {
|
||||
enums = append(enums, fmt.Sprintf("%v", enum))
|
||||
}
|
||||
cErr.Detail = fmt.Sprintf("value %v at %s must be one of: %s",
|
||||
innerErr.Value,
|
||||
toJSONPointer(innerErr.JSONPointer()),
|
||||
strings.Join(enums, ", "))
|
||||
value := fmt.Sprintf("%v", innerErr.Value)
|
||||
if e.Parameter != nil &&
|
||||
(e.Parameter.Explode == nil || *e.Parameter.Explode) &&
|
||||
(e.Parameter.Style == "" || e.Parameter.Style == "form") &&
|
||||
strings.Contains(value, ",") {
|
||||
parts := strings.Split(value, ",")
|
||||
cErr.Detail = fmt.Sprintf("%s; perhaps you intended '?%s=%s'",
|
||||
cErr.Detail,
|
||||
e.Parameter.Name,
|
||||
strings.Join(parts, "&"+e.Parameter.Name+"="))
|
||||
}
|
||||
}
|
||||
return cErr
|
||||
}
|
||||
|
||||
func toJSONPointer(reversePath []string) string {
|
||||
return "/" + strings.Join(reversePath, "/")
|
||||
}
|
||||
103
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_handler.go
generated
vendored
Normal file
103
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_handler.go
generated
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/getkin/kin-openapi/routers"
|
||||
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"
|
||||
)
|
||||
|
||||
type AuthenticationFunc func(context.Context, *AuthenticationInput) error
|
||||
|
||||
func NoopAuthenticationFunc(context.Context, *AuthenticationInput) error { return nil }
|
||||
|
||||
var _ AuthenticationFunc = NoopAuthenticationFunc
|
||||
|
||||
type ValidationHandler struct {
|
||||
Handler http.Handler
|
||||
AuthenticationFunc AuthenticationFunc
|
||||
File string
|
||||
ErrorEncoder ErrorEncoder
|
||||
router routers.Router
|
||||
}
|
||||
|
||||
func (h *ValidationHandler) Load() error {
|
||||
loader := openapi3.NewLoader()
|
||||
doc, err := loader.LoadFromFile(h.File)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := doc.Validate(loader.Context); err != nil {
|
||||
return err
|
||||
}
|
||||
if h.router, err = legacyrouter.NewRouter(doc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set defaults
|
||||
if h.Handler == nil {
|
||||
h.Handler = http.DefaultServeMux
|
||||
}
|
||||
if h.AuthenticationFunc == nil {
|
||||
h.AuthenticationFunc = NoopAuthenticationFunc
|
||||
}
|
||||
if h.ErrorEncoder == nil {
|
||||
h.ErrorEncoder = DefaultErrorEncoder
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *ValidationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if handled := h.before(w, r); handled {
|
||||
return
|
||||
}
|
||||
// TODO: validateResponse
|
||||
h.Handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// Middleware implements gorilla/mux MiddlewareFunc
|
||||
func (h *ValidationHandler) Middleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if handled := h.before(w, r); handled {
|
||||
return
|
||||
}
|
||||
// TODO: validateResponse
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (h *ValidationHandler) before(w http.ResponseWriter, r *http.Request) (handled bool) {
|
||||
if err := h.validateRequest(r); err != nil {
|
||||
h.ErrorEncoder(r.Context(), err, w)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *ValidationHandler) validateRequest(r *http.Request) error {
|
||||
// Find route
|
||||
route, pathParams, err := h.router.FindRoute(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
options := &Options{
|
||||
AuthenticationFunc: h.AuthenticationFunc,
|
||||
}
|
||||
|
||||
// Validate request
|
||||
requestValidationInput := &RequestValidationInput{
|
||||
Request: r,
|
||||
PathParams: pathParams,
|
||||
Route: route,
|
||||
Options: options,
|
||||
}
|
||||
if err = ValidateRequest(r.Context(), requestValidationInput); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
85
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_kit.go
generated
vendored
Normal file
85
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_kit.go
generated
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// We didn't want to tie kin-openapi too tightly with go-kit.
|
||||
// This file contains the ErrorEncoder and DefaultErrorEncoder function
|
||||
// borrowed from this project.
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2015 Peter Bourgon
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ErrorEncoder is responsible for encoding an error to the ResponseWriter.
|
||||
// Users are encouraged to use custom ErrorEncoders to encode HTTP errors to
|
||||
// their clients, and will likely want to pass and check for their own error
|
||||
// types. See the example shipping/handling service.
|
||||
type ErrorEncoder func(ctx context.Context, err error, w http.ResponseWriter)
|
||||
|
||||
// StatusCoder is checked by DefaultErrorEncoder. If an error value implements
|
||||
// StatusCoder, the StatusCode will be used when encoding the error. By default,
|
||||
// StatusInternalServerError (500) is used.
|
||||
type StatusCoder interface {
|
||||
StatusCode() int
|
||||
}
|
||||
|
||||
// Headerer is checked by DefaultErrorEncoder. If an error value implements
|
||||
// Headerer, the provided headers will be applied to the response writer, after
|
||||
// the Content-Type is set.
|
||||
type Headerer interface {
|
||||
Headers() http.Header
|
||||
}
|
||||
|
||||
// DefaultErrorEncoder writes the error to the ResponseWriter, by default a
|
||||
// content type of text/plain, a body of the plain text of the error, and a
|
||||
// status code of 500. If the error implements Headerer, the provided headers
|
||||
// will be applied to the response. If the error implements json.Marshaler, and
|
||||
// the marshaling succeeds, a content type of application/json and the JSON
|
||||
// encoded form of the error will be used. If the error implements StatusCoder,
|
||||
// the provided StatusCode will be used instead of 500.
|
||||
func DefaultErrorEncoder(_ context.Context, err error, w http.ResponseWriter) {
|
||||
contentType, body := "text/plain; charset=utf-8", []byte(err.Error())
|
||||
if marshaler, ok := err.(json.Marshaler); ok {
|
||||
if jsonBody, marshalErr := marshaler.MarshalJSON(); marshalErr == nil {
|
||||
contentType, body = "application/json; charset=utf-8", jsonBody
|
||||
}
|
||||
}
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
if headerer, ok := err.(Headerer); ok {
|
||||
for k, values := range headerer.Headers() {
|
||||
for _, v := range values {
|
||||
w.Header().Add(k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
code := http.StatusInternalServerError
|
||||
if sc, ok := err.(StatusCoder); ok {
|
||||
code = sc.StatusCode()
|
||||
}
|
||||
w.WriteHeader(code)
|
||||
w.Write(body)
|
||||
}
|
||||
328
vendor/github.com/getkin/kin-openapi/routers/legacy/pathpattern/node.go
generated
vendored
Normal file
328
vendor/github.com/getkin/kin-openapi/routers/legacy/pathpattern/node.go
generated
vendored
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
// Package pathpattern implements path matching.
|
||||
//
|
||||
// Examples of supported patterns:
|
||||
// * "/"
|
||||
// * "/abc""
|
||||
// * "/abc/{variable}" (matches until next '/' or end-of-string)
|
||||
// * "/abc/{variable*}" (matches everything, including "/abc" if "/abc" has noot)
|
||||
// * "/abc/{ variable | prefix_(.*}_suffix }" (matches regular expressions)
|
||||
package pathpattern
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var DefaultOptions = &Options{
|
||||
SupportWildcard: true,
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
SupportWildcard bool
|
||||
SupportRegExp bool
|
||||
}
|
||||
|
||||
// PathFromHost converts a host pattern to a path pattern.
|
||||
//
|
||||
// Examples:
|
||||
// * PathFromHost("some-subdomain.domain.com", false) -> "com/./domain/./some-subdomain"
|
||||
// * PathFromHost("some-subdomain.domain.com", true) -> "com/./domain/./subdomain/-/some"
|
||||
func PathFromHost(host string, specialDashes bool) string {
|
||||
buf := make([]byte, 0, len(host))
|
||||
end := len(host)
|
||||
|
||||
// Go from end to start
|
||||
for start := end - 1; start >= 0; start-- {
|
||||
switch host[start] {
|
||||
case '.':
|
||||
buf = append(buf, host[start+1:end]...)
|
||||
buf = append(buf, '/', '.', '/')
|
||||
end = start
|
||||
case '-':
|
||||
if specialDashes {
|
||||
buf = append(buf, host[start+1:end]...)
|
||||
buf = append(buf, '/', '-', '/')
|
||||
end = start
|
||||
}
|
||||
}
|
||||
}
|
||||
buf = append(buf, host[:end]...)
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
VariableNames []string
|
||||
Value interface{}
|
||||
Suffixes SuffixList
|
||||
}
|
||||
|
||||
func (currentNode *Node) String() string {
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 255))
|
||||
currentNode.toBuffer(buf, "")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (currentNode *Node) toBuffer(buf *bytes.Buffer, linePrefix string) {
|
||||
if value := currentNode.Value; value != nil {
|
||||
buf.WriteString(linePrefix)
|
||||
buf.WriteString("VALUE: ")
|
||||
fmt.Fprint(buf, value)
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
suffixes := currentNode.Suffixes
|
||||
if len(suffixes) > 0 {
|
||||
newLinePrefix := linePrefix + " "
|
||||
for _, suffix := range suffixes {
|
||||
buf.WriteString(linePrefix)
|
||||
buf.WriteString("PATTERN: ")
|
||||
buf.WriteString(suffix.String())
|
||||
buf.WriteString("\n")
|
||||
suffix.Node.toBuffer(buf, newLinePrefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type SuffixKind int
|
||||
|
||||
// Note that order is important!
|
||||
const (
|
||||
// SuffixKindConstant matches a constant string
|
||||
SuffixKindConstant = SuffixKind(iota)
|
||||
|
||||
// SuffixKindRegExp matches a regular expression
|
||||
SuffixKindRegExp
|
||||
|
||||
// SuffixKindVariable matches everything until '/'
|
||||
SuffixKindVariable
|
||||
|
||||
// SuffixKindEverything matches everything (until end-of-string)
|
||||
SuffixKindEverything
|
||||
)
|
||||
|
||||
// Suffix describes condition that
|
||||
type Suffix struct {
|
||||
Kind SuffixKind
|
||||
Pattern string
|
||||
|
||||
// compiled regular expression
|
||||
regExp *regexp.Regexp
|
||||
|
||||
// Next node
|
||||
Node *Node
|
||||
}
|
||||
|
||||
func EqualSuffix(a, b Suffix) bool {
|
||||
return a.Kind == b.Kind && a.Pattern == b.Pattern
|
||||
}
|
||||
|
||||
func (suffix Suffix) String() string {
|
||||
switch suffix.Kind {
|
||||
case SuffixKindConstant:
|
||||
return suffix.Pattern
|
||||
case SuffixKindVariable:
|
||||
return "{_}"
|
||||
case SuffixKindEverything:
|
||||
return "{_*}"
|
||||
default:
|
||||
return "{_|" + suffix.Pattern + "}"
|
||||
}
|
||||
}
|
||||
|
||||
type SuffixList []Suffix
|
||||
|
||||
func (list SuffixList) Less(i, j int) bool {
|
||||
a, b := list[i], list[j]
|
||||
ak, bk := a.Kind, b.Kind
|
||||
if ak < bk {
|
||||
return true
|
||||
} else if bk < ak {
|
||||
return false
|
||||
}
|
||||
return a.Pattern > b.Pattern
|
||||
}
|
||||
|
||||
func (list SuffixList) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list SuffixList) Swap(i, j int) {
|
||||
a, b := list[i], list[j]
|
||||
list[i], list[j] = b, a
|
||||
}
|
||||
|
||||
func (currentNode *Node) MustAdd(path string, value interface{}, options *Options) {
|
||||
node, err := currentNode.CreateNode(path, options)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
node.Value = value
|
||||
}
|
||||
|
||||
func (currentNode *Node) Add(path string, value interface{}, options *Options) error {
|
||||
node, err := currentNode.CreateNode(path, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
node.Value = value
|
||||
return nil
|
||||
}
|
||||
|
||||
func (currentNode *Node) CreateNode(path string, options *Options) (*Node, error) {
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
}
|
||||
for strings.HasSuffix(path, "/") {
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
remaining := path
|
||||
var variableNames []string
|
||||
loop:
|
||||
for {
|
||||
//remaining = strings.TrimPrefix(remaining, "/")
|
||||
if len(remaining) == 0 {
|
||||
// This node is the right one
|
||||
// Check whether another route already leads to this node
|
||||
currentNode.VariableNames = variableNames
|
||||
return currentNode, nil
|
||||
}
|
||||
|
||||
suffix := Suffix{}
|
||||
var i int
|
||||
if strings.HasPrefix(remaining, "/") {
|
||||
remaining = remaining[1:]
|
||||
suffix.Kind = SuffixKindConstant
|
||||
suffix.Pattern = "/"
|
||||
} else {
|
||||
i = strings.IndexAny(remaining, "/{")
|
||||
if i < 0 {
|
||||
i = len(remaining)
|
||||
}
|
||||
if i > 0 {
|
||||
// Constant string pattern
|
||||
suffix.Kind = SuffixKindConstant
|
||||
suffix.Pattern = remaining[:i]
|
||||
remaining = remaining[i:]
|
||||
} else if remaining[0] == '{' {
|
||||
// This is probably a variable
|
||||
suffix.Kind = SuffixKindVariable
|
||||
|
||||
// Find variable name
|
||||
i := strings.IndexByte(remaining, '}')
|
||||
if i < 0 {
|
||||
return nil, fmt.Errorf("missing '}' in: %s", path)
|
||||
}
|
||||
variableName := strings.TrimSpace(remaining[1:i])
|
||||
remaining = remaining[i+1:]
|
||||
|
||||
if options.SupportRegExp {
|
||||
// See if it has regular expression
|
||||
i = strings.IndexByte(variableName, '|')
|
||||
if i >= 0 {
|
||||
suffix.Kind = SuffixKindRegExp
|
||||
suffix.Pattern = strings.TrimSpace(variableName[i+1:])
|
||||
variableName = strings.TrimSpace(variableName[:i])
|
||||
}
|
||||
}
|
||||
if suffix.Kind == SuffixKindVariable && options.SupportWildcard {
|
||||
if strings.HasSuffix(variableName, "*") {
|
||||
suffix.Kind = SuffixKindEverything
|
||||
}
|
||||
}
|
||||
variableNames = append(variableNames, variableName)
|
||||
}
|
||||
}
|
||||
|
||||
// Find existing matcher
|
||||
for _, existing := range currentNode.Suffixes {
|
||||
if EqualSuffix(existing, suffix) {
|
||||
currentNode = existing.Node
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
|
||||
// Compile regular expression
|
||||
if suffix.Kind == SuffixKindRegExp {
|
||||
regExp, err := regexp.Compile(suffix.Pattern)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid regular expression in: %s", path)
|
||||
}
|
||||
suffix.regExp = regExp
|
||||
}
|
||||
|
||||
// Create new node
|
||||
newNode := &Node{}
|
||||
suffix.Node = newNode
|
||||
currentNode.Suffixes = append(currentNode.Suffixes, suffix)
|
||||
sort.Sort(currentNode.Suffixes)
|
||||
currentNode = newNode
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
|
||||
func (currentNode *Node) Match(path string) (*Node, []string) {
|
||||
for strings.HasSuffix(path, "/") {
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
variableValues := make([]string, 0, 8)
|
||||
return currentNode.matchRemaining(path, variableValues)
|
||||
}
|
||||
|
||||
func (currentNode *Node) matchRemaining(remaining string, paramValues []string) (*Node, []string) {
|
||||
// Check if this node matches
|
||||
if len(remaining) == 0 && currentNode.Value != nil {
|
||||
return currentNode, paramValues
|
||||
}
|
||||
|
||||
// See if any suffix matches
|
||||
for _, suffix := range currentNode.Suffixes {
|
||||
var resultNode *Node
|
||||
var resultValues []string
|
||||
switch suffix.Kind {
|
||||
case SuffixKindConstant:
|
||||
pattern := suffix.Pattern
|
||||
if strings.HasPrefix(remaining, pattern) {
|
||||
newRemaining := remaining[len(pattern):]
|
||||
resultNode, resultValues = suffix.Node.matchRemaining(newRemaining, paramValues)
|
||||
} else if len(remaining) == 0 && pattern == "/" {
|
||||
resultNode, resultValues = suffix.Node.matchRemaining(remaining, paramValues)
|
||||
}
|
||||
case SuffixKindVariable:
|
||||
i := strings.IndexByte(remaining, '/')
|
||||
if i < 0 {
|
||||
i = len(remaining)
|
||||
}
|
||||
newParamValues := append(paramValues, remaining[:i])
|
||||
newRemaining := remaining[i:]
|
||||
resultNode, resultValues = suffix.Node.matchRemaining(newRemaining, newParamValues)
|
||||
case SuffixKindEverything:
|
||||
newParamValues := append(paramValues, remaining)
|
||||
resultNode, resultValues = suffix.Node, newParamValues
|
||||
case SuffixKindRegExp:
|
||||
i := strings.IndexByte(remaining, '/')
|
||||
if i < 0 {
|
||||
i = len(remaining)
|
||||
}
|
||||
paramValue := remaining[:i]
|
||||
regExp := suffix.regExp
|
||||
if regExp.MatchString(paramValue) {
|
||||
matches := regExp.FindStringSubmatch(paramValue)
|
||||
if len(matches) > 1 {
|
||||
paramValue = matches[1]
|
||||
}
|
||||
newParamValues := append(paramValues, paramValue)
|
||||
newRemaining := remaining[i:]
|
||||
resultNode, resultValues = suffix.Node.matchRemaining(newRemaining, newParamValues)
|
||||
}
|
||||
}
|
||||
if resultNode != nil && resultNode.Value != nil {
|
||||
// This suffix matched
|
||||
return resultNode, resultValues
|
||||
}
|
||||
}
|
||||
|
||||
// No suffix matched
|
||||
return nil, nil
|
||||
}
|
||||
167
vendor/github.com/getkin/kin-openapi/routers/legacy/router.go
generated
vendored
Normal file
167
vendor/github.com/getkin/kin-openapi/routers/legacy/router.go
generated
vendored
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
// Package legacy implements a router.
|
||||
//
|
||||
// It differs from the gorilla/mux router:
|
||||
// * it provides granular errors: "path not found", "method not allowed", "variable missing from path"
|
||||
// * it does not handle matching routes with extensions (e.g. /books/{id}.json)
|
||||
// * it handles path patterns with a different syntax (e.g. /params/{x}/{y}/{z.*})
|
||||
package legacy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/getkin/kin-openapi/routers"
|
||||
"github.com/getkin/kin-openapi/routers/legacy/pathpattern"
|
||||
)
|
||||
|
||||
// Routers maps a HTTP request to a Router.
|
||||
type Routers []*Router
|
||||
|
||||
// FindRoute extracts the route and parameters of an http.Request
|
||||
func (rs Routers) FindRoute(req *http.Request) (routers.Router, *routers.Route, map[string]string, error) {
|
||||
for _, router := range rs {
|
||||
// Skip routers that have DO NOT have servers
|
||||
if len(router.doc.Servers) == 0 {
|
||||
continue
|
||||
}
|
||||
route, pathParams, err := router.FindRoute(req)
|
||||
if err == nil {
|
||||
return router, route, pathParams, nil
|
||||
}
|
||||
}
|
||||
for _, router := range rs {
|
||||
// Skip routers that DO have servers
|
||||
if len(router.doc.Servers) > 0 {
|
||||
continue
|
||||
}
|
||||
route, pathParams, err := router.FindRoute(req)
|
||||
if err == nil {
|
||||
return router, route, pathParams, nil
|
||||
}
|
||||
}
|
||||
return nil, nil, nil, &routers.RouteError{
|
||||
Reason: "none of the routers match",
|
||||
}
|
||||
}
|
||||
|
||||
// Router maps a HTTP request to an OpenAPI operation.
|
||||
type Router struct {
|
||||
doc *openapi3.T
|
||||
pathNode *pathpattern.Node
|
||||
}
|
||||
|
||||
// NewRouter creates a new router.
|
||||
//
|
||||
// If the given OpenAPIv3 document has servers, router will use them.
|
||||
// All operations of the document will be added to the router.
|
||||
func NewRouter(doc *openapi3.T) (routers.Router, error) {
|
||||
if err := doc.Validate(context.Background()); err != nil {
|
||||
return nil, fmt.Errorf("validating OpenAPI failed: %v", err)
|
||||
}
|
||||
router := &Router{doc: doc}
|
||||
root := router.node()
|
||||
for path, pathItem := range doc.Paths {
|
||||
for method, operation := range pathItem.Operations() {
|
||||
method = strings.ToUpper(method)
|
||||
if err := root.Add(method+" "+path, &routers.Route{
|
||||
Spec: doc,
|
||||
Path: path,
|
||||
PathItem: pathItem,
|
||||
Method: method,
|
||||
Operation: operation,
|
||||
}, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return router, nil
|
||||
}
|
||||
|
||||
// AddRoute adds a route in the router.
|
||||
func (router *Router) AddRoute(route *routers.Route) error {
|
||||
method := route.Method
|
||||
if method == "" {
|
||||
return errors.New("route is missing method")
|
||||
}
|
||||
method = strings.ToUpper(method)
|
||||
path := route.Path
|
||||
if path == "" {
|
||||
return errors.New("route is missing path")
|
||||
}
|
||||
return router.node().Add(method+" "+path, router, nil)
|
||||
}
|
||||
|
||||
func (router *Router) node() *pathpattern.Node {
|
||||
root := router.pathNode
|
||||
if root == nil {
|
||||
root = &pathpattern.Node{}
|
||||
router.pathNode = root
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
// FindRoute extracts the route and parameters of an http.Request
|
||||
func (router *Router) FindRoute(req *http.Request) (*routers.Route, map[string]string, error) {
|
||||
method, url := req.Method, req.URL
|
||||
doc := router.doc
|
||||
|
||||
// Get server
|
||||
servers := doc.Servers
|
||||
var server *openapi3.Server
|
||||
var remainingPath string
|
||||
var pathParams map[string]string
|
||||
if len(servers) == 0 {
|
||||
remainingPath = url.Path
|
||||
} else {
|
||||
var paramValues []string
|
||||
server, paramValues, remainingPath = servers.MatchURL(url)
|
||||
if server == nil {
|
||||
return nil, nil, &routers.RouteError{
|
||||
Reason: routers.ErrPathNotFound.Error(),
|
||||
}
|
||||
}
|
||||
pathParams = make(map[string]string, 8)
|
||||
paramNames, err := server.ParameterNames()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for i, value := range paramValues {
|
||||
name := paramNames[i]
|
||||
pathParams[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
// Get PathItem
|
||||
root := router.node()
|
||||
var route *routers.Route
|
||||
node, paramValues := root.Match(method + " " + remainingPath)
|
||||
if node != nil {
|
||||
route, _ = node.Value.(*routers.Route)
|
||||
}
|
||||
if route == nil {
|
||||
pathItem := doc.Paths[remainingPath]
|
||||
if pathItem == nil {
|
||||
return nil, nil, &routers.RouteError{Reason: routers.ErrPathNotFound.Error()}
|
||||
}
|
||||
if pathItem.GetOperation(method) == nil {
|
||||
return nil, nil, &routers.RouteError{Reason: routers.ErrMethodNotAllowed.Error()}
|
||||
}
|
||||
}
|
||||
|
||||
if pathParams == nil {
|
||||
pathParams = make(map[string]string, len(paramValues))
|
||||
}
|
||||
paramKeys := node.VariableNames
|
||||
for i, value := range paramValues {
|
||||
key := paramKeys[i]
|
||||
if strings.HasSuffix(key, "*") {
|
||||
key = key[:len(key)-1]
|
||||
}
|
||||
pathParams[key] = value
|
||||
}
|
||||
return route, pathParams, nil
|
||||
}
|
||||
42
vendor/github.com/getkin/kin-openapi/routers/types.go
generated
vendored
Normal file
42
vendor/github.com/getkin/kin-openapi/routers/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package routers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
)
|
||||
|
||||
// Router helps link http.Request.s and an OpenAPIv3 spec
|
||||
type Router interface {
|
||||
// FindRoute matches an HTTP request with the operation it resolves to.
|
||||
// Hosts are matched from the OpenAPIv3 servers key.
|
||||
//
|
||||
// If you experience ErrPathNotFound and have localhost hosts specified as your servers,
|
||||
// turning these server URLs as relative (leaving only the path) should resolve this.
|
||||
//
|
||||
// See openapi3filter for example uses with request and response validation.
|
||||
FindRoute(req *http.Request) (route *Route, pathParams map[string]string, err error)
|
||||
}
|
||||
|
||||
// Route describes the operation an http.Request can match
|
||||
type Route struct {
|
||||
Spec *openapi3.T
|
||||
Server *openapi3.Server
|
||||
Path string
|
||||
PathItem *openapi3.PathItem
|
||||
Method string
|
||||
Operation *openapi3.Operation
|
||||
}
|
||||
|
||||
// ErrPathNotFound is returned when no route match is found
|
||||
var ErrPathNotFound error = &RouteError{"no matching operation was found"}
|
||||
|
||||
// ErrMethodNotAllowed is returned when no method of the matched route matches
|
||||
var ErrMethodNotAllowed error = &RouteError{"method not allowed"}
|
||||
|
||||
// RouteError describes Router errors
|
||||
type RouteError struct {
|
||||
Reason string
|
||||
}
|
||||
|
||||
func (e *RouteError) Error() string { return e.Reason }
|
||||
2
vendor/github.com/go-openapi/swag/.gitattributes
generated
vendored
Normal file
2
vendor/github.com/go-openapi/swag/.gitattributes
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# gofmt always uses LF, whereas Git uses CRLF on Windows.
|
||||
*.go text eol=lf
|
||||
28
vendor/github.com/go-openapi/swag/.golangci.yml
generated
vendored
28
vendor/github.com/go-openapi/swag/.golangci.yml
generated
vendored
|
|
@ -20,3 +20,31 @@ linters:
|
|||
- lll
|
||||
- gochecknoinits
|
||||
- gochecknoglobals
|
||||
- nlreturn
|
||||
- testpackage
|
||||
- wrapcheck
|
||||
- gomnd
|
||||
- exhaustive
|
||||
- exhaustivestruct
|
||||
- goerr113
|
||||
- wsl
|
||||
- whitespace
|
||||
- gofumpt
|
||||
- godot
|
||||
- nestif
|
||||
- godox
|
||||
- funlen
|
||||
- gci
|
||||
- gocognit
|
||||
- paralleltest
|
||||
- thelper
|
||||
- ifshort
|
||||
- gomoddirectives
|
||||
- cyclop
|
||||
- forcetypeassert
|
||||
- ireturn
|
||||
- tagliatelle
|
||||
- varnamelen
|
||||
- goimports
|
||||
- tenv
|
||||
- golint
|
||||
|
|
|
|||
15
vendor/github.com/go-openapi/swag/.travis.yml
generated
vendored
15
vendor/github.com/go-openapi/swag/.travis.yml
generated
vendored
|
|
@ -1,15 +0,0 @@
|
|||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
install:
|
||||
- GO111MODULE=off go get -u gotest.tools/gotestsum
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
language: go
|
||||
notifications:
|
||||
slack:
|
||||
secure: QUWvCkBBK09GF7YtEvHHVt70JOkdlNBG0nIKu/5qc4/nW5HP8I2w0SEf/XR2je0eED1Qe3L/AfMCWwrEj+IUZc3l4v+ju8X8R3Lomhme0Eb0jd1MTMCuPcBT47YCj0M7RON7vXtbFfm1hFJ/jLe5+9FXz0hpXsR24PJc5ZIi/ogNwkaPqG4BmndzecpSh0vc2FJPZUD9LT0I09REY/vXR0oQAalLkW0asGD5taHZTUZq/kBpsNxaAFrLM23i4mUcf33M5fjLpvx5LRICrX/57XpBrDh2TooBU6Qj3CgoY0uPRYUmSNxbVx1czNzl2JtEpb5yjoxfVPQeg0BvQM00G8LJINISR+ohrjhkZmAqchDupAX+yFrxTtORa78CtnIL6z/aTNlgwwVD8kvL/1pFA/JWYmKDmz93mV/+6wubGzNSQCstzjkFA4/iZEKewKUoRIAi/fxyscP6L/rCpmY/4llZZvrnyTqVbt6URWpopUpH4rwYqreXAtJxJsfBJIeSmUIiDIOMGkCTvyTEW3fWGmGoqWtSHLoaWDyAIGb7azb+KvfpWtEcoPFWfSWU+LGee0A/YsUhBl7ADB9A0CJEuR8q4BPpKpfLwPKSiKSAXL7zDkyjExyhtgqbSl2jS+rKIHOZNL8JkCcTP2MKMVd563C5rC5FMKqu3S9m2b6380E=
|
||||
script:
|
||||
- gotestsum -f short-verbose -- -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
1
vendor/github.com/go-openapi/swag/README.md
generated
vendored
1
vendor/github.com/go-openapi/swag/README.md
generated
vendored
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
[](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE)
|
||||
[](http://godoc.org/github.com/go-openapi/swag)
|
||||
[](https://golangci.com)
|
||||
[](https://goreportcard.com/report/github.com/go-openapi/swag)
|
||||
|
||||
Contains a bunch of helper functions for go-openapi and go-swagger projects.
|
||||
|
|
|
|||
16
vendor/github.com/go-openapi/swag/convert.go
generated
vendored
16
vendor/github.com/go-openapi/swag/convert.go
generated
vendored
|
|
@ -88,7 +88,7 @@ func ConvertFloat64(str string) (float64, error) {
|
|||
return strconv.ParseFloat(str, 64)
|
||||
}
|
||||
|
||||
// ConvertInt8 turn a string into int8 boolean
|
||||
// ConvertInt8 turn a string into an int8
|
||||
func ConvertInt8(str string) (int8, error) {
|
||||
i, err := strconv.ParseInt(str, 10, 8)
|
||||
if err != nil {
|
||||
|
|
@ -97,7 +97,7 @@ func ConvertInt8(str string) (int8, error) {
|
|||
return int8(i), nil
|
||||
}
|
||||
|
||||
// ConvertInt16 turn a string into a int16
|
||||
// ConvertInt16 turn a string into an int16
|
||||
func ConvertInt16(str string) (int16, error) {
|
||||
i, err := strconv.ParseInt(str, 10, 16)
|
||||
if err != nil {
|
||||
|
|
@ -106,7 +106,7 @@ func ConvertInt16(str string) (int16, error) {
|
|||
return int16(i), nil
|
||||
}
|
||||
|
||||
// ConvertInt32 turn a string into a int32
|
||||
// ConvertInt32 turn a string into an int32
|
||||
func ConvertInt32(str string) (int32, error) {
|
||||
i, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
|
|
@ -115,12 +115,12 @@ func ConvertInt32(str string) (int32, error) {
|
|||
return int32(i), nil
|
||||
}
|
||||
|
||||
// ConvertInt64 turn a string into a int64
|
||||
// ConvertInt64 turn a string into an int64
|
||||
func ConvertInt64(str string) (int64, error) {
|
||||
return strconv.ParseInt(str, 10, 64)
|
||||
}
|
||||
|
||||
// ConvertUint8 turn a string into a uint8
|
||||
// ConvertUint8 turn a string into an uint8
|
||||
func ConvertUint8(str string) (uint8, error) {
|
||||
i, err := strconv.ParseUint(str, 10, 8)
|
||||
if err != nil {
|
||||
|
|
@ -129,7 +129,7 @@ func ConvertUint8(str string) (uint8, error) {
|
|||
return uint8(i), nil
|
||||
}
|
||||
|
||||
// ConvertUint16 turn a string into a uint16
|
||||
// ConvertUint16 turn a string into an uint16
|
||||
func ConvertUint16(str string) (uint16, error) {
|
||||
i, err := strconv.ParseUint(str, 10, 16)
|
||||
if err != nil {
|
||||
|
|
@ -138,7 +138,7 @@ func ConvertUint16(str string) (uint16, error) {
|
|||
return uint16(i), nil
|
||||
}
|
||||
|
||||
// ConvertUint32 turn a string into a uint32
|
||||
// ConvertUint32 turn a string into an uint32
|
||||
func ConvertUint32(str string) (uint32, error) {
|
||||
i, err := strconv.ParseUint(str, 10, 32)
|
||||
if err != nil {
|
||||
|
|
@ -147,7 +147,7 @@ func ConvertUint32(str string) (uint32, error) {
|
|||
return uint32(i), nil
|
||||
}
|
||||
|
||||
// ConvertUint64 turn a string into a uint64
|
||||
// ConvertUint64 turn a string into an uint64
|
||||
func ConvertUint64(str string) (uint64, error) {
|
||||
return strconv.ParseUint(str, 10, 64)
|
||||
}
|
||||
|
|
|
|||
195
vendor/github.com/go-openapi/swag/convert_types.go
generated
vendored
195
vendor/github.com/go-openapi/swag/convert_types.go
generated
vendored
|
|
@ -181,12 +181,12 @@ func IntValueMap(src map[string]*int) map[string]int {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Int32 returns a pointer to of the int64 value passed in.
|
||||
// Int32 returns a pointer to of the int32 value passed in.
|
||||
func Int32(v int32) *int32 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Int32Value returns the value of the int64 pointer passed in or
|
||||
// Int32Value returns the value of the int32 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Int32Value(v *int32) int32 {
|
||||
if v != nil {
|
||||
|
|
@ -195,7 +195,7 @@ func Int32Value(v *int32) int32 {
|
|||
return 0
|
||||
}
|
||||
|
||||
// Int32Slice converts a slice of int64 values into a slice of
|
||||
// Int32Slice converts a slice of int32 values into a slice of
|
||||
// int32 pointers
|
||||
func Int32Slice(src []int32) []*int32 {
|
||||
dst := make([]*int32, len(src))
|
||||
|
|
@ -299,13 +299,80 @@ func Int64ValueMap(src map[string]*int64) map[string]int64 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Uint returns a pouinter to of the uint value passed in.
|
||||
// Uint16 returns a pointer to of the uint16 value passed in.
|
||||
func Uint16(v uint16) *uint16 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Uint16Value returns the value of the uint16 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Uint16Value(v *uint16) uint16 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Uint16Slice converts a slice of uint16 values into a slice of
|
||||
// uint16 pointers
|
||||
func Uint16Slice(src []uint16) []*uint16 {
|
||||
dst := make([]*uint16, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint16ValueSlice converts a slice of uint16 pointers into a slice of
|
||||
// uint16 values
|
||||
func Uint16ValueSlice(src []*uint16) []uint16 {
|
||||
dst := make([]uint16, len(src))
|
||||
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint16Map converts a string map of uint16 values into a string
|
||||
// map of uint16 pointers
|
||||
func Uint16Map(src map[string]uint16) map[string]*uint16 {
|
||||
dst := make(map[string]*uint16)
|
||||
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint16ValueMap converts a string map of uint16 pointers into a string
|
||||
// map of uint16 values
|
||||
func Uint16ValueMap(src map[string]*uint16) map[string]uint16 {
|
||||
dst := make(map[string]uint16)
|
||||
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint returns a pointer to of the uint value passed in.
|
||||
func Uint(v uint) *uint {
|
||||
return &v
|
||||
}
|
||||
|
||||
// UintValue returns the value of the uint pouinter passed in or
|
||||
// 0 if the pouinter is nil.
|
||||
// UintValue returns the value of the uint pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func UintValue(v *uint) uint {
|
||||
if v != nil {
|
||||
return *v
|
||||
|
|
@ -313,8 +380,8 @@ func UintValue(v *uint) uint {
|
|||
return 0
|
||||
}
|
||||
|
||||
// UintSlice converts a slice of uint values uinto a slice of
|
||||
// uint pouinters
|
||||
// UintSlice converts a slice of uint values into a slice of
|
||||
// uint pointers
|
||||
func UintSlice(src []uint) []*uint {
|
||||
dst := make([]*uint, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
|
|
@ -323,7 +390,7 @@ func UintSlice(src []uint) []*uint {
|
|||
return dst
|
||||
}
|
||||
|
||||
// UintValueSlice converts a slice of uint pouinters uinto a slice of
|
||||
// UintValueSlice converts a slice of uint pointers into a slice of
|
||||
// uint values
|
||||
func UintValueSlice(src []*uint) []uint {
|
||||
dst := make([]uint, len(src))
|
||||
|
|
@ -335,8 +402,8 @@ func UintValueSlice(src []*uint) []uint {
|
|||
return dst
|
||||
}
|
||||
|
||||
// UintMap converts a string map of uint values uinto a string
|
||||
// map of uint pouinters
|
||||
// UintMap converts a string map of uint values into a string
|
||||
// map of uint pointers
|
||||
func UintMap(src map[string]uint) map[string]*uint {
|
||||
dst := make(map[string]*uint)
|
||||
for k, val := range src {
|
||||
|
|
@ -346,7 +413,7 @@ func UintMap(src map[string]uint) map[string]*uint {
|
|||
return dst
|
||||
}
|
||||
|
||||
// UintValueMap converts a string map of uint pouinters uinto a string
|
||||
// UintValueMap converts a string map of uint pointers into a string
|
||||
// map of uint values
|
||||
func UintValueMap(src map[string]*uint) map[string]uint {
|
||||
dst := make(map[string]uint)
|
||||
|
|
@ -358,13 +425,13 @@ func UintValueMap(src map[string]*uint) map[string]uint {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Uint32 returns a pouinter to of the uint64 value passed in.
|
||||
// Uint32 returns a pointer to of the uint32 value passed in.
|
||||
func Uint32(v uint32) *uint32 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Uint32Value returns the value of the uint64 pouinter passed in or
|
||||
// 0 if the pouinter is nil.
|
||||
// Uint32Value returns the value of the uint32 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Uint32Value(v *uint32) uint32 {
|
||||
if v != nil {
|
||||
return *v
|
||||
|
|
@ -372,8 +439,8 @@ func Uint32Value(v *uint32) uint32 {
|
|||
return 0
|
||||
}
|
||||
|
||||
// Uint32Slice converts a slice of uint64 values uinto a slice of
|
||||
// uint32 pouinters
|
||||
// Uint32Slice converts a slice of uint32 values into a slice of
|
||||
// uint32 pointers
|
||||
func Uint32Slice(src []uint32) []*uint32 {
|
||||
dst := make([]*uint32, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
|
|
@ -382,7 +449,7 @@ func Uint32Slice(src []uint32) []*uint32 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Uint32ValueSlice converts a slice of uint32 pouinters uinto a slice of
|
||||
// Uint32ValueSlice converts a slice of uint32 pointers into a slice of
|
||||
// uint32 values
|
||||
func Uint32ValueSlice(src []*uint32) []uint32 {
|
||||
dst := make([]uint32, len(src))
|
||||
|
|
@ -394,8 +461,8 @@ func Uint32ValueSlice(src []*uint32) []uint32 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Uint32Map converts a string map of uint32 values uinto a string
|
||||
// map of uint32 pouinters
|
||||
// Uint32Map converts a string map of uint32 values into a string
|
||||
// map of uint32 pointers
|
||||
func Uint32Map(src map[string]uint32) map[string]*uint32 {
|
||||
dst := make(map[string]*uint32)
|
||||
for k, val := range src {
|
||||
|
|
@ -405,7 +472,7 @@ func Uint32Map(src map[string]uint32) map[string]*uint32 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Uint32ValueMap converts a string map of uint32 pouinters uinto a string
|
||||
// Uint32ValueMap converts a string map of uint32 pointers into a string
|
||||
// map of uint32 values
|
||||
func Uint32ValueMap(src map[string]*uint32) map[string]uint32 {
|
||||
dst := make(map[string]uint32)
|
||||
|
|
@ -417,13 +484,13 @@ func Uint32ValueMap(src map[string]*uint32) map[string]uint32 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Uint64 returns a pouinter to of the uint64 value passed in.
|
||||
// Uint64 returns a pointer to of the uint64 value passed in.
|
||||
func Uint64(v uint64) *uint64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Uint64Value returns the value of the uint64 pouinter passed in or
|
||||
// 0 if the pouinter is nil.
|
||||
// Uint64Value returns the value of the uint64 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Uint64Value(v *uint64) uint64 {
|
||||
if v != nil {
|
||||
return *v
|
||||
|
|
@ -431,8 +498,8 @@ func Uint64Value(v *uint64) uint64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
// Uint64Slice converts a slice of uint64 values uinto a slice of
|
||||
// uint64 pouinters
|
||||
// Uint64Slice converts a slice of uint64 values into a slice of
|
||||
// uint64 pointers
|
||||
func Uint64Slice(src []uint64) []*uint64 {
|
||||
dst := make([]*uint64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
|
|
@ -441,7 +508,7 @@ func Uint64Slice(src []uint64) []*uint64 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Uint64ValueSlice converts a slice of uint64 pouinters uinto a slice of
|
||||
// Uint64ValueSlice converts a slice of uint64 pointers into a slice of
|
||||
// uint64 values
|
||||
func Uint64ValueSlice(src []*uint64) []uint64 {
|
||||
dst := make([]uint64, len(src))
|
||||
|
|
@ -453,8 +520,8 @@ func Uint64ValueSlice(src []*uint64) []uint64 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Uint64Map converts a string map of uint64 values uinto a string
|
||||
// map of uint64 pouinters
|
||||
// Uint64Map converts a string map of uint64 values into a string
|
||||
// map of uint64 pointers
|
||||
func Uint64Map(src map[string]uint64) map[string]*uint64 {
|
||||
dst := make(map[string]*uint64)
|
||||
for k, val := range src {
|
||||
|
|
@ -464,7 +531,7 @@ func Uint64Map(src map[string]uint64) map[string]*uint64 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Uint64ValueMap converts a string map of uint64 pouinters uinto a string
|
||||
// Uint64ValueMap converts a string map of uint64 pointers into a string
|
||||
// map of uint64 values
|
||||
func Uint64ValueMap(src map[string]*uint64) map[string]uint64 {
|
||||
dst := make(map[string]uint64)
|
||||
|
|
@ -476,6 +543,74 @@ func Uint64ValueMap(src map[string]*uint64) map[string]uint64 {
|
|||
return dst
|
||||
}
|
||||
|
||||
// Float32 returns a pointer to of the float32 value passed in.
|
||||
func Float32(v float32) *float32 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Float32Value returns the value of the float32 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Float32Value(v *float32) float32 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Float32Slice converts a slice of float32 values into a slice of
|
||||
// float32 pointers
|
||||
func Float32Slice(src []float32) []*float32 {
|
||||
dst := make([]*float32, len(src))
|
||||
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float32ValueSlice converts a slice of float32 pointers into a slice of
|
||||
// float32 values
|
||||
func Float32ValueSlice(src []*float32) []float32 {
|
||||
dst := make([]float32, len(src))
|
||||
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float32Map converts a string map of float32 values into a string
|
||||
// map of float32 pointers
|
||||
func Float32Map(src map[string]float32) map[string]*float32 {
|
||||
dst := make(map[string]*float32)
|
||||
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float32ValueMap converts a string map of float32 pointers into a string
|
||||
// map of float32 values
|
||||
func Float32ValueMap(src map[string]*float32) map[string]float32 {
|
||||
dst := make(map[string]float32)
|
||||
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float64 returns a pointer to of the float64 value passed in.
|
||||
func Float64(v float64) *float64 {
|
||||
return &v
|
||||
|
|
|
|||
33
vendor/github.com/go-openapi/swag/file.go
generated
vendored
Normal file
33
vendor/github.com/go-openapi/swag/file.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package swag
|
||||
|
||||
import "mime/multipart"
|
||||
|
||||
// File represents an uploaded file.
|
||||
type File struct {
|
||||
Data multipart.File
|
||||
Header *multipart.FileHeader
|
||||
}
|
||||
|
||||
// Read bytes from the file
|
||||
func (f *File) Read(p []byte) (n int, err error) {
|
||||
return f.Data.Read(p)
|
||||
}
|
||||
|
||||
// Close the file
|
||||
func (f *File) Close() error {
|
||||
return f.Data.Close()
|
||||
}
|
||||
14
vendor/github.com/go-openapi/swag/go.mod
generated
vendored
14
vendor/github.com/go-openapi/swag/go.mod
generated
vendored
|
|
@ -2,13 +2,17 @@ module github.com/go-openapi/swag
|
|||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63
|
||||
github.com/stretchr/testify v1.3.0
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.2
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.6
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/stretchr/testify v1.6.1
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
||||
)
|
||||
|
||||
replace github.com/golang/lint => golang.org/x/lint v0.0.0-20190409202823-959b441ac422
|
||||
|
||||
replace sourcegraph.com/sourcegraph/go-diff => github.com/sourcegraph/go-diff v0.5.1
|
||||
|
||||
go 1.11
|
||||
|
|
|
|||
29
vendor/github.com/go-openapi/swag/go.sum
generated
vendored
29
vendor/github.com/go-openapi/swag/go.sum
generated
vendored
|
|
@ -1,20 +1,29 @@
|
|||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
8
vendor/github.com/go-openapi/swag/json.go
generated
vendored
8
vendor/github.com/go-openapi/swag/json.go
generated
vendored
|
|
@ -51,7 +51,7 @@ type ejUnmarshaler interface {
|
|||
UnmarshalEasyJSON(w *jlexer.Lexer)
|
||||
}
|
||||
|
||||
// WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaller
|
||||
// WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaler
|
||||
// so it takes the fastest option available.
|
||||
func WriteJSON(data interface{}) ([]byte, error) {
|
||||
if d, ok := data.(ejMarshaler); ok {
|
||||
|
|
@ -65,8 +65,8 @@ func WriteJSON(data interface{}) ([]byte, error) {
|
|||
return json.Marshal(data)
|
||||
}
|
||||
|
||||
// ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaller
|
||||
// so it takes the fastes option available
|
||||
// ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaler
|
||||
// so it takes the fastest option available
|
||||
func ReadJSON(data []byte, value interface{}) error {
|
||||
trimmedData := bytes.Trim(data, "\x00")
|
||||
if d, ok := value.(ejUnmarshaler); ok {
|
||||
|
|
@ -189,7 +189,7 @@ func FromDynamicJSON(data, target interface{}) error {
|
|||
return json.Unmarshal(b, target)
|
||||
}
|
||||
|
||||
// NameProvider represents an object capabale of translating from go property names
|
||||
// NameProvider represents an object capable of translating from go property names
|
||||
// to json property names
|
||||
// This type is thread-safe.
|
||||
type NameProvider struct {
|
||||
|
|
|
|||
42
vendor/github.com/go-openapi/swag/loading.go
generated
vendored
42
vendor/github.com/go-openapi/swag/loading.go
generated
vendored
|
|
@ -19,7 +19,9 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
|
@ -27,6 +29,15 @@ import (
|
|||
// LoadHTTPTimeout the default timeout for load requests
|
||||
var LoadHTTPTimeout = 30 * time.Second
|
||||
|
||||
// LoadHTTPBasicAuthUsername the username to use when load requests require basic auth
|
||||
var LoadHTTPBasicAuthUsername = ""
|
||||
|
||||
// LoadHTTPBasicAuthPassword the password to use when load requests require basic auth
|
||||
var LoadHTTPBasicAuthPassword = ""
|
||||
|
||||
// LoadHTTPCustomHeaders an optional collection of custom HTTP headers for load requests
|
||||
var LoadHTTPCustomHeaders = map[string]string{}
|
||||
|
||||
// LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the path passed in
|
||||
func LoadFromFileOrHTTP(path string) ([]byte, error) {
|
||||
return LoadStrategy(path, ioutil.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(path)
|
||||
|
|
@ -48,6 +59,26 @@ func LoadStrategy(path string, local, remote func(string) ([]byte, error)) func(
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strings.HasPrefix(pth, `file://`) {
|
||||
if runtime.GOOS == "windows" {
|
||||
// support for canonical file URIs on windows.
|
||||
// Zero tolerance here for dodgy URIs.
|
||||
u, _ := url.Parse(upth)
|
||||
if u.Host != "" {
|
||||
// assume UNC name (volume share)
|
||||
// file://host/share/folder\... ==> \\host\share\path\folder
|
||||
// NOTE: UNC port not yet supported
|
||||
upth = strings.Join([]string{`\`, u.Host, u.Path}, `\`)
|
||||
} else {
|
||||
// file:///c:/folder/... ==> just remove the leading slash
|
||||
upth = strings.TrimPrefix(upth, `file:///`)
|
||||
}
|
||||
} else {
|
||||
upth = strings.TrimPrefix(upth, `file://`)
|
||||
}
|
||||
}
|
||||
|
||||
return local(filepath.FromSlash(upth))
|
||||
}
|
||||
}
|
||||
|
|
@ -55,10 +86,19 @@ func LoadStrategy(path string, local, remote func(string) ([]byte, error)) func(
|
|||
func loadHTTPBytes(timeout time.Duration) func(path string) ([]byte, error) {
|
||||
return func(path string) ([]byte, error) {
|
||||
client := &http.Client{Timeout: timeout}
|
||||
req, err := http.NewRequest("GET", path, nil)
|
||||
req, err := http.NewRequest("GET", path, nil) // nolint: noctx
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if LoadHTTPBasicAuthUsername != "" && LoadHTTPBasicAuthPassword != "" {
|
||||
req.SetBasicAuth(LoadHTTPBasicAuthUsername, LoadHTTPBasicAuthPassword)
|
||||
}
|
||||
|
||||
for key, val := range LoadHTTPCustomHeaders {
|
||||
req.Header.Set(key, val)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
defer func() {
|
||||
if resp != nil {
|
||||
|
|
|
|||
1
vendor/github.com/go-openapi/swag/post_go18.go
generated
vendored
1
vendor/github.com/go-openapi/swag/post_go18.go
generated
vendored
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build go1.8
|
||||
// +build go1.8
|
||||
|
||||
package swag
|
||||
|
|
|
|||
1
vendor/github.com/go-openapi/swag/post_go19.go
generated
vendored
1
vendor/github.com/go-openapi/swag/post_go19.go
generated
vendored
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package swag
|
||||
|
|
|
|||
1
vendor/github.com/go-openapi/swag/pre_go18.go
generated
vendored
1
vendor/github.com/go-openapi/swag/pre_go18.go
generated
vendored
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !go1.8
|
||||
// +build !go1.8
|
||||
|
||||
package swag
|
||||
|
|
|
|||
1
vendor/github.com/go-openapi/swag/pre_go19.go
generated
vendored
1
vendor/github.com/go-openapi/swag/pre_go19.go
generated
vendored
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !go1.9
|
||||
// +build !go1.9
|
||||
|
||||
package swag
|
||||
|
|
|
|||
6
vendor/github.com/go-openapi/swag/util.go
generated
vendored
6
vendor/github.com/go-openapi/swag/util.go
generated
vendored
|
|
@ -31,7 +31,7 @@ var isInitialism func(string) bool
|
|||
// GoNamePrefixFunc sets an optional rule to prefix go names
|
||||
// which do not start with a letter.
|
||||
//
|
||||
// e.g. to help converting "123" into "{prefix}123"
|
||||
// e.g. to help convert "123" into "{prefix}123"
|
||||
//
|
||||
// The default is to prefix with "X"
|
||||
var GoNamePrefixFunc func(string) string
|
||||
|
|
@ -91,7 +91,7 @@ func init() {
|
|||
}
|
||||
|
||||
const (
|
||||
//collectionFormatComma = "csv"
|
||||
// collectionFormatComma = "csv"
|
||||
collectionFormatSpace = "ssv"
|
||||
collectionFormatTab = "tsv"
|
||||
collectionFormatPipe = "pipes"
|
||||
|
|
@ -370,7 +370,7 @@ func IsZero(data interface{}) bool {
|
|||
// AddInitialisms add additional initialisms
|
||||
func AddInitialisms(words ...string) {
|
||||
for _, word := range words {
|
||||
//commonInitialisms[upper(word)] = true
|
||||
// commonInitialisms[upper(word)] = true
|
||||
commonInitialisms.add(upper(word))
|
||||
}
|
||||
// sort again
|
||||
|
|
|
|||
5
vendor/github.com/josharian/intern/README.md
generated
vendored
Normal file
5
vendor/github.com/josharian/intern/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Docs: https://godoc.org/github.com/josharian/intern
|
||||
|
||||
See also [Go issue 5160](https://golang.org/issue/5160).
|
||||
|
||||
License: MIT
|
||||
3
vendor/github.com/josharian/intern/go.mod
generated
vendored
Normal file
3
vendor/github.com/josharian/intern/go.mod
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/josharian/intern
|
||||
|
||||
go 1.5
|
||||
44
vendor/github.com/josharian/intern/intern.go
generated
vendored
Normal file
44
vendor/github.com/josharian/intern/intern.go
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Package intern interns strings.
|
||||
// Interning is best effort only.
|
||||
// Interned strings may be removed automatically
|
||||
// at any time without notification.
|
||||
// All functions may be called concurrently
|
||||
// with themselves and each other.
|
||||
package intern
|
||||
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
pool sync.Pool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make(map[string]string)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// String returns s, interned.
|
||||
func String(s string) string {
|
||||
m := pool.Get().(map[string]string)
|
||||
c, ok := m[s]
|
||||
if ok {
|
||||
pool.Put(m)
|
||||
return c
|
||||
}
|
||||
m[s] = s
|
||||
pool.Put(m)
|
||||
return s
|
||||
}
|
||||
|
||||
// Bytes returns b converted to a string, interned.
|
||||
func Bytes(b []byte) string {
|
||||
m := pool.Get().(map[string]string)
|
||||
c, ok := m[string(b)]
|
||||
if ok {
|
||||
pool.Put(m)
|
||||
return c
|
||||
}
|
||||
s := string(b)
|
||||
m[s] = s
|
||||
pool.Put(m)
|
||||
return s
|
||||
}
|
||||
21
vendor/github.com/josharian/intern/license.md
generated
vendored
Normal file
21
vendor/github.com/josharian/intern/license.md
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Josh Bleecher Snyder
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
72
vendor/github.com/mailru/easyjson/buffer/pool.go
generated
vendored
72
vendor/github.com/mailru/easyjson/buffer/pool.go
generated
vendored
|
|
@ -4,6 +4,7 @@ package buffer
|
|||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
|
|
@ -52,14 +53,12 @@ func putBuf(buf []byte) {
|
|||
|
||||
// getBuf gets a chunk from reuse pool or creates a new one if reuse failed.
|
||||
func getBuf(size int) []byte {
|
||||
if size < config.PooledSize {
|
||||
return make([]byte, 0, size)
|
||||
}
|
||||
|
||||
if c := buffers[size]; c != nil {
|
||||
v := c.Get()
|
||||
if v != nil {
|
||||
return v.([]byte)
|
||||
if size >= config.PooledSize {
|
||||
if c := buffers[size]; c != nil {
|
||||
v := c.Get()
|
||||
if v != nil {
|
||||
return v.([]byte)
|
||||
}
|
||||
}
|
||||
}
|
||||
return make([]byte, 0, size)
|
||||
|
|
@ -78,9 +77,12 @@ type Buffer struct {
|
|||
// EnsureSpace makes sure that the current chunk contains at least s free bytes,
|
||||
// possibly creating a new chunk.
|
||||
func (b *Buffer) EnsureSpace(s int) {
|
||||
if cap(b.Buf)-len(b.Buf) >= s {
|
||||
return
|
||||
if cap(b.Buf)-len(b.Buf) < s {
|
||||
b.ensureSpaceSlow(s)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Buffer) ensureSpaceSlow(s int) {
|
||||
l := len(b.Buf)
|
||||
if l > 0 {
|
||||
if cap(b.toPool) != cap(b.Buf) {
|
||||
|
|
@ -105,18 +107,22 @@ func (b *Buffer) EnsureSpace(s int) {
|
|||
|
||||
// AppendByte appends a single byte to buffer.
|
||||
func (b *Buffer) AppendByte(data byte) {
|
||||
if cap(b.Buf) == len(b.Buf) { // EnsureSpace won't be inlined.
|
||||
b.EnsureSpace(1)
|
||||
}
|
||||
b.EnsureSpace(1)
|
||||
b.Buf = append(b.Buf, data)
|
||||
}
|
||||
|
||||
// AppendBytes appends a byte slice to buffer.
|
||||
func (b *Buffer) AppendBytes(data []byte) {
|
||||
if len(data) <= cap(b.Buf)-len(b.Buf) {
|
||||
b.Buf = append(b.Buf, data...) // fast path
|
||||
} else {
|
||||
b.appendBytesSlow(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Buffer) appendBytesSlow(data []byte) {
|
||||
for len(data) > 0 {
|
||||
if cap(b.Buf) == len(b.Buf) { // EnsureSpace won't be inlined.
|
||||
b.EnsureSpace(1)
|
||||
}
|
||||
b.EnsureSpace(1)
|
||||
|
||||
sz := cap(b.Buf) - len(b.Buf)
|
||||
if sz > len(data) {
|
||||
|
|
@ -128,12 +134,18 @@ func (b *Buffer) AppendBytes(data []byte) {
|
|||
}
|
||||
}
|
||||
|
||||
// AppendBytes appends a string to buffer.
|
||||
// AppendString appends a string to buffer.
|
||||
func (b *Buffer) AppendString(data string) {
|
||||
if len(data) <= cap(b.Buf)-len(b.Buf) {
|
||||
b.Buf = append(b.Buf, data...) // fast path
|
||||
} else {
|
||||
b.appendStringSlow(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Buffer) appendStringSlow(data string) {
|
||||
for len(data) > 0 {
|
||||
if cap(b.Buf) == len(b.Buf) { // EnsureSpace won't be inlined.
|
||||
b.EnsureSpace(1)
|
||||
}
|
||||
b.EnsureSpace(1)
|
||||
|
||||
sz := cap(b.Buf) - len(b.Buf)
|
||||
if sz > len(data) {
|
||||
|
|
@ -156,18 +168,14 @@ func (b *Buffer) Size() int {
|
|||
|
||||
// DumpTo outputs the contents of a buffer to a writer and resets the buffer.
|
||||
func (b *Buffer) DumpTo(w io.Writer) (written int, err error) {
|
||||
var n int
|
||||
for _, buf := range b.bufs {
|
||||
if err == nil {
|
||||
n, err = w.Write(buf)
|
||||
written += n
|
||||
}
|
||||
putBuf(buf)
|
||||
bufs := net.Buffers(b.bufs)
|
||||
if len(b.Buf) > 0 {
|
||||
bufs = append(bufs, b.Buf)
|
||||
}
|
||||
n, err := bufs.WriteTo(w)
|
||||
|
||||
if err == nil {
|
||||
n, err = w.Write(b.Buf)
|
||||
written += n
|
||||
for _, buf := range b.bufs {
|
||||
putBuf(buf)
|
||||
}
|
||||
putBuf(b.toPool)
|
||||
|
||||
|
|
@ -175,7 +183,7 @@ func (b *Buffer) DumpTo(w io.Writer) (written int, err error) {
|
|||
b.Buf = nil
|
||||
b.toPool = nil
|
||||
|
||||
return
|
||||
return int(n), err
|
||||
}
|
||||
|
||||
// BuildBytes creates a single byte slice with all the contents of the buffer. Data is
|
||||
|
|
@ -192,7 +200,7 @@ func (b *Buffer) BuildBytes(reuse ...[]byte) []byte {
|
|||
var ret []byte
|
||||
size := b.Size()
|
||||
|
||||
// If we got a buffer as argument and it is big enought, reuse it.
|
||||
// If we got a buffer as argument and it is big enough, reuse it.
|
||||
if len(reuse) == 1 && cap(reuse[0]) >= size {
|
||||
ret = reuse[0][:0]
|
||||
} else {
|
||||
|
|
|
|||
216
vendor/github.com/mailru/easyjson/jlexer/lexer.go
generated
vendored
216
vendor/github.com/mailru/easyjson/jlexer/lexer.go
generated
vendored
|
|
@ -5,6 +5,7 @@
|
|||
package jlexer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
|
@ -14,6 +15,8 @@ import (
|
|||
"unicode"
|
||||
"unicode/utf16"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/josharian/intern"
|
||||
)
|
||||
|
||||
// tokenKind determines type of a token.
|
||||
|
|
@ -32,9 +35,10 @@ const (
|
|||
type token struct {
|
||||
kind tokenKind // Type of a token.
|
||||
|
||||
boolValue bool // Value if a boolean literal token.
|
||||
byteValue []byte // Raw value of a token.
|
||||
delimValue byte
|
||||
boolValue bool // Value if a boolean literal token.
|
||||
byteValueCloned bool // true if byteValue was allocated and does not refer to original json body
|
||||
byteValue []byte // Raw value of a token.
|
||||
delimValue byte
|
||||
}
|
||||
|
||||
// Lexer is a JSON lexer: it iterates over JSON tokens in a byte slice.
|
||||
|
|
@ -240,23 +244,65 @@ func (r *Lexer) fetchNumber() {
|
|||
|
||||
// findStringLen tries to scan into the string literal for ending quote char to determine required size.
|
||||
// The size will be exact if no escapes are present and may be inexact if there are escaped chars.
|
||||
func findStringLen(data []byte) (isValid, hasEscapes bool, length int) {
|
||||
delta := 0
|
||||
|
||||
for i := 0; i < len(data); i++ {
|
||||
switch data[i] {
|
||||
case '\\':
|
||||
i++
|
||||
delta++
|
||||
if i < len(data) && data[i] == 'u' {
|
||||
delta++
|
||||
}
|
||||
case '"':
|
||||
return true, (delta > 0), (i - delta)
|
||||
func findStringLen(data []byte) (isValid bool, length int) {
|
||||
for {
|
||||
idx := bytes.IndexByte(data, '"')
|
||||
if idx == -1 {
|
||||
return false, len(data)
|
||||
}
|
||||
if idx == 0 || (idx > 0 && data[idx-1] != '\\') {
|
||||
return true, length + idx
|
||||
}
|
||||
|
||||
// count \\\\\\\ sequences. even number of slashes means quote is not really escaped
|
||||
cnt := 1
|
||||
for idx-cnt-1 >= 0 && data[idx-cnt-1] == '\\' {
|
||||
cnt++
|
||||
}
|
||||
if cnt%2 == 0 {
|
||||
return true, length + idx
|
||||
}
|
||||
|
||||
length += idx + 1
|
||||
data = data[idx+1:]
|
||||
}
|
||||
}
|
||||
|
||||
// unescapeStringToken performs unescaping of string token.
|
||||
// if no escaping is needed, original string is returned, otherwise - a new one allocated
|
||||
func (r *Lexer) unescapeStringToken() (err error) {
|
||||
data := r.token.byteValue
|
||||
var unescapedData []byte
|
||||
|
||||
for {
|
||||
i := bytes.IndexByte(data, '\\')
|
||||
if i == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
escapedRune, escapedBytes, err := decodeEscape(data[i:])
|
||||
if err != nil {
|
||||
r.errParse(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
if unescapedData == nil {
|
||||
unescapedData = make([]byte, 0, len(r.token.byteValue))
|
||||
}
|
||||
|
||||
var d [4]byte
|
||||
s := utf8.EncodeRune(d[:], escapedRune)
|
||||
unescapedData = append(unescapedData, data[:i]...)
|
||||
unescapedData = append(unescapedData, d[:s]...)
|
||||
|
||||
data = data[i+escapedBytes:]
|
||||
}
|
||||
|
||||
return false, false, len(data)
|
||||
if unescapedData != nil {
|
||||
r.token.byteValue = append(unescapedData, data...)
|
||||
r.token.byteValueCloned = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
|
||||
|
|
@ -286,36 +332,30 @@ func getu4(s []byte) rune {
|
|||
return val
|
||||
}
|
||||
|
||||
// processEscape processes a single escape sequence and returns number of bytes processed.
|
||||
func (r *Lexer) processEscape(data []byte) (int, error) {
|
||||
// decodeEscape processes a single escape sequence and returns number of bytes processed.
|
||||
func decodeEscape(data []byte) (decoded rune, bytesProcessed int, err error) {
|
||||
if len(data) < 2 {
|
||||
return 0, fmt.Errorf("syntax error at %v", string(data))
|
||||
return 0, 0, errors.New("incorrect escape symbol \\ at the end of token")
|
||||
}
|
||||
|
||||
c := data[1]
|
||||
switch c {
|
||||
case '"', '/', '\\':
|
||||
r.token.byteValue = append(r.token.byteValue, c)
|
||||
return 2, nil
|
||||
return rune(c), 2, nil
|
||||
case 'b':
|
||||
r.token.byteValue = append(r.token.byteValue, '\b')
|
||||
return 2, nil
|
||||
return '\b', 2, nil
|
||||
case 'f':
|
||||
r.token.byteValue = append(r.token.byteValue, '\f')
|
||||
return 2, nil
|
||||
return '\f', 2, nil
|
||||
case 'n':
|
||||
r.token.byteValue = append(r.token.byteValue, '\n')
|
||||
return 2, nil
|
||||
return '\n', 2, nil
|
||||
case 'r':
|
||||
r.token.byteValue = append(r.token.byteValue, '\r')
|
||||
return 2, nil
|
||||
return '\r', 2, nil
|
||||
case 't':
|
||||
r.token.byteValue = append(r.token.byteValue, '\t')
|
||||
return 2, nil
|
||||
return '\t', 2, nil
|
||||
case 'u':
|
||||
rr := getu4(data)
|
||||
if rr < 0 {
|
||||
return 0, errors.New("syntax error")
|
||||
return 0, 0, errors.New("incorrectly escaped \\uXXXX sequence")
|
||||
}
|
||||
|
||||
read := 6
|
||||
|
|
@ -328,13 +368,10 @@ func (r *Lexer) processEscape(data []byte) (int, error) {
|
|||
rr = unicode.ReplacementChar
|
||||
}
|
||||
}
|
||||
var d [4]byte
|
||||
s := utf8.EncodeRune(d[:], rr)
|
||||
r.token.byteValue = append(r.token.byteValue, d[:s]...)
|
||||
return read, nil
|
||||
return rr, read, nil
|
||||
}
|
||||
|
||||
return 0, errors.New("syntax error")
|
||||
return 0, 0, errors.New("incorrectly escaped bytes")
|
||||
}
|
||||
|
||||
// fetchString scans a string literal token.
|
||||
|
|
@ -342,43 +379,14 @@ func (r *Lexer) fetchString() {
|
|||
r.pos++
|
||||
data := r.Data[r.pos:]
|
||||
|
||||
isValid, hasEscapes, length := findStringLen(data)
|
||||
isValid, length := findStringLen(data)
|
||||
if !isValid {
|
||||
r.pos += length
|
||||
r.errParse("unterminated string literal")
|
||||
return
|
||||
}
|
||||
if !hasEscapes {
|
||||
r.token.byteValue = data[:length]
|
||||
r.pos += length + 1
|
||||
return
|
||||
}
|
||||
|
||||
r.token.byteValue = make([]byte, 0, length)
|
||||
p := 0
|
||||
for i := 0; i < len(data); {
|
||||
switch data[i] {
|
||||
case '"':
|
||||
r.pos += i + 1
|
||||
r.token.byteValue = append(r.token.byteValue, data[p:i]...)
|
||||
i++
|
||||
return
|
||||
|
||||
case '\\':
|
||||
r.token.byteValue = append(r.token.byteValue, data[p:i]...)
|
||||
off, err := r.processEscape(data[i:])
|
||||
if err != nil {
|
||||
r.errParse(err.Error())
|
||||
return
|
||||
}
|
||||
i += off
|
||||
p = i
|
||||
|
||||
default:
|
||||
i++
|
||||
}
|
||||
}
|
||||
r.errParse("unterminated string literal")
|
||||
r.token.byteValue = data[:length]
|
||||
r.pos += length + 1 // skip closing '"' as well
|
||||
}
|
||||
|
||||
// scanToken scans the next token if no token is currently available in the lexer.
|
||||
|
|
@ -602,7 +610,7 @@ func (r *Lexer) Consumed() {
|
|||
}
|
||||
}
|
||||
|
||||
func (r *Lexer) unsafeString() (string, []byte) {
|
||||
func (r *Lexer) unsafeString(skipUnescape bool) (string, []byte) {
|
||||
if r.token.kind == tokenUndef && r.Ok() {
|
||||
r.FetchToken()
|
||||
}
|
||||
|
|
@ -610,6 +618,13 @@ func (r *Lexer) unsafeString() (string, []byte) {
|
|||
r.errInvalidToken("string")
|
||||
return "", nil
|
||||
}
|
||||
if !skipUnescape {
|
||||
if err := r.unescapeStringToken(); err != nil {
|
||||
r.errInvalidToken("string")
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
bytes := r.token.byteValue
|
||||
ret := bytesToStr(r.token.byteValue)
|
||||
r.consume()
|
||||
|
|
@ -621,13 +636,19 @@ func (r *Lexer) unsafeString() (string, []byte) {
|
|||
// Warning: returned string may point to the input buffer, so the string should not outlive
|
||||
// the input buffer. Intended pattern of usage is as an argument to a switch statement.
|
||||
func (r *Lexer) UnsafeString() string {
|
||||
ret, _ := r.unsafeString()
|
||||
ret, _ := r.unsafeString(false)
|
||||
return ret
|
||||
}
|
||||
|
||||
// UnsafeBytes returns the byte slice if the token is a string literal.
|
||||
func (r *Lexer) UnsafeBytes() []byte {
|
||||
_, ret := r.unsafeString()
|
||||
_, ret := r.unsafeString(false)
|
||||
return ret
|
||||
}
|
||||
|
||||
// UnsafeFieldName returns current member name string token
|
||||
func (r *Lexer) UnsafeFieldName(skipUnescape bool) string {
|
||||
ret, _ := r.unsafeString(skipUnescape)
|
||||
return ret
|
||||
}
|
||||
|
||||
|
|
@ -640,7 +661,34 @@ func (r *Lexer) String() string {
|
|||
r.errInvalidToken("string")
|
||||
return ""
|
||||
}
|
||||
ret := string(r.token.byteValue)
|
||||
if err := r.unescapeStringToken(); err != nil {
|
||||
r.errInvalidToken("string")
|
||||
return ""
|
||||
}
|
||||
var ret string
|
||||
if r.token.byteValueCloned {
|
||||
ret = bytesToStr(r.token.byteValue)
|
||||
} else {
|
||||
ret = string(r.token.byteValue)
|
||||
}
|
||||
r.consume()
|
||||
return ret
|
||||
}
|
||||
|
||||
// StringIntern reads a string literal, and performs string interning on it.
|
||||
func (r *Lexer) StringIntern() string {
|
||||
if r.token.kind == tokenUndef && r.Ok() {
|
||||
r.FetchToken()
|
||||
}
|
||||
if !r.Ok() || r.token.kind != tokenString {
|
||||
r.errInvalidToken("string")
|
||||
return ""
|
||||
}
|
||||
if err := r.unescapeStringToken(); err != nil {
|
||||
r.errInvalidToken("string")
|
||||
return ""
|
||||
}
|
||||
ret := intern.Bytes(r.token.byteValue)
|
||||
r.consume()
|
||||
return ret
|
||||
}
|
||||
|
|
@ -839,7 +887,7 @@ func (r *Lexer) Int() int {
|
|||
}
|
||||
|
||||
func (r *Lexer) Uint8Str() uint8 {
|
||||
s, b := r.unsafeString()
|
||||
s, b := r.unsafeString(false)
|
||||
if !r.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -856,7 +904,7 @@ func (r *Lexer) Uint8Str() uint8 {
|
|||
}
|
||||
|
||||
func (r *Lexer) Uint16Str() uint16 {
|
||||
s, b := r.unsafeString()
|
||||
s, b := r.unsafeString(false)
|
||||
if !r.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -873,7 +921,7 @@ func (r *Lexer) Uint16Str() uint16 {
|
|||
}
|
||||
|
||||
func (r *Lexer) Uint32Str() uint32 {
|
||||
s, b := r.unsafeString()
|
||||
s, b := r.unsafeString(false)
|
||||
if !r.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -890,7 +938,7 @@ func (r *Lexer) Uint32Str() uint32 {
|
|||
}
|
||||
|
||||
func (r *Lexer) Uint64Str() uint64 {
|
||||
s, b := r.unsafeString()
|
||||
s, b := r.unsafeString(false)
|
||||
if !r.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -915,7 +963,7 @@ func (r *Lexer) UintptrStr() uintptr {
|
|||
}
|
||||
|
||||
func (r *Lexer) Int8Str() int8 {
|
||||
s, b := r.unsafeString()
|
||||
s, b := r.unsafeString(false)
|
||||
if !r.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -932,7 +980,7 @@ func (r *Lexer) Int8Str() int8 {
|
|||
}
|
||||
|
||||
func (r *Lexer) Int16Str() int16 {
|
||||
s, b := r.unsafeString()
|
||||
s, b := r.unsafeString(false)
|
||||
if !r.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -949,7 +997,7 @@ func (r *Lexer) Int16Str() int16 {
|
|||
}
|
||||
|
||||
func (r *Lexer) Int32Str() int32 {
|
||||
s, b := r.unsafeString()
|
||||
s, b := r.unsafeString(false)
|
||||
if !r.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -966,7 +1014,7 @@ func (r *Lexer) Int32Str() int32 {
|
|||
}
|
||||
|
||||
func (r *Lexer) Int64Str() int64 {
|
||||
s, b := r.unsafeString()
|
||||
s, b := r.unsafeString(false)
|
||||
if !r.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -1004,7 +1052,7 @@ func (r *Lexer) Float32() float32 {
|
|||
}
|
||||
|
||||
func (r *Lexer) Float32Str() float32 {
|
||||
s, b := r.unsafeString()
|
||||
s, b := r.unsafeString(false)
|
||||
if !r.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -1037,7 +1085,7 @@ func (r *Lexer) Float64() float64 {
|
|||
}
|
||||
|
||||
func (r *Lexer) Float64Str() float64 {
|
||||
s, b := r.unsafeString()
|
||||
s, b := r.unsafeString(false)
|
||||
if !r.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
|
|
|||
41
vendor/github.com/mailru/easyjson/jwriter/writer.go
generated
vendored
41
vendor/github.com/mailru/easyjson/jwriter/writer.go
generated
vendored
|
|
@ -270,16 +270,25 @@ func (w *Writer) Bool(v bool) {
|
|||
|
||||
const chars = "0123456789abcdef"
|
||||
|
||||
func isNotEscapedSingleChar(c byte, escapeHTML bool) bool {
|
||||
// Note: might make sense to use a table if there are more chars to escape. With 4 chars
|
||||
// it benchmarks the same.
|
||||
if escapeHTML {
|
||||
return c != '<' && c != '>' && c != '&' && c != '\\' && c != '"' && c >= 0x20 && c < utf8.RuneSelf
|
||||
} else {
|
||||
return c != '\\' && c != '"' && c >= 0x20 && c < utf8.RuneSelf
|
||||
func getTable(falseValues ...int) [128]bool {
|
||||
table := [128]bool{}
|
||||
|
||||
for i := 0; i < 128; i++ {
|
||||
table[i] = true
|
||||
}
|
||||
|
||||
for _, v := range falseValues {
|
||||
table[v] = false
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
var (
|
||||
htmlEscapeTable = getTable(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, '"', '&', '<', '>', '\\')
|
||||
htmlNoEscapeTable = getTable(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, '"', '\\')
|
||||
)
|
||||
|
||||
func (w *Writer) String(s string) {
|
||||
w.Buffer.AppendByte('"')
|
||||
|
||||
|
|
@ -288,15 +297,21 @@ func (w *Writer) String(s string) {
|
|||
|
||||
p := 0 // last non-escape symbol
|
||||
|
||||
escapeTable := &htmlEscapeTable
|
||||
if w.NoEscapeHTML {
|
||||
escapeTable = &htmlNoEscapeTable
|
||||
}
|
||||
|
||||
for i := 0; i < len(s); {
|
||||
c := s[i]
|
||||
|
||||
if isNotEscapedSingleChar(c, !w.NoEscapeHTML) {
|
||||
// single-width character, no escaping is required
|
||||
i++
|
||||
continue
|
||||
} else if c < utf8.RuneSelf {
|
||||
// single-with character, need to escape
|
||||
if c < utf8.RuneSelf {
|
||||
if escapeTable[c] {
|
||||
// single-width character, no escaping is required
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
w.Buffer.AppendString(s[p:i])
|
||||
switch c {
|
||||
case '\t':
|
||||
|
|
|
|||
13
vendor/modules.txt
vendored
13
vendor/modules.txt
vendored
|
|
@ -153,15 +153,20 @@ github.com/deepmap/oapi-codegen/pkg/util
|
|||
github.com/dimchansky/utfbom
|
||||
# github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02
|
||||
github.com/dougm/pretty
|
||||
# github.com/getkin/kin-openapi v0.61.0
|
||||
# github.com/getkin/kin-openapi v0.93.0
|
||||
## explicit
|
||||
github.com/getkin/kin-openapi/jsoninfo
|
||||
github.com/getkin/kin-openapi/openapi3
|
||||
github.com/getkin/kin-openapi/openapi3filter
|
||||
github.com/getkin/kin-openapi/routers
|
||||
github.com/getkin/kin-openapi/routers/legacy
|
||||
github.com/getkin/kin-openapi/routers/legacy/pathpattern
|
||||
# github.com/ghodss/yaml v1.0.0
|
||||
github.com/ghodss/yaml
|
||||
# github.com/go-openapi/jsonpointer v0.19.5
|
||||
github.com/go-openapi/jsonpointer
|
||||
# github.com/go-openapi/swag v0.19.5
|
||||
# github.com/go-openapi/swag v0.21.1
|
||||
## explicit
|
||||
github.com/go-openapi/swag
|
||||
# github.com/gobwas/glob v0.2.3
|
||||
## explicit
|
||||
|
|
@ -255,6 +260,8 @@ github.com/jackc/pgx/v4/pgxpool
|
|||
github.com/jackc/puddle
|
||||
# github.com/jmespath/go-jmespath v0.4.0
|
||||
github.com/jmespath/go-jmespath
|
||||
# github.com/josharian/intern v1.0.0
|
||||
github.com/josharian/intern
|
||||
# github.com/json-iterator/go v1.1.12
|
||||
github.com/json-iterator/go
|
||||
# github.com/julienschmidt/httprouter v1.3.0
|
||||
|
|
@ -275,7 +282,7 @@ github.com/labstack/gommon/bytes
|
|||
github.com/labstack/gommon/color
|
||||
github.com/labstack/gommon/log
|
||||
github.com/labstack/gommon/random
|
||||
# github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e
|
||||
# github.com/mailru/easyjson v0.7.6
|
||||
github.com/mailru/easyjson/buffer
|
||||
github.com/mailru/easyjson/jlexer
|
||||
github.com/mailru/easyjson/jwriter
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue