diff options
Diffstat (limited to 'vendor/github.com/gin-gonic')
31 files changed, 409 insertions, 421 deletions
diff --git a/vendor/github.com/gin-gonic/gin/.golangci.yml b/vendor/github.com/gin-gonic/gin/.golangci.yml deleted file mode 100644 index 78a4259a1..000000000 --- a/vendor/github.com/gin-gonic/gin/.golangci.yml +++ /dev/null @@ -1,22 +0,0 @@ -run: - timeout: 5m -linters: - enable: - - gofmt - - misspell - - revive -issues: - exclude-rules: - - linters: - - structcheck - - unused - text: "`data` is unused" - - linters: - - staticcheck - text: "SA1019:" - - linters: - - revive - text: "var-naming:" - - linters: - - revive - text: "exported:" diff --git a/vendor/github.com/gin-gonic/gin/.travis.yml b/vendor/github.com/gin-gonic/gin/.travis.yml new file mode 100644 index 000000000..bcc21414d --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/.travis.yml @@ -0,0 +1,48 @@ +language: go + +matrix: + fast_finish: true + include: + - go: 1.13.x + - go: 1.13.x + env: + - TESTTAGS=nomsgpack + - go: 1.14.x + - go: 1.14.x + env: + - TESTTAGS=nomsgpack + - go: 1.15.x + - go: 1.15.x + env: + - TESTTAGS=nomsgpack + - go: master + +git: + depth: 10 + +before_install: + - if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi + +install: + - if [[ "${GO111MODULE}" = "on" ]]; then go mod download; fi + - if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi + - if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi + +go_import_path: github.com/gin-gonic/gin + +script: + - make vet + - make fmt-check + - make misspell-check + - make test + +after_success: + - bash <(curl -s https://codecov.io/bash) + +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/7f95bf605c4d356372f4 + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: false # default: false diff --git a/vendor/github.com/gin-gonic/gin/CHANGELOG.md b/vendor/github.com/gin-gonic/gin/CHANGELOG.md index 308af74c3..4c806a5a7 100644 --- a/vendor/github.com/gin-gonic/gin/CHANGELOG.md +++ b/vendor/github.com/gin-gonic/gin/CHANGELOG.md @@ -1,5 +1,35 @@ # Gin ChangeLog +## Gin v1.7.7 + +### BUGFIXES + +* Fixed X-Forwarded-For unsafe handling of CVE-2020-28483 [#2844](https://github.com/gin-gonic/gin/pull/2844), closed issue [#2862](https://github.com/gin-gonic/gin/issues/2862). +* Tree: updated the code logic for `latestNode` [#2897](https://github.com/gin-gonic/gin/pull/2897), closed issue [#2894](https://github.com/gin-gonic/gin/issues/2894) [#2878](https://github.com/gin-gonic/gin/issues/2878). +* Tree: fixed the misplacement of adding slashes [#2847](https://github.com/gin-gonic/gin/pull/2847), closed issue [#2843](https://github.com/gin-gonic/gin/issues/2843). +* Tree: fixed tsr with mixed static and wildcard paths [#2924](https://github.com/gin-gonic/gin/pull/2924), closed issue [#2918](https://github.com/gin-gonic/gin/issues/2918). + +### ENHANCEMENTS + +* TrustedProxies: make it backward-compatible [#2887](https://github.com/gin-gonic/gin/pull/2887), closed issue [#2819](https://github.com/gin-gonic/gin/issues/2819). +* TrustedPlatform: provide custom options for another CDN services [#2906](https://github.com/gin-gonic/gin/pull/2906). + +### DOCS + +* NoMethod: added usage annotation ([#2832](https://github.com/gin-gonic/gin/pull/2832#issuecomment-929954463)). + +## Gin v1.7.6 + +### BUGFIXES + +* bump new release to fix v1.7.5 release error by using v1.7.4 codes. + +## Gin v1.7.4 + +### BUGFIXES + +* bump new release to fix checksum mismatch + ## Gin v1.7.3 ### BUGFIXES diff --git a/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md b/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md index d1c723c67..97daa808f 100644 --- a/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md +++ b/vendor/github.com/gin-gonic/gin/CONTRIBUTING.md @@ -8,6 +8,6 @@ - With pull requests: - Open your pull request against `master` - Your pull request should have no more than two commits, if not you should squash them. - - It should pass all tests in the available continuous integration systems such as GitHub Actions. + - It should pass all tests in the available continuous integration systems such as TravisCI. - You should add/modify tests to cover your proposed code changes. - If your pull request contains a new feature, please document it on the README. diff --git a/vendor/github.com/gin-gonic/gin/Makefile b/vendor/github.com/gin-gonic/gin/Makefile index 5d55b444c..1a9919395 100644 --- a/vendor/github.com/gin-gonic/gin/Makefile +++ b/vendor/github.com/gin-gonic/gin/Makefile @@ -1,6 +1,5 @@ GO ?= go GOFMT ?= gofmt "-s" -GO_VERSION=$(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2) PACKAGES ?= $(shell $(GO) list ./...) VETPACKAGES ?= $(shell $(GO) list ./... | grep -v /examples/) GOFILES := $(shell find . -name "*.go") @@ -68,10 +67,5 @@ misspell: .PHONY: tools tools: - @if [ $(GO_VERSION) -gt 15 ]; then \ - $(GO) install golang.org/x/lint/golint@latest; \ - $(GO) install github.com/client9/misspell/cmd/misspell@latest; \ - elif [ $(GO_VERSION) -lt 16 ]; then \ - $(GO) install golang.org/x/lint/golint; \ - $(GO) install github.com/client9/misspell/cmd/misspell; \ - fi + go install golang.org/x/lint/golint; \ + go install github.com/client9/misspell/cmd/misspell; diff --git a/vendor/github.com/gin-gonic/gin/README.md b/vendor/github.com/gin-gonic/gin/README.md index 198bf0119..9bf459b09 100644 --- a/vendor/github.com/gin-gonic/gin/README.md +++ b/vendor/github.com/gin-gonic/gin/README.md @@ -2,7 +2,7 @@ <img align="right" width="159px" src="https://raw.githubusercontent.com/gin-gonic/logo/master/color.png"> -[](https://github.com/gin-gonic/gin/actions?query=branch%3Amaster) +[](https://travis-ci.org/gin-gonic/gin) [](https://codecov.io/gh/gin-gonic/gin) [](https://goreportcard.com/report/github.com/gin-gonic/gin) [](https://pkg.go.dev/github.com/gin-gonic/gin?tab=doc) @@ -23,8 +23,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi - [Quick start](#quick-start) - [Benchmarks](#benchmarks) - [Gin v1. stable](#gin-v1-stable) - - [Build with jsoniter/go-json](#build-with-json-replacement) - - [Build without `MsgPack` rendering feature](#build-without-msgpack-rendering-feature) + - [Build with jsoniter](#build-with-jsoniter) - [API Examples](#api-examples) - [Using GET, POST, PUT, PATCH, DELETE and OPTIONS](#using-get-post-put-patch-delete-and-options) - [Parameters in path](#parameters-in-path) @@ -78,6 +77,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi - [http2 server push](#http2-server-push) - [Define format for the log of routes](#define-format-for-the-log-of-routes) - [Set and get a cookie](#set-and-get-a-cookie) + - [Don't trust all proxies](#don't-trust-all-proxies) - [Testing](#testing) - [Users](#users) @@ -183,28 +183,13 @@ Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httpr - [x] Battle tested. - [x] API frozen, new releases will not break your code. -## Build with json replacement +## Build with [jsoniter](https://github.com/json-iterator/go) -Gin uses `encoding/json` as default json package but you can change it by build from other tags. +Gin uses `encoding/json` as default json package but you can change to [jsoniter](https://github.com/json-iterator/go) by build from other tags. -[jsoniter](https://github.com/json-iterator/go) ```sh $ go build -tags=jsoniter . ``` -[go-json](https://github.com/goccy/go-json) -```sh -$ go build -tags=go_json . -``` - -## Build without `MsgPack` rendering feature - -Gin enables `MsgPack` rendering feature by default. But you can disable this feature by specifying `nomsgpack` build tag. - -```sh -$ go build -tags=nomsgpack . -``` - -This is useful to reduce the binary size of executable files. See the [detail information](https://github.com/gin-gonic/gin/pull/1852). ## API Examples @@ -256,15 +241,14 @@ func main() { // For each matched request Context will hold the route definition router.POST("/user/:name/*action", func(c *gin.Context) { - b := c.FullPath() == "/user/:name/*action" // true - c.String(http.StatusOK, "%t", b) + c.FullPath() == "/user/:name/*action" // true }) // This handler will add a new router for /user/groups. // Exact routes are resolved before param routes, regardless of the order they were defined. // Routes starting with /user/groups are never interpreted as /user/:name/... routes router.GET("/user/groups", func(c *gin.Context) { - c.String(http.StatusOK, "The available groups are [...]") + c.String(http.StatusOK, "The available groups are [...]", name) }) router.Run(":8080") @@ -703,7 +687,7 @@ func main() { // Example for binding XML ( // <?xml version="1.0" encoding="UTF-8"?> // <root> - // <user>manu</user> + // <user>user</user> // <password>123</password> // </root>) router.POST("/loginXML", func(c *gin.Context) { @@ -942,7 +926,7 @@ func main() { route.GET("/:name/:id", func(c *gin.Context) { var person Person if err := c.ShouldBindUri(&person); err != nil { - c.JSON(400, gin.H{"msg": err.Error()}) + c.JSON(400, gin.H{"msg": err}) return } c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID}) @@ -2022,61 +2006,6 @@ enough to call binding at once. can be called by `c.ShouldBind()` multiple times without any damage to performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)). -### Bind form-data request with custom struct and custom tag - -```go -const ( - customerTag = "url" - defaultMemory = 32 << 20 -) - -type customerBinding struct {} - -func (customerBinding) Name() string { - return "form" -} - -func (customerBinding) Bind(req *http.Request, obj interface{}) error { - if err := req.ParseForm(); err != nil { - return err - } - if err := req.ParseMultipartForm(defaultMemory); err != nil { - if err != http.ErrNotMultipart { - return err - } - } - if err := binding.MapFormWithTag(obj, req.Form, customerTag); err != nil { - return err - } - return validate(obj) -} - -func validate(obj interface{}) error { - if binding.Validator == nil { - return nil - } - return binding.Validator.ValidateStruct(obj) -} - -// Now we can do this!!! -// FormA is a external type that we can't modify it's tag -type FormA struct { - FieldA string `url:"field_a"` -} - -func ListHandler(s *Service) func(ctx *gin.Context) { - return func(ctx *gin.Context) { - var urlBinding = customerBinding{} - var opt FormA - err := ctx.MustBindWith(&opt, urlBinding) - if err != nil { - ... - } - ... - } -} -``` - ### http2 server push http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information. @@ -2202,11 +2131,17 @@ Gin lets you specify which headers to hold the real client IP (if any), as well as specifying which proxies (or direct clients) you trust to specify one of these headers. -The `TrustedProxies` slice on your `gin.Engine` specifes network addresses or -network CIDRs from where clients which their request headers related to client +Use function `SetTrustedProxies()` on your `gin.Engine` to specify network addresses +or network CIDRs from where clients which their request headers related to client IP can be trusted. They can be IPv4 addresses, IPv4 CIDRs, IPv6 addresses or IPv6 CIDRs. +**Attention:** Gin trust all proxies by default if you don't specify a trusted +proxy using the function above, **this is NOT safe**. At the same time, if you don't +use any proxy, you can disable this feature by using `Engine.SetTrustedProxies(nil)`, +then `Context.ClientIP()` will return the remote address directly to avoid some +unnecessary computation. + ```go import ( "fmt" @@ -2217,7 +2152,7 @@ import ( func main() { router := gin.Default() - router.TrustedProxies = []string{"192.168.1.2"} + router.SetTrustedProxies([]string{"192.168.1.2"}) router.GET("/", func(c *gin.Context) { // If the client is 192.168.1.2, use the X-Forwarded-For @@ -2230,6 +2165,34 @@ func main() { } ``` +**Notice:** If you are using a CDN service, you can set the `Engine.TrustedPlatform` +to skip TrustedProxies check, it has a higher priority than TrustedProxies. +Look at the example below: +```go +import ( + "fmt" + + "github.com/gin-gonic/gin" +) + +func main() { + + router := gin.Default() + // Use predefined header gin.PlatformXXX + router.TrustedPlatform = gin.PlatformGoogleAppEngine + // Or set your own trusted request header for another trusted proxy service + // Don't set it to any suspect request header, it's unsafe + router.TrustedPlatform = "X-CDN-IP" + + router.GET("/", func(c *gin.Context) { + // If you set TrustedPlatform, ClientIP() will resolve the + // corresponding header and return IP directly + fmt.Printf("ClientIP: %s\n", c.ClientIP()) + }) + router.Run() +} +``` + ## Testing The `net/http/httptest` package is preferable way for HTTP testing. @@ -2287,4 +2250,3 @@ Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framewor * [picfit](https://github.com/thoas/picfit): An image resizing server written in Go. * [brigade](https://github.com/brigadecore/brigade): Event-based Scripting for Kubernetes. * [dkron](https://github.com/distribworks/dkron): Distributed, fault tolerant job scheduling system. - diff --git a/vendor/github.com/gin-gonic/gin/binding/binding.go b/vendor/github.com/gin-gonic/gin/binding/binding.go index deb71661b..5caeb581a 100644 --- a/vendor/github.com/gin-gonic/gin/binding/binding.go +++ b/vendor/github.com/gin-gonic/gin/binding/binding.go @@ -49,7 +49,7 @@ type BindingUri interface { // StructValidator is the minimal interface which needs to be implemented in // order for it to be used as the validator engine for ensuring the correctness // of the request. Gin provides a default implementation for this using -// https://github.com/go-playground/validator/tree/v10.6.1. +// https://github.com/go-playground/validator/tree/v8.18.2. type StructValidator interface { // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. // If the received type is a slice|array, the validation should be performed travel on every element. @@ -65,7 +65,7 @@ type StructValidator interface { } // Validator is the default validator which implements the StructValidator -// interface. It uses https://github.com/go-playground/validator/tree/v10.6.1 +// interface. It uses https://github.com/go-playground/validator/tree/v8.18.2 // under the hood. var Validator StructValidator = &defaultValidator{} diff --git a/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go b/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go index 234244707..9afa3dcf6 100644 --- a/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go +++ b/vendor/github.com/gin-gonic/gin/binding/binding_nomsgpack.go @@ -47,7 +47,7 @@ type BindingUri interface { // StructValidator is the minimal interface which needs to be implemented in // order for it to be used as the validator engine for ensuring the correctness // of the request. Gin provides a default implementation for this using -// https://github.com/go-playground/validator/tree/v10.6.1. +// https://github.com/go-playground/validator/tree/v8.18.2. type StructValidator interface { // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. // If the received type is not a struct, any validation should be skipped and nil must be returned. @@ -62,7 +62,7 @@ type StructValidator interface { } // Validator is the default validator which implements the StructValidator -// interface. It uses https://github.com/go-playground/validator/tree/v10.6.1 +// interface. It uses https://github.com/go-playground/validator/tree/v8.18.2 // under the hood. var Validator StructValidator = &defaultValidator{} diff --git a/vendor/github.com/gin-gonic/gin/binding/default_validator.go b/vendor/github.com/gin-gonic/gin/binding/default_validator.go index 87fc4c665..c57a120fc 100644 --- a/vendor/github.com/gin-gonic/gin/binding/default_validator.go +++ b/vendor/github.com/gin-gonic/gin/binding/default_validator.go @@ -20,27 +20,15 @@ type defaultValidator struct { type sliceValidateError []error -// Error concatenates all error elements in sliceValidateError into a single string separated by \n. func (err sliceValidateError) Error() string { - n := len(err) - switch n { - case 0: - return "" - default: - var b strings.Builder - if err[0] != nil { - fmt.Fprintf(&b, "[%d]: %s", 0, err[0].Error()) - } - if n > 1 { - for i := 1; i < n; i++ { - if err[i] != nil { - b.WriteString("\n") - fmt.Fprintf(&b, "[%d]: %s", i, err[i].Error()) - } - } + var errMsgs []string + for i, e := range err { + if e == nil { + continue } - return b.String() + errMsgs = append(errMsgs, fmt.Sprintf("[%d]: %s", i, e.Error())) } + return strings.Join(errMsgs, "\n") } var _ StructValidator = &defaultValidator{} @@ -83,7 +71,7 @@ func (v *defaultValidator) validateStruct(obj interface{}) error { // Engine returns the underlying validator engine which powers the default // Validator instance. This is useful if you want to register custom validations // or struct level validations. See validator GoDoc for more info - -// https://pkg.go.dev/github.com/go-playground/validator/v10 +// https://godoc.org/gopkg.in/go-playground/validator.v8 func (v *defaultValidator) Engine() interface{} { v.lazyinit() return v.validate diff --git a/vendor/github.com/gin-gonic/gin/binding/form.go b/vendor/github.com/gin-gonic/gin/binding/form.go index 040af9e20..b93c34cf4 100644 --- a/vendor/github.com/gin-gonic/gin/binding/form.go +++ b/vendor/github.com/gin-gonic/gin/binding/form.go @@ -22,8 +22,10 @@ func (formBinding) Bind(req *http.Request, obj interface{}) error { if err := req.ParseForm(); err != nil { return err } - if err := req.ParseMultipartForm(defaultMemory); err != nil && err != http.ErrNotMultipart { - return err + if err := req.ParseMultipartForm(defaultMemory); err != nil { + if err != http.ErrNotMultipart { + return err + } } if err := mapForm(obj, req.Form); err != nil { return err diff --git a/vendor/github.com/gin-gonic/gin/binding/form_mapping.go b/vendor/github.com/gin-gonic/gin/binding/form_mapping.go index f8b4b1239..2f4e45b40 100644 --- a/vendor/github.com/gin-gonic/gin/binding/form_mapping.go +++ b/vendor/github.com/gin-gonic/gin/binding/form_mapping.go @@ -16,17 +16,9 @@ import ( "github.com/gin-gonic/gin/internal/json" ) -var ( - errUnknownType = errors.New("unknown type") +var errUnknownType = errors.New("unknown type") - // ErrConvertMapStringSlice can not covert to map[string][]string - ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings") - - // ErrConvertToMapString can not convert to map[string]string - ErrConvertToMapString = errors.New("can not convert to map of strings") -) - -func mapURI(ptr interface{}, m map[string][]string) error { +func mapUri(ptr interface{}, m map[string][]string) error { return mapFormByTag(ptr, m, "uri") } @@ -34,10 +26,6 @@ func mapForm(ptr interface{}, form map[string][]string) error { return mapFormByTag(ptr, form, "form") } -func MapFormWithTag(ptr interface{}, form map[string][]string, tag string) error { - return mapFormByTag(ptr, form, tag) -} - var emptyField = reflect.StructField{} func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error { @@ -83,7 +71,7 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag return false, nil } - vKind := value.Kind() + var vKind = value.Kind() if vKind == reflect.Ptr { var isNew bool @@ -121,7 +109,7 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag if sf.PkgPath != "" && !sf.Anonymous { // unexported continue } - ok, err := mapping(value.Field(i), sf, setter, tag) + ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag) if err != nil { return false, err } @@ -210,7 +198,7 @@ func setWithProperType(val string, value reflect.Value, field reflect.StructFiel case reflect.Int64: switch value.Interface().(type) { case time.Duration: - return setTimeDuration(val, value) + return setTimeDuration(val, value, field) } return setIntField(val, 64, value) case reflect.Uint: @@ -310,6 +298,7 @@ func setTimeField(val string, structField reflect.StructField, value reflect.Val t := time.Unix(tv/int64(d), tv%int64(d)) value.Set(reflect.ValueOf(t)) return nil + } if val == "" { @@ -359,7 +348,7 @@ func setSlice(vals []string, value reflect.Value, field reflect.StructField) err return nil } -func setTimeDuration(val string, value reflect.Value) error { +func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error { d, err := time.ParseDuration(val) if err != nil { return err @@ -382,7 +371,7 @@ func setFormMap(ptr interface{}, form map[string][]string) error { if el.Kind() == reflect.Slice { ptrMap, ok := ptr.(map[string][]string) if !ok { - return ErrConvertMapStringSlice + return errors.New("cannot convert to map slices of strings") } for k, v := range form { ptrMap[k] = v @@ -393,7 +382,7 @@ func setFormMap(ptr interface{}, form map[string][]string) error { ptrMap, ok := ptr.(map[string]string) if !ok { - return ErrConvertToMapString + return errors.New("cannot convert to map of strings") } for k, v := range form { ptrMap[k] = v[len(v)-1] // pick last diff --git a/vendor/github.com/gin-gonic/gin/binding/header.go b/vendor/github.com/gin-gonic/gin/binding/header.go index b99302af8..179ce4ea2 100644 --- a/vendor/github.com/gin-gonic/gin/binding/header.go +++ b/vendor/github.com/gin-gonic/gin/binding/header.go @@ -29,6 +29,6 @@ type headerSource map[string][]string var _ setter = headerSource(nil) -func (hs headerSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (bool, error) { +func (hs headerSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) { return setByForm(value, field, hs, textproto.CanonicalMIMEHeaderKey(tagValue), opt) } diff --git a/vendor/github.com/gin-gonic/gin/binding/json.go b/vendor/github.com/gin-gonic/gin/binding/json.go index 45aaa4948..d62e07059 100644 --- a/vendor/github.com/gin-gonic/gin/binding/json.go +++ b/vendor/github.com/gin-gonic/gin/binding/json.go @@ -6,7 +6,7 @@ package binding import ( "bytes" - "errors" + "fmt" "io" "net/http" @@ -32,7 +32,7 @@ func (jsonBinding) Name() string { func (jsonBinding) Bind(req *http.Request, obj interface{}) error { if req == nil || req.Body == nil { - return errors.New("invalid request") + return fmt.Errorf("invalid request") } return decodeJSON(req.Body, obj) } diff --git a/vendor/github.com/gin-gonic/gin/binding/multipart_form_mapping.go b/vendor/github.com/gin-gonic/gin/binding/multipart_form_mapping.go index 69c0a5443..f85a1aa60 100644 --- a/vendor/github.com/gin-gonic/gin/binding/multipart_form_mapping.go +++ b/vendor/github.com/gin-gonic/gin/binding/multipart_form_mapping.go @@ -15,16 +15,8 @@ type multipartRequest http.Request var _ setter = (*multipartRequest)(nil) -var ( - // ErrMultiFileHeader multipart.FileHeader invalid - ErrMultiFileHeader = errors.New("unsupported field type for multipart.FileHeader") - - // ErrMultiFileHeaderLenInvalid array for []*multipart.FileHeader len invalid - ErrMultiFileHeaderLenInvalid = errors.New("unsupported len of array for []*multipart.FileHeader") -) - // TrySet tries to set a value by the multipart request with the binding a form file -func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (bool, error) { +func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) { if files := r.MultipartForm.File[key]; len(files) != 0 { return setByMultipartFormFile(value, field, files) } @@ -57,12 +49,12 @@ func setByMultipartFormFile(value reflect.Value, field reflect.StructField, file case reflect.Array: return setArrayOfMultipartFormFiles(value, field, files) } - return false, ErrMultiFileHeader + return false, errors.New("unsupported field type for multipart.FileHeader") } func setArrayOfMultipartFormFiles(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSetted bool, err error) { if value.Len() != len(files) { - return false, ErrMultiFileHeaderLenInvalid + return false, errors.New("unsupported len of array for []*multipart.FileHeader") } for i := range files { setted, err := setByMultipartFormFile(value.Index(i), field, files[i:i+1]) diff --git a/vendor/github.com/gin-gonic/gin/binding/protobuf.go b/vendor/github.com/gin-gonic/gin/binding/protobuf.go index a4e471535..f9ece928d 100644 --- a/vendor/github.com/gin-gonic/gin/binding/protobuf.go +++ b/vendor/github.com/gin-gonic/gin/binding/protobuf.go @@ -5,11 +5,10 @@ package binding import ( - "errors" "io/ioutil" "net/http" - "google.golang.org/protobuf/proto" + "github.com/golang/protobuf/proto" ) type protobufBinding struct{} @@ -27,11 +26,7 @@ func (b protobufBinding) Bind(req *http.Request, obj interface{}) error { } func (protobufBinding) BindBody(body []byte, obj interface{}) error { - msg, ok := obj.(proto.Message) - if !ok { - return errors.New("obj is not ProtoMessage") - } - if err := proto.Unmarshal(body, msg); err != nil { + if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil { return err } // Here it's same to return validate(obj), but util now we can't add diff --git a/vendor/github.com/gin-gonic/gin/binding/uri.go b/vendor/github.com/gin-gonic/gin/binding/uri.go index a3c0df515..f91ec3819 100644 --- a/vendor/github.com/gin-gonic/gin/binding/uri.go +++ b/vendor/github.com/gin-gonic/gin/binding/uri.go @@ -11,7 +11,7 @@ func (uriBinding) Name() string { } func (uriBinding) BindUri(m map[string][]string, obj interface{}) error { - if err := mapURI(obj, m); err != nil { + if err := mapUri(obj, m); err != nil { return err } return validate(obj) diff --git a/vendor/github.com/gin-gonic/gin/context.go b/vendor/github.com/gin-gonic/gin/context.go index 62849488b..220d1bc7b 100644 --- a/vendor/github.com/gin-gonic/gin/context.go +++ b/vendor/github.com/gin-gonic/gin/context.go @@ -40,8 +40,7 @@ const ( // BodyBytesKey indicates a default body bytes key. const BodyBytesKey = "_gin-gonic/gin/bodybyteskey" -// abortIndex represents a typical value used in abort functions. -const abortIndex int8 = math.MaxInt8 >> 1 +const abortIndex int8 = math.MaxInt8 / 2 // Context is the most important part of gin. It allows us to pass variables between middleware, // manage the flow, validate the JSON of a request and render a JSON response for example. @@ -55,8 +54,9 @@ type Context struct { index int8 fullPath string - engine *Engine - params *Params + engine *Engine + params *Params + skippedNodes *[]skippedNode // This mutex protect Keys map mu sync.RWMutex @@ -88,17 +88,18 @@ type Context struct { func (c *Context) reset() { c.Writer = &c.writermem - c.Params = c.Params[:0] + c.Params = c.Params[0:0] c.handlers = nil c.index = -1 c.fullPath = "" c.Keys = nil - c.Errors = c.Errors[:0] + c.Errors = c.Errors[0:0] c.Accepted = nil c.queryCache = nil c.formCache = nil *c.params = (*c.params)[:0] + *c.skippedNodes = (*c.skippedNodes)[:0] } // Copy returns a copy of the current context that can be safely used outside the request's scope. @@ -383,15 +384,6 @@ func (c *Context) Param(key string) string { return c.Params.ByName(key) } -// AddParam adds param to context and -// replaces path param key with given value for e2e testing purposes -// Example Route: "/user/:id" -// AddParam("id", 1) -// Result: "/user/1" -func (c *Context) AddParam(key, value string) { - c.Params = append(c.Params, Param{Key: key, Value: value}) -} - // Query returns the keyed url query value if it exists, // otherwise it returns an empty string `("")`. // It is shortcut for `c.Request.URL.Query().Get(key)` @@ -400,9 +392,9 @@ func (c *Context) AddParam(key, value string) { // c.Query("name") == "Manu" // c.Query("value") == "" // c.Query("wtf") == "" -func (c *Context) Query(key string) (value string) { - value, _ = c.GetQuery(key) - return +func (c *Context) Query(key string) string { + value, _ := c.GetQuery(key) + return value } // DefaultQuery returns the keyed url query value if it exists, @@ -436,9 +428,9 @@ func (c *Context) GetQuery(key string) (string, bool) { // QueryArray returns a slice of strings for a given query key. // The length of the slice depends on the number of params with the given key. -func (c *Context) QueryArray(key string) (values []string) { - values, _ = c.GetQueryArray(key) - return +func (c *Context) QueryArray(key string) []string { + values, _ := c.GetQueryArray(key) + return values } func (c *Context) initQueryCache() { @@ -453,16 +445,18 @@ func (c *Context) initQueryCache() { // GetQueryArray returns a slice of strings for a given query key, plus // a boolean value whether at least one value exists for the given key. -func (c *Context) GetQueryArray(key string) (values []string, ok bool) { +func (c *Context) GetQueryArray(key string) ([]string, bool) { c.initQueryCache() - values, ok = c.queryCache[key] - return + if values, ok := c.queryCache[key]; ok && len(values) > 0 { + return values, true + } + return []string{}, false } // QueryMap returns a map for a given query key. -func (c *Context) QueryMap(key string) (dicts map[string]string) { - dicts, _ = c.GetQueryMap(key) - return +func (c *Context) QueryMap(key string) map[string]string { + dicts, _ := c.GetQueryMap(key) + return dicts } // GetQueryMap returns a map for a given query key, plus a boolean value @@ -474,9 +468,9 @@ func (c *Context) GetQueryMap(key string) (map[string]string, bool) { // PostForm returns the specified key from a POST urlencoded form or multipart form // when it exists, otherwise it returns an empty string `("")`. -func (c *Context) PostForm(key string) (value string) { - value, _ = c.GetPostForm(key) - return +func (c *Context) PostForm(key string) string { + value, _ := c.GetPostForm(key) + return value } // DefaultPostForm returns the specified key from a POST urlencoded form or multipart form @@ -505,9 +499,9 @@ func (c *Context) GetPostForm(key string) (string, bool) { // PostFormArray returns a slice of strings for a given form key. // The length of the slice depends on the number of params with the given key. -func (c *Context) PostFormArray(key string) (values []string) { - values, _ = c.GetPostFormArray(key) - return +func (c *Context) PostFormArray(key string) []string { + values, _ := c.GetPostFormArray(key) + return values } func (c *Context) initFormCache() { @@ -525,16 +519,18 @@ func (c *Context) initFormCache() { // GetPostFormArray returns a slice of strings for a given form key, plus // a boolean value whether at least one value exists for the given key. -func (c *Context) GetPostFormArray(key string) (values []string, ok bool) { +func (c *Context) GetPostFormArray(key string) ([]string, bool) { c.initFormCache() - values, ok = c.formCache[key] - return + if values := c.formCache[key]; len(values) > 0 { + return values, true + } + return []string{}, false } // PostFormMap returns a map for a given form key. -func (c *Context) PostFormMap(key string) (dicts map[string]string) { - dicts, _ = c.GetPostFormMap(key) - return +func (c *Context) PostFormMap(key string) map[string]string { + dicts, _ := c.GetPostFormMap(key) + return dicts } // GetPostFormMap returns a map for a given form key, plus a boolean value @@ -732,20 +728,16 @@ func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (e return bb.BindBody(body, obj) } -// ClientIP implements a best effort algorithm to return the real client IP. +// ClientIP implements one best effort algorithm to return the real client IP. // It called c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not. -// If it's it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]). -// If the headers are nots syntactically valid OR the remote IP does not correspong to a trusted proxy, +// If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]). +// If the headers are not syntactically valid OR the remote IP does not correspond to a trusted proxy, // the remote IP (coming form Request.RemoteAddr) is returned. func (c *Context) ClientIP() string { - // Check if we're running on a trusted platform - switch c.engine.TrustedPlatform { - case PlatformGoogleAppEngine: - if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" { - return addr - } - case PlatformCloudflare: - if addr := c.requestHeader("CF-Connecting-IP"); addr != "" { + // Check if we're running on a trusted platform, continue running backwards if error + if c.engine.TrustedPlatform != "" { + // Developers can define their own header of Trusted Platform or use predefined constants + if addr := c.requestHeader(c.engine.TrustedPlatform); addr != "" { return addr } } @@ -765,7 +757,7 @@ func (c *Context) ClientIP() string { if trusted && c.engine.ForwardedByClientIP && c.engine.RemoteIPHeaders != nil { for _, headerName := range c.engine.RemoteIPHeaders { - ip, valid := validateHeader(c.requestHeader(headerName)) + ip, valid := c.engine.validateHeader(c.requestHeader(headerName)) if valid { return ip } @@ -774,10 +766,21 @@ func (c *Context) ClientIP() string { return remoteIP.String() } +func (e *Engine) isTrustedProxy(ip net.IP) bool { + if e.trustedCIDRs != nil { + for _, cidr := range e.trustedCIDRs { + if cidr.Contains(ip) { + return true + } + } + } + return false +} + // RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port). // It also checks if the remoteIP is a trusted proxy or not. // In order to perform this validation, it will see if the IP is contained within at least one of the CIDR blocks -// defined in Engine.TrustedProxies +// defined by Engine.SetTrustedProxies() func (c *Context) RemoteIP() (net.IP, bool) { ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr)) if err != nil { @@ -788,35 +791,25 @@ func (c *Context) RemoteIP() (net.IP, bool) { return nil, false } - if c.engine.trustedCIDRs != nil { - for _, cidr := range c.engine.trustedCIDRs { - if cidr.Contains(remoteIP) { - return remoteIP, true - } - } - } - - return remoteIP, false + return remoteIP, c.engine.isTrustedProxy(remoteIP) } -func validateHeader(header string) (clientIP string, valid bool) { +func (e *Engine) validateHeader(header string) (clientIP string, valid bool) { if header == "" { return "", false } items := strings.Split(header, ",") - for i, ipStr := range items { - ipStr = strings.TrimSpace(ipStr) + for i := len(items) - 1; i >= 0; i-- { + ipStr := strings.TrimSpace(items[i]) ip := net.ParseIP(ipStr) if ip == nil { return "", false } - // We need to return the first IP in the list, but, - // we should not early return since we need to validate that - // the rest of the header is syntactically valid - if i == 0 { - clientIP = ipStr - valid = true + // X-Forwarded-For is appended by proxy + // Check IPs in reverse order and stop when find untrusted proxy + if (i == 0) || (!e.isTrustedProxy(ip)) { + return ipStr, true } } return @@ -1166,28 +1159,22 @@ func (c *Context) SetAccepted(formats ...string) { /***** GOLANG.ORG/X/NET/CONTEXT *****/ /************************************/ -// Deadline returns that there is no deadline (ok==false) when c.Request has no Context. +// Deadline always returns that there is no deadline (ok==false), +// maybe you want to use Request.Context().Deadline() instead. func (c *Context) Deadline() (deadline time.Time, ok bool) { - if c.Request == nil || c.Request.Context() == nil { - return - } - return c.Request.Context().Deadline() + return } -// Done returns nil (chan which will wait forever) when c.Request has no Context. +// Done always returns nil (chan which will wait forever), +// if you want to abort your work when the connection was closed +// you should use Request.Context().Done() instead. func (c *Context) Done() <-chan struct{} { - if c.Request == nil || c.Request.Context() == nil { - return nil - } - return c.Request.Context().Done() + return nil } -// Err returns nil when c.Request has no Context. +// Err always returns nil, maybe you want to use Request.Context().Err() instead. func (c *Context) Err() error { - if c.Request == nil || c.Request.Context() == nil { - return nil - } - return c.Request.Context().Err() + return nil } // Value returns the value associated with this context for key, or nil @@ -1198,12 +1185,8 @@ func (c *Context) Value(key interface{}) interface{} { return c.Request } if keyAsString, ok := key.(string); ok { - if val, exists := c.Get(keyAsString); exists { - return val - } + val, _ := c.Get(keyAsString) + return val } - if c.Request == nil || c.Request.Context() == nil { - return nil - } - return c.Request.Context().Value(key) + return nil } diff --git a/vendor/github.com/gin-gonic/gin/debug.go b/vendor/github.com/gin-gonic/gin/debug.go index ed313868e..9bacc6857 100644 --- a/vendor/github.com/gin-gonic/gin/debug.go +++ b/vendor/github.com/gin-gonic/gin/debug.go @@ -95,7 +95,9 @@ at initialization. ie. before any route is registered or the router is listening } func debugPrintError(err error) { - if err != nil && IsDebugging() { - fmt.Fprintf(DefaultErrorWriter, "[GIN-debug] [ERROR] %v\n", err) + if err != nil { + if IsDebugging() { + fmt.Fprintf(DefaultErrorWriter, "[GIN-debug] [ERROR] %v\n", err) + } } } diff --git a/vendor/github.com/gin-gonic/gin/fs.go b/vendor/github.com/gin-gonic/gin/fs.go index e5f3d602a..007d9b755 100644 --- a/vendor/github.com/gin-gonic/gin/fs.go +++ b/vendor/github.com/gin-gonic/gin/fs.go @@ -17,7 +17,7 @@ type neuteredReaddirFile struct { http.File } -// Dir returns a http.FileSystem that can be used by http.FileServer(). It is used internally +// Dir returns a http.Filesystem that can be used by http.FileServer(). It is used internally // in router.Static(). // if listDirectory == true, then it works the same as http.Dir() otherwise it returns // a filesystem that prevents http.FileServer() to list the directory files. diff --git a/vendor/github.com/gin-gonic/gin/gin.go b/vendor/github.com/gin-gonic/gin/gin.go index 6ab2be66d..58e76f41f 100644 --- a/vendor/github.com/gin-gonic/gin/gin.go +++ b/vendor/github.com/gin-gonic/gin/gin.go @@ -11,6 +11,7 @@ import ( "net/http" "os" "path" + "reflect" "strings" "sync" @@ -27,6 +28,8 @@ var ( var defaultPlatform string +var defaultTrustedCIDRs = []*net.IPNet{{IP: net.IP{0x0, 0x0, 0x0, 0x0}, Mask: net.IPMask{0x0, 0x0, 0x0, 0x0}}} // 0.0.0.0/0 + // HandlerFunc defines the handler used by gin middleware as return value. type HandlerFunc func(*Context) @@ -56,10 +59,10 @@ type RoutesInfo []RouteInfo const ( // When running on Google App Engine. Trust X-Appengine-Remote-Addr // for determining the client's IP - PlatformGoogleAppEngine = "google-app-engine" + PlatformGoogleAppEngine = "X-Appengine-Remote-Addr" // When using Cloudflare's CDN. Trust CF-Connecting-IP for determining // the client's IP - PlatformCloudflare = "cloudflare" + PlatformCloudflare = "CF-Connecting-IP" ) // Engine is the framework's instance, it contains the muxer, middleware and configuration settings. @@ -119,15 +122,9 @@ type Engine struct { // List of headers used to obtain the client IP when // `(*gin.Engine).ForwardedByClientIP` is `true` and // `(*gin.Context).Request.RemoteAddr` is matched by at least one of the - // network origins of `(*gin.Engine).TrustedProxies`. + // network origins of list defined by `(*gin.Engine).SetTrustedProxies()`. RemoteIPHeaders []string - // List of network origins (IPv4 addresses, IPv4 CIDRs, IPv6 addresses or - // IPv6 CIDRs) from which to trust request's headers that contain - // alternative client IP when `(*gin.Engine).ForwardedByClientIP` is - // `true`. - TrustedProxies []string - // If set to a constant of value gin.Platform*, trusts the headers set by // that platform, for example to determine the client IP TrustedPlatform string @@ -147,6 +144,8 @@ type Engine struct { pool sync.Pool trees methodTrees maxParams uint16 + maxSections uint16 + trustedProxies []string trustedCIDRs []*net.IPNet } @@ -174,7 +173,6 @@ func New() *Engine { HandleMethodNotAllowed: false, ForwardedByClientIP: true, RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"}, - TrustedProxies: []string{"0.0.0.0/0"}, TrustedPlatform: defaultPlatform, UseRawPath: false, RemoveExtraSlash: false, @@ -183,6 +181,8 @@ func New() *Engine { trees: make(methodTrees, 0, 9), delims: render.Delims{Left: "{{", Right: "}}"}, secureJSONPrefix: "while(1);", + trustedProxies: []string{"0.0.0.0/0"}, + trustedCIDRs: defaultTrustedCIDRs, } engine.RouterGroup.engine = engine engine.pool.New = func() interface{} { @@ -201,7 +201,8 @@ func Default() *Engine { func (engine *Engine) allocateContext() *Context { v := make(Params, 0, engine.maxParams) - return &Context{engine: engine, params: &v} + skippedNodes := make([]skippedNode, 0, engine.maxSections) + return &Context{engine: engine, params: &v, skippedNodes: &skippedNodes} } // Delims sets template left and right delims and returns a Engine instance. @@ -264,7 +265,7 @@ func (engine *Engine) NoRoute(handlers ...HandlerFunc) { engine.rebuild404Handlers() } -// NoMethod sets the handlers called when... TODO. +// NoMethod sets the handlers called when Engine.HandleMethodNotAllowed = true. func (engine *Engine) NoMethod(handlers ...HandlerFunc) { engine.noMethod = handlers engine.rebuild405Handlers() @@ -307,6 +308,10 @@ func (engine *Engine) addRoute(method, path string, handlers HandlersChain) { if paramsCount := countParams(path); paramsCount > engine.maxParams { engine.maxParams = paramsCount } + + if sectionsCount := countSections(path); sectionsCount > engine.maxSections { + engine.maxSections = sectionsCount + } } // Routes returns a slice of registered routes, including some useful information, such as: @@ -341,9 +346,9 @@ func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo { func (engine *Engine) Run(addr ...string) (err error) { defer func() { debugPrintError(err) }() - err = engine.parseTrustedProxies() - if err != nil { - return err + if engine.isUnsafeTrustedProxies() { + debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + + "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") } address := resolveAddress(addr) @@ -353,12 +358,12 @@ func (engine *Engine) Run(addr ...string) (err error) { } func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) { - if engine.TrustedProxies == nil { + if engine.trustedProxies == nil { return nil, nil } - cidr := make([]*net.IPNet, 0, len(engine.TrustedProxies)) - for _, trustedProxy := range engine.TrustedProxies { + cidr := make([]*net.IPNet, 0, len(engine.trustedProxies)) + for _, trustedProxy := range engine.trustedProxies { if !strings.Contains(trustedProxy, "/") { ip := parseIP(trustedProxy) if ip == nil { @@ -381,13 +386,25 @@ func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) { return cidr, nil } -// SetTrustedProxies set Engine.TrustedProxies +// SetTrustedProxies set a list of network origins (IPv4 addresses, +// IPv4 CIDRs, IPv6 addresses or IPv6 CIDRs) from which to trust +// request's headers that contain alternative client IP when +// `(*gin.Engine).ForwardedByClientIP` is `true`. `TrustedProxies` +// feature is enabled by default, and it also trusts all proxies +// by default. If you want to disable this feature, use +// Engine.SetTrustedProxies(nil), then Context.ClientIP() will +// return the remote address directly. func (engine *Engine) SetTrustedProxies(trustedProxies []string) error { - engine.TrustedProxies = trustedProxies + engine.trustedProxies = trustedProxies return engine.parseTrustedProxies() } -// parseTrustedProxies parse Engine.TrustedProxies to Engine.trustedCIDRs +// isUnsafeTrustedProxies compares Engine.trustedCIDRs and defaultTrustedCIDRs, it's not safe if equal (returns true) +func (engine *Engine) isUnsafeTrustedProxies() bool { + return reflect.DeepEqual(engine.trustedCIDRs, defaultTrustedCIDRs) +} + +// parseTrustedProxies parse Engine.trustedProxies to Engine.trustedCIDRs func (engine *Engine) parseTrustedProxies() error { trustedCIDRs, err := engine.prepareTrustedCIDRs() engine.trustedCIDRs = trustedCIDRs @@ -415,9 +432,9 @@ func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) { debugPrint("Listening and serving HTTPS on %s\n", addr) defer func() { debugPrintError(err) }() - err = engine.parseTrustedProxies() - if err != nil { - return err + if engine.isUnsafeTrustedProxies() { + debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + + "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") } err = http.ListenAndServeTLS(addr, certFile, keyFile, engine) @@ -431,9 +448,9 @@ func (engine *Engine) RunUnix(file string) (err error) { debugPrint("Listening and serving HTTP on unix:/%s", file) defer func() { debugPrintError(err) }() - err = engine.parseTrustedProxies() - if err != nil { - return err + if engine.isUnsafeTrustedProxies() { + debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + + "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") } listener, err := net.Listen("unix", file) @@ -454,9 +471,9 @@ func (engine *Engine) RunFd(fd int) (err error) { debugPrint("Listening and serving HTTP on fd@%d", fd) defer func() { debugPrintError(err) }() - err = engine.parseTrustedProxies() - if err != nil { - return err + if engine.isUnsafeTrustedProxies() { + debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + + "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") } f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd)) @@ -475,9 +492,9 @@ func (engine *Engine) RunListener(listener net.Listener) (err error) { debugPrint("Listening and serving HTTP on listener what's bind with address@%s", listener.Addr()) defer func() { debugPrintError(err) }() - err = engine.parseTrustedProxies() - if err != nil { - return err + if engine.isUnsafeTrustedProxies() { + debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" + + "Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.") } err = http.Serve(listener, engine) @@ -528,7 +545,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) { } root := t[i].root // Find route in tree - value := root.getValue(rPath, c.params, unescape) + value := root.getValue(rPath, c.params, c.skippedNodes, unescape) if value.params != nil { c.Params = *value.params } @@ -539,7 +556,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) { c.writermem.WriteHeaderNow() return } - if httpMethod != http.MethodConnect && rPath != "/" { + if httpMethod != "CONNECT" && rPath != "/" { if value.tsr && engine.RedirectTrailingSlash { redirectTrailingSlash(c) return @@ -556,7 +573,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) { if tree.method == httpMethod { continue } - if value := tree.root.getValue(rPath, nil, unescape); value.handlers != nil { + if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil { c.handlers = engine.allNoMethod serveError(c, http.StatusMethodNotAllowed, default405Body) return diff --git a/vendor/github.com/gin-gonic/gin/internal/json/go_json.go b/vendor/github.com/gin-gonic/gin/internal/json/go_json.go deleted file mode 100644 index da960571a..000000000 --- a/vendor/github.com/gin-gonic/gin/internal/json/go_json.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017 Bo-Yi Wu. All rights reserved. -// Use of this source code is governed by a MIT style -// license that can be found in the LICENSE file. - -//go:build go_json -// +build go_json - -package json - -import json "github.com/goccy/go-json" - -var ( - // Marshal is exported by gin/json package. - Marshal = json.Marshal - // Unmarshal is exported by gin/json package. - Unmarshal = json.Unmarshal - // MarshalIndent is exported by gin/json package. - MarshalIndent = json.MarshalIndent - // NewDecoder is exported by gin/json package. - NewDecoder = json.NewDecoder - // NewEncoder is exported by gin/json package. - NewEncoder = json.NewEncoder -) diff --git a/vendor/github.com/gin-gonic/gin/internal/json/json.go b/vendor/github.com/gin-gonic/gin/internal/json/json.go index 75b602240..172aeb241 100644 --- a/vendor/github.com/gin-gonic/gin/internal/json/json.go +++ b/vendor/github.com/gin-gonic/gin/internal/json/json.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. -//go:build !jsoniter && !go_json -// +build !jsoniter,!go_json +//go:build !jsoniter +// +build !jsoniter package json diff --git a/vendor/github.com/gin-gonic/gin/logger.go b/vendor/github.com/gin-gonic/gin/logger.go index 22138a8d3..d361b74d3 100644 --- a/vendor/github.com/gin-gonic/gin/logger.go +++ b/vendor/github.com/gin-gonic/gin/logger.go @@ -138,7 +138,8 @@ var defaultLogFormatter = func(param LogFormatterParams) string { } if param.Latency > time.Minute { - param.Latency = param.Latency.Truncate(time.Second) + // Truncate in a golang < 1.8 safe way + param.Latency = param.Latency - param.Latency%time.Second } return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s", param.TimeStamp.Format("2006/01/02 - 15:04:05"), diff --git a/vendor/github.com/gin-gonic/gin/mode.go b/vendor/github.com/gin-gonic/gin/mode.go index 4d199df30..c8813aff2 100644 --- a/vendor/github.com/gin-gonic/gin/mode.go +++ b/vendor/github.com/gin-gonic/gin/mode.go @@ -41,10 +41,8 @@ var DefaultWriter io.Writer = os.Stdout // DefaultErrorWriter is the default io.Writer used by Gin to debug errors var DefaultErrorWriter io.Writer = os.Stderr -var ( - ginMode = debugCode - modeName = DebugMode -) +var ginMode = debugCode +var modeName = DebugMode func init() { mode := os.Getenv(EnvGinMode) diff --git a/vendor/github.com/gin-gonic/gin/recovery.go b/vendor/github.com/gin-gonic/gin/recovery.go index 3101fe28a..563f5aaa8 100644 --- a/vendor/github.com/gin-gonic/gin/recovery.go +++ b/vendor/github.com/gin-gonic/gin/recovery.go @@ -34,7 +34,7 @@ func Recovery() HandlerFunc { return RecoveryWithWriter(DefaultErrorWriter) } -// CustomRecovery returns a middleware that recovers from any panics and calls the provided handle func to handle it. +//CustomRecovery returns a middleware that recovers from any panics and calls the provided handle func to handle it. func CustomRecovery(handle RecoveryFunc) HandlerFunc { return RecoveryWithWriter(DefaultErrorWriter, handle) } @@ -165,7 +165,7 @@ func function(pc uintptr) []byte { return name } -// timeFormat returns a customized time string for logger. func timeFormat(t time.Time) string { - return t.Format("2006/01/02 - 15:04:05") + timeString := t.Format("2006/01/02 - 15:04:05") + return timeString } diff --git a/vendor/github.com/gin-gonic/gin/render/json.go b/vendor/github.com/gin-gonic/gin/render/json.go index 3ebcee970..418630939 100644 --- a/vendor/github.com/gin-gonic/gin/render/json.go +++ b/vendor/github.com/gin-gonic/gin/render/json.go @@ -46,11 +46,9 @@ type PureJSON struct { Data interface{} } -var ( - jsonContentType = []string{"application/json; charset=utf-8"} - jsonpContentType = []string{"application/javascript; charset=utf-8"} - jsonASCIIContentType = []string{"application/json"} -) +var jsonContentType = []string{"application/json; charset=utf-8"} +var jsonpContentType = []string{"application/javascript; charset=utf-8"} +var jsonAsciiContentType = []string{"application/json"} // Render (JSON) writes data with custom ContentType. func (r JSON) Render(w http.ResponseWriter) (err error) { @@ -102,7 +100,8 @@ func (r SecureJSON) Render(w http.ResponseWriter) error { // if the jsonBytes is array values if bytes.HasPrefix(jsonBytes, bytesconv.StringToBytes("[")) && bytes.HasSuffix(jsonBytes, bytesconv.StringToBytes("]")) { - if _, err = w.Write(bytesconv.StringToBytes(r.Prefix)); err != nil { + _, err = w.Write(bytesconv.StringToBytes(r.Prefix)) + if err != nil { return err } } @@ -129,19 +128,20 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) { } callback := template.JSEscapeString(r.Callback) - if _, err = w.Write(bytesconv.StringToBytes(callback)); err != nil { + _, err = w.Write(bytesconv.StringToBytes(callback)) + if err != nil { return err } - - if _, err = w.Write(bytesconv.StringToBytes("(")); err != nil { + _, err = w.Write(bytesconv.StringToBytes("(")) + if err != nil { return err } - - if _, err = w.Write(ret); err != nil { + _, err = w.Write(ret) + if err != nil { return err } - - if _, err = w.Write(bytesconv.StringToBytes(");")); err != nil { + _, err = w.Write(bytesconv.StringToBytes(");")) + if err != nil { return err } @@ -176,7 +176,7 @@ func (r AsciiJSON) Render(w http.ResponseWriter) (err error) { // WriteContentType (AsciiJSON) writes JSON ContentType. func (r AsciiJSON) WriteContentType(w http.ResponseWriter) { - writeContentType(w, jsonASCIIContentType) + writeContentType(w, jsonAsciiContentType) } // Render (PureJSON) writes custom ContentType and encodes the given interface object. diff --git a/vendor/github.com/gin-gonic/gin/render/msgpack.go b/vendor/github.com/gin-gonic/gin/render/msgpack.go index 7f17ca4d9..6ef5b6e51 100644 --- a/vendor/github.com/gin-gonic/gin/render/msgpack.go +++ b/vendor/github.com/gin-gonic/gin/render/msgpack.go @@ -13,8 +13,6 @@ import ( "github.com/ugorji/go/codec" ) -// Check interface implemented here to support go build tag nomsgpack. -// See: https://github.com/gin-gonic/gin/pull/1852/ var ( _ Render = MsgPack{} ) diff --git a/vendor/github.com/gin-gonic/gin/render/protobuf.go b/vendor/github.com/gin-gonic/gin/render/protobuf.go index 1d2aa871c..15aca9959 100644 --- a/vendor/github.com/gin-gonic/gin/render/protobuf.go +++ b/vendor/github.com/gin-gonic/gin/render/protobuf.go @@ -7,7 +7,7 @@ package render import ( "net/http" - "google.golang.org/protobuf/proto" + "github.com/golang/protobuf/proto" ) // ProtoBuf contains the given interface object. diff --git a/vendor/github.com/gin-gonic/gin/routergroup.go b/vendor/github.com/gin-gonic/gin/routergroup.go index bb24bd523..15d9930d3 100644 --- a/vendor/github.com/gin-gonic/gin/routergroup.go +++ b/vendor/github.com/gin-gonic/gin/routergroup.go @@ -11,11 +11,6 @@ import ( "strings" ) -var ( - // reg match english letters for http method name - regEnLetter = regexp.MustCompile("^[A-Z]+$") -) - // IRouter defines all router handle interface includes single and group router. type IRouter interface { IRoutes @@ -92,7 +87,7 @@ func (group *RouterGroup) handle(httpMethod, relativePath string, handlers Handl // frequently used, non-standardized or custom methods (e.g. for internal // communication with a proxy). func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes { - if matched := regEnLetter.MatchString(httpMethod); !matched { + if matches, err := regexp.MatchString("^[A-Z]+$", httpMethod); !matches || err != nil { panic("http method " + httpMethod + " is not valid") } return group.handle(httpMethod, relativePath, handlers) @@ -214,7 +209,9 @@ func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileS func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain { finalSize := len(group.Handlers) + len(handlers) - assert1(finalSize < int(abortIndex), "too many handlers") + if finalSize >= int(abortIndex) { + panic("too many handlers") + } mergedHandlers := make(HandlersChain, finalSize) copy(mergedHandlers, group.Handlers) copy(mergedHandlers[len(group.Handlers):], handlers) diff --git a/vendor/github.com/gin-gonic/gin/tree.go b/vendor/github.com/gin-gonic/gin/tree.go index fb0a5935c..158a33908 100644 --- a/vendor/github.com/gin-gonic/gin/tree.go +++ b/vendor/github.com/gin-gonic/gin/tree.go @@ -17,6 +17,7 @@ import ( var ( strColon = []byte(":") strStar = []byte("*") + strSlash = []byte("/") ) // Param is a single URL parameter, consisting of a key and a value. @@ -30,8 +31,8 @@ type Param struct { // It is therefore safe to read values by the index. type Params []Param -// Get returns the value of the first Param which key matches the given name and a boolean true. -// If no matching Param is found, an empty string is returned and a boolean false . +// Get returns the value of the first Param which key matches the given name. +// If no matching Param is found, an empty string is returned. func (ps Params) Get(name string) (string, bool) { for _, entry := range ps { if entry.Key == name { @@ -98,10 +99,16 @@ func countParams(path string) uint16 { return n } +func countSections(path string) uint16 { + s := bytesconv.StringToBytes(path) + return uint16(bytes.Count(s, strSlash)) +} + type nodeType uint8 const ( - root nodeType = iota + 1 + static nodeType = iota // default + root param catchAll ) @@ -393,16 +400,19 @@ type nodeValue struct { fullPath string } +type skippedNode struct { + path string + node *node + paramsCount int16 +} + // Returns the handle registered with the given path (key). The values of // wildcards are saved to a map. // If no handle can be found, a TSR (trailing slash redirect) recommendation is // made if a handle exists with an extra (without the) trailing slash for the // given path. -func (n *node) getValue(path string, params *Params, unescape bool) (value nodeValue) { - var ( - skippedPath string - latestNode = n // Caching the latest node - ) +func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode, unescape bool) (value nodeValue) { + var globalParamsCount int16 walk: // Outer loop for walking the tree for { @@ -417,15 +427,20 @@ walk: // Outer loop for walking the tree if c == idxc { // strings.HasPrefix(n.children[len(n.children)-1].path, ":") == n.wildChild if n.wildChild { - skippedPath = prefix + path - latestNode = &node{ - path: n.path, - wildChild: n.wildChild, - nType: n.nType, - priority: n.priority, - children: n.children, - handlers: n.handlers, - fullPath: n.fullPath, + index := len(*skippedNodes) + *skippedNodes = (*skippedNodes)[:index+1] + (*skippedNodes)[index] = skippedNode{ + path: prefix + path, + node: &node{ + path: n.path, + wildChild: n.wildChild, + nType: n.nType, + priority: n.priority, + children: n.children, + handlers: n.handlers, + fullPath: n.fullPath, + }, + paramsCount: globalParamsCount, } } @@ -433,15 +448,26 @@ walk: // Outer loop for walking the tree continue walk } } - // If the path at the end of the loop is not equal to '/' and the current node has no child nodes - // the current node needs to be equal to the latest matching node - matched := path != "/" && !n.wildChild - if matched { - n = latestNode - } - // If there is no wildcard pattern, recommend a redirection if !n.wildChild { + // If the path at the end of the loop is not equal to '/' and the current node has no child nodes + // the current node needs to roll back to last vaild skippedNode + if path != "/" { + for l := len(*skippedNodes); l > 0; { + skippedNode := (*skippedNodes)[l-1] + *skippedNodes = (*skippedNodes)[:l-1] + if strings.HasSuffix(skippedNode.path, path) { + path = skippedNode.path + n = skippedNode.node + if value.params != nil { + *value.params = (*value.params)[:skippedNode.paramsCount] + } + globalParamsCount = skippedNode.paramsCount + continue walk + } + } + } + // Nothing found. // We can recommend to redirect to the same URL without a // trailing slash if a leaf exists for that path. @@ -451,18 +477,12 @@ walk: // Outer loop for walking the tree // Handle wildcard child, which is always at the end of the array n = n.children[len(n.children)-1] + globalParamsCount++ switch n.nType { case param: // fix truncate the parameter // tree_test.go line: 204 - if matched { - path = prefix + path - // The saved path is used after the prefix route is intercepted by matching - if n.indices == "/" { - path = skippedPath[1:] - } - } // Find param end (either '/' or path end) end := 0 @@ -548,9 +568,22 @@ walk: // Outer loop for walking the tree if path == prefix { // If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node - // the current node needs to be equal to the latest matching node - if latestNode.wildChild && n.handlers == nil && path != "/" { - n = latestNode.children[len(latestNode.children)-1] + // the current node needs to roll back to last vaild skippedNode + if n.handlers == nil && path != "/" { + for l := len(*skippedNodes); l > 0; { + skippedNode := (*skippedNodes)[l-1] + *skippedNodes = (*skippedNodes)[:l-1] + if strings.HasSuffix(skippedNode.path, path) { + path = skippedNode.path + n = skippedNode.node + if value.params != nil { + *value.params = (*value.params)[:skippedNode.paramsCount] + } + globalParamsCount = skippedNode.paramsCount + continue walk + } + } + // n = latestNode.children[len(latestNode.children)-1] } // We should have reached the node containing the handle. // Check if this node has a handle registered. @@ -581,25 +614,29 @@ walk: // Outer loop for walking the tree return } - if path != "/" && len(skippedPath) > 0 && strings.HasSuffix(skippedPath, path) { - path = skippedPath - // Reduce the number of cycles - n, latestNode = latestNode, n - // skippedPath cannot execute - // example: - // * /:cc/cc - // call /a/cc expectations:match/200 Actual:match/200 - // call /a/dd expectations:unmatch/404 Actual: panic - // call /addr/dd/aa expectations:unmatch/404 Actual: panic - // skippedPath: It can only be executed if the secondary route is not found - skippedPath = "" - continue walk - } - // Nothing found. We can recommend to redirect to the same URL with an // extra trailing slash if a leaf exists for that path value.tsr = path == "/" || - (len(prefix) == len(path)+1 && n.handlers != nil) + (len(prefix) == len(path)+1 && prefix[len(path)] == '/' && + path == prefix[:len(prefix)-1] && n.handlers != nil) + + // roll back to last valid skippedNode + if !value.tsr && path != "/" { + for l := len(*skippedNodes); l > 0; { + skippedNode := (*skippedNodes)[l-1] + *skippedNodes = (*skippedNodes)[:l-1] + if strings.HasSuffix(skippedNode.path, path) { + path = skippedNode.path + n = skippedNode.node + if value.params != nil { + *value.params = (*value.params)[:skippedNode.paramsCount] + } + globalParamsCount = skippedNode.paramsCount + continue walk + } + } + } + return } } diff --git a/vendor/github.com/gin-gonic/gin/version.go b/vendor/github.com/gin-gonic/gin/version.go index 535bfc827..4b69b9b91 100644 --- a/vendor/github.com/gin-gonic/gin/version.go +++ b/vendor/github.com/gin-gonic/gin/version.go @@ -5,4 +5,4 @@ package gin // Version is the current gin framework's version. -const Version = "v1.7.3" +const Version = "v1.7.7" |