diff --git a/.travis.yml b/.travis.yml index 27c80ef8..8b3b5a29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ matrix: env: GO111MODULE=on - go: 1.12.x env: GO111MODULE=on + - go: 1.13.x - go: master env: GO111MODULE=on diff --git a/README.md b/README.md index 8d7705d3..529746a1 100644 --- a/README.md +++ b/README.md @@ -622,10 +622,10 @@ Note that you need to set the corresponding binding tag on all fields you want t Also, Gin provides two sets of methods for binding: - **Type** - Must bind - - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML` + - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML`, `BindHeader` - **Behavior** - These methods use `MustBindWith` under the hood. If there is a binding error, the request is aborted with `c.AbortWithError(400, err).SetType(ErrorTypeBind)`. This sets the response status code to 400 and the `Content-Type` header is set to `text/plain; charset=utf-8`. Note that if you try to set the response code after this, it will result in a warning `[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422`. If you wish to have greater control over the behavior, consider using the `ShouldBind` equivalent method. - **Type** - Should bind - - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML` + - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML`, `ShouldBindHeader` - **Behavior** - These methods use `ShouldBindWith` under the hood. If there is a binding error, the error is returned and it is the developer's responsibility to handle the request and error appropriately. When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`. @@ -846,9 +846,11 @@ import ( ) type Person struct { - Name string `form:"name"` - Address string `form:"address"` - Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"` + Name string `form:"name"` + Address string `form:"address"` + Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"` + CreateTime time.Time `form:"createTime" time_format:"unixNano"` + UnixTime time.Time `form:"unixTime" time_format:"unix"` } func main() { @@ -862,11 +864,13 @@ func startPage(c *gin.Context) { // If `GET`, only `Form` binding engine (`query`) used. // If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`). // See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48 - if c.ShouldBind(&person) == nil { - log.Println(person.Name) - log.Println(person.Address) - log.Println(person.Birthday) - } + if c.ShouldBind(&person) == nil { + log.Println(person.Name) + log.Println(person.Address) + log.Println(person.Birthday) + log.Println(person.CreateTime) + log.Println(person.UnixTime) + } c.String(200, "Success") } @@ -874,7 +878,7 @@ func startPage(c *gin.Context) { Test it with: ```sh -$ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz&birthday=1992-03-15" +$ curl -X GET "localhost:8085/testing?name=appleboy&address=xyz&birthday=1992-03-15&createTime=1562400033000000123&unixTime=1562400033" ``` ### Bind Uri diff --git a/auth.go b/auth.go index 9ed81b5d..c96b1e29 100644 --- a/auth.go +++ b/auth.go @@ -5,7 +5,6 @@ package gin import ( - "crypto/subtle" "encoding/base64" "net/http" "strconv" @@ -86,11 +85,3 @@ func authorizationHeader(user, password string) string { base := user + ":" + password return "Basic " + base64.StdEncoding.EncodeToString([]byte(base)) } - -func secureCompare(given, actual string) bool { - if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 { - return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1 - } - // Securely compare actual to itself to keep constant time, but always return false. - return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false -} diff --git a/auth_test.go b/auth_test.go index 197e9208..e44bd100 100644 --- a/auth_test.go +++ b/auth_test.go @@ -81,13 +81,6 @@ func TestBasicAuthAuthorizationHeader(t *testing.T) { assert.Equal(t, "Basic YWRtaW46cGFzc3dvcmQ=", authorizationHeader("admin", "password")) } -func TestBasicAuthSecureCompare(t *testing.T) { - assert.True(t, secureCompare("1234567890", "1234567890")) - assert.False(t, secureCompare("123456789", "1234567890")) - assert.False(t, secureCompare("12345678900", "1234567890")) - assert.False(t, secureCompare("1234567891", "1234567890")) -} - func TestBasicAuthSucceed(t *testing.T) { accounts := Accounts{"admin": "password"} router := New() diff --git a/binding/binding_test.go b/binding/binding_test.go index 827518f9..806f3ac9 100644 --- a/binding/binding_test.go +++ b/binding/binding_test.go @@ -65,8 +65,15 @@ type FooStructUseNumber struct { } type FooBarStructForTimeType struct { - TimeFoo time.Time `form:"time_foo" time_format:"2006-01-02" time_utc:"1" time_location:"Asia/Chongqing"` - TimeBar time.Time `form:"time_bar" time_format:"2006-01-02" time_utc:"1"` + TimeFoo time.Time `form:"time_foo" time_format:"2006-01-02" time_utc:"1" time_location:"Asia/Chongqing"` + TimeBar time.Time `form:"time_bar" time_format:"2006-01-02" time_utc:"1"` + CreateTime time.Time `form:"createTime" time_format:"unixNano"` + UnixTime time.Time `form:"unixTime" time_format:"unix"` +} + +type FooStructForTimeTypeNotUnixFormat struct { + CreateTime time.Time `form:"createTime" time_format:"unixNano"` + UnixTime time.Time `form:"unixTime" time_format:"unix"` } type FooStructForTimeTypeNotFormat struct { @@ -226,7 +233,10 @@ func TestBindingFormDefaultValue2(t *testing.T) { func TestBindingFormForTime(t *testing.T) { testFormBindingForTime(t, "POST", "/", "/", - "time_foo=2017-11-15&time_bar=", "bar2=foo") + "time_foo=2017-11-15&time_bar=&createTime=1562400033000000123&unixTime=1562400033", "bar2=foo") + testFormBindingForTimeNotUnixFormat(t, "POST", + "/", "/", + "time_foo=2017-11-15&createTime=bad&unixTime=bad", "bar2=foo") testFormBindingForTimeNotFormat(t, "POST", "/", "/", "time_foo=2017-11-15", "bar2=foo") @@ -240,8 +250,11 @@ func TestBindingFormForTime(t *testing.T) { func TestBindingFormForTime2(t *testing.T) { testFormBindingForTime(t, "GET", - "/?time_foo=2017-11-15&time_bar=", "/?bar2=foo", + "/?time_foo=2017-11-15&time_bar=&createTime=1562400033000000123&unixTime=1562400033", "/?bar2=foo", "", "") + testFormBindingForTimeNotUnixFormat(t, "POST", + "/", "/", + "time_foo=2017-11-15&createTime=bad&unixTime=bad", "bar2=foo") testFormBindingForTimeNotFormat(t, "GET", "/?time_foo=2017-11-15", "/?bar2=foo", "", "") @@ -849,6 +862,8 @@ func testFormBindingForTime(t *testing.T, method, path, badPath, body, badBody s assert.Equal(t, "Asia/Chongqing", obj.TimeFoo.Location().String()) assert.Equal(t, int64(-62135596800), obj.TimeBar.Unix()) assert.Equal(t, "UTC", obj.TimeBar.Location().String()) + assert.Equal(t, int64(1562400033000000123), obj.CreateTime.UnixNano()) + assert.Equal(t, int64(1562400033), obj.UnixTime.Unix()) obj = FooBarStructForTimeType{} req = requestWithBody(method, badPath, badBody) @@ -856,6 +871,24 @@ func testFormBindingForTime(t *testing.T, method, path, badPath, body, badBody s assert.Error(t, err) } +func testFormBindingForTimeNotUnixFormat(t *testing.T, method, path, badPath, body, badBody string) { + b := Form + assert.Equal(t, "form", b.Name()) + + obj := FooStructForTimeTypeNotUnixFormat{} + req := requestWithBody(method, path, body) + if method == "POST" { + req.Header.Add("Content-Type", MIMEPOSTForm) + } + err := b.Bind(req, &obj) + assert.Error(t, err) + + obj = FooStructForTimeTypeNotUnixFormat{} + req = requestWithBody(method, badPath, badBody) + err = JSON.Bind(req, &obj) + assert.Error(t, err) +} + func testFormBindingForTimeNotFormat(t *testing.T, method, path, badPath, body, badBody string) { b := Form assert.Equal(t, "form", b.Name()) diff --git a/binding/form_mapping.go b/binding/form_mapping.go index ebf3b199..80b1d15a 100644 --- a/binding/form_mapping.go +++ b/binding/form_mapping.go @@ -266,6 +266,24 @@ func setTimeField(val string, structField reflect.StructField, value reflect.Val timeFormat = time.RFC3339 } + switch tf := strings.ToLower(timeFormat); tf { + case "unix", "unixnano": + tv, err := strconv.ParseInt(val, 10, 0) + if err != nil { + return err + } + + d := time.Duration(1) + if tf == "unixnano" { + d = time.Second + } + + t := time.Unix(tv/int64(d), tv%int64(d)) + value.Set(reflect.ValueOf(t)) + return nil + + } + if val == "" { value.Set(reflect.ValueOf(time.Time{})) return nil diff --git a/context_test.go b/context_test.go index 439e8ee6..f7bb0f51 100644 --- a/context_test.go +++ b/context_test.go @@ -676,7 +676,7 @@ func TestContextRenderJSONP(t *testing.T) { c.JSONP(http.StatusCreated, H{"foo": "bar"}) assert.Equal(t, http.StatusCreated, w.Code) - assert.Equal(t, "x({\"foo\":\"bar\"})", w.Body.String()) + assert.Equal(t, "x({\"foo\":\"bar\"});", w.Body.String()) assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type")) } diff --git a/gin.go b/gin.go index e27b1579..94002886 100644 --- a/gin.go +++ b/gin.go @@ -437,7 +437,6 @@ func serveError(c *Context, code int, defaultMessage []byte) { return } c.writermem.WriteHeaderNow() - return } func redirectTrailingSlash(c *Context) { diff --git a/go.mod b/go.mod index 7680d4f7..849f8c70 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,11 @@ require ( github.com/gin-contrib/sse v0.1.0 github.com/golang/protobuf v1.3.1 github.com/json-iterator/go v1.1.6 - github.com/mattn/go-isatty v0.0.7 + github.com/mattn/go-isatty v0.0.9 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 v1.1.4 - golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c + github.com/ugorji/go/codec v1.1.7 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 diff --git a/go.sum b/go.sum index 8610eae2..de17ae7d 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 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= @@ -17,15 +17,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -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= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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= diff --git a/logger.go b/logger.go index 5ab4639e..fcf90c25 100644 --- a/logger.go +++ b/logger.go @@ -22,18 +22,19 @@ const ( forceColor ) -var ( - green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) - white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) - yellow = string([]byte{27, 91, 57, 48, 59, 52, 51, 109}) - red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109}) - blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109}) - magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109}) - cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109}) - reset = string([]byte{27, 91, 48, 109}) - consoleColorMode = autoColor +const ( + green = "\033[97;42m" + white = "\033[90;47m" + yellow = "\033[90;43m" + red = "\033[97;41m" + blue = "\033[97;44m" + magenta = "\033[97;45m" + cyan = "\033[97;46m" + reset = "\033[0m" ) +var consoleColorMode = autoColor + // LoggerConfig defines the config for Logger middleware. type LoggerConfig struct { // Optional. Default value is gin.defaultLogFormatter diff --git a/logger_test.go b/logger_test.go index 9177e1d9..fc53f356 100644 --- a/logger_test.go +++ b/logger_test.go @@ -291,14 +291,14 @@ func TestColorForMethod(t *testing.T) { return p.MethodColor() } - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 52, 109}), colorForMethod("GET"), "get should be blue") - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 54, 109}), colorForMethod("POST"), "post should be cyan") - assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 51, 109}), colorForMethod("PUT"), "put should be yellow") - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 49, 109}), colorForMethod("DELETE"), "delete should be red") - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), colorForMethod("PATCH"), "patch should be green") - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 53, 109}), colorForMethod("HEAD"), "head should be magenta") - assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 55, 109}), colorForMethod("OPTIONS"), "options should be white") - assert.Equal(t, string([]byte{27, 91, 48, 109}), colorForMethod("TRACE"), "trace is not defined and should be the reset color") + assert.Equal(t, blue, colorForMethod("GET"), "get should be blue") + assert.Equal(t, cyan, colorForMethod("POST"), "post should be cyan") + assert.Equal(t, yellow, colorForMethod("PUT"), "put should be yellow") + assert.Equal(t, red, colorForMethod("DELETE"), "delete should be red") + assert.Equal(t, green, colorForMethod("PATCH"), "patch should be green") + assert.Equal(t, magenta, colorForMethod("HEAD"), "head should be magenta") + assert.Equal(t, white, colorForMethod("OPTIONS"), "options should be white") + assert.Equal(t, reset, colorForMethod("TRACE"), "trace is not defined and should be the reset color") } func TestColorForStatus(t *testing.T) { @@ -309,10 +309,10 @@ func TestColorForStatus(t *testing.T) { return p.StatusCodeColor() } - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), colorForStatus(http.StatusOK), "2xx should be green") - assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 55, 109}), colorForStatus(http.StatusMovedPermanently), "3xx should be white") - assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 51, 109}), colorForStatus(http.StatusNotFound), "4xx should be yellow") - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 49, 109}), colorForStatus(2), "other things should be red") + assert.Equal(t, green, colorForStatus(http.StatusOK), "2xx should be green") + assert.Equal(t, white, colorForStatus(http.StatusMovedPermanently), "3xx should be white") + assert.Equal(t, yellow, colorForStatus(http.StatusNotFound), "4xx should be yellow") + assert.Equal(t, red, colorForStatus(2), "other things should be red") } func TestResetColor(t *testing.T) { diff --git a/render/json.go b/render/json.go index 2b07cba0..70506f78 100644 --- a/render/json.go +++ b/render/json.go @@ -138,7 +138,7 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) { if err != nil { return err } - _, err = w.Write([]byte(")")) + _, err = w.Write([]byte(");")) if err != nil { return err } diff --git a/render/reader.go b/render/reader.go index 312af741..502d9398 100644 --- a/render/reader.go +++ b/render/reader.go @@ -21,7 +21,9 @@ type Reader struct { // Render (Reader) writes data with custom ContentType and headers. func (r Reader) Render(w http.ResponseWriter) (err error) { r.WriteContentType(w) - r.Headers["Content-Length"] = strconv.FormatInt(r.ContentLength, 10) + if r.ContentLength >= 0 { + r.Headers["Content-Length"] = strconv.FormatInt(r.ContentLength, 10) + } r.writeHeaders(w, r.Headers) _, err = io.Copy(w, r.Reader) return diff --git a/render/render_test.go b/render/render_test.go index 9d7eaeef..b27134ff 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -45,7 +45,7 @@ func TestRenderMsgPack(t *testing.T) { err = codec.NewEncoder(buf, h).Encode(data) assert.NoError(t, err) - assert.Equal(t, w.Body.String(), string(buf.Bytes())) + assert.Equal(t, w.Body.String(), buf.String()) assert.Equal(t, "application/msgpack; charset=utf-8", w.Header().Get("Content-Type")) } @@ -146,7 +146,7 @@ func TestRenderJsonpJSON(t *testing.T) { err1 := (JsonpJSON{"x", data}).Render(w1) assert.NoError(t, err1) - assert.Equal(t, "x({\"foo\":\"bar\"})", w1.Body.String()) + assert.Equal(t, "x({\"foo\":\"bar\"});", w1.Body.String()) assert.Equal(t, "application/javascript; charset=utf-8", w1.Header().Get("Content-Type")) w2 := httptest.NewRecorder() @@ -158,7 +158,7 @@ func TestRenderJsonpJSON(t *testing.T) { err2 := (JsonpJSON{"x", datas}).Render(w2) assert.NoError(t, err2) - assert.Equal(t, "x([{\"foo\":\"bar\"},{\"bar\":\"foo\"}])", w2.Body.String()) + assert.Equal(t, "x([{\"foo\":\"bar\"},{\"bar\":\"foo\"}]);", w2.Body.String()) assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type")) } @@ -498,3 +498,26 @@ func TestRenderReader(t *testing.T) { assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition")) assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id")) } + +func TestRenderReaderNoContentLength(t *testing.T) { + w := httptest.NewRecorder() + + body := "#!PNG some raw data" + headers := make(map[string]string) + headers["Content-Disposition"] = `attachment; filename="filename.png"` + headers["x-request-id"] = "requestId" + + err := (Reader{ + ContentLength: -1, + ContentType: "image/png", + Reader: strings.NewReader(body), + Headers: headers, + }).Render(w) + + assert.NoError(t, err) + assert.Equal(t, body, w.Body.String()) + assert.Equal(t, "image/png", w.Header().Get("Content-Type")) + assert.NotContains(t, "Content-Length", w.Header()) + assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition")) + assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id")) +} diff --git a/utils.go b/utils.go index f4532d56..71b80de7 100644 --- a/utils.go +++ b/utils.go @@ -146,6 +146,6 @@ func resolveAddress(addr []string) string { case 1: return addr[0] default: - panic("too much parameters") + panic("too many parameters") } } diff --git a/vendor/vendor.json b/vendor/vendor.json index a225eb57..fa8fd13a 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -83,12 +83,12 @@ "versionExact": "v1.2.2" }, { - "checksumSHA1": "csplo594qomjp2IZj82y7mTueOw=", + "checksumSHA1": "S4ei9eSqVThDio0Jn2sav6yUbvg=", "path": "github.com/ugorji/go/codec", - "revision": "2adff0894ba3bc2eeb9f9aea45fefd49802e1a13", - "revisionTime": "2019-04-08T19:08:48Z", + "revision": "82dbfaf494e3b01d2d481376f11f6a5c8cf9599f", + "revisionTime": "2019-07-02T14:15:27Z", "version": "v1.1", - "versionExact": "v1.1.4" + "versionExact": "v1.1.6" }, { "checksumSHA1": "2gaep1KNRDNyDA3O+KgPTQsGWvs=",