diff --git a/binding/default_validator.go b/binding/default_validator.go index 87fc4c66..a91e0496 100644 --- a/binding/default_validator.go +++ b/binding/default_validator.go @@ -8,13 +8,11 @@ import ( "fmt" "reflect" "strings" - "sync" "github.com/go-playground/validator/v10" ) type defaultValidator struct { - once sync.Once validate *validator.Validate } @@ -76,7 +74,7 @@ func (v *defaultValidator) ValidateStruct(obj interface{}) error { // validateStruct receives struct type func (v *defaultValidator) validateStruct(obj interface{}) error { - v.lazyinit() + v.lazyInit() return v.validate.Struct(obj) } @@ -85,13 +83,14 @@ func (v *defaultValidator) validateStruct(obj interface{}) error { // or struct level validations. See validator GoDoc for more info - // https://pkg.go.dev/github.com/go-playground/validator/v10 func (v *defaultValidator) Engine() interface{} { - v.lazyinit() + v.lazyInit() return v.validate } -func (v *defaultValidator) lazyinit() { - v.once.Do(func() { +// lazyInit initialize the validate Settings, no need to use sync.once +func (v *defaultValidator) lazyInit() { + if v.validate == nil { v.validate = validator.New() v.validate.SetTagName("binding") - }) + } } diff --git a/binding/form_mapping.go b/binding/form_mapping.go index f8b4b123..30c65dca 100644 --- a/binding/form_mapping.go +++ b/binding/form_mapping.go @@ -17,7 +17,8 @@ import ( ) var ( - errUnknownType = errors.New("unknown type") + // ErrUnknownType unknown type + ErrUnknownType = errors.New("unknown type") // ErrConvertMapStringSlice can not covert to map[string][]string ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings") @@ -164,7 +165,7 @@ func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter return setter.TrySet(value, field, tagValue, setOpt) } -func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSetted bool, err error) { +func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (bool, error) { vs, ok := form[tagValue] if !ok && !opt.isDefaultExists { return false, nil @@ -240,7 +241,7 @@ func setWithProperType(val string, value reflect.Value, field reflect.StructFiel case reflect.Map: return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface()) default: - return errUnknownType + return ErrUnknownType } return nil } diff --git a/binding/form_mapping_test.go b/binding/form_mapping_test.go index 516554eb..2e4e7d4c 100644 --- a/binding/form_mapping_test.go +++ b/binding/form_mapping_test.go @@ -124,7 +124,7 @@ func TestMappingUnknownFieldType(t *testing.T) { err := mappingByPtr(&s, formSource{"U": {"unknown"}}, "form") assert.Error(t, err) - assert.Equal(t, errUnknownType, err) + assert.Equal(t, ErrUnknownType, err) } func TestMappingURI(t *testing.T) { diff --git a/binding/multipart_form_mapping.go b/binding/multipart_form_mapping.go index 69c0a544..b8887105 100644 --- a/binding/multipart_form_mapping.go +++ b/binding/multipart_form_mapping.go @@ -32,7 +32,7 @@ func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField return setByForm(value, field, r.MultipartForm.Value, key, opt) } -func setByMultipartFormFile(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSetted bool, err error) { +func setByMultipartFormFile(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (bool, error) { switch value.Kind() { case reflect.Ptr: switch value.Interface().(type) { @@ -48,7 +48,7 @@ func setByMultipartFormFile(value reflect.Value, field reflect.StructField, file } case reflect.Slice: slice := reflect.MakeSlice(value.Type(), len(files), len(files)) - isSetted, err = setArrayOfMultipartFormFiles(slice, field, files) + isSetted, err := setArrayOfMultipartFormFiles(slice, field, files) if err != nil || !isSetted { return isSetted, err } @@ -60,7 +60,7 @@ func setByMultipartFormFile(value reflect.Value, field reflect.StructField, file return false, ErrMultiFileHeader } -func setArrayOfMultipartFormFiles(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSetted bool, err error) { +func setArrayOfMultipartFormFiles(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (bool, error) { if value.Len() != len(files) { return false, ErrMultiFileHeaderLenInvalid } diff --git a/context.go b/context.go index 8a2f46d1..39284dbd 100644 --- a/context.go +++ b/context.go @@ -766,7 +766,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 := getIPFromHeader(c.requestHeader(headerName)) if valid { return ip } @@ -800,10 +800,17 @@ func (c *Context) RemoteIP() (net.IP, bool) { return remoteIP, false } -func validateHeader(header string) (clientIP string, valid bool) { +// getIPFromHeader return clientIP,valid when validate ip address +func getIPFromHeader(header string) (string, bool) { if header == "" { return "", false } + + var ( + clientIP string + valid bool + ) + items := strings.Split(header, ",") for i, ipStr := range items { ipStr = strings.TrimSpace(ipStr) @@ -820,7 +827,8 @@ func validateHeader(header string) (clientIP string, valid bool) { valid = true } } - return + + return clientIP, valid } // ContentType returns the Content-Type header of the request. diff --git a/ginS/gins.go b/ginS/gins.go index 3080fd34..0effc8e6 100644 --- a/ginS/gins.go +++ b/ginS/gins.go @@ -7,100 +7,97 @@ package ginS import ( "html/template" "net/http" - "sync" "github.com/gin-gonic/gin" ) -var once sync.Once -var internalEngine *gin.Engine +var engine *gin.Engine -func engine() *gin.Engine { - once.Do(func() { - internalEngine = gin.Default() - }) - return internalEngine +func init() { + if engine == nil { + engine = gin.Default() + } } // LoadHTMLGlob is a wrapper for Engine.LoadHTMLGlob. func LoadHTMLGlob(pattern string) { - engine().LoadHTMLGlob(pattern) + engine.LoadHTMLGlob(pattern) } // LoadHTMLFiles is a wrapper for Engine.LoadHTMLFiles. func LoadHTMLFiles(files ...string) { - engine().LoadHTMLFiles(files...) + engine.LoadHTMLFiles(files...) } // SetHTMLTemplate is a wrapper for Engine.SetHTMLTemplate. func SetHTMLTemplate(templ *template.Template) { - engine().SetHTMLTemplate(templ) + engine.SetHTMLTemplate(templ) } // NoRoute adds handlers for NoRoute. It return a 404 code by default. func NoRoute(handlers ...gin.HandlerFunc) { - engine().NoRoute(handlers...) + engine.NoRoute(handlers...) } // NoMethod is a wrapper for Engine.NoMethod. func NoMethod(handlers ...gin.HandlerFunc) { - engine().NoMethod(handlers...) + engine.NoMethod(handlers...) } // Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix. // For example, all the routes that use a common middleware for authorization could be grouped. func Group(relativePath string, handlers ...gin.HandlerFunc) *gin.RouterGroup { - return engine().Group(relativePath, handlers...) + return engine.Group(relativePath, handlers...) } // Handle is a wrapper for Engine.Handle. func Handle(httpMethod, relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { - return engine().Handle(httpMethod, relativePath, handlers...) + return engine.Handle(httpMethod, relativePath, handlers...) } // POST is a shortcut for router.Handle("POST", path, handle) func POST(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { - return engine().POST(relativePath, handlers...) + return engine.POST(relativePath, handlers...) } // GET is a shortcut for router.Handle("GET", path, handle) func GET(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { - return engine().GET(relativePath, handlers...) + return engine.GET(relativePath, handlers...) } // DELETE is a shortcut for router.Handle("DELETE", path, handle) func DELETE(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { - return engine().DELETE(relativePath, handlers...) + return engine.DELETE(relativePath, handlers...) } // PATCH is a shortcut for router.Handle("PATCH", path, handle) func PATCH(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { - return engine().PATCH(relativePath, handlers...) + return engine.PATCH(relativePath, handlers...) } // PUT is a shortcut for router.Handle("PUT", path, handle) func PUT(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { - return engine().PUT(relativePath, handlers...) + return engine.PUT(relativePath, handlers...) } // OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle) func OPTIONS(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { - return engine().OPTIONS(relativePath, handlers...) + return engine.OPTIONS(relativePath, handlers...) } // HEAD is a shortcut for router.Handle("HEAD", path, handle) func HEAD(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { - return engine().HEAD(relativePath, handlers...) + return engine.HEAD(relativePath, handlers...) } // Any is a wrapper for Engine.Any. func Any(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { - return engine().Any(relativePath, handlers...) + return engine.Any(relativePath, handlers...) } // StaticFile is a wrapper for Engine.StaticFile. func StaticFile(relativePath, filepath string) gin.IRoutes { - return engine().StaticFile(relativePath, filepath) + return engine.StaticFile(relativePath, filepath) } // Static serves files from the given file system root. @@ -110,50 +107,50 @@ func StaticFile(relativePath, filepath string) gin.IRoutes { // use : // router.Static("/static", "/var/www") func Static(relativePath, root string) gin.IRoutes { - return engine().Static(relativePath, root) + return engine.Static(relativePath, root) } // StaticFS is a wrapper for Engine.StaticFS. func StaticFS(relativePath string, fs http.FileSystem) gin.IRoutes { - return engine().StaticFS(relativePath, fs) + return engine.StaticFS(relativePath, fs) } // Use attaches a global middleware to the router. ie. the middlewares attached though Use() will be // included in the handlers chain for every single request. Even 404, 405, static files... // For example, this is the right place for a logger or error management middleware. func Use(middlewares ...gin.HandlerFunc) gin.IRoutes { - return engine().Use(middlewares...) + return engine.Use(middlewares...) } // Routes returns a slice of registered routes. func Routes() gin.RoutesInfo { - return engine().Routes() + return engine.Routes() } // Run attaches to a http.Server and starts listening and serving HTTP requests. // It is a shortcut for http.ListenAndServe(addr, router) // Note: this method will block the calling goroutine indefinitely unless an error happens. func Run(addr ...string) (err error) { - return engine().Run(addr...) + return engine.Run(addr...) } // RunTLS attaches to a http.Server and starts listening and serving HTTPS requests. // It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router) // Note: this method will block the calling goroutine indefinitely unless an error happens. func RunTLS(addr, certFile, keyFile string) (err error) { - return engine().RunTLS(addr, certFile, keyFile) + return engine.RunTLS(addr, certFile, keyFile) } // RunUnix attaches to a http.Server and starts listening and serving HTTP requests // through the specified unix socket (ie. a file) // Note: this method will block the calling goroutine indefinitely unless an error happens. func RunUnix(file string) (err error) { - return engine().RunUnix(file) + return engine.RunUnix(file) } // RunFd attaches the router to a http.Server and starts listening and serving HTTP requests // through the specified file descriptor. // Note: the method will block the calling goroutine indefinitely unless on error happens. func RunFd(fd int) (err error) { - return engine().RunFd(fd) + return engine.RunFd(fd) } diff --git a/render/render_test.go b/render/render_test.go index e417731a..e36d7755 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -321,8 +321,7 @@ func TestRenderRedirect(t *testing.T) { w = httptest.NewRecorder() assert.PanicsWithValue(t, "Cannot redirect with status code 200", func() { - err := data2.Render(w) - assert.NoError(t, err) + assert.NoError(t, data2.Render(w)) }) data3 := Redirect{