mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 21:32:11 +08:00
Merge 068942b5ce84ee37c62b0b52d3dad8cdb0db16eb into f469c1be3925ab32bd38fbf944b230c70abe9e2b
This commit is contained in:
commit
72a077e151
@ -8,13 +8,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
)
|
)
|
||||||
|
|
||||||
type defaultValidator struct {
|
type defaultValidator struct {
|
||||||
once sync.Once
|
|
||||||
validate *validator.Validate
|
validate *validator.Validate
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +74,7 @@ func (v *defaultValidator) ValidateStruct(obj interface{}) error {
|
|||||||
|
|
||||||
// validateStruct receives struct type
|
// validateStruct receives struct type
|
||||||
func (v *defaultValidator) validateStruct(obj interface{}) error {
|
func (v *defaultValidator) validateStruct(obj interface{}) error {
|
||||||
v.lazyinit()
|
v.lazyInit()
|
||||||
return v.validate.Struct(obj)
|
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 -
|
// or struct level validations. See validator GoDoc for more info -
|
||||||
// https://pkg.go.dev/github.com/go-playground/validator/v10
|
// https://pkg.go.dev/github.com/go-playground/validator/v10
|
||||||
func (v *defaultValidator) Engine() interface{} {
|
func (v *defaultValidator) Engine() interface{} {
|
||||||
v.lazyinit()
|
v.lazyInit()
|
||||||
return v.validate
|
return v.validate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *defaultValidator) lazyinit() {
|
// lazyInit initialize the validate Settings, no need to use sync.once
|
||||||
v.once.Do(func() {
|
func (v *defaultValidator) lazyInit() {
|
||||||
|
if v.validate == nil {
|
||||||
v.validate = validator.New()
|
v.validate = validator.New()
|
||||||
v.validate.SetTagName("binding")
|
v.validate.SetTagName("binding")
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errUnknownType = errors.New("unknown type")
|
// ErrUnknownType unknown type
|
||||||
|
ErrUnknownType = errors.New("unknown type")
|
||||||
|
|
||||||
// ErrConvertMapStringSlice can not covert to map[string][]string
|
// ErrConvertMapStringSlice can not covert to map[string][]string
|
||||||
ErrConvertMapStringSlice = errors.New("can not convert to map slices of strings")
|
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)
|
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]
|
vs, ok := form[tagValue]
|
||||||
if !ok && !opt.isDefaultExists {
|
if !ok && !opt.isDefaultExists {
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -240,7 +241,7 @@ func setWithProperType(val string, value reflect.Value, field reflect.StructFiel
|
|||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
|
return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
|
||||||
default:
|
default:
|
||||||
return errUnknownType
|
return ErrUnknownType
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ func TestMappingUnknownFieldType(t *testing.T) {
|
|||||||
|
|
||||||
err := mappingByPtr(&s, formSource{"U": {"unknown"}}, "form")
|
err := mappingByPtr(&s, formSource{"U": {"unknown"}}, "form")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, errUnknownType, err)
|
assert.Equal(t, ErrUnknownType, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMappingURI(t *testing.T) {
|
func TestMappingURI(t *testing.T) {
|
||||||
|
@ -32,7 +32,7 @@ func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField
|
|||||||
return setByForm(value, field, r.MultipartForm.Value, key, opt)
|
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() {
|
switch value.Kind() {
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
switch value.Interface().(type) {
|
switch value.Interface().(type) {
|
||||||
@ -48,7 +48,7 @@ func setByMultipartFormFile(value reflect.Value, field reflect.StructField, file
|
|||||||
}
|
}
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
slice := reflect.MakeSlice(value.Type(), len(files), len(files))
|
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 {
|
if err != nil || !isSetted {
|
||||||
return isSetted, err
|
return isSetted, err
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ func setByMultipartFormFile(value reflect.Value, field reflect.StructField, file
|
|||||||
return false, ErrMultiFileHeader
|
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) {
|
if value.Len() != len(files) {
|
||||||
return false, ErrMultiFileHeaderLenInvalid
|
return false, ErrMultiFileHeaderLenInvalid
|
||||||
}
|
}
|
||||||
|
14
context.go
14
context.go
@ -766,7 +766,7 @@ func (c *Context) ClientIP() string {
|
|||||||
|
|
||||||
if trusted && c.engine.ForwardedByClientIP && c.engine.RemoteIPHeaders != nil {
|
if trusted && c.engine.ForwardedByClientIP && c.engine.RemoteIPHeaders != nil {
|
||||||
for _, headerName := range c.engine.RemoteIPHeaders {
|
for _, headerName := range c.engine.RemoteIPHeaders {
|
||||||
ip, valid := validateHeader(c.requestHeader(headerName))
|
ip, valid := getIPFromHeader(c.requestHeader(headerName))
|
||||||
if valid {
|
if valid {
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
@ -800,10 +800,17 @@ func (c *Context) RemoteIP() (net.IP, bool) {
|
|||||||
return remoteIP, false
|
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 == "" {
|
if header == "" {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
clientIP string
|
||||||
|
valid bool
|
||||||
|
)
|
||||||
|
|
||||||
items := strings.Split(header, ",")
|
items := strings.Split(header, ",")
|
||||||
for i, ipStr := range items {
|
for i, ipStr := range items {
|
||||||
ipStr = strings.TrimSpace(ipStr)
|
ipStr = strings.TrimSpace(ipStr)
|
||||||
@ -820,7 +827,8 @@ func validateHeader(header string) (clientIP string, valid bool) {
|
|||||||
valid = true
|
valid = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
return clientIP, valid
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContentType returns the Content-Type header of the request.
|
// ContentType returns the Content-Type header of the request.
|
||||||
|
61
ginS/gins.go
61
ginS/gins.go
@ -7,100 +7,97 @@ package ginS
|
|||||||
import (
|
import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
var once sync.Once
|
var engine *gin.Engine
|
||||||
var internalEngine *gin.Engine
|
|
||||||
|
|
||||||
func engine() *gin.Engine {
|
func init() {
|
||||||
once.Do(func() {
|
if engine == nil {
|
||||||
internalEngine = gin.Default()
|
engine = gin.Default()
|
||||||
})
|
}
|
||||||
return internalEngine
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadHTMLGlob is a wrapper for Engine.LoadHTMLGlob.
|
// LoadHTMLGlob is a wrapper for Engine.LoadHTMLGlob.
|
||||||
func LoadHTMLGlob(pattern string) {
|
func LoadHTMLGlob(pattern string) {
|
||||||
engine().LoadHTMLGlob(pattern)
|
engine.LoadHTMLGlob(pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadHTMLFiles is a wrapper for Engine.LoadHTMLFiles.
|
// LoadHTMLFiles is a wrapper for Engine.LoadHTMLFiles.
|
||||||
func LoadHTMLFiles(files ...string) {
|
func LoadHTMLFiles(files ...string) {
|
||||||
engine().LoadHTMLFiles(files...)
|
engine.LoadHTMLFiles(files...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHTMLTemplate is a wrapper for Engine.SetHTMLTemplate.
|
// SetHTMLTemplate is a wrapper for Engine.SetHTMLTemplate.
|
||||||
func SetHTMLTemplate(templ *template.Template) {
|
func SetHTMLTemplate(templ *template.Template) {
|
||||||
engine().SetHTMLTemplate(templ)
|
engine.SetHTMLTemplate(templ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoRoute adds handlers for NoRoute. It return a 404 code by default.
|
// NoRoute adds handlers for NoRoute. It return a 404 code by default.
|
||||||
func NoRoute(handlers ...gin.HandlerFunc) {
|
func NoRoute(handlers ...gin.HandlerFunc) {
|
||||||
engine().NoRoute(handlers...)
|
engine.NoRoute(handlers...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoMethod is a wrapper for Engine.NoMethod.
|
// NoMethod is a wrapper for Engine.NoMethod.
|
||||||
func NoMethod(handlers ...gin.HandlerFunc) {
|
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.
|
// 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.
|
// For example, all the routes that use a common middleware for authorization could be grouped.
|
||||||
func Group(relativePath string, handlers ...gin.HandlerFunc) *gin.RouterGroup {
|
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.
|
// Handle is a wrapper for Engine.Handle.
|
||||||
func Handle(httpMethod, relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
|
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)
|
// POST is a shortcut for router.Handle("POST", path, handle)
|
||||||
func POST(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
|
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)
|
// GET is a shortcut for router.Handle("GET", path, handle)
|
||||||
func GET(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
|
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)
|
// DELETE is a shortcut for router.Handle("DELETE", path, handle)
|
||||||
func DELETE(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
|
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)
|
// PATCH is a shortcut for router.Handle("PATCH", path, handle)
|
||||||
func PATCH(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
|
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)
|
// PUT is a shortcut for router.Handle("PUT", path, handle)
|
||||||
func PUT(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
|
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)
|
// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
|
||||||
func OPTIONS(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
|
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)
|
// HEAD is a shortcut for router.Handle("HEAD", path, handle)
|
||||||
func HEAD(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
|
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.
|
// Any is a wrapper for Engine.Any.
|
||||||
func Any(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {
|
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.
|
// StaticFile is a wrapper for Engine.StaticFile.
|
||||||
func StaticFile(relativePath, filepath string) gin.IRoutes {
|
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.
|
// Static serves files from the given file system root.
|
||||||
@ -110,50 +107,50 @@ func StaticFile(relativePath, filepath string) gin.IRoutes {
|
|||||||
// use :
|
// use :
|
||||||
// router.Static("/static", "/var/www")
|
// router.Static("/static", "/var/www")
|
||||||
func Static(relativePath, root string) gin.IRoutes {
|
func Static(relativePath, root string) gin.IRoutes {
|
||||||
return engine().Static(relativePath, root)
|
return engine.Static(relativePath, root)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StaticFS is a wrapper for Engine.StaticFS.
|
// StaticFS is a wrapper for Engine.StaticFS.
|
||||||
func StaticFS(relativePath string, fs http.FileSystem) gin.IRoutes {
|
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
|
// 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...
|
// 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.
|
// For example, this is the right place for a logger or error management middleware.
|
||||||
func Use(middlewares ...gin.HandlerFunc) gin.IRoutes {
|
func Use(middlewares ...gin.HandlerFunc) gin.IRoutes {
|
||||||
return engine().Use(middlewares...)
|
return engine.Use(middlewares...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routes returns a slice of registered routes.
|
// Routes returns a slice of registered routes.
|
||||||
func Routes() gin.RoutesInfo {
|
func Routes() gin.RoutesInfo {
|
||||||
return engine().Routes()
|
return engine.Routes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run attaches to a http.Server and starts listening and serving HTTP requests.
|
// Run attaches to a http.Server and starts listening and serving HTTP requests.
|
||||||
// It is a shortcut for http.ListenAndServe(addr, router)
|
// It is a shortcut for http.ListenAndServe(addr, router)
|
||||||
// Note: this method will block the calling goroutine indefinitely unless an error happens.
|
// Note: this method will block the calling goroutine indefinitely unless an error happens.
|
||||||
func Run(addr ...string) (err error) {
|
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.
|
// RunTLS attaches to a http.Server and starts listening and serving HTTPS requests.
|
||||||
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
|
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
|
||||||
// Note: this method will block the calling goroutine indefinitely unless an error happens.
|
// Note: this method will block the calling goroutine indefinitely unless an error happens.
|
||||||
func RunTLS(addr, certFile, keyFile string) (err error) {
|
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
|
// RunUnix attaches to a http.Server and starts listening and serving HTTP requests
|
||||||
// through the specified unix socket (ie. a file)
|
// through the specified unix socket (ie. a file)
|
||||||
// Note: this method will block the calling goroutine indefinitely unless an error happens.
|
// Note: this method will block the calling goroutine indefinitely unless an error happens.
|
||||||
func RunUnix(file string) (err error) {
|
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
|
// RunFd attaches the router to a http.Server and starts listening and serving HTTP requests
|
||||||
// through the specified file descriptor.
|
// through the specified file descriptor.
|
||||||
// Note: the method will block the calling goroutine indefinitely unless on error happens.
|
// Note: the method will block the calling goroutine indefinitely unless on error happens.
|
||||||
func RunFd(fd int) (err error) {
|
func RunFd(fd int) (err error) {
|
||||||
return engine().RunFd(fd)
|
return engine.RunFd(fd)
|
||||||
}
|
}
|
||||||
|
@ -321,8 +321,7 @@ func TestRenderRedirect(t *testing.T) {
|
|||||||
|
|
||||||
w = httptest.NewRecorder()
|
w = httptest.NewRecorder()
|
||||||
assert.PanicsWithValue(t, "Cannot redirect with status code 200", func() {
|
assert.PanicsWithValue(t, "Cannot redirect with status code 200", func() {
|
||||||
err := data2.Render(w)
|
assert.NoError(t, data2.Render(w))
|
||||||
assert.NoError(t, err)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
data3 := Redirect{
|
data3 := Redirect{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user