forked from mirror/gin
Push branch develop into master
This commit is contained in:
commit
5caaac4c5c
|
@ -3,6 +3,7 @@
|
||||||
<img align="right" src="https://raw.githubusercontent.com/gin-gonic/gin/master/logo.jpg">
|
<img align="right" src="https://raw.githubusercontent.com/gin-gonic/gin/master/logo.jpg">
|
||||||
[![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin)
|
[![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin)
|
||||||
[![Coverage Status](https://coveralls.io/repos/gin-gonic/gin/badge.svg?branch=master)](https://coveralls.io/r/gin-gonic/gin?branch=master)
|
[![Coverage Status](https://coveralls.io/repos/gin-gonic/gin/badge.svg?branch=master)](https://coveralls.io/r/gin-gonic/gin?branch=master)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin)
|
||||||
[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin)
|
[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin)
|
||||||
[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package gin
|
||||||
import (
|
import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ func BenchmarkManyHandlers(B *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Benchmark5Params(B *testing.B) {
|
func Benchmark5Params(B *testing.B) {
|
||||||
DefaultWriter = newMockWriter()
|
DefaultWriter = os.Stdout
|
||||||
router := New()
|
router := New()
|
||||||
router.Use(func(c *Context) {})
|
router.Use(func(c *Context) {})
|
||||||
router.GET("/param/:param1/:params2/:param3/:param4/:param5", func(c *Context) {})
|
router.GET("/param/:param1/:params2/:param3/:param4/:param5", func(c *Context) {})
|
||||||
|
|
|
@ -13,11 +13,11 @@ import (
|
||||||
|
|
||||||
type protobufBinding struct{}
|
type protobufBinding struct{}
|
||||||
|
|
||||||
func (_ protobufBinding) Name() string {
|
func (protobufBinding) Name() string {
|
||||||
return "protobuf"
|
return "protobuf"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ protobufBinding) Bind(req *http.Request, obj interface{}) error {
|
func (protobufBinding) Bind(req *http.Request, obj interface{}) error {
|
||||||
|
|
||||||
buf, err := ioutil.ReadAll(req.Body)
|
buf, err := ioutil.ReadAll(req.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -16,15 +16,15 @@ type testInterface interface {
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type substruct_noValidation struct {
|
type substructNoValidation struct {
|
||||||
I_String string
|
IString string
|
||||||
I_Int int
|
IInt int
|
||||||
}
|
}
|
||||||
|
|
||||||
type mapNoValidationSub map[string]substruct_noValidation
|
type mapNoValidationSub map[string]substructNoValidation
|
||||||
|
|
||||||
type struct_noValidation_values struct {
|
type structNoValidationValues struct {
|
||||||
substruct_noValidation
|
substructNoValidation
|
||||||
|
|
||||||
Boolean bool
|
Boolean bool
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ type struct_noValidation_values struct {
|
||||||
|
|
||||||
Date time.Time
|
Date time.Time
|
||||||
|
|
||||||
Struct substruct_noValidation
|
Struct substructNoValidation
|
||||||
InlinedStruct struct {
|
InlinedStruct struct {
|
||||||
String []string
|
String []string
|
||||||
Integer int
|
Integer int
|
||||||
|
@ -54,8 +54,8 @@ type struct_noValidation_values struct {
|
||||||
|
|
||||||
IntSlice []int
|
IntSlice []int
|
||||||
IntPointerSlice []*int
|
IntPointerSlice []*int
|
||||||
StructPointerSlice []*substruct_noValidation
|
StructPointerSlice []*substructNoValidation
|
||||||
StructSlice []substruct_noValidation
|
StructSlice []substructNoValidation
|
||||||
InterfaceSlice []testInterface
|
InterfaceSlice []testInterface
|
||||||
|
|
||||||
UniversalInterface interface{}
|
UniversalInterface interface{}
|
||||||
|
@ -65,9 +65,9 @@ type struct_noValidation_values struct {
|
||||||
StructMap mapNoValidationSub
|
StructMap mapNoValidationSub
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNoValidation_values() struct_noValidation_values {
|
func createNoValidationValues() structNoValidationValues {
|
||||||
integer := 1
|
integer := 1
|
||||||
s := struct_noValidation_values{
|
s := structNoValidationValues{
|
||||||
Boolean: true,
|
Boolean: true,
|
||||||
Uinteger: 1 << 29,
|
Uinteger: 1 << 29,
|
||||||
Integer: -10000,
|
Integer: -10000,
|
||||||
|
@ -84,33 +84,33 @@ func createNoValidation_values() struct_noValidation_values {
|
||||||
String: "text",
|
String: "text",
|
||||||
Date: time.Time{},
|
Date: time.Time{},
|
||||||
CustomInterface: &bytes.Buffer{},
|
CustomInterface: &bytes.Buffer{},
|
||||||
Struct: substruct_noValidation{},
|
Struct: substructNoValidation{},
|
||||||
IntSlice: []int{-3, -2, 1, 0, 1, 2, 3},
|
IntSlice: []int{-3, -2, 1, 0, 1, 2, 3},
|
||||||
IntPointerSlice: []*int{&integer},
|
IntPointerSlice: []*int{&integer},
|
||||||
StructSlice: []substruct_noValidation{},
|
StructSlice: []substructNoValidation{},
|
||||||
UniversalInterface: 1.2,
|
UniversalInterface: 1.2,
|
||||||
FloatMap: map[string]float32{
|
FloatMap: map[string]float32{
|
||||||
"foo": 1.23,
|
"foo": 1.23,
|
||||||
"bar": 232.323,
|
"bar": 232.323,
|
||||||
},
|
},
|
||||||
StructMap: mapNoValidationSub{
|
StructMap: mapNoValidationSub{
|
||||||
"foo": substruct_noValidation{},
|
"foo": substructNoValidation{},
|
||||||
"bar": substruct_noValidation{},
|
"bar": substructNoValidation{},
|
||||||
},
|
},
|
||||||
// StructPointerSlice []noValidationSub
|
// StructPointerSlice []noValidationSub
|
||||||
// InterfaceSlice []testInterface
|
// InterfaceSlice []testInterface
|
||||||
}
|
}
|
||||||
s.InlinedStruct.Integer = 1000
|
s.InlinedStruct.Integer = 1000
|
||||||
s.InlinedStruct.String = []string{"first", "second"}
|
s.InlinedStruct.String = []string{"first", "second"}
|
||||||
s.I_String = "substring"
|
s.IString = "substring"
|
||||||
s.I_Int = 987654
|
s.IInt = 987654
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateNoValidationValues(t *testing.T) {
|
func TestValidateNoValidationValues(t *testing.T) {
|
||||||
origin := createNoValidation_values()
|
origin := createNoValidationValues()
|
||||||
test := createNoValidation_values()
|
test := createNoValidationValues()
|
||||||
empty := struct_noValidation_values{}
|
empty := structNoValidationValues{}
|
||||||
|
|
||||||
assert.Nil(t, validate(test))
|
assert.Nil(t, validate(test))
|
||||||
assert.Nil(t, validate(&test))
|
assert.Nil(t, validate(&test))
|
||||||
|
@ -120,8 +120,8 @@ func TestValidateNoValidationValues(t *testing.T) {
|
||||||
assert.Equal(t, origin, test)
|
assert.Equal(t, origin, test)
|
||||||
}
|
}
|
||||||
|
|
||||||
type struct_noValidation_pointer struct {
|
type structNoValidationPointer struct {
|
||||||
substruct_noValidation
|
substructNoValidation
|
||||||
|
|
||||||
Boolean bool
|
Boolean bool
|
||||||
|
|
||||||
|
@ -143,12 +143,12 @@ type struct_noValidation_pointer struct {
|
||||||
|
|
||||||
Date *time.Time
|
Date *time.Time
|
||||||
|
|
||||||
Struct *substruct_noValidation
|
Struct *substructNoValidation
|
||||||
|
|
||||||
IntSlice *[]int
|
IntSlice *[]int
|
||||||
IntPointerSlice *[]*int
|
IntPointerSlice *[]*int
|
||||||
StructPointerSlice *[]*substruct_noValidation
|
StructPointerSlice *[]*substructNoValidation
|
||||||
StructSlice *[]substruct_noValidation
|
StructSlice *[]substructNoValidation
|
||||||
InterfaceSlice *[]testInterface
|
InterfaceSlice *[]testInterface
|
||||||
|
|
||||||
FloatMap *map[string]float32
|
FloatMap *map[string]float32
|
||||||
|
@ -158,7 +158,7 @@ type struct_noValidation_pointer struct {
|
||||||
func TestValidateNoValidationPointers(t *testing.T) {
|
func TestValidateNoValidationPointers(t *testing.T) {
|
||||||
//origin := createNoValidation_values()
|
//origin := createNoValidation_values()
|
||||||
//test := createNoValidation_values()
|
//test := createNoValidation_values()
|
||||||
empty := struct_noValidation_pointer{}
|
empty := structNoValidationPointer{}
|
||||||
|
|
||||||
//assert.Nil(t, validate(test))
|
//assert.Nil(t, validate(test))
|
||||||
//assert.Nil(t, validate(&test))
|
//assert.Nil(t, validate(&test))
|
||||||
|
|
12
context.go
12
context.go
|
@ -69,7 +69,7 @@ func (c *Context) reset() {
|
||||||
// Copy returns a copy of the current context that can be safely used outside the request's scope.
|
// Copy returns a copy of the current context that can be safely used outside the request's scope.
|
||||||
// This have to be used then the context has to be passed to a goroutine.
|
// This have to be used then the context has to be passed to a goroutine.
|
||||||
func (c *Context) Copy() *Context {
|
func (c *Context) Copy() *Context {
|
||||||
var cp Context = *c
|
var cp = *c
|
||||||
cp.writermem.ResponseWriter = nil
|
cp.writermem.ResponseWriter = nil
|
||||||
cp.Writer = &cp.writermem
|
cp.Writer = &cp.writermem
|
||||||
cp.index = abortIndex
|
cp.index = abortIndex
|
||||||
|
@ -115,6 +115,7 @@ func (c *Context) Abort() {
|
||||||
// For example, a failed attempt to authentificate a request could use: context.AbortWithStatus(401).
|
// For example, a failed attempt to authentificate a request could use: context.AbortWithStatus(401).
|
||||||
func (c *Context) AbortWithStatus(code int) {
|
func (c *Context) AbortWithStatus(code int) {
|
||||||
c.Status(code)
|
c.Status(code)
|
||||||
|
c.Writer.WriteHeaderNow()
|
||||||
c.Abort()
|
c.Abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +172,7 @@ func (c *Context) Get(key string) (value interface{}, exists bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the value for the given key if it exists, otherwise it panics.
|
// MustGet returns the value for the given key if it exists, otherwise it panics.
|
||||||
func (c *Context) MustGet(key string) interface{} {
|
func (c *Context) MustGet(key string) interface{} {
|
||||||
if value, exists := c.Get(key); exists {
|
if value, exists := c.Get(key); exists {
|
||||||
return value
|
return value
|
||||||
|
@ -243,7 +244,7 @@ func (c *Context) PostForm(key string) string {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostForm returns the specified key from a POST urlencoded form or multipart form
|
// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form
|
||||||
// when it exists, otherwise it returns the specified defaultValue string.
|
// when it exists, otherwise it returns the specified defaultValue string.
|
||||||
// See: PostForm() and GetPostForm() for further information.
|
// See: PostForm() and GetPostForm() for further information.
|
||||||
func (c *Context) DefaultPostForm(key, defaultValue string) string {
|
func (c *Context) DefaultPostForm(key, defaultValue string) string {
|
||||||
|
@ -426,6 +427,11 @@ func (c *Context) XML(code int, obj interface{}) {
|
||||||
c.Render(code, render.XML{Data: obj})
|
c.Render(code, render.XML{Data: obj})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// YAML serializes the given struct as YAML into the response body.
|
||||||
|
func (c *Context) YAML(code int, obj interface{}) {
|
||||||
|
c.Render(code, render.YAML{Data: obj})
|
||||||
|
}
|
||||||
|
|
||||||
// String writes the given string into the response body.
|
// String writes the given string into the response body.
|
||||||
func (c *Context) String(code int, format string, values ...interface{}) {
|
func (c *Context) String(code int, format string, values ...interface{}) {
|
||||||
c.Status(code)
|
c.Status(code)
|
||||||
|
|
|
@ -262,14 +262,14 @@ func TestContextPostFormMultipart(t *testing.T) {
|
||||||
Bar string `form:"bar"`
|
Bar string `form:"bar"`
|
||||||
BarAsInt int `form:"bar"`
|
BarAsInt int `form:"bar"`
|
||||||
Array []string `form:"array"`
|
Array []string `form:"array"`
|
||||||
Id string `form:"id"`
|
ID string `form:"id"`
|
||||||
}
|
}
|
||||||
assert.NoError(t, c.Bind(&obj))
|
assert.NoError(t, c.Bind(&obj))
|
||||||
assert.Equal(t, obj.Foo, "bar")
|
assert.Equal(t, obj.Foo, "bar")
|
||||||
assert.Equal(t, obj.Bar, "10")
|
assert.Equal(t, obj.Bar, "10")
|
||||||
assert.Equal(t, obj.BarAsInt, 10)
|
assert.Equal(t, obj.BarAsInt, 10)
|
||||||
assert.Equal(t, obj.Array, []string{"first", "second"})
|
assert.Equal(t, obj.Array, []string{"first", "second"})
|
||||||
assert.Equal(t, obj.Id, "")
|
assert.Equal(t, obj.ID, "")
|
||||||
|
|
||||||
value, ok := c.GetQuery("foo")
|
value, ok := c.GetQuery("foo")
|
||||||
assert.False(t, ok)
|
assert.False(t, ok)
|
||||||
|
@ -433,6 +433,17 @@ func TestContextRenderFile(t *testing.T) {
|
||||||
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8")
|
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestContextRenderYAML tests that the response is serialized as YAML
|
||||||
|
// and Content-Type is set to application/x-yaml
|
||||||
|
func TestContextRenderYAML(t *testing.T) {
|
||||||
|
c, w, _ := CreateTestContext()
|
||||||
|
c.YAML(201, H{"foo": "bar"})
|
||||||
|
|
||||||
|
assert.Equal(t, w.Code, 201)
|
||||||
|
assert.Equal(t, w.Body.String(), "foo: bar\n")
|
||||||
|
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/x-yaml; charset=utf-8")
|
||||||
|
}
|
||||||
|
|
||||||
func TestContextHeaders(t *testing.T) {
|
func TestContextHeaders(t *testing.T) {
|
||||||
c, _, _ := CreateTestContext()
|
c, _, _ := CreateTestContext()
|
||||||
c.Header("Content-Type", "text/plain")
|
c.Header("Content-Type", "text/plain")
|
||||||
|
@ -545,7 +556,6 @@ func TestContextAbortWithStatus(t *testing.T) {
|
||||||
c, w, _ := CreateTestContext()
|
c, w, _ := CreateTestContext()
|
||||||
c.index = 4
|
c.index = 4
|
||||||
c.AbortWithStatus(401)
|
c.AbortWithStatus(401)
|
||||||
c.Writer.WriteHeaderNow()
|
|
||||||
|
|
||||||
assert.Equal(t, c.index, abortIndex)
|
assert.Equal(t, c.index, abortIndex)
|
||||||
assert.Equal(t, c.Writer.Status(), 401)
|
assert.Equal(t, c.Writer.Status(), 401)
|
||||||
|
@ -596,7 +606,6 @@ func TestContextTypedError(t *testing.T) {
|
||||||
func TestContextAbortWithError(t *testing.T) {
|
func TestContextAbortWithError(t *testing.T) {
|
||||||
c, w, _ := CreateTestContext()
|
c, w, _ := CreateTestContext()
|
||||||
c.AbortWithError(401, errors.New("bad input")).SetMeta("some input")
|
c.AbortWithError(401, errors.New("bad input")).SetMeta("some input")
|
||||||
c.Writer.WriteHeaderNow()
|
|
||||||
|
|
||||||
assert.Equal(t, w.Code, 401)
|
assert.Equal(t, w.Code, 401)
|
||||||
assert.Equal(t, c.index, abortIndex)
|
assert.Equal(t, c.index, abortIndex)
|
||||||
|
|
|
@ -66,7 +66,7 @@ func (msg *Error) JSON() interface{} {
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements the json.Marshaller interface
|
// MarshalJSON implements the json.Marshaller interface
|
||||||
func (msg *Error) MarshalJSON() ([]byte, error) {
|
func (msg *Error) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(msg.JSON())
|
return json.Marshal(msg.JSON())
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ func (a errorMsgs) ByType(typ ErrorType) errorMsgs {
|
||||||
if typ == ErrorTypeAny {
|
if typ == ErrorTypeAny {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
var result errorMsgs = nil
|
var result errorMsgs
|
||||||
for _, msg := range a {
|
for _, msg := range a {
|
||||||
if msg.IsType(typ) {
|
if msg.IsType(typ) {
|
||||||
result = append(result, msg)
|
result = append(result, msg)
|
||||||
|
|
|
@ -16,9 +16,9 @@ var savedStats map[string]uint64
|
||||||
|
|
||||||
func statsWorker() {
|
func statsWorker() {
|
||||||
c := time.Tick(1 * time.Second)
|
c := time.Tick(1 * time.Second)
|
||||||
var lastMallocs uint64 = 0
|
var lastMallocs uint64
|
||||||
var lastFrees uint64 = 0
|
var lastFrees uint64
|
||||||
for _ = range c {
|
for range c {
|
||||||
var stats runtime.MemStats
|
var stats runtime.MemStats
|
||||||
runtime.ReadMemStats(&stats)
|
runtime.ReadMemStats(&stats)
|
||||||
|
|
||||||
|
|
8
gin.go
8
gin.go
|
@ -14,7 +14,7 @@ import (
|
||||||
"github.com/gin-gonic/gin/render"
|
"github.com/gin-gonic/gin/render"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Framework's version
|
// Version is Framework's version
|
||||||
const Version = "v1.0rc2"
|
const Version = "v1.0rc2"
|
||||||
|
|
||||||
var default404Body = []byte("404 page not found")
|
var default404Body = []byte("404 page not found")
|
||||||
|
@ -147,19 +147,19 @@ func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
|
||||||
engine.HTMLRender = render.HTMLProduction{Template: templ}
|
engine.HTMLRender = render.HTMLProduction{Template: templ}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds handlers for NoRoute. It return a 404 code by default.
|
// NoRoute adds handlers for NoRoute. It return a 404 code by default.
|
||||||
func (engine *Engine) NoRoute(handlers ...HandlerFunc) {
|
func (engine *Engine) NoRoute(handlers ...HandlerFunc) {
|
||||||
engine.noRoute = handlers
|
engine.noRoute = handlers
|
||||||
engine.rebuild404Handlers()
|
engine.rebuild404Handlers()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the handlers called when... TODO
|
// NoMethod sets the handlers called when... TODO
|
||||||
func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
|
func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
|
||||||
engine.noMethod = handlers
|
engine.noMethod = handlers
|
||||||
engine.rebuild405Handlers()
|
engine.rebuild405Handlers()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attachs a global middleware to the router. ie. the middleware attached though Use() will be
|
// Use attachs 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...
|
// included in the handlers chain for every single request. Even 404, 405, static files...
|
||||||
// For example, this is the right place for a logger or error management middleware.
|
// For example, this is the right place for a logger or error management middleware.
|
||||||
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
|
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
|
||||||
|
|
14
ginS/gins.go
14
ginS/gins.go
|
@ -34,17 +34,17 @@ func SetHTMLTemplate(templ *template.Template) {
|
||||||
engine().SetHTMLTemplate(templ)
|
engine().SetHTMLTemplate(templ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds handlers for NoRoute. It return a 404 code by default.
|
// NoRoute adds handlers for NoRoute. It return a 404 code by default.
|
||||||
func NoRoute(handlers ...HandlerFunc) {
|
func NoRoute(handlers ...HandlerFunc) {
|
||||||
engine().NoRoute(handlers...)
|
engine().NoRoute(handlers...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the handlers called when... TODO
|
// NoMethod sets the handlers called when... TODO
|
||||||
func NoMethod(handlers ...HandlerFunc) {
|
func NoMethod(handlers ...HandlerFunc) {
|
||||||
engine().NoMethod(handlers...)
|
engine().NoMethod(handlers...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new router group. You should add all the routes that have common middlwares or the same path prefix.
|
// Group creates a new router group. You should add all the routes that have common middlwares or the same path prefix.
|
||||||
// For example, all the routes that use a common middlware for authorization could be grouped.
|
// For example, all the routes that use a common middlware for authorization could be grouped.
|
||||||
func Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
|
func Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
|
||||||
return engine().Group(relativePath, handlers...)
|
return engine().Group(relativePath, handlers...)
|
||||||
|
@ -111,28 +111,28 @@ func StaticFS(relativePath string, fs http.FileSystem) IRoutes {
|
||||||
return engine().StaticFS(relativePath, fs)
|
return engine().StaticFS(relativePath, fs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attachs a global middleware to the router. ie. the middlewares attached though Use() will be
|
// Use attachs a global middleware to the router. ie. the middlewares attached though Use() will be
|
||||||
// included in the handlers chain for every single request. Even 404, 405, static files...
|
// included in the handlers chain for every single request. Even 404, 405, static files...
|
||||||
// For example, this is the right place for a logger or error management middleware.
|
// For example, this is the right place for a logger or error management middleware.
|
||||||
func Use(middlewares ...HandlerFunc) IRoutes {
|
func Use(middlewares ...HandlerFunc) IRoutes {
|
||||||
return engine().Use(middlewares...)
|
return engine().Use(middlewares...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The router is attached to a http.Server and starts listening and serving HTTP requests.
|
// Run : The router is attached to a http.Server and starts listening and serving HTTP requests.
|
||||||
// It is a shortcut for http.ListenAndServe(addr, router)
|
// It is a shortcut for http.ListenAndServe(addr, router)
|
||||||
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
||||||
func Run(addr ...string) (err error) {
|
func Run(addr ...string) (err error) {
|
||||||
return engine().Run(addr...)
|
return engine().Run(addr...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The router is attached to a http.Server and starts listening and serving HTTPS requests.
|
// RunTLS : The router is attached to a http.Server and starts listening and serving HTTPS requests.
|
||||||
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
|
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
|
||||||
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
||||||
func RunTLS(addr string, certFile string, keyFile string) (err error) {
|
func RunTLS(addr string, certFile string, keyFile string) (err error) {
|
||||||
return engine().RunTLS(addr, certFile, keyFile)
|
return engine().RunTLS(addr, certFile, keyFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The router is attached to a http.Server and starts listening and serving HTTP requests
|
// RunUnix : The router is attached to a http.Server and starts listening and serving HTTP requests
|
||||||
// through the specified unix socket (ie. a file)
|
// through the specified unix socket (ie. a file)
|
||||||
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
||||||
func RunUnix(file string) (err error) {
|
func RunUnix(file string) (err error) {
|
||||||
|
|
24
gin_test.go
24
gin_test.go
|
@ -201,13 +201,13 @@ func compareFunc(t *testing.T, a, b interface{}) {
|
||||||
|
|
||||||
func TestListOfRoutes(t *testing.T) {
|
func TestListOfRoutes(t *testing.T) {
|
||||||
router := New()
|
router := New()
|
||||||
router.GET("/favicon.ico", handler_test1)
|
router.GET("/favicon.ico", handlerTest1)
|
||||||
router.GET("/", handler_test1)
|
router.GET("/", handlerTest1)
|
||||||
group := router.Group("/users")
|
group := router.Group("/users")
|
||||||
{
|
{
|
||||||
group.GET("/", handler_test2)
|
group.GET("/", handlerTest2)
|
||||||
group.GET("/:id", handler_test1)
|
group.GET("/:id", handlerTest1)
|
||||||
group.POST("/:id", handler_test2)
|
group.POST("/:id", handlerTest2)
|
||||||
}
|
}
|
||||||
router.Static("/static", ".")
|
router.Static("/static", ".")
|
||||||
|
|
||||||
|
@ -217,27 +217,27 @@ func TestListOfRoutes(t *testing.T) {
|
||||||
assertRoutePresent(t, list, RouteInfo{
|
assertRoutePresent(t, list, RouteInfo{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Path: "/favicon.ico",
|
Path: "/favicon.ico",
|
||||||
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handler_test1$",
|
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest1$",
|
||||||
})
|
})
|
||||||
assertRoutePresent(t, list, RouteInfo{
|
assertRoutePresent(t, list, RouteInfo{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Path: "/",
|
Path: "/",
|
||||||
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handler_test1$",
|
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest1$",
|
||||||
})
|
})
|
||||||
assertRoutePresent(t, list, RouteInfo{
|
assertRoutePresent(t, list, RouteInfo{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Path: "/users/",
|
Path: "/users/",
|
||||||
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handler_test2$",
|
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest2$",
|
||||||
})
|
})
|
||||||
assertRoutePresent(t, list, RouteInfo{
|
assertRoutePresent(t, list, RouteInfo{
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Path: "/users/:id",
|
Path: "/users/:id",
|
||||||
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handler_test1$",
|
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest1$",
|
||||||
})
|
})
|
||||||
assertRoutePresent(t, list, RouteInfo{
|
assertRoutePresent(t, list, RouteInfo{
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
Path: "/users/:id",
|
Path: "/users/:id",
|
||||||
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handler_test2$",
|
Handler: "^(.*/vendor/)?github.com/gin-gonic/gin.handlerTest2$",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,5 +251,5 @@ func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo)
|
||||||
t.Errorf("route not found: %v", wantRoute)
|
t.Errorf("route not found: %v", wantRoute)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handler_test1(c *Context) {}
|
func handlerTest1(c *Context) {}
|
||||||
func handler_test2(c *Context) {}
|
func handlerTest2(c *Context) {}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -298,7 +299,7 @@ func githubConfigRouter(router *Engine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGithubAPI(t *testing.T) {
|
func TestGithubAPI(t *testing.T) {
|
||||||
DefaultWriter = newMockWriter()
|
DefaultWriter = os.Stdout
|
||||||
router := Default()
|
router := Default()
|
||||||
githubConfigRouter(router)
|
githubConfigRouter(router)
|
||||||
|
|
||||||
|
@ -341,7 +342,7 @@ func exampleFromPath(path string) (string, Params) {
|
||||||
if start >= 0 {
|
if start >= 0 {
|
||||||
value := fmt.Sprint(rand.Intn(100000))
|
value := fmt.Sprint(rand.Intn(100000))
|
||||||
params = append(params, Param{
|
params = append(params, Param{
|
||||||
Key: path[start:len(path)],
|
Key: path[start:],
|
||||||
Value: value,
|
Value: value,
|
||||||
})
|
})
|
||||||
output.WriteString(value)
|
output.WriteString(value)
|
||||||
|
@ -357,7 +358,7 @@ func BenchmarkGithub(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkParallelGithub(b *testing.B) {
|
func BenchmarkParallelGithub(b *testing.B) {
|
||||||
DefaultWriter = newMockWriter()
|
DefaultWriter = os.Stdout
|
||||||
router := New()
|
router := New()
|
||||||
githubConfigRouter(router)
|
githubConfigRouter(router)
|
||||||
|
|
||||||
|
@ -373,7 +374,7 @@ func BenchmarkParallelGithub(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkParallelGithubDefault(b *testing.B) {
|
func BenchmarkParallelGithubDefault(b *testing.B) {
|
||||||
DefaultWriter = newMockWriter()
|
DefaultWriter = os.Stdout
|
||||||
router := Default()
|
router := Default()
|
||||||
githubConfigRouter(router)
|
githubConfigRouter(router)
|
||||||
|
|
||||||
|
|
13
logger.go
13
logger.go
|
@ -28,23 +28,20 @@ func ErrorLogger() HandlerFunc {
|
||||||
func ErrorLoggerT(typ ErrorType) HandlerFunc {
|
func ErrorLoggerT(typ ErrorType) HandlerFunc {
|
||||||
return func(c *Context) {
|
return func(c *Context) {
|
||||||
c.Next()
|
c.Next()
|
||||||
// avoid writting if we already wrote into the response body
|
errors := c.Errors.ByType(typ)
|
||||||
if !c.Writer.Written() {
|
if len(errors) > 0 {
|
||||||
errors := c.Errors.ByType(typ)
|
c.JSON(-1, errors)
|
||||||
if len(errors) > 0 {
|
|
||||||
c.JSON(-1, errors)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instances a Logger middleware that will write the logs to gin.DefaultWriter
|
// Logger instances a Logger middleware that will write the logs to gin.DefaultWriter
|
||||||
// By default gin.DefaultWriter = os.Stdout
|
// By default gin.DefaultWriter = os.Stdout
|
||||||
func Logger() HandlerFunc {
|
func Logger() HandlerFunc {
|
||||||
return LoggerWithWriter(DefaultWriter)
|
return LoggerWithWriter(DefaultWriter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instance a Logger middleware with the specified writter buffer.
|
// LoggerWithWriter instance a Logger middleware with the specified writter buffer.
|
||||||
// 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 {
|
||||||
var skip map[string]struct{}
|
var skip map[string]struct{}
|
||||||
|
|
|
@ -116,7 +116,7 @@ func TestErrorLogger(t *testing.T) {
|
||||||
|
|
||||||
w = performRequest(router, "GET", "/print")
|
w = performRequest(router, "GET", "/print")
|
||||||
assert.Equal(t, w.Code, 500)
|
assert.Equal(t, w.Code, 500)
|
||||||
assert.Equal(t, w.Body.String(), "hola!")
|
assert.Equal(t, w.Body.String(), "hola!{\"error\":\"this is an error\"}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSkippingPaths(t *testing.T) {
|
func TestSkippingPaths(t *testing.T) {
|
||||||
|
|
9
mode.go
9
mode.go
|
@ -5,7 +5,6 @@
|
||||||
package gin
|
package gin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
@ -31,11 +30,11 @@ const (
|
||||||
// To support coloring in Windows use:
|
// To support coloring in Windows use:
|
||||||
// import "github.com/mattn/go-colorable"
|
// import "github.com/mattn/go-colorable"
|
||||||
// gin.DefaultWriter = colorable.NewColorableStdout()
|
// gin.DefaultWriter = colorable.NewColorableStdout()
|
||||||
var DefaultWriter io.Writer = os.Stdout
|
var DefaultWriter = os.Stdout
|
||||||
var DefaultErrorWriter io.Writer = os.Stderr
|
var DefaultErrorWriter = os.Stderr
|
||||||
|
|
||||||
var ginMode int = debugCode
|
var ginMode = debugCode
|
||||||
var modeName string = DebugMode
|
var modeName = DebugMode
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
mode := os.Getenv(ENV_GIN_MODE)
|
mode := os.Getenv(ENV_GIN_MODE)
|
||||||
|
|
|
@ -39,5 +39,5 @@ func TestPanicWithAbort(t *testing.T) {
|
||||||
// RUN
|
// RUN
|
||||||
w := performRequest(router, "GET", "/recovery")
|
w := performRequest(router, "GET", "/recovery")
|
||||||
// TEST
|
// TEST
|
||||||
assert.Equal(t, w.Code, 500) // NOT SURE
|
assert.Equal(t, w.Code, 400)
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,6 @@ func (r HTML) Render(w http.ResponseWriter) error {
|
||||||
writeContentType(w, htmlContentType)
|
writeContentType(w, htmlContentType)
|
||||||
if len(r.Name) == 0 {
|
if len(r.Name) == 0 {
|
||||||
return r.Template.Execute(w, r.Data)
|
return r.Template.Execute(w, r.Data)
|
||||||
} else {
|
|
||||||
return r.Template.ExecuteTemplate(w, r.Name, r.Data)
|
|
||||||
}
|
}
|
||||||
|
return r.Template.ExecuteTemplate(w, r.Name, r.Data)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ var (
|
||||||
_ Render = HTML{}
|
_ Render = HTML{}
|
||||||
_ HTMLRender = HTMLDebug{}
|
_ HTMLRender = HTMLDebug{}
|
||||||
_ HTMLRender = HTMLProduction{}
|
_ HTMLRender = HTMLProduction{}
|
||||||
|
_ Render = YAML{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func writeContentType(w http.ResponseWriter, value []string) {
|
func writeContentType(w http.ResponseWriter, value []string) {
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package render
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type YAML struct {
|
||||||
|
Data interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var yamlContentType = []string{"application/x-yaml; charset=utf-8"}
|
||||||
|
|
||||||
|
func (r YAML) Render(w http.ResponseWriter) error {
|
||||||
|
writeContentType(w, yamlContentType)
|
||||||
|
|
||||||
|
bytes, err := yaml.Marshal(r.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write(bytes)
|
||||||
|
return nil
|
||||||
|
}
|
4
tree.go
4
tree.go
|
@ -20,7 +20,7 @@ type Param struct {
|
||||||
// It is therefore safe to read values by the index.
|
// It is therefore safe to read values by the index.
|
||||||
type Params []Param
|
type Params []Param
|
||||||
|
|
||||||
// ByName returns the value of the first Param which key matches the given name.
|
// Get returns the value of the first Param which key matches the given name.
|
||||||
// If no matching Param is found, an empty string is returned.
|
// If no matching Param is found, an empty string is returned.
|
||||||
func (ps Params) Get(name string) (string, bool) {
|
func (ps Params) Get(name string) (string, bool) {
|
||||||
for _, entry := range ps {
|
for _, entry := range ps {
|
||||||
|
@ -31,6 +31,8 @@ func (ps Params) Get(name string) (string, bool) {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ByName returns the value of the first Param which key matches the given name.
|
||||||
|
// If no matching Param is found, an empty string is returned.
|
||||||
func (ps Params) ByName(name string) (va string) {
|
func (ps Params) ByName(name string) (va string) {
|
||||||
va, _ = ps.Get(name)
|
va, _ = ps.Get(name)
|
||||||
return
|
return
|
||||||
|
|
|
@ -21,7 +21,7 @@ func printChildren(n *node, prefix string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used as a workaround since we can't compare functions or their adresses
|
// Used as a workaround since we can't compare functions or their addressses
|
||||||
var fakeHandlerValue string
|
var fakeHandlerValue string
|
||||||
|
|
||||||
func fakeHandler(val string) HandlersChain {
|
func fakeHandler(val string) HandlersChain {
|
||||||
|
|
7
utils.go
7
utils.go
|
@ -47,7 +47,7 @@ func WrapH(h http.Handler) HandlerFunc {
|
||||||
|
|
||||||
type H map[string]interface{}
|
type H map[string]interface{}
|
||||||
|
|
||||||
// Allows type H to be used with xml.Marshal
|
// MarshalXML allows type H to be used with xml.Marshal
|
||||||
func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
start.Name = xml.Name{
|
start.Name = xml.Name{
|
||||||
Space: "",
|
Space: "",
|
||||||
|
@ -143,10 +143,9 @@ func resolveAddress(addr []string) string {
|
||||||
if port := os.Getenv("PORT"); len(port) > 0 {
|
if port := os.Getenv("PORT"); len(port) > 0 {
|
||||||
debugPrint("Environment variable PORT=\"%s\"", port)
|
debugPrint("Environment variable PORT=\"%s\"", port)
|
||||||
return ":" + port
|
return ":" + port
|
||||||
} else {
|
|
||||||
debugPrint("Environment variable PORT is undefined. Using port :8080 by default")
|
|
||||||
return ":8080"
|
|
||||||
}
|
}
|
||||||
|
debugPrint("Environment variable PORT is undefined. Using port :8080 by default")
|
||||||
|
return ":8080"
|
||||||
case 1:
|
case 1:
|
||||||
return addr[0]
|
return addr[0]
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue