mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-21 16:58:08 +08:00
Merge remote-tracking branch 'upstream/master' into up-readme-for-website
This commit is contained in:
commit
e5aa0bd727
@ -72,7 +72,7 @@ $ govendor fetch github.com/gin-gonic/gin@v1.3
|
||||
4. Copy a starting template inside your project
|
||||
|
||||
```sh
|
||||
$ curl https://raw.githubusercontent.com/gin-gonic/gin/master/examples/basic/main.go > main.go
|
||||
$ curl https://raw.githubusercontent.com/gin-gonic/examples/master/basic/main.go > main.go
|
||||
```
|
||||
|
||||
5. Run your project
|
||||
|
@ -1413,3 +1413,20 @@ func TestBindingUnknownTypeChan(t *testing.T) {
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, errUnknownType, err)
|
||||
}
|
||||
|
||||
func TestBindingTimeDuration(t *testing.T) {
|
||||
var s struct {
|
||||
Timeout time.Duration `form:"timeout"`
|
||||
}
|
||||
|
||||
// ok
|
||||
req := formPostRequest("", "timeout=5s")
|
||||
err := Form.Bind(req, &s)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 5*time.Second, s.Timeout)
|
||||
|
||||
// error
|
||||
req = formPostRequest("", "timeout=wrong")
|
||||
err = Form.Bind(req, &s)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
@ -5,12 +5,13 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin/internal/json"
|
||||
)
|
||||
|
||||
var errUnknownType = errors.New("Unknown type")
|
||||
@ -141,6 +142,10 @@ func setWithProperType(val string, value reflect.Value, field reflect.StructFiel
|
||||
case reflect.Int32:
|
||||
return setIntField(val, 32, value)
|
||||
case reflect.Int64:
|
||||
switch value.Interface().(type) {
|
||||
case time.Duration:
|
||||
return setTimeDuration(val, value, field)
|
||||
}
|
||||
return setIntField(val, 64, value)
|
||||
case reflect.Uint:
|
||||
return setUintField(val, 0, value)
|
||||
@ -263,6 +268,15 @@ func setSlice(vals []string, value reflect.Value, field reflect.StructField) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error {
|
||||
d, err := time.ParseDuration(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value.Set(reflect.ValueOf(d))
|
||||
return nil
|
||||
}
|
||||
|
||||
func head(str, sep string) (head string, tail string) {
|
||||
idx := strings.Index(str, sep)
|
||||
if idx < 0 {
|
||||
|
@ -53,7 +53,7 @@ func (msg *Error) SetMeta(data interface{}) *Error {
|
||||
return msg
|
||||
}
|
||||
|
||||
// JSON creates a properly formated JSON
|
||||
// JSON creates a properly formatted JSON
|
||||
func (msg *Error) JSON() interface{} {
|
||||
json := H{}
|
||||
if msg.Meta != nil {
|
||||
|
18
gin.go
18
gin.go
@ -225,7 +225,7 @@ func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
|
||||
engine.rebuild405Handlers()
|
||||
}
|
||||
|
||||
// Use attachs a global middleware to the router. ie. the middleware attached though Use() will be
|
||||
// Use attaches a global middleware to the router. ie. the middleware 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 (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
|
||||
@ -366,10 +366,10 @@ func (engine *Engine) HandleContext(c *Context) {
|
||||
|
||||
func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||
httpMethod := c.Request.Method
|
||||
path := c.Request.URL.Path
|
||||
rPath := c.Request.URL.Path
|
||||
unescape := false
|
||||
if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
|
||||
path = c.Request.URL.RawPath
|
||||
rPath = c.Request.URL.RawPath
|
||||
unescape = engine.UnescapePathValues
|
||||
}
|
||||
|
||||
@ -381,7 +381,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||
}
|
||||
root := t[i].root
|
||||
// Find route in tree
|
||||
handlers, params, tsr := root.getValue(path, c.Params, unescape)
|
||||
handlers, params, tsr := root.getValue(rPath, c.Params, unescape)
|
||||
if handlers != nil {
|
||||
c.handlers = handlers
|
||||
c.Params = params
|
||||
@ -389,7 +389,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||
c.writermem.WriteHeaderNow()
|
||||
return
|
||||
}
|
||||
if httpMethod != "CONNECT" && path != "/" {
|
||||
if httpMethod != "CONNECT" && rPath != "/" {
|
||||
if tsr && engine.RedirectTrailingSlash {
|
||||
redirectTrailingSlash(c)
|
||||
return
|
||||
@ -406,7 +406,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||
if tree.method == httpMethod {
|
||||
continue
|
||||
}
|
||||
if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil {
|
||||
if handlers, _, _ := tree.root.getValue(rPath, nil, unescape); handlers != nil {
|
||||
c.handlers = engine.allNoMethod
|
||||
serveError(c, http.StatusMethodNotAllowed, default405Body)
|
||||
return
|
||||
@ -459,15 +459,15 @@ func redirectTrailingSlash(c *Context) {
|
||||
|
||||
func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool {
|
||||
req := c.Request
|
||||
path := req.URL.Path
|
||||
rPath := req.URL.Path
|
||||
|
||||
if fixedPath, ok := root.findCaseInsensitivePath(cleanPath(path), trailingSlash); ok {
|
||||
if fixedPath, ok := root.findCaseInsensitivePath(cleanPath(rPath), trailingSlash); ok {
|
||||
code := http.StatusMovedPermanently // Permanent redirect, request with GET method
|
||||
if req.Method != "GET" {
|
||||
code = http.StatusTemporaryRedirect
|
||||
}
|
||||
req.URL.Path = string(fixedPath)
|
||||
debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String())
|
||||
debugPrint("redirecting request %d: %s --> %s", code, rPath, req.URL.String())
|
||||
http.Redirect(c.Writer, req, req.URL.String(), code)
|
||||
c.writermem.WriteHeaderNow()
|
||||
return true
|
||||
|
12
go.mod
12
go.mod
@ -1,17 +1,17 @@
|
||||
module github.com/gin-gonic/gin
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/sse v0.0.0-20190125020943-a7658810eb74
|
||||
github.com/golang/protobuf v1.2.0
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3
|
||||
github.com/golang/protobuf v1.3.0
|
||||
github.com/json-iterator/go v1.1.5
|
||||
github.com/mattn/go-isatty v0.0.4
|
||||
github.com/mattn/go-isatty v0.0.6
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
|
||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0 // indirect
|
||||
golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2
|
||||
gopkg.in/yaml.v2 v2.2.2
|
||||
|
31
go.sum
31
go.sum
@ -1,14 +1,18 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gin-contrib/sse v0.0.0-20190125020943-a7658810eb74 h1:FaI7wNyesdMBSkIRVUuEEYEvmzufs7EqQvRAxfEXGbQ=
|
||||
github.com/gin-contrib/sse v0.0.0-20190125020943-a7658810eb74/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk=
|
||||
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||
github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.6 h1:SrwhHcpV4nWrMGdNcC2kXpMfcBVYGDuTArqyhocJgvA=
|
||||
github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
@ -17,14 +21,17 @@ github.com/ugorji/go v1.1.2 h1:JON3E2/GPW2iDNGoSAusl1KDf5TRQ8k8q7Tp097pZGs=
|
||||
github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
|
||||
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43 h1:BasDe+IErOQKrMVXab7UayvSlIpiyGwRvuX3EKYY7UA=
|
||||
github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0 h1:bzeyCHgoAyjZjAhvTpks+qM7sdlh4cCSitmXeCEO3B4=
|
||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95 h1:fY7Dsw114eJN4boqzVSbpVHO6rTdhq6/GnXeu+PKnzU=
|
||||
golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
|
@ -11,6 +11,8 @@ import "encoding/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.
|
||||
|
@ -12,6 +12,8 @@ var (
|
||||
json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
// 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.
|
||||
|
10
recovery.go
10
recovery.go
@ -52,12 +52,12 @@ func RecoveryWithWriter(out io.Writer) HandlerFunc {
|
||||
}
|
||||
if logger != nil {
|
||||
stack := stack(3)
|
||||
httprequest, _ := httputil.DumpRequest(c.Request, false)
|
||||
httpRequest, _ := httputil.DumpRequest(c.Request, false)
|
||||
if brokenPipe {
|
||||
logger.Printf("%s\n%s%s", err, string(httprequest), reset)
|
||||
logger.Printf("%s\n%s%s", err, string(httpRequest), reset)
|
||||
} else if IsDebugging() {
|
||||
logger.Printf("[Recovery] %s panic recovered:\n%s\n%s\n%s%s",
|
||||
timeFormat(time.Now()), string(httprequest), err, stack, reset)
|
||||
timeFormat(time.Now()), string(httpRequest), err, stack, reset)
|
||||
} else {
|
||||
logger.Printf("[Recovery] %s panic recovered:\n%s\n%s%s",
|
||||
timeFormat(time.Now()), err, stack, reset)
|
||||
@ -128,8 +128,8 @@ func function(pc uintptr) []byte {
|
||||
// *T.ptrmethod
|
||||
// Also the package path might contains dot (e.g. code.google.com/...),
|
||||
// so first eliminate the path prefix
|
||||
if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
|
||||
name = name[lastslash+1:]
|
||||
if lastSlash := bytes.LastIndex(name, slash); lastSlash >= 0 {
|
||||
name = name[lastSlash+1:]
|
||||
}
|
||||
if period := bytes.Index(name, dot); period >= 0 {
|
||||
name = name[period+1:]
|
||||
|
Loading…
x
Reference in New Issue
Block a user