mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-22 09:34:33 +08:00
fix conflict
This commit is contained in:
commit
c18fef0042
5
Makefile
5
Makefile
@ -18,7 +18,10 @@ test:
|
|||||||
cat tmp.out; \
|
cat tmp.out; \
|
||||||
if grep -q "^--- FAIL" tmp.out; then \
|
if grep -q "^--- FAIL" tmp.out; then \
|
||||||
rm tmp.out; \
|
rm tmp.out; \
|
||||||
exit 1;\
|
exit 1; \
|
||||||
|
elif grep -q "build failed" tmp.out; then \
|
||||||
|
rm tmp.out; \
|
||||||
|
exit; \
|
||||||
fi; \
|
fi; \
|
||||||
if [ -f profile.out ]; then \
|
if [ -f profile.out ]; then \
|
||||||
cat profile.out | grep -v "mode:" >> coverage.out; \
|
cat profile.out | grep -v "mode:" >> coverage.out; \
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -515,28 +516,28 @@ func createFormPostRequestFail() *http.Request {
|
|||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFormMultipartRequest() *http.Request {
|
func createFormMultipartRequest(t *testing.T) *http.Request {
|
||||||
boundary := "--testboundary"
|
boundary := "--testboundary"
|
||||||
body := new(bytes.Buffer)
|
body := new(bytes.Buffer)
|
||||||
mw := multipart.NewWriter(body)
|
mw := multipart.NewWriter(body)
|
||||||
defer mw.Close()
|
defer mw.Close()
|
||||||
|
|
||||||
mw.SetBoundary(boundary)
|
assert.NoError(t, mw.SetBoundary(boundary))
|
||||||
mw.WriteField("foo", "bar")
|
assert.NoError(t, mw.WriteField("foo", "bar"))
|
||||||
mw.WriteField("bar", "foo")
|
assert.NoError(t, mw.WriteField("bar", "foo"))
|
||||||
req, _ := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
|
req, _ := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
|
||||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFormMultipartRequestFail() *http.Request {
|
func createFormMultipartRequestFail(t *testing.T) *http.Request {
|
||||||
boundary := "--testboundary"
|
boundary := "--testboundary"
|
||||||
body := new(bytes.Buffer)
|
body := new(bytes.Buffer)
|
||||||
mw := multipart.NewWriter(body)
|
mw := multipart.NewWriter(body)
|
||||||
defer mw.Close()
|
defer mw.Close()
|
||||||
|
|
||||||
mw.SetBoundary(boundary)
|
assert.NoError(t, mw.SetBoundary(boundary))
|
||||||
mw.WriteField("map_foo", "bar")
|
assert.NoError(t, mw.WriteField("map_foo", "bar"))
|
||||||
req, _ := http.NewRequest("POST", "/?map_foo=getfoo", body)
|
req, _ := http.NewRequest("POST", "/?map_foo=getfoo", body)
|
||||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
||||||
return req
|
return req
|
||||||
@ -545,7 +546,7 @@ func createFormMultipartRequestFail() *http.Request {
|
|||||||
func TestBindingFormPost(t *testing.T) {
|
func TestBindingFormPost(t *testing.T) {
|
||||||
req := createFormPostRequest()
|
req := createFormPostRequest()
|
||||||
var obj FooBarStruct
|
var obj FooBarStruct
|
||||||
FormPost.Bind(req, &obj)
|
assert.NoError(t, FormPost.Bind(req, &obj))
|
||||||
|
|
||||||
assert.Equal(t, "form-urlencoded", FormPost.Name())
|
assert.Equal(t, "form-urlencoded", FormPost.Name())
|
||||||
assert.Equal(t, "bar", obj.Foo)
|
assert.Equal(t, "bar", obj.Foo)
|
||||||
@ -555,7 +556,7 @@ func TestBindingFormPost(t *testing.T) {
|
|||||||
func TestBindingDefaultValueFormPost(t *testing.T) {
|
func TestBindingDefaultValueFormPost(t *testing.T) {
|
||||||
req := createDefaultFormPostRequest()
|
req := createDefaultFormPostRequest()
|
||||||
var obj FooDefaultBarStruct
|
var obj FooDefaultBarStruct
|
||||||
FormPost.Bind(req, &obj)
|
assert.NoError(t, FormPost.Bind(req, &obj))
|
||||||
|
|
||||||
assert.Equal(t, "bar", obj.Foo)
|
assert.Equal(t, "bar", obj.Foo)
|
||||||
assert.Equal(t, "hello", obj.Bar)
|
assert.Equal(t, "hello", obj.Bar)
|
||||||
@ -569,9 +570,9 @@ func TestBindingFormPostFail(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBindingFormMultipart(t *testing.T) {
|
func TestBindingFormMultipart(t *testing.T) {
|
||||||
req := createFormMultipartRequest()
|
req := createFormMultipartRequest(t)
|
||||||
var obj FooBarStruct
|
var obj FooBarStruct
|
||||||
FormMultipart.Bind(req, &obj)
|
assert.NoError(t, FormMultipart.Bind(req, &obj))
|
||||||
|
|
||||||
assert.Equal(t, "multipart/form-data", FormMultipart.Name())
|
assert.Equal(t, "multipart/form-data", FormMultipart.Name())
|
||||||
assert.Equal(t, "bar", obj.Foo)
|
assert.Equal(t, "bar", obj.Foo)
|
||||||
@ -579,7 +580,7 @@ func TestBindingFormMultipart(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBindingFormMultipartFail(t *testing.T) {
|
func TestBindingFormMultipartFail(t *testing.T) {
|
||||||
req := createFormMultipartRequestFail()
|
req := createFormMultipartRequestFail(t)
|
||||||
var obj FooStructForMapType
|
var obj FooStructForMapType
|
||||||
err := FormMultipart.Bind(req, &obj)
|
err := FormMultipart.Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
@ -690,6 +691,28 @@ func TestUriBinding(t *testing.T) {
|
|||||||
assert.Equal(t, map[string]interface{}(nil), not.Name)
|
assert.Equal(t, map[string]interface{}(nil), not.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUriInnerBinding(t *testing.T) {
|
||||||
|
type Tag struct {
|
||||||
|
Name string `uri:"name"`
|
||||||
|
S struct {
|
||||||
|
Age int `uri:"age"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedName := "mike"
|
||||||
|
expectedAge := 25
|
||||||
|
|
||||||
|
m := map[string][]string{
|
||||||
|
"name": {expectedName},
|
||||||
|
"age": {strconv.Itoa(expectedAge)},
|
||||||
|
}
|
||||||
|
|
||||||
|
var tag Tag
|
||||||
|
assert.NoError(t, Uri.BindUri(m, &tag))
|
||||||
|
assert.Equal(t, tag.Name, expectedName)
|
||||||
|
assert.Equal(t, tag.S.Age, expectedAge)
|
||||||
|
}
|
||||||
|
|
||||||
func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
|
func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
|
||||||
b := Form
|
b := Form
|
||||||
assert.Equal(t, "form", b.Name())
|
assert.Equal(t, "form", b.Name())
|
||||||
|
@ -20,7 +20,11 @@ func (formBinding) Bind(req *http.Request, obj interface{}) error {
|
|||||||
if err := req.ParseForm(); err != nil {
|
if err := req.ParseForm(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
req.ParseMultipartForm(defaultMemory)
|
if err := req.ParseMultipartForm(defaultMemory); err != nil {
|
||||||
|
if err != http.ErrNotMultipart {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := mapForm(obj, req.Form); err != nil {
|
if err := mapForm(obj, req.Form); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
|
|||||||
structFieldKind = structField.Kind()
|
structFieldKind = structField.Kind()
|
||||||
}
|
}
|
||||||
if structFieldKind == reflect.Struct {
|
if structFieldKind == reflect.Struct {
|
||||||
err := mapForm(structField.Addr().Interface(), form)
|
err := mapFormByTag(structField.Addr().Interface(), form, tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
33
context.go
33
context.go
@ -105,8 +105,9 @@ func (c *Context) Handler() HandlerFunc {
|
|||||||
// See example in GitHub.
|
// See example in GitHub.
|
||||||
func (c *Context) Next() {
|
func (c *Context) Next() {
|
||||||
c.index++
|
c.index++
|
||||||
for s := int8(len(c.handlers)); c.index < s; c.index++ {
|
for c.index < int8(len(c.handlers)) {
|
||||||
c.handlers[c.index](c)
|
c.handlers[c.index](c)
|
||||||
|
c.index++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,7 +416,11 @@ func (c *Context) PostFormArray(key string) []string {
|
|||||||
// a boolean value whether at least one value exists for the given key.
|
// a boolean value whether at least one value exists for the given key.
|
||||||
func (c *Context) GetPostFormArray(key string) ([]string, bool) {
|
func (c *Context) GetPostFormArray(key string) ([]string, bool) {
|
||||||
req := c.Request
|
req := c.Request
|
||||||
req.ParseMultipartForm(c.engine.MaxMultipartMemory)
|
if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil {
|
||||||
|
if err != http.ErrNotMultipart {
|
||||||
|
debugPrint("error on parse multipart form array: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
if values := req.PostForm[key]; len(values) > 0 {
|
if values := req.PostForm[key]; len(values) > 0 {
|
||||||
return values, true
|
return values, true
|
||||||
}
|
}
|
||||||
@ -432,7 +437,11 @@ func (c *Context) PostFormMap(key string) map[string]string {
|
|||||||
// whether at least one value exists for the given key.
|
// whether at least one value exists for the given key.
|
||||||
func (c *Context) GetPostFormMap(key string) (map[string]string, bool) {
|
func (c *Context) GetPostFormMap(key string) (map[string]string, bool) {
|
||||||
req := c.Request
|
req := c.Request
|
||||||
req.ParseMultipartForm(c.engine.MaxMultipartMemory)
|
if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil {
|
||||||
|
if err != http.ErrNotMultipart {
|
||||||
|
debugPrint("error on parse multipart form map: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
return c.get(req.PostForm, key)
|
return c.get(req.PostForm, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,8 +491,8 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error
|
|||||||
}
|
}
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
|
|
||||||
io.Copy(out, src)
|
_, err = io.Copy(out, src)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind checks the Content-Type to select a binding engine automatically,
|
// Bind checks the Content-Type to select a binding engine automatically,
|
||||||
@ -523,7 +532,7 @@ func (c *Context) BindYAML(obj interface{}) error {
|
|||||||
// It will abort the request with HTTP 400 if any error occurs.
|
// It will abort the request with HTTP 400 if any error occurs.
|
||||||
func (c *Context) BindUri(obj interface{}) error {
|
func (c *Context) BindUri(obj interface{}) error {
|
||||||
if err := c.ShouldBindUri(obj); err != nil {
|
if err := c.ShouldBindUri(obj); err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind)
|
c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -534,7 +543,7 @@ func (c *Context) BindUri(obj interface{}) error {
|
|||||||
// See the binding package.
|
// See the binding package.
|
||||||
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
|
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
|
||||||
if err := c.ShouldBindWith(obj, b); err != nil {
|
if err := c.ShouldBindWith(obj, b); err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind)
|
c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -908,7 +917,7 @@ func (c *Context) Negotiate(code int, config Negotiate) {
|
|||||||
c.XML(code, data)
|
c.XML(code, data)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server"))
|
c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) // nolint: errcheck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -944,15 +953,15 @@ func (c *Context) SetAccepted(formats ...string) {
|
|||||||
// Deadline returns the time when work done on behalf of this context
|
// Deadline returns the time when work done on behalf of this context
|
||||||
// should be canceled. Deadline returns ok==false when no deadline is
|
// should be canceled. Deadline returns ok==false when no deadline is
|
||||||
// set. Successive calls to Deadline return the same results.
|
// set. Successive calls to Deadline return the same results.
|
||||||
func (c *Context) Deadline() (time.Time, bool) {
|
func (c *Context) Deadline() (deadline time.Time, ok bool) {
|
||||||
return c.Request.Context().Deadline()
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done returns a channel that's closed when work done on behalf of this
|
// Done returns a channel that's closed when work done on behalf of this
|
||||||
// context should be canceled. Done may return nil if this context can
|
// context should be canceled. Done may return nil if this context can
|
||||||
// never be canceled. Successive calls to Done return the same value.
|
// never be canceled. Successive calls to Done return the same value.
|
||||||
func (c *Context) Done() <-chan struct{} {
|
func (c *Context) Done() <-chan struct{} {
|
||||||
return c.Request.Context().Done()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Err returns a non-nil error value after Done is closed,
|
// Err returns a non-nil error value after Done is closed,
|
||||||
@ -962,7 +971,7 @@ func (c *Context) Done() <-chan struct{} {
|
|||||||
// Canceled if the context was canceled
|
// Canceled if the context was canceled
|
||||||
// or DeadlineExceeded if the context's deadline passed.
|
// or DeadlineExceeded if the context's deadline passed.
|
||||||
func (c *Context) Err() error {
|
func (c *Context) Err() error {
|
||||||
return c.Request.Context().Err()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value returns the value associated with this context for key, or nil
|
// Value returns the value associated with this context for key, or nil
|
||||||
|
17
context_17.go
Normal file
17
context_17.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2018 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin/render"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PureJSON serializes the given struct as JSON into the response body.
|
||||||
|
// PureJSON, unlike JSON, does not replace special html characters with their unicode entities.
|
||||||
|
func (c *Context) PureJSON(code int, obj interface{}) {
|
||||||
|
c.Render(code, render.PureJSON{Data: obj})
|
||||||
|
}
|
27
context_17_test.go
Normal file
27
context_17_test.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2018 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tests that the response is serialized as JSON
|
||||||
|
// and Content-Type is set to application/json
|
||||||
|
// and special HTML characters are preserved
|
||||||
|
func TestContextRenderPureJSON(t *testing.T) {
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
c, _ := CreateTestContext(w)
|
||||||
|
c.PureJSON(http.StatusCreated, H{"foo": "bar", "html": "<b>"})
|
||||||
|
assert.Equal(t, http.StatusCreated, w.Code)
|
||||||
|
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"<b>\"}\n", w.Body.String())
|
||||||
|
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
}
|
@ -70,7 +70,8 @@ func TestContextFormFile(t *testing.T) {
|
|||||||
mw := multipart.NewWriter(buf)
|
mw := multipart.NewWriter(buf)
|
||||||
w, err := mw.CreateFormFile("file", "test")
|
w, err := mw.CreateFormFile("file", "test")
|
||||||
if assert.NoError(t, err) {
|
if assert.NoError(t, err) {
|
||||||
w.Write([]byte("test"))
|
_, err = w.Write([]byte("test"))
|
||||||
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
mw.Close()
|
mw.Close()
|
||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||||
@ -100,10 +101,11 @@ func TestContextFormFileFailed(t *testing.T) {
|
|||||||
func TestContextMultipartForm(t *testing.T) {
|
func TestContextMultipartForm(t *testing.T) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
mw := multipart.NewWriter(buf)
|
mw := multipart.NewWriter(buf)
|
||||||
mw.WriteField("foo", "bar")
|
assert.NoError(t, mw.WriteField("foo", "bar"))
|
||||||
w, err := mw.CreateFormFile("file", "test")
|
w, err := mw.CreateFormFile("file", "test")
|
||||||
if assert.NoError(t, err) {
|
if assert.NoError(t, err) {
|
||||||
w.Write([]byte("test"))
|
_, err = w.Write([]byte("test"))
|
||||||
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
mw.Close()
|
mw.Close()
|
||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||||
@ -137,7 +139,8 @@ func TestSaveUploadedCreateFailed(t *testing.T) {
|
|||||||
mw := multipart.NewWriter(buf)
|
mw := multipart.NewWriter(buf)
|
||||||
w, err := mw.CreateFormFile("file", "test")
|
w, err := mw.CreateFormFile("file", "test")
|
||||||
if assert.NoError(t, err) {
|
if assert.NoError(t, err) {
|
||||||
w.Write([]byte("test"))
|
_, err = w.Write([]byte("test"))
|
||||||
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
mw.Close()
|
mw.Close()
|
||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||||
@ -159,7 +162,7 @@ func TestContextReset(t *testing.T) {
|
|||||||
c.index = 2
|
c.index = 2
|
||||||
c.Writer = &responseWriter{ResponseWriter: httptest.NewRecorder()}
|
c.Writer = &responseWriter{ResponseWriter: httptest.NewRecorder()}
|
||||||
c.Params = Params{Param{}}
|
c.Params = Params{Param{}}
|
||||||
c.Error(errors.New("test"))
|
c.Error(errors.New("test")) // nolint: errcheck
|
||||||
c.Set("foo", "bar")
|
c.Set("foo", "bar")
|
||||||
c.reset()
|
c.reset()
|
||||||
|
|
||||||
@ -809,7 +812,7 @@ func TestContextRenderHTML2(t *testing.T) {
|
|||||||
assert.Len(t, router.trees, 1)
|
assert.Len(t, router.trees, 1)
|
||||||
|
|
||||||
templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
|
templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
|
||||||
re := captureOutput(func() {
|
re := captureOutput(t, func() {
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
router.SetHTMLTemplate(templ)
|
router.SetHTMLTemplate(templ)
|
||||||
SetMode(TestMode)
|
SetMode(TestMode)
|
||||||
@ -1220,7 +1223,8 @@ func TestContextAbortWithStatusJSON(t *testing.T) {
|
|||||||
assert.Equal(t, "application/json; charset=utf-8", contentType)
|
assert.Equal(t, "application/json; charset=utf-8", contentType)
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
buf.ReadFrom(w.Body)
|
_, err := buf.ReadFrom(w.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
jsonStringBody := buf.String()
|
jsonStringBody := buf.String()
|
||||||
assert.Equal(t, fmt.Sprint(`{"foo":"fooValue","bar":"barValue"}`), jsonStringBody)
|
assert.Equal(t, fmt.Sprint(`{"foo":"fooValue","bar":"barValue"}`), jsonStringBody)
|
||||||
}
|
}
|
||||||
@ -1229,11 +1233,11 @@ func TestContextError(t *testing.T) {
|
|||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||||
assert.Empty(t, c.Errors)
|
assert.Empty(t, c.Errors)
|
||||||
|
|
||||||
c.Error(errors.New("first error"))
|
c.Error(errors.New("first error")) // nolint: errcheck
|
||||||
assert.Len(t, c.Errors, 1)
|
assert.Len(t, c.Errors, 1)
|
||||||
assert.Equal(t, "Error #01: first error\n", c.Errors.String())
|
assert.Equal(t, "Error #01: first error\n", c.Errors.String())
|
||||||
|
|
||||||
c.Error(&Error{
|
c.Error(&Error{ // nolint: errcheck
|
||||||
Err: errors.New("second error"),
|
Err: errors.New("second error"),
|
||||||
Meta: "some data 2",
|
Meta: "some data 2",
|
||||||
Type: ErrorTypePublic,
|
Type: ErrorTypePublic,
|
||||||
@ -1255,13 +1259,13 @@ func TestContextError(t *testing.T) {
|
|||||||
t.Error("didn't panic")
|
t.Error("didn't panic")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
c.Error(nil)
|
c.Error(nil) // nolint: errcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContextTypedError(t *testing.T) {
|
func TestContextTypedError(t *testing.T) {
|
||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||||
c.Error(errors.New("externo 0")).SetType(ErrorTypePublic)
|
c.Error(errors.New("externo 0")).SetType(ErrorTypePublic) // nolint: errcheck
|
||||||
c.Error(errors.New("interno 0")).SetType(ErrorTypePrivate)
|
c.Error(errors.New("interno 0")).SetType(ErrorTypePrivate) // nolint: errcheck
|
||||||
|
|
||||||
for _, err := range c.Errors.ByType(ErrorTypePublic) {
|
for _, err := range c.Errors.ByType(ErrorTypePublic) {
|
||||||
assert.Equal(t, ErrorTypePublic, err.Type)
|
assert.Equal(t, ErrorTypePublic, err.Type)
|
||||||
@ -1276,7 +1280,7 @@ func TestContextAbortWithError(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
|
|
||||||
c.AbortWithError(http.StatusUnauthorized, errors.New("bad input")).SetMeta("some input")
|
c.AbortWithError(http.StatusUnauthorized, errors.New("bad input")).SetMeta("some input") // nolint: errcheck
|
||||||
|
|
||||||
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
||||||
assert.Equal(t, abortIndex, c.index)
|
assert.Equal(t, abortIndex, c.index)
|
||||||
@ -1466,7 +1470,7 @@ func TestContextShouldBindWithXML(t *testing.T) {
|
|||||||
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?>
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<root>
|
<root>
|
||||||
<foo>FOO</foo>
|
<foo>FOO</foo>
|
||||||
<bar>BAR</bar>
|
<bar>BAR</bar>
|
||||||
</root>`))
|
</root>`))
|
||||||
c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type
|
c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type
|
||||||
|
|
||||||
@ -1484,15 +1488,19 @@ func TestContextShouldBindWithQuery(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
|
|
||||||
c.Request, _ = http.NewRequest("POST", "/?foo=bar&bar=foo", bytes.NewBufferString("foo=unused"))
|
c.Request, _ = http.NewRequest("POST", "/?foo=bar&bar=foo&Foo=bar1&Bar=foo1", bytes.NewBufferString("foo=unused"))
|
||||||
|
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `form:"foo"`
|
Foo string `form:"foo"`
|
||||||
Bar string `form:"bar"`
|
Bar string `form:"bar"`
|
||||||
|
Foo1 string `form:"Foo"`
|
||||||
|
Bar1 string `form:"Bar"`
|
||||||
}
|
}
|
||||||
assert.NoError(t, c.ShouldBindQuery(&obj))
|
assert.NoError(t, c.ShouldBindQuery(&obj))
|
||||||
assert.Equal(t, "foo", obj.Bar)
|
assert.Equal(t, "foo", obj.Bar)
|
||||||
assert.Equal(t, "bar", obj.Foo)
|
assert.Equal(t, "bar", obj.Foo)
|
||||||
|
assert.Equal(t, "foo1", obj.Bar1)
|
||||||
|
assert.Equal(t, "bar1", obj.Foo1)
|
||||||
assert.Equal(t, 0, w.Body.Len())
|
assert.Equal(t, 0, w.Body.Len())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1718,7 +1726,8 @@ func TestContextStream(t *testing.T) {
|
|||||||
stopStream = false
|
stopStream = false
|
||||||
}()
|
}()
|
||||||
|
|
||||||
w.Write([]byte("test"))
|
_, err := w.Write([]byte("test"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
return stopStream
|
return stopStream
|
||||||
})
|
})
|
||||||
@ -1735,7 +1744,8 @@ func TestContextStreamWithClientGone(t *testing.T) {
|
|||||||
w.closeClient()
|
w.closeClient()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
writer.Write([]byte("test"))
|
_, err := writer.Write([]byte("test"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -1743,48 +1753,14 @@ func TestContextStreamWithClientGone(t *testing.T) {
|
|||||||
assert.Equal(t, "test", w.Body.String())
|
assert.Equal(t, "test", w.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContextHTTPContext(t *testing.T) {
|
func TestContextResetInHandler(t *testing.T) {
|
||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
w := CreateTestResponseRecorder()
|
||||||
req, _ := http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
c, _ := CreateTestContext(w)
|
||||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
|
||||||
defer cancelFunc()
|
|
||||||
c.Request = req.WithContext(ctx)
|
|
||||||
|
|
||||||
assert.NoError(t, c.Err())
|
c.handlers = []HandlerFunc{
|
||||||
assert.NotNil(t, c.Done())
|
func(c *Context) { c.reset() },
|
||||||
select {
|
|
||||||
case <-c.Done():
|
|
||||||
assert.Fail(t, "context should not be canceled")
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
ti, ok := c.Deadline()
|
|
||||||
assert.Equal(t, ti, time.Time{})
|
|
||||||
assert.False(t, ok)
|
|
||||||
assert.Equal(t, c.Value(0), c.Request)
|
|
||||||
|
|
||||||
cancelFunc()
|
|
||||||
assert.NotNil(t, c.Done())
|
|
||||||
select {
|
|
||||||
case <-c.Done():
|
|
||||||
default:
|
|
||||||
assert.Fail(t, "context should be canceled")
|
|
||||||
}
|
}
|
||||||
}
|
assert.NotPanics(t, func() {
|
||||||
|
c.Next()
|
||||||
func TestContextHTTPContextWithDeadline(t *testing.T) {
|
})
|
||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
|
||||||
req, _ := http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
|
||||||
location, _ := time.LoadLocation("Europe/Paris")
|
|
||||||
assert.NotNil(t, location)
|
|
||||||
date := time.Date(2031, 12, 27, 16, 00, 00, 00, location)
|
|
||||||
ctx, cancelFunc := context.WithDeadline(context.Background(), date)
|
|
||||||
defer cancelFunc()
|
|
||||||
c.Request = req.WithContext(ctx)
|
|
||||||
|
|
||||||
assert.NoError(t, c.Err())
|
|
||||||
|
|
||||||
ti, ok := c.Deadline()
|
|
||||||
assert.Equal(t, ti, date)
|
|
||||||
assert.True(t, ok)
|
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ func TestIsDebugging(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDebugPrint(t *testing.T) {
|
func TestDebugPrint(t *testing.T) {
|
||||||
re := captureOutput(func() {
|
re := captureOutput(t, func() {
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
SetMode(ReleaseMode)
|
SetMode(ReleaseMode)
|
||||||
debugPrint("DEBUG this!")
|
debugPrint("DEBUG this!")
|
||||||
@ -46,7 +46,7 @@ func TestDebugPrint(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDebugPrintError(t *testing.T) {
|
func TestDebugPrintError(t *testing.T) {
|
||||||
re := captureOutput(func() {
|
re := captureOutput(t, func() {
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
debugPrintError(nil)
|
debugPrintError(nil)
|
||||||
debugPrintError(errors.New("this is an error"))
|
debugPrintError(errors.New("this is an error"))
|
||||||
@ -56,7 +56,7 @@ func TestDebugPrintError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDebugPrintRoutes(t *testing.T) {
|
func TestDebugPrintRoutes(t *testing.T) {
|
||||||
re := captureOutput(func() {
|
re := captureOutput(t, func() {
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
debugPrintRoute("GET", "/path/to/route/:param", HandlersChain{func(c *Context) {}, handlerNameTest})
|
debugPrintRoute("GET", "/path/to/route/:param", HandlersChain{func(c *Context) {}, handlerNameTest})
|
||||||
SetMode(TestMode)
|
SetMode(TestMode)
|
||||||
@ -65,7 +65,7 @@ func TestDebugPrintRoutes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDebugPrintLoadTemplate(t *testing.T) {
|
func TestDebugPrintLoadTemplate(t *testing.T) {
|
||||||
re := captureOutput(func() {
|
re := captureOutput(t, func() {
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./testdata/template/hello.tmpl"))
|
templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./testdata/template/hello.tmpl"))
|
||||||
debugPrintLoadTemplate(templ)
|
debugPrintLoadTemplate(templ)
|
||||||
@ -75,7 +75,7 @@ func TestDebugPrintLoadTemplate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDebugPrintWARNINGSetHTMLTemplate(t *testing.T) {
|
func TestDebugPrintWARNINGSetHTMLTemplate(t *testing.T) {
|
||||||
re := captureOutput(func() {
|
re := captureOutput(t, func() {
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
debugPrintWARNINGSetHTMLTemplate()
|
debugPrintWARNINGSetHTMLTemplate()
|
||||||
SetMode(TestMode)
|
SetMode(TestMode)
|
||||||
@ -84,7 +84,7 @@ func TestDebugPrintWARNINGSetHTMLTemplate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDebugPrintWARNINGDefault(t *testing.T) {
|
func TestDebugPrintWARNINGDefault(t *testing.T) {
|
||||||
re := captureOutput(func() {
|
re := captureOutput(t, func() {
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
debugPrintWARNINGDefault()
|
debugPrintWARNINGDefault()
|
||||||
SetMode(TestMode)
|
SetMode(TestMode)
|
||||||
@ -98,7 +98,7 @@ func TestDebugPrintWARNINGDefault(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDebugPrintWARNINGNew(t *testing.T) {
|
func TestDebugPrintWARNINGNew(t *testing.T) {
|
||||||
re := captureOutput(func() {
|
re := captureOutput(t, func() {
|
||||||
SetMode(DebugMode)
|
SetMode(DebugMode)
|
||||||
debugPrintWARNINGNew()
|
debugPrintWARNINGNew()
|
||||||
SetMode(TestMode)
|
SetMode(TestMode)
|
||||||
@ -106,7 +106,7 @@ func TestDebugPrintWARNINGNew(t *testing.T) {
|
|||||||
assert.Equal(t, "[GIN-debug] [WARNING] Running in \"debug\" mode. Switch to \"release\" mode in production.\n - using env:\texport GIN_MODE=release\n - using code:\tgin.SetMode(gin.ReleaseMode)\n\n", re)
|
assert.Equal(t, "[GIN-debug] [WARNING] Running in \"debug\" mode. Switch to \"release\" mode in production.\n - using env:\texport GIN_MODE=release\n - using code:\tgin.SetMode(gin.ReleaseMode)\n\n", re)
|
||||||
}
|
}
|
||||||
|
|
||||||
func captureOutput(f func()) string {
|
func captureOutput(t *testing.T, f func()) string {
|
||||||
reader, writer, err := os.Pipe()
|
reader, writer, err := os.Pipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -127,7 +127,8 @@ func captureOutput(f func()) string {
|
|||||||
go func() {
|
go func() {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
wg.Done()
|
wg.Done()
|
||||||
io.Copy(&buf, reader)
|
_, err := io.Copy(&buf, reader)
|
||||||
|
assert.NoError(t, err)
|
||||||
out <- buf.String()
|
out <- buf.String()
|
||||||
}()
|
}()
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
@ -34,7 +34,7 @@ func TestError(t *testing.T) {
|
|||||||
jsonBytes, _ := json.Marshal(err)
|
jsonBytes, _ := json.Marshal(err)
|
||||||
assert.Equal(t, "{\"error\":\"test error\",\"meta\":\"some data\"}", string(jsonBytes))
|
assert.Equal(t, "{\"error\":\"test error\",\"meta\":\"some data\"}", string(jsonBytes))
|
||||||
|
|
||||||
err.SetMeta(H{
|
err.SetMeta(H{ // nolint: errcheck
|
||||||
"status": "200",
|
"status": "200",
|
||||||
"data": "some data",
|
"data": "some data",
|
||||||
})
|
})
|
||||||
@ -44,7 +44,7 @@ func TestError(t *testing.T) {
|
|||||||
"data": "some data",
|
"data": "some data",
|
||||||
}, err.JSON())
|
}, err.JSON())
|
||||||
|
|
||||||
err.SetMeta(H{
|
err.SetMeta(H{ // nolint: errcheck
|
||||||
"error": "custom error",
|
"error": "custom error",
|
||||||
"status": "200",
|
"status": "200",
|
||||||
"data": "some data",
|
"data": "some data",
|
||||||
@ -59,7 +59,7 @@ func TestError(t *testing.T) {
|
|||||||
status string
|
status string
|
||||||
data string
|
data string
|
||||||
}
|
}
|
||||||
err.SetMeta(customError{status: "200", data: "other data"})
|
err.SetMeta(customError{status: "200", data: "other data"}) // nolint: errcheck
|
||||||
assert.Equal(t, customError{status: "200", data: "other data"}, err.JSON())
|
assert.Equal(t, customError{status: "200", data: "other data"}, err.JSON())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
gin.go
5
gin.go
@ -422,7 +422,10 @@ func serveError(c *Context, code int, defaultMessage []byte) {
|
|||||||
}
|
}
|
||||||
if c.writermem.Status() == code {
|
if c.writermem.Status() == code {
|
||||||
c.writermem.Header()["Content-Type"] = mimePlain
|
c.writermem.Header()["Content-Type"] = mimePlain
|
||||||
c.Writer.Write(defaultMessage)
|
_, err := c.Writer.Write(defaultMessage)
|
||||||
|
if err != nil {
|
||||||
|
debugPrint("cannot write message to writer during serve error: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.writermem.WriteHeaderNow()
|
c.writermem.WriteHeaderNow()
|
||||||
|
@ -87,7 +87,7 @@ func TestRunEmptyWithEnv(t *testing.T) {
|
|||||||
func TestRunTooMuchParams(t *testing.T) {
|
func TestRunTooMuchParams(t *testing.T) {
|
||||||
router := New()
|
router := New()
|
||||||
assert.Panics(t, func() {
|
assert.Panics(t, func() {
|
||||||
router.Run("2", "2")
|
assert.NoError(t, router.Run("2", "2"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ func TestBadUnixSocket(t *testing.T) {
|
|||||||
func TestFileDescriptor(t *testing.T) {
|
func TestFileDescriptor(t *testing.T) {
|
||||||
router := New()
|
router := New()
|
||||||
|
|
||||||
addr, err := net.ResolveTCPAddr("tcp", ":8000")
|
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
listener, err := net.ListenTCP("tcp", addr)
|
listener, err := net.ListenTCP("tcp", addr)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -152,7 +152,7 @@ func TestFileDescriptor(t *testing.T) {
|
|||||||
// otherwise the main thread will complete
|
// otherwise the main thread will complete
|
||||||
time.Sleep(5 * time.Millisecond)
|
time.Sleep(5 * time.Millisecond)
|
||||||
|
|
||||||
c, err := net.Dial("tcp", "localhost:8000")
|
c, err := net.Dial("tcp", listener.Addr().String())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
fmt.Fprintf(c, "GET /example HTTP/1.0\r\n\r\n")
|
fmt.Fprintf(c, "GET /example HTTP/1.0\r\n\r\n")
|
||||||
|
17
gin_test.go
17
gin_test.go
@ -471,6 +471,23 @@ func TestListOfRoutes(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEngineHandleContext(t *testing.T) {
|
||||||
|
r := New()
|
||||||
|
r.GET("/", func(c *Context) {
|
||||||
|
c.Request.URL.Path = "/v2"
|
||||||
|
r.HandleContext(c)
|
||||||
|
})
|
||||||
|
v2 := r.Group("/v2")
|
||||||
|
{
|
||||||
|
v2.GET("/", func(c *Context) {})
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NotPanics(t, func() {
|
||||||
|
w := performRequest(r, "GET", "/")
|
||||||
|
assert.Equal(t, 301, w.Code)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo) {
|
func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo) {
|
||||||
for _, gotRoute := range gotRoutes {
|
for _, gotRoute := range gotRoutes {
|
||||||
if gotRoute.Path == wantRoute.Path && gotRoute.Method == wantRoute.Method {
|
if gotRoute.Path == wantRoute.Path && gotRoute.Method == wantRoute.Method {
|
||||||
|
@ -338,7 +338,7 @@ func TestBindUriError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
router.Handle("GET", "/new/rest/:num", func(c *Context) {
|
router.Handle("GET", "/new/rest/:num", func(c *Context) {
|
||||||
var m Member
|
var m Member
|
||||||
c.BindUri(&m)
|
assert.Error(t, c.BindUri(&m))
|
||||||
})
|
})
|
||||||
|
|
||||||
path1, _ := exampleFromPath("/new/rest/:num")
|
path1, _ := exampleFromPath("/new/rest/:num")
|
||||||
|
35
logger.go
35
logger.go
@ -35,9 +35,9 @@ type LoggerConfig struct {
|
|||||||
// Optional. Default value is gin.DefaultWriter.
|
// Optional. Default value is gin.DefaultWriter.
|
||||||
Output io.Writer
|
Output io.Writer
|
||||||
|
|
||||||
// SkipPathes is a url path array which logs are not written.
|
// SkipPaths is a url path array which logs are not written.
|
||||||
// Optional.
|
// Optional.
|
||||||
SkipPathes []string
|
SkipPaths []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
|
// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
|
||||||
@ -45,15 +45,24 @@ type LogFormatter func(params LogFormatterParams) string
|
|||||||
|
|
||||||
// LogFormatterParams is the structure any formatter will be handed when time to log comes
|
// LogFormatterParams is the structure any formatter will be handed when time to log comes
|
||||||
type LogFormatterParams struct {
|
type LogFormatterParams struct {
|
||||||
Request *http.Request
|
Request *http.Request
|
||||||
TimeStamp time.Time
|
|
||||||
StatusCode int
|
// TimeStamp shows the time after the server returns a response.
|
||||||
Latency time.Duration
|
TimeStamp time.Time
|
||||||
ClientIP string
|
// StatusCode is HTTP response code.
|
||||||
Method string
|
StatusCode int
|
||||||
Path string
|
// Latency is how much time the server cost to process a certain request.
|
||||||
|
Latency time.Duration
|
||||||
|
// ClientIP equals Context's ClientIP method.
|
||||||
|
ClientIP string
|
||||||
|
// Method is the HTTP method given to the request.
|
||||||
|
Method string
|
||||||
|
// Path is a path the client requests.
|
||||||
|
Path string
|
||||||
|
// ErrorMessage is set if error has occurred in processing the request.
|
||||||
ErrorMessage string
|
ErrorMessage string
|
||||||
IsTerm bool
|
// IsTerm shows whether does gin's output descriptor refers to a terminal.
|
||||||
|
IsTerm bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultLogFormatter is the default log format function Logger middleware uses.
|
// defaultLogFormatter is the default log format function Logger middleware uses.
|
||||||
@ -114,8 +123,8 @@ func LoggerWithFormatter(f LogFormatter) HandlerFunc {
|
|||||||
// Example: os.Stdout, a file opened in write mode, a socket...
|
// Example: os.Stdout, a file opened in write mode, a socket...
|
||||||
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
|
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
|
||||||
return LoggerWithConfig(LoggerConfig{
|
return LoggerWithConfig(LoggerConfig{
|
||||||
Output: out,
|
Output: out,
|
||||||
SkipPathes: notlogged,
|
SkipPaths: notlogged,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +140,7 @@ func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
|
|||||||
out = DefaultWriter
|
out = DefaultWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
notlogged := conf.SkipPathes
|
notlogged := conf.SkipPaths
|
||||||
|
|
||||||
isTerm := true
|
isTerm := true
|
||||||
|
|
||||||
|
@ -278,13 +278,13 @@ func TestErrorLogger(t *testing.T) {
|
|||||||
router := New()
|
router := New()
|
||||||
router.Use(ErrorLogger())
|
router.Use(ErrorLogger())
|
||||||
router.GET("/error", func(c *Context) {
|
router.GET("/error", func(c *Context) {
|
||||||
c.Error(errors.New("this is an error"))
|
c.Error(errors.New("this is an error")) // nolint: errcheck
|
||||||
})
|
})
|
||||||
router.GET("/abort", func(c *Context) {
|
router.GET("/abort", func(c *Context) {
|
||||||
c.AbortWithError(http.StatusUnauthorized, errors.New("no authorized"))
|
c.AbortWithError(http.StatusUnauthorized, errors.New("no authorized")) // nolint: errcheck
|
||||||
})
|
})
|
||||||
router.GET("/print", func(c *Context) {
|
router.GET("/print", func(c *Context) {
|
||||||
c.Error(errors.New("this is an error"))
|
c.Error(errors.New("this is an error")) // nolint: errcheck
|
||||||
c.String(http.StatusInternalServerError, "hola!")
|
c.String(http.StatusInternalServerError, "hola!")
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -320,8 +320,8 @@ func TestLoggerWithConfigSkippingPaths(t *testing.T) {
|
|||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
router := New()
|
router := New()
|
||||||
router.Use(LoggerWithConfig(LoggerConfig{
|
router.Use(LoggerWithConfig(LoggerConfig{
|
||||||
Output: buffer,
|
Output: buffer,
|
||||||
SkipPathes: []string{"/skipped"},
|
SkipPaths: []string{"/skipped"},
|
||||||
}))
|
}))
|
||||||
router.GET("/logged", func(c *Context) {})
|
router.GET("/logged", func(c *Context) {})
|
||||||
router.GET("/skipped", func(c *Context) {})
|
router.GET("/skipped", func(c *Context) {})
|
||||||
|
@ -208,7 +208,7 @@ func TestMiddlewareFailHandlersChain(t *testing.T) {
|
|||||||
router := New()
|
router := New()
|
||||||
router.Use(func(context *Context) {
|
router.Use(func(context *Context) {
|
||||||
signature += "A"
|
signature += "A"
|
||||||
context.AbortWithError(http.StatusInternalServerError, errors.New("foo"))
|
context.AbortWithError(http.StatusInternalServerError, errors.New("foo")) // nolint: errcheck
|
||||||
})
|
})
|
||||||
router.Use(func(context *Context) {
|
router.Use(func(context *Context) {
|
||||||
signature += "B"
|
signature += "B"
|
||||||
|
@ -66,7 +66,7 @@ func RecoveryWithWriter(out io.Writer) HandlerFunc {
|
|||||||
|
|
||||||
// If the connection is dead, we can't write a status to it.
|
// If the connection is dead, we can't write a status to it.
|
||||||
if brokenPipe {
|
if brokenPipe {
|
||||||
c.Error(err.(error))
|
c.Error(err.(error)) // nolint: errcheck
|
||||||
c.Abort()
|
c.Abort()
|
||||||
} else {
|
} else {
|
||||||
c.AbortWithStatus(http.StatusInternalServerError)
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
|
@ -72,8 +72,8 @@ func WriteJSON(w http.ResponseWriter, obj interface{}) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.Write(jsonBytes)
|
_, err = w.Write(jsonBytes)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render (IndentedJSON) marshals the given interface object and writes it with custom ContentType.
|
// Render (IndentedJSON) marshals the given interface object and writes it with custom ContentType.
|
||||||
@ -83,8 +83,8 @@ func (r IndentedJSON) Render(w http.ResponseWriter) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.Write(jsonBytes)
|
_, err = w.Write(jsonBytes)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteContentType (IndentedJSON) writes JSON ContentType.
|
// WriteContentType (IndentedJSON) writes JSON ContentType.
|
||||||
@ -101,10 +101,13 @@ func (r SecureJSON) Render(w http.ResponseWriter) error {
|
|||||||
}
|
}
|
||||||
// if the jsonBytes is array values
|
// if the jsonBytes is array values
|
||||||
if bytes.HasPrefix(jsonBytes, []byte("[")) && bytes.HasSuffix(jsonBytes, []byte("]")) {
|
if bytes.HasPrefix(jsonBytes, []byte("[")) && bytes.HasSuffix(jsonBytes, []byte("]")) {
|
||||||
w.Write([]byte(r.Prefix))
|
_, err = w.Write([]byte(r.Prefix))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
w.Write(jsonBytes)
|
_, err = w.Write(jsonBytes)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteContentType (SecureJSON) writes JSON ContentType.
|
// WriteContentType (SecureJSON) writes JSON ContentType.
|
||||||
@ -121,15 +124,27 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if r.Callback == "" {
|
if r.Callback == "" {
|
||||||
w.Write(ret)
|
_, err = w.Write(ret)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
callback := template.JSEscapeString(r.Callback)
|
callback := template.JSEscapeString(r.Callback)
|
||||||
w.Write([]byte(callback))
|
_, err = w.Write([]byte(callback))
|
||||||
w.Write([]byte("("))
|
if err != nil {
|
||||||
w.Write(ret)
|
return err
|
||||||
w.Write([]byte(")"))
|
}
|
||||||
|
_, err = w.Write([]byte("("))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = w.Write(ret)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = w.Write([]byte(")"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -156,8 +171,8 @@ func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
|
|||||||
buffer.WriteString(cvt)
|
buffer.WriteString(cvt)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(buffer.Bytes())
|
_, err = w.Write(buffer.Bytes())
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteContentType (AsciiJSON) writes JSON ContentType.
|
// WriteContentType (AsciiJSON) writes JSON ContentType.
|
||||||
|
@ -26,8 +26,8 @@ func (r ProtoBuf) Render(w http.ResponseWriter) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(bytes)
|
_, err = w.Write(bytes)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteContentType (ProtoBuf) writes ProtoBuf ContentType.
|
// WriteContentType (ProtoBuf) writes ProtoBuf ContentType.
|
||||||
|
@ -71,7 +71,7 @@ func TestRenderJSONPanics(t *testing.T) {
|
|||||||
data := make(chan int)
|
data := make(chan int)
|
||||||
|
|
||||||
// json: unsupported type: chan int
|
// json: unsupported type: chan int
|
||||||
assert.Panics(t, func() { (JSON{data}).Render(w) })
|
assert.Panics(t, func() { assert.NoError(t, (JSON{data}).Render(w)) })
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderIndentedJSON(t *testing.T) {
|
func TestRenderIndentedJSON(t *testing.T) {
|
||||||
@ -347,7 +347,7 @@ func TestRenderRedirect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w = httptest.NewRecorder()
|
w = httptest.NewRecorder()
|
||||||
assert.Panics(t, func() { data2.Render(w) })
|
assert.Panics(t, func() { assert.NoError(t, data2.Render(w)) })
|
||||||
|
|
||||||
// only improve coverage
|
// only improve coverage
|
||||||
data2.WriteContentType(w)
|
data2.WriteContentType(w)
|
||||||
|
@ -20,8 +20,7 @@ var plainContentType = []string{"text/plain; charset=utf-8"}
|
|||||||
|
|
||||||
// Render (String) writes data with custom ContentType.
|
// Render (String) writes data with custom ContentType.
|
||||||
func (r String) Render(w http.ResponseWriter) error {
|
func (r String) Render(w http.ResponseWriter) error {
|
||||||
WriteString(w, r.Format, r.Data)
|
return WriteString(w, r.Format, r.Data)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteContentType (String) writes Plain ContentType.
|
// WriteContentType (String) writes Plain ContentType.
|
||||||
@ -30,11 +29,12 @@ func (r String) WriteContentType(w http.ResponseWriter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteString writes data according to its format and write custom ContentType.
|
// WriteString writes data according to its format and write custom ContentType.
|
||||||
func WriteString(w http.ResponseWriter, format string, data []interface{}) {
|
func WriteString(w http.ResponseWriter, format string, data []interface{}) (err error) {
|
||||||
writeContentType(w, plainContentType)
|
writeContentType(w, plainContentType)
|
||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
fmt.Fprintf(w, format, data...)
|
_, err = fmt.Fprintf(w, format, data...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
io.WriteString(w, format)
|
_, err = io.WriteString(w, format)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,8 @@ func (r YAML) Render(w http.ResponseWriter) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(bytes)
|
_, err = w.Write(bytes)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteContentType (YAML) writes YAML ContentType for response.
|
// WriteContentType (YAML) writes YAML ContentType for response.
|
||||||
|
@ -103,7 +103,8 @@ func TestResponseWriterHijack(t *testing.T) {
|
|||||||
w := ResponseWriter(writer)
|
w := ResponseWriter(writer)
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.Panics(t, func() {
|
||||||
w.Hijack()
|
_, _, err := w.Hijack()
|
||||||
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
assert.True(t, w.Written())
|
assert.True(t, w.Written())
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ type RouterGroup struct {
|
|||||||
|
|
||||||
var _ IRouter = &RouterGroup{}
|
var _ IRouter = &RouterGroup{}
|
||||||
|
|
||||||
// Use adds middleware to the group, see example code in github.
|
// Use adds middleware to the group, see example code in GitHub.
|
||||||
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
|
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
|
||||||
group.Handlers = append(group.Handlers, middleware...)
|
group.Handlers = append(group.Handlers, middleware...)
|
||||||
return group.returnObj()
|
return group.returnObj()
|
||||||
@ -78,7 +78,7 @@ func (group *RouterGroup) handle(httpMethod, relativePath string, handlers Handl
|
|||||||
|
|
||||||
// Handle registers a new request handle and middleware with the given path and method.
|
// Handle registers a new request handle and middleware with the given path and method.
|
||||||
// The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes.
|
// The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes.
|
||||||
// See the example code in github.
|
// See the example code in GitHub.
|
||||||
//
|
//
|
||||||
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
|
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
|
||||||
// functions can be used.
|
// functions can be used.
|
||||||
|
@ -251,7 +251,8 @@ func TestRouteStaticFile(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
defer os.Remove(f.Name())
|
defer os.Remove(f.Name())
|
||||||
f.WriteString("Gin Web Framework")
|
_, err = f.WriteString("Gin Web Framework")
|
||||||
|
assert.NoError(t, err)
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
||||||
dir, filename := filepath.Split(f.Name())
|
dir, filename := filepath.Split(f.Name())
|
||||||
@ -426,6 +427,16 @@ func TestRouterStaticFSNotFound(t *testing.T) {
|
|||||||
assert.Equal(t, "non existent", w.Body.String())
|
assert.Equal(t, "non existent", w.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRouterStaticFSFileNotFound(t *testing.T) {
|
||||||
|
router := New()
|
||||||
|
|
||||||
|
router.StaticFS("/", http.FileSystem(http.Dir(".")))
|
||||||
|
|
||||||
|
assert.NotPanics(t, func() {
|
||||||
|
performRequest(router, "GET", "/nonexistent")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestRouteRawPath(t *testing.T) {
|
func TestRouteRawPath(t *testing.T) {
|
||||||
route := New()
|
route := New()
|
||||||
route.UseRawPath = true
|
route.UseRawPath = true
|
||||||
|
@ -4,12 +4,12 @@
|
|||||||
|
|
||||||
// +build tools
|
// +build tools
|
||||||
|
|
||||||
// This file exists to cause `go mod` and `go get` to believe these tools
|
// This package exists to cause `go mod` and `go get` to believe these tools
|
||||||
// are dependencies, even though they are not runtime dependencies of any
|
// are dependencies, even though they are not runtime dependencies of any
|
||||||
// gin package. This means they will appear in `go.mod` file, but will not
|
// gin package. This means they will appear in `go.mod` file, but will not
|
||||||
// be a part of the build.
|
// be a part of the build.
|
||||||
|
|
||||||
package gin
|
package tools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "github.com/campoy/embedmd"
|
_ "github.com/campoy/embedmd"
|
Loading…
x
Reference in New Issue
Block a user