Merge branch 'master' into chore/v1.3.0

This commit is contained in:
Javier Provecho Fernandez 2018-08-12 20:46:30 +02:00 committed by GitHub
commit c3580351ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 97 additions and 56 deletions

View File

@ -1117,7 +1117,7 @@ func main() {
router.SetFuncMap(template.FuncMap{ router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate, "formatAsDate": formatAsDate,
}) })
router.LoadHTMLFiles("./fixtures/basic/raw.tmpl") router.LoadHTMLFiles("./testdata/template/raw.tmpl")
router.GET("/raw", func(c *gin.Context) { router.GET("/raw", func(c *gin.Context) {
c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{

View File

@ -5,7 +5,7 @@ import (
"io/ioutil" "io/ioutil"
"testing" "testing"
"github.com/gin-gonic/gin/binding/example" "github.com/gin-gonic/gin/testdata/protoexample"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
@ -55,12 +55,12 @@ func msgPackBody(t *testing.T) string {
} }
func TestBindingBodyProto(t *testing.T) { func TestBindingBodyProto(t *testing.T) {
test := example.Test{ test := protoexample.Test{
Label: proto.String("FOO"), Label: proto.String("FOO"),
} }
data, _ := proto.Marshal(&test) data, _ := proto.Marshal(&test)
req := requestWithBody("POST", "/", string(data)) req := requestWithBody("POST", "/", string(data))
form := example.Test{} form := protoexample.Test{}
body, _ := ioutil.ReadAll(req.Body) body, _ := ioutil.ReadAll(req.Body)
assert.NoError(t, ProtoBuf.BindBody(body, &form)) assert.NoError(t, ProtoBuf.BindBody(body, &form))
assert.Equal(t, test, form) assert.Equal(t, test, form)

View File

@ -14,7 +14,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/gin-gonic/gin/binding/example" "github.com/gin-gonic/gin/testdata/protoexample"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
@ -562,7 +562,7 @@ func TestBindingFormMultipartFail(t *testing.T) {
} }
func TestBindingProtoBuf(t *testing.T) { func TestBindingProtoBuf(t *testing.T) {
test := &example.Test{ test := &protoexample.Test{
Label: proto.String("yes"), Label: proto.String("yes"),
} }
data, _ := proto.Marshal(test) data, _ := proto.Marshal(test)
@ -574,7 +574,7 @@ func TestBindingProtoBuf(t *testing.T) {
} }
func TestBindingProtoBufFail(t *testing.T) { func TestBindingProtoBufFail(t *testing.T) {
test := &example.Test{ test := &protoexample.Test{
Label: proto.String("yes"), Label: proto.String("yes"),
} }
data, _ := proto.Marshal(test) data, _ := proto.Marshal(test)
@ -1156,14 +1156,14 @@ func testBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, bad
func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) { func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
assert.Equal(t, name, b.Name()) assert.Equal(t, name, b.Name())
obj := example.Test{} obj := protoexample.Test{}
req := requestWithBody("POST", path, body) req := requestWithBody("POST", path, body)
req.Header.Add("Content-Type", MIMEPROTOBUF) req.Header.Add("Content-Type", MIMEPROTOBUF)
err := b.Bind(req, &obj) err := b.Bind(req, &obj)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "yes", *obj.Label) assert.Equal(t, "yes", *obj.Label)
obj = example.Test{} obj = protoexample.Test{}
req = requestWithBody("POST", badPath, badBody) req = requestWithBody("POST", badPath, badBody)
req.Header.Add("Content-Type", MIMEPROTOBUF) req.Header.Add("Content-Type", MIMEPROTOBUF)
err = ProtoBuf.Bind(req, &obj) err = ProtoBuf.Bind(req, &obj)
@ -1179,7 +1179,7 @@ func (h hook) Read([]byte) (int, error) {
func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) { func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
assert.Equal(t, name, b.Name()) assert.Equal(t, name, b.Name())
obj := example.Test{} obj := protoexample.Test{}
req := requestWithBody("POST", path, body) req := requestWithBody("POST", path, body)
req.Body = ioutil.NopCloser(&hook{}) req.Body = ioutil.NopCloser(&hook{})
@ -1187,7 +1187,7 @@ func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body
err := b.Bind(req, &obj) err := b.Bind(req, &obj)
assert.Error(t, err) assert.Error(t, err)
obj = example.Test{} obj = protoexample.Test{}
req = requestWithBody("POST", badPath, badBody) req = requestWithBody("POST", badPath, badBody)
req.Header.Add("Content-Type", MIMEPROTOBUF) req.Header.Add("Content-Type", MIMEPROTOBUF)
err = ProtoBuf.Bind(req, &obj) err = ProtoBuf.Bind(req, &obj)

View File

@ -72,7 +72,7 @@ func TestDebugPrintLoadTemplate(t *testing.T) {
setup(&w) setup(&w)
defer teardown() defer teardown()
templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./fixtures/basic/hello.tmpl")) templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./testdata/template/hello.tmpl"))
debugPrintLoadTemplate(templ) debugPrintLoadTemplate(templ)
assert.Regexp(t, `^\[GIN-debug\] Loaded HTML Templates \(2\): \n(\t- \n|\t- hello\.tmpl\n){2}\n`, w.String()) assert.Regexp(t, `^\[GIN-debug\] Loaded HTML Templates \(2\): \n(\t- \n|\t- hello\.tmpl\n){2}\n`, w.String())
} }

View File

@ -20,7 +20,7 @@ func main() {
router.SetFuncMap(template.FuncMap{ router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate, "formatAsDate": formatAsDate,
}) })
router.LoadHTMLFiles("../../fixtures/basic/raw.tmpl") router.LoadHTMLFiles("../../testdata/template/raw.tmpl")
router.GET("/raw", func(c *gin.Context) { router.GET("/raw", func(c *gin.Context) {
c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{

69
gin.go
View File

@ -349,38 +349,40 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
// Find root of the tree for the given HTTP method // Find root of the tree for the given HTTP method
t := engine.trees t := engine.trees
for i, tl := 0, len(t); i < tl; i++ { for i, tl := 0, len(t); i < tl; i++ {
if t[i].method == httpMethod { if t[i].method != httpMethod {
root := t[i].root continue
// Find route in tree }
handlers, params, tsr := root.getValue(path, c.Params, unescape) root := t[i].root
if handlers != nil { // Find route in tree
c.handlers = handlers handlers, params, tsr := root.getValue(path, c.Params, unescape)
c.Params = params if handlers != nil {
c.Next() c.handlers = handlers
c.writermem.WriteHeaderNow() c.Params = params
c.Next()
c.writermem.WriteHeaderNow()
return
}
if httpMethod != "CONNECT" && path != "/" {
if tsr && engine.RedirectTrailingSlash {
redirectTrailingSlash(c)
return return
} }
if httpMethod != "CONNECT" && path != "/" { if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
if tsr && engine.RedirectTrailingSlash { return
redirectTrailingSlash(c)
return
}
if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
return
}
} }
break
} }
break
} }
if engine.HandleMethodNotAllowed { if engine.HandleMethodNotAllowed {
for _, tree := range engine.trees { for _, tree := range engine.trees {
if tree.method != httpMethod { if tree.method == httpMethod {
if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil { continue
c.handlers = engine.allNoMethod }
serveError(c, http.StatusMethodNotAllowed, default405Body) if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil {
return c.handlers = engine.allNoMethod
} serveError(c, http.StatusMethodNotAllowed, default405Body)
return
} }
} }
} }
@ -393,14 +395,16 @@ var mimePlain = []string{MIMEPlain}
func serveError(c *Context, code int, defaultMessage []byte) { func serveError(c *Context, code int, defaultMessage []byte) {
c.writermem.status = code c.writermem.status = code
c.Next() c.Next()
if !c.writermem.Written() { if c.writermem.Written() {
if c.writermem.Status() == code { return
c.writermem.Header()["Content-Type"] = mimePlain
c.Writer.Write(defaultMessage)
} else {
c.writermem.WriteHeaderNow()
}
} }
if c.writermem.Status() == code {
c.writermem.Header()["Content-Type"] = mimePlain
c.Writer.Write(defaultMessage)
return
}
c.writermem.WriteHeaderNow()
return
} }
func redirectTrailingSlash(c *Context) { func redirectTrailingSlash(c *Context) {
@ -411,10 +415,9 @@ func redirectTrailingSlash(c *Context) {
code = http.StatusTemporaryRedirect code = http.StatusTemporaryRedirect
} }
req.URL.Path = path + "/"
if length := len(path); length > 1 && path[length-1] == '/' { if length := len(path); length > 1 && path[length-1] == '/' {
req.URL.Path = path[:length-1] req.URL.Path = path[:length-1]
} else {
req.URL.Path = path + "/"
} }
debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String()) debugPrint("redirecting request %d: %s --> %s", code, path, req.URL.String())
http.Redirect(c.Writer, req, req.URL.String(), code) http.Redirect(c.Writer, req, req.URL.String(), code)

View File

@ -30,7 +30,7 @@ func setupHTMLFiles(t *testing.T, mode string, tls bool) func() {
router.SetFuncMap(template.FuncMap{ router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate, "formatAsDate": formatAsDate,
}) })
router.LoadHTMLFiles("./fixtures/basic/hello.tmpl", "./fixtures/basic/raw.tmpl") router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl")
router.GET("/test", func(c *Context) { router.GET("/test", func(c *Context) {
c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"}) c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
}) })
@ -41,7 +41,7 @@ func setupHTMLFiles(t *testing.T, mode string, tls bool) func() {
}) })
if tls { if tls {
// these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1` // these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1`
router.RunTLS(":9999", "./fixtures/testdata/cert.pem", "./fixtures/testdata/key.pem") router.RunTLS(":9999", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem")
} else { } else {
router.Run(":8888") router.Run(":8888")
} }
@ -59,7 +59,7 @@ func setupHTMLGlob(t *testing.T, mode string, tls bool) func() {
router.SetFuncMap(template.FuncMap{ router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate, "formatAsDate": formatAsDate,
}) })
router.LoadHTMLGlob("./fixtures/basic/*") router.LoadHTMLGlob("./testdata/template/*")
router.GET("/test", func(c *Context) { router.GET("/test", func(c *Context) {
c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"}) c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
}) })
@ -70,7 +70,7 @@ func setupHTMLGlob(t *testing.T, mode string, tls bool) func() {
}) })
if tls { if tls {
// these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1` // these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1`
router.RunTLS(":9999", "./fixtures/testdata/cert.pem", "./fixtures/testdata/key.pem") router.RunTLS(":9999", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem")
} else { } else {
router.Run(":8888") router.Run(":8888")
} }

View File

@ -158,6 +158,21 @@ func TestRenderJsonpJSON(t *testing.T) {
assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type")) assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type"))
} }
func TestRenderJsonpJSONError2(t *testing.T) {
w := httptest.NewRecorder()
data := map[string]interface{}{
"foo": "bar",
}
(JsonpJSON{"", data}).WriteContentType(w)
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
e := (JsonpJSON{"", data}).Render(w)
assert.NoError(t, e)
assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
}
func TestRenderJsonpJSONFail(t *testing.T) { func TestRenderJsonpJSONFail(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
data := make(chan int) data := make(chan int)
@ -373,7 +388,7 @@ func TestRenderHTMLTemplateEmptyName(t *testing.T) {
func TestRenderHTMLDebugFiles(t *testing.T) { func TestRenderHTMLDebugFiles(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
htmlRender := HTMLDebug{Files: []string{"../fixtures/basic/hello.tmpl"}, htmlRender := HTMLDebug{Files: []string{"../testdata/template/hello.tmpl"},
Glob: "", Glob: "",
Delims: Delims{Left: "{[{", Right: "}]}"}, Delims: Delims{Left: "{[{", Right: "}]}"},
FuncMap: nil, FuncMap: nil,
@ -392,7 +407,7 @@ func TestRenderHTMLDebugFiles(t *testing.T) {
func TestRenderHTMLDebugGlob(t *testing.T) { func TestRenderHTMLDebugGlob(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
htmlRender := HTMLDebug{Files: nil, htmlRender := HTMLDebug{Files: nil,
Glob: "../fixtures/basic/hello*", Glob: "../testdata/template/hello*",
Delims: Delims{Left: "{[{", Right: "}]}"}, Delims: Delims{Left: "{[{", Right: "}]}"},
FuncMap: nil, FuncMap: nil,
} }

View File

@ -333,6 +333,16 @@ func TestRouteNotAllowedEnabled(t *testing.T) {
assert.Equal(t, http.StatusTeapot, w.Code) assert.Equal(t, http.StatusTeapot, w.Code)
} }
func TestRouteNotAllowedEnabled2(t *testing.T) {
router := New()
router.HandleMethodNotAllowed = true
// add one methodTree to trees
router.addRoute("POST", "/", HandlersChain{func(_ *Context) {}})
router.GET("/path2", func(c *Context) {})
w := performRequest(router, "POST", "/path2")
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
}
func TestRouteNotAllowedDisabled(t *testing.T) { func TestRouteNotAllowedDisabled(t *testing.T) {
router := New() router := New()
router.HandleMethodNotAllowed = false router.HandleMethodNotAllowed = false

View File

@ -3,7 +3,7 @@
// DO NOT EDIT! // DO NOT EDIT!
/* /*
Package example is a generated protocol buffer package. Package protoexample is a generated protocol buffer package.
It is generated from these files: It is generated from these files:
test.proto test.proto
@ -11,7 +11,7 @@ It is generated from these files:
It has these top-level messages: It has these top-level messages:
Test Test
*/ */
package example package protoexample
import proto "github.com/golang/protobuf/proto" import proto "github.com/golang/protobuf/proto"
import math "math" import math "math"
@ -109,5 +109,5 @@ func (m *Test_OptionalGroup) GetRequiredField() string {
} }
func init() { func init() {
proto.RegisterEnum("example.FOO", FOO_name, FOO_value) proto.RegisterEnum("protoexample.FOO", FOO_name, FOO_value)
} }

View File

@ -1,4 +1,4 @@
package example; package protoexample;
enum FOO {X=17;}; enum FOO {X=17;};

View File

@ -5,6 +5,8 @@
package gin package gin
import ( import (
"bytes"
"encoding/xml"
"fmt" "fmt"
"net/http" "net/http"
"testing" "testing"
@ -124,3 +126,14 @@ func TestBindMiddleware(t *testing.T) {
Bind(&bindTestStruct{}) Bind(&bindTestStruct{})
}) })
} }
func TestMarshalXMLforH(t *testing.T) {
h := H{
"": "test",
}
var b bytes.Buffer
enc := xml.NewEncoder(&b)
var x xml.StartElement
e := h.MarshalXML(enc, x)
assert.Error(t, e)
}