update gin to v1.2

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
Bo-Yi Wu 2017-08-04 10:43:13 +08:00
parent 6864ffe9f0
commit b9104de2c5
21 changed files with 237 additions and 414 deletions

View File

@ -1,46 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at teamgingonic@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -1,13 +0,0 @@
## Contributing
- With issues:
- Use the search tool before opening a new issue.
- Please provide source code and commit sha if you found a bug.
- Review existing issues and provide feedback or react to them.
- With pull requests:
- Open your pull request against `master`
- Your pull request should have no more than two commits, if not you should squash them.
- It should pass all tests in the available continuous integrations systems such as TravisCI.
- You should add/modify tests to cover your proposed code changes.
- If your pull request contains a new feature, please document it on the README.

View File

@ -1,6 +1,6 @@
# Gin Web Framework # Gin Web Framework
<img align="right" width="159px" src="https://raw.githubusercontent.com/gin-gonic/logo/master/color.png"> <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)
[![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin) [![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin)
@ -13,8 +13,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
![Gin console logger](https://gin-gonic.github.io/gin/other/console.png) ![Gin console logger](https://gin-gonic.github.io/gin/other/console.png)
```sh ```sh
# assume the following codes in example.go file $ cat test.go
$ cat example.go
``` ```
```go ```go
@ -33,11 +32,6 @@ func main() {
} }
``` ```
```
# run example.go and visit 0.0.0.0:8080/ping on browser
$ go run example.go
```
## Benchmarks ## Benchmarks
Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter) Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httprouter)
@ -109,38 +103,6 @@ import "github.com/gin-gonic/gin"
import "net/http" import "net/http"
``` ```
### Use a vendor tool like [Govendor](https://github.com/kardianos/govendor)
1. `go get` govendor
```sh
$ go get github.com/kardianos/govendor
```
2. Create your project folder and `cd` inside
```sh
$ mkdir -p ~/go/src/github.com/myusername/project && cd "$_"
```
3. Vendor init your project and add gin
```sh
$ govendor init
$ govendor fetch github.com/gin-gonic/gin@v1.2
```
4. Copy a starting template inside your project
```sh
$ curl https://raw.githubusercontent.com/gin-gonic/gin/master/examples/basic/main.go > main.go
```
5. Run your project
```sh
$ go run main.go
```
## API Examples ## API Examples
### Using GET, POST, PUT, PATCH, DELETE and OPTIONS ### Using GET, POST, PUT, PATCH, DELETE and OPTIONS
@ -276,7 +238,7 @@ func main() {
file, _ := c.FormFile("file") file, _ := c.FormFile("file")
log.Println(file.Filename) log.Println(file.Filename)
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) c.String(http.StatusOK, fmt.Printf("'%s' uploaded!", file.Filename))
}) })
router.Run(":8080") router.Run(":8080")
} }
@ -305,7 +267,7 @@ func main() {
for _, file := range files { for _, file := range files {
log.Println(file.Filename) log.Println(file.Filename)
} }
c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files))) c.String(http.StatusOK, fmt.Printf("%d files uploaded!", len(files)))
}) })
router.Run(":8080") router.Run(":8080")
} }
@ -471,7 +433,7 @@ func startPage(c *gin.Context) {
var person Person var person Person
// If `GET`, only `Form` binding engine (`query`) used. // If `GET`, only `Form` binding engine (`query`) used.
// If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`). // If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`).
// See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48 // See more at https://github.com/gin-gonic/gin/blob/develop/binding/binding.go#L45
if c.Bind(&person) == nil { if c.Bind(&person) == nil {
log.Println(person.Name) log.Println(person.Name)
log.Println(person.Address) log.Println(person.Address)
@ -481,52 +443,6 @@ func startPage(c *gin.Context) {
} }
``` ```
### Bind HTML checkboxes
See the [detail information](https://github.com/gin-gonic/gin/issues/129#issuecomment-124260092)
main.go
```go
...
type myForm struct {
Colors []string `form:"colors[]"`
}
...
func formHandler(c *gin.Context) {
var fakeForm myForm
c.Bind(&fakeForm)
c.JSON(200, gin.H{"color": fakeForm.Colors})
}
...
```
form.html
```html
<form action="/" method="POST">
<p>Check some colors</p>
<label for="red">Red</label>
<input type="checkbox" name="colors[]" value="red" id="red" />
<label for="green">Green</label>
<input type="checkbox" name="colors[]" value="green" id="green" />
<label for="blue">Blue</label>
<input type="checkbox" name="colors[]" value="blue" id="blue" />
<input type="submit" />
</form>
```
result:
```
{"color":["red","green","blue"]}
```
### Multipart/Urlencoded binding ### Multipart/Urlencoded binding
```go ```go
@ -605,29 +521,6 @@ func main() {
} }
``` ```
#### SecureJSON
Using SecureJSON to prevent json hijacking. Default prepends `"while(1),"` to response body if the given struct is array values.
```go
func main() {
r := gin.Default()
// You can also use your own secure json prefix
// r.SecureJsonPrefix(")]}',\n")
r.GET("/someJSON", func(c *gin.Context) {
names := []string{"lena", "austin", "foo"}
// Will output : while(1);["lena","austin","foo"]
c.SecureJSON(http.StatusOK, names)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
### Serving static files ### Serving static files
```go ```go
@ -714,8 +607,6 @@ templates/users/index.tmpl
{{ end }} {{ end }}
``` ```
#### Custom Template renderer
You can also use your own html template render You can also use your own html template render
```go ```go
@ -729,8 +620,6 @@ func main() {
} }
``` ```
#### Custom Delimiters
You may use custom delims You may use custom delims
```go ```go
@ -739,7 +628,7 @@ You may use custom delims
r.LoadHTMLGlob("/path/to/templates")) r.LoadHTMLGlob("/path/to/templates"))
``` ```
#### Custom Template Funcs #### Add custom template funcs
main.go main.go
@ -989,7 +878,7 @@ func main() {
Cache: autocert.DirCache("/var/www/.cache"), Cache: autocert.DirCache("/var/www/.cache"),
} }
log.Fatal(autotls.RunWithManager(r, &m)) log.Fatal(autotls.RunWithManager(r, m))
} }
``` ```
@ -1067,7 +956,20 @@ func main() {
} }
``` ```
## Users [![Sourcegraph](https://sourcegraph.com/github.com/gin-gonic/gin/-/badge.svg)](https://sourcegraph.com/github.com/gin-gonic/gin?badge) ## Contributing
- With issues:
- Use the search tool before opening a new issue.
- Please provide source code and commit sha if you found a bug.
- Review existing issues and provide feedback or react to them.
- With pull requests:
- Open your pull request against develop
- Your pull request should have no more than two commits, if not you should squash them.
- It should pass all tests in the available continuous integrations systems such as TravisCI.
- You should add/modify tests to cover your proposed code changes.
- If your pull request contains a new feature, please document it on the README.
## Users
Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework. Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework.

View File

@ -10,18 +10,16 @@ import (
"strconv" "strconv"
) )
// AuthUserKey is the cookie name for user credential in basic auth
const AuthUserKey = "user" const AuthUserKey = "user"
// Accounts defines a key/value for user/pass list of authorized logins type (
type Accounts map[string]string Accounts map[string]string
authPair struct {
type authPair struct {
Value string Value string
User string User string
} }
authPairs []authPair
type authPairs []authPair )
func (a authPairs) searchCredential(authValue string) (string, bool) { func (a authPairs) searchCredential(authValue string) (string, bool) {
if len(authValue) == 0 { if len(authValue) == 0 {
@ -89,6 +87,6 @@ func secureCompare(given, actual string) bool {
if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 { if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 {
return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1 return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1
} }
// Securely compare actual to itself to keep constant time, but always return false /* Securely compare actual to itself to keep constant time, but always return false */
return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false
} }

View File

@ -49,14 +49,8 @@ type Context struct {
index int8 index int8
engine *Engine engine *Engine
// Keys is a key/value pair exclusively for the context of each request
Keys map[string]interface{} Keys map[string]interface{}
// Errors is a list of errors attached to all the handlers/middlewares who used this context
Errors errorMsgs Errors errorMsgs
// Accepted defines a list of manually accepted formats for content negotiation
Accepted []string Accepted []string
} }
@ -85,8 +79,8 @@ func (c *Context) Copy() *Context {
return &cp return &cp
} }
// HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()", // HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()", this
// this function will return "main.handleGetUsers" // function will return "main.handleGetUsers"
func (c *Context) HandlerName() string { func (c *Context) HandlerName() string {
return nameOfFunction(c.handlers.Last()) return nameOfFunction(c.handlers.Last())
} }
@ -117,8 +111,8 @@ func (c *Context) IsAborted() bool {
} }
// Abort prevents pending handlers from being called. Note that this will not stop the current handler. // Abort prevents pending handlers from being called. Note that this will not stop the current handler.
// Let's say you have an authorization middleware that validates that the current request is authorized. // Let's say you have an authorization middleware that validates that the current request is authorized. If the
// If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers // authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers
// for this request are not called. // for this request are not called.
func (c *Context) Abort() { func (c *Context) Abort() {
c.index = abortIndex c.index = abortIndex
@ -132,16 +126,15 @@ func (c *Context) AbortWithStatus(code int) {
c.Abort() c.Abort()
} }
// AbortWithStatusJSON calls `Abort()` and then `JSON` internally. // AbortWithStatusJSON calls `Abort()` and then `JSON` internally. This method stops the chain, writes the status code and return a JSON body
// This method stops the chain, writes the status code and return a JSON body.
// It also sets the Content-Type as "application/json". // It also sets the Content-Type as "application/json".
func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) { func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) {
c.Abort() c.Abort()
c.JSON(code, jsonObj) c.JSON(code, jsonObj)
} }
// AbortWithError calls `AbortWithStatus()` and `Error()` internally. // AbortWithError calls `AbortWithStatus()` and `Error()` internally. This method stops the chain, writes the status code and
// This method stops the chain, writes the status code and pushes the specified error to `c.Errors`. // pushes the specified error to `c.Errors`.
// See Context.Error() for more details. // See Context.Error() for more details.
func (c *Context) AbortWithError(code int, err error) *Error { func (c *Context) AbortWithError(code int, err error) *Error {
c.AbortWithStatus(code) c.AbortWithStatus(code)
@ -152,15 +145,11 @@ func (c *Context) AbortWithError(code int, err error) *Error {
/********* ERROR MANAGEMENT *********/ /********* ERROR MANAGEMENT *********/
/************************************/ /************************************/
// Error attaches an error to the current context. The error is pushed to a list of errors. // Attaches an error to the current context. The error is pushed to a list of errors.
// It's a good idea to call Error for each error that occurred during the resolution of a request. // It's a good idea to call Error for each error that occurred during the resolution of a request.
// A middleware can be used to collect all the errors and push them to a database together, // A middleware can be used to collect all the errors
// print a log, or append it in the HTTP response. // and push them to a database together, print a log, or append it in the HTTP response.
// Error will panic if err is nil.
func (c *Context) Error(err error) *Error { func (c *Context) Error(err error) *Error {
if err == nil {
panic("err is nil")
}
var parsedError *Error var parsedError *Error
switch err.(type) { switch err.(type) {
case *Error: case *Error:
@ -563,7 +552,15 @@ func (c *Context) GetRawData() ([]byte, error) {
return ioutil.ReadAll(c.Request.Body) return ioutil.ReadAll(c.Request.Body)
} }
func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) { func (c *Context) SetCookie(
name string,
value string,
maxAge int,
path string,
domain string,
secure bool,
httpOnly bool,
) {
if path == "" { if path == "" {
path = "/" path = "/"
} }
@ -617,13 +614,6 @@ func (c *Context) IndentedJSON(code int, obj interface{}) {
c.Render(code, render.IndentedJSON{Data: obj}) c.Render(code, render.IndentedJSON{Data: obj})
} }
// SecureJSON serializes the given struct as Secure JSON into the response body.
// Default prepends "while(1)," to response body if the given struct is array values.
// It also sets the Content-Type as "application/json".
func (c *Context) SecureJSON(code int, obj interface{}) {
c.Render(code, render.SecureJSON{Prefix: c.engine.secureJsonPrefix, Data: obj})
}
// JSON serializes the given struct as JSON into the response body. // JSON serializes the given struct as JSON into the response body.
// It also sets the Content-Type as "application/json". // It also sets the Content-Type as "application/json".
func (c *Context) JSON(code int, obj interface{}) { func (c *Context) JSON(code int, obj interface{}) {

View File

@ -15,7 +15,7 @@ func init() {
} }
// IsDebugging returns true if the framework is running in debug mode. // IsDebugging returns true if the framework is running in debug mode.
// Use SetMode(gin.Release) to disable debug mode. // Use SetMode(gin.Release) to switch to disable the debug mode.
func IsDebugging() bool { func IsDebugging() bool {
return ginMode == debugCode return ginMode == debugCode
} }

View File

@ -5,11 +5,15 @@
package gin package gin
import ( import (
"log"
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
"log"
) )
func (c *Context) GetCookie(name string) (string, error) {
log.Println("GetCookie() method is deprecated. Use Cookie() instead.")
return c.Cookie(name)
}
// BindWith binds the passed struct pointer using the specified binding engine. // BindWith binds the passed struct pointer using the specified binding engine.
// See the binding package. // See the binding package.
func (c *Context) BindWith(obj interface{}, b binding.Binding) error { func (c *Context) BindWith(obj interface{}, b binding.Binding) error {

View File

@ -1,6 +0,0 @@
/*
Package gin implements a HTTP web framework called gin.
See https://gin-gonic.github.io/gin/ for more information about gin.
*/
package gin // import "github.com/gin-gonic/gin"

View File

@ -6,14 +6,11 @@ package gin
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"reflect" "reflect"
"github.com/json-iterator/go"
) )
var json = jsoniter.ConfigCompatibleWithStandardLibrary
type ErrorType uint64 type ErrorType uint64
const ( const (
@ -26,13 +23,15 @@ const (
ErrorTypeNu = 2 ErrorTypeNu = 2
) )
type Error struct { type (
Error struct {
Err error Err error
Type ErrorType Type ErrorType
Meta interface{} Meta interface{}
} }
type errorMsgs []*Error errorMsgs []*Error
)
var _ error = &Error{} var _ error = &Error{}
@ -72,7 +71,7 @@ func (msg *Error) MarshalJSON() ([]byte, error) {
return json.Marshal(msg.JSON()) return json.Marshal(msg.JSON())
} }
// Error implements the error interface // Implements the error interface
func (msg Error) Error() string { func (msg Error) Error() string {
return msg.Err.Error() return msg.Err.Error()
} }
@ -81,7 +80,7 @@ func (msg *Error) IsType(flags ErrorType) bool {
return (msg.Type & flags) > 0 return (msg.Type & flags) > 0
} }
// ByType returns a readonly copy filtered the byte. // Returns a readonly copy filtered the byte.
// ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic // ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic
func (a errorMsgs) ByType(typ ErrorType) errorMsgs { func (a errorMsgs) ByType(typ ErrorType) errorMsgs {
if len(a) == 0 { if len(a) == 0 {
@ -99,16 +98,17 @@ func (a errorMsgs) ByType(typ ErrorType) errorMsgs {
return result return result
} }
// Last returns the last error in the slice. It returns nil if the array is empty. // Returns the last error in the slice. It returns nil if the array is empty.
// Shortcut for errors[len(errors)-1] // Shortcut for errors[len(errors)-1]
func (a errorMsgs) Last() *Error { func (a errorMsgs) Last() *Error {
if length := len(a); length > 0 { length := len(a)
if length > 0 {
return a[length-1] return a[length-1]
} }
return nil return nil
} }
// Errors returns an array will all the error messages. // Returns an array will all the error messages.
// Example: // Example:
// c.Error(errors.New("first")) // c.Error(errors.New("first"))
// c.Error(errors.New("second")) // c.Error(errors.New("second"))

View File

@ -9,13 +9,14 @@ import (
"os" "os"
) )
type onlyfilesFS struct { type (
onlyfilesFS struct {
fs http.FileSystem fs http.FileSystem
} }
neuteredReaddirFile struct {
type neuteredReaddirFile struct {
http.File http.File
} }
)
// Dir returns a http.Filesystem that can be used by http.FileServer(). It is used internally // Dir returns a http.Filesystem that can be used by http.FileServer(). It is used internally
// in router.Static(). // in router.Static().
@ -29,7 +30,7 @@ func Dir(root string, listDirectory bool) http.FileSystem {
return &onlyfilesFS{fs} return &onlyfilesFS{fs}
} }
// Open conforms to http.Filesystem // Conforms to http.Filesystem
func (fs onlyfilesFS) Open(name string) (http.File, error) { func (fs onlyfilesFS) Open(name string) (http.File, error) {
f, err := fs.fs.Open(name) f, err := fs.fs.Open(name)
if err != nil { if err != nil {
@ -38,7 +39,7 @@ func (fs onlyfilesFS) Open(name string) (http.File, error) {
return neuteredReaddirFile{f}, nil return neuteredReaddirFile{f}, nil
} }
// Readdir overrides the http.File default implementation // Overrides the http.File default implementation
func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) { func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
// this disables directory listing // this disables directory listing
return nil, nil return nil, nil

View File

@ -26,26 +26,26 @@ type HandlersChain []HandlerFunc
// Last returns the last handler in the chain. ie. the last handler is the main own. // Last returns the last handler in the chain. ie. the last handler is the main own.
func (c HandlersChain) Last() HandlerFunc { func (c HandlersChain) Last() HandlerFunc {
if length := len(c); length > 0 { length := len(c)
if length > 0 {
return c[length-1] return c[length-1]
} }
return nil return nil
} }
type RouteInfo struct { type (
RoutesInfo []RouteInfo
RouteInfo struct {
Method string Method string
Path string Path string
Handler string Handler string
} }
type RoutesInfo []RouteInfo // Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
// Create an instance of Engine, by using New() or Default()
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings. Engine struct {
// Create an instance of Engine, by using New() or Default()
type Engine struct {
RouterGroup RouterGroup
delims render.Delims delims render.Delims
secureJsonPrefix string
HTMLRender render.HTMLRender HTMLRender render.HTMLRender
FuncMap template.FuncMap FuncMap template.FuncMap
allNoRoute HandlersChain allNoRoute HandlersChain
@ -92,7 +92,8 @@ type Engine struct {
// If UseRawPath is false (by default), the UnescapePathValues effectively is true, // If UseRawPath is false (by default), the UnescapePathValues effectively is true,
// as url.Path gonna be used, which is already unescaped. // as url.Path gonna be used, which is already unescaped.
UnescapePathValues bool UnescapePathValues bool
} }
)
var _ IRouter = &Engine{} var _ IRouter = &Engine{}
@ -122,7 +123,6 @@ func New() *Engine {
UnescapePathValues: true, UnescapePathValues: true,
trees: make(methodTrees, 0, 9), trees: make(methodTrees, 0, 9),
delims: render.Delims{"{{", "}}"}, delims: render.Delims{"{{", "}}"},
secureJsonPrefix: "while(1);",
} }
engine.RouterGroup.engine = engine engine.RouterGroup.engine = engine
engine.pool.New = func() interface{} { engine.pool.New = func() interface{} {
@ -147,11 +147,6 @@ func (engine *Engine) Delims(left, right string) *Engine {
return engine return engine
} }
func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
engine.secureJsonPrefix = prefix
return engine
}
func (engine *Engine) LoadHTMLGlob(pattern string) { func (engine *Engine) LoadHTMLGlob(pattern string) {
if IsDebugging() { if IsDebugging() {
debugPrintLoadTemplate(template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseGlob(pattern))) debugPrintLoadTemplate(template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseGlob(pattern)))
@ -291,7 +286,7 @@ func (engine *Engine) RunUnix(file string) (err error) {
return return
} }
// ServeHTTP conforms to the http.Handler interface. // Conforms to the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := engine.pool.Get().(*Context) c := engine.pool.Get().(*Context)
c.writermem.reset(w) c.writermem.reset(w)
@ -303,7 +298,7 @@ func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
engine.pool.Put(c) engine.pool.Put(c)
} }
// HandleContext re-enter a context that has been rewritten. // Re-enter a context that has been rewritten.
// This can be done by setting c.Request.Path to your new target. // This can be done by setting c.Request.Path to your new target.
// Disclaimer: You can loop yourself to death with this, use wisely. // Disclaimer: You can loop yourself to death with this, use wisely.
func (engine *Engine) HandleContext(c *Context) { func (engine *Engine) HandleContext(c *Context) {
@ -351,6 +346,7 @@ func (engine *Engine) handleHTTPRequest(context *Context) {
} }
} }
// TODO: unit test
if engine.HandleMethodNotAllowed { if engine.HandleMethodNotAllowed {
for _, tree := range engine.trees { for _, tree := range engine.trees {
if tree.method != httpMethod { if tree.method != httpMethod {

View File

@ -25,17 +25,14 @@ var (
disableColor = false disableColor = false
) )
// DisableConsoleColor disables color output in the console
func DisableConsoleColor() { func DisableConsoleColor() {
disableColor = true disableColor = true
} }
// ErrorLogger returns a handlerfunc for any error type
func ErrorLogger() HandlerFunc { func ErrorLogger() HandlerFunc {
return ErrorLoggerT(ErrorTypeAny) return ErrorLoggerT(ErrorTypeAny)
} }
// ErrorLoggerT returns a handlerfunc for a given error type
func ErrorLoggerT(typ ErrorType) HandlerFunc { func ErrorLoggerT(typ ErrorType) HandlerFunc {
return func(c *Context) { return func(c *Context) {
c.Next() c.Next()
@ -77,7 +74,6 @@ func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
// Start timer // Start timer
start := time.Now() start := time.Now()
path := c.Request.URL.Path path := c.Request.URL.Path
raw := c.Request.URL.RawQuery
// Process request // Process request
c.Next() c.Next()
@ -98,10 +94,6 @@ func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
} }
comment := c.Errors.ByType(ErrorTypePrivate).String() comment := c.Errors.ByType(ErrorTypePrivate).String()
if raw != "" {
path = path + "?" + raw
}
fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %15s |%s %s %-7s %s\n%s", fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %15s |%s %s %-7s %s\n%s",
end.Format("2006/01/02 - 15:04:05"), end.Format("2006/01/02 - 15:04:05"),
statusColor, statusCode, reset, statusColor, statusCode, reset,

BIN
vendor/github.com/gin-gonic/gin/logo.jpg generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -64,10 +64,6 @@ func DisableBindValidation() {
binding.Validator = nil binding.Validator = nil
} }
func EnableJsonDecoderUseNumber() {
binding.EnableDecoderUseNumber = true
}
func Mode() string { func Mode() string {
return modeName return modeName
} }

View File

@ -5,7 +5,7 @@
package gin package gin
// cleanPath is the URL version of path.Clean, it returns a canonical URL path // CleanPath is the URL version of path.Clean, it returns a canonical URL path
// for p, eliminating . and .. elements. // for p, eliminating . and .. elements.
// //
// The following rules are applied iteratively until no further processing can // The following rules are applied iteratively until no further processing can

View File

@ -16,7 +16,8 @@ const (
defaultStatus = 200 defaultStatus = 200
) )
type ResponseWriter interface { type (
ResponseWriter interface {
http.ResponseWriter http.ResponseWriter
http.Hijacker http.Hijacker
http.Flusher http.Flusher
@ -37,13 +38,14 @@ type ResponseWriter interface {
// Forces to write the http header (status code + headers). // Forces to write the http header (status code + headers).
WriteHeaderNow() WriteHeaderNow()
} }
type responseWriter struct { responseWriter struct {
http.ResponseWriter http.ResponseWriter
size int size int
status int status int
} }
)
var _ ResponseWriter = &responseWriter{} var _ ResponseWriter = &responseWriter{}
@ -95,7 +97,7 @@ func (w *responseWriter) Written() bool {
return w.size != noWritten return w.size != noWritten
} }
// Hijack implements the http.Hijacker interface // Implements the http.Hijacker interface
func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if w.size < 0 { if w.size < 0 {
w.size = 0 w.size = 0
@ -103,12 +105,12 @@ func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return w.ResponseWriter.(http.Hijacker).Hijack() return w.ResponseWriter.(http.Hijacker).Hijack()
} }
// CloseNotify implements the http.CloseNotify interface // Implements the http.CloseNotify interface
func (w *responseWriter) CloseNotify() <-chan bool { func (w *responseWriter) CloseNotify() <-chan bool {
return w.ResponseWriter.(http.CloseNotifier).CloseNotify() return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
} }
// Flush implements the http.Flush interface // Implements the http.Flush interface
func (w *responseWriter) Flush() { func (w *responseWriter) Flush() {
w.ResponseWriter.(http.Flusher).Flush() w.ResponseWriter.(http.Flusher).Flush()
} }

View File

@ -11,12 +11,13 @@ import (
"strings" "strings"
) )
type IRouter interface { type (
IRouter interface {
IRoutes IRoutes
Group(string, ...HandlerFunc) *RouterGroup Group(string, ...HandlerFunc) *RouterGroup
} }
type IRoutes interface { IRoutes interface {
Use(...HandlerFunc) IRoutes Use(...HandlerFunc) IRoutes
Handle(string, string, ...HandlerFunc) IRoutes Handle(string, string, ...HandlerFunc) IRoutes
@ -32,16 +33,17 @@ type IRoutes interface {
StaticFile(string, string) IRoutes StaticFile(string, string) IRoutes
Static(string, string) IRoutes Static(string, string) IRoutes
StaticFS(string, http.FileSystem) IRoutes StaticFS(string, http.FileSystem) IRoutes
} }
// RouterGroup is used internally to configure router, a RouterGroup is associated with a prefix // RouterGroup is used internally to configure router, a RouterGroup is associated with a prefix
// and an array of handlers (middleware) // and an array of handlers (middleware)
type RouterGroup struct { RouterGroup struct {
Handlers HandlersChain Handlers HandlersChain
basePath string basePath string
engine *Engine engine *Engine
root bool root bool
} }
)
var _ IRouter = &RouterGroup{} var _ IRouter = &RouterGroup{}

View File

@ -8,7 +8,6 @@ import (
"net/http" "net/http"
) )
// CreateTestContext returns a fresh engine and context for testing purposes
func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) { func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) {
r = New() r = New()
c = r.allocateContext() c = r.allocateContext()

View File

@ -105,7 +105,9 @@ func (n *node) incrementChildPrio(pos int) int {
newPos := pos newPos := pos
for newPos > 0 && n.children[newPos-1].priority < prio { for newPos > 0 && n.children[newPos-1].priority < prio {
// swap node positions // swap node positions
n.children[newPos-1], n.children[newPos] = n.children[newPos], n.children[newPos-1] tmpN := n.children[newPos-1]
n.children[newPos-1] = n.children[newPos]
n.children[newPos] = tmpN
newPos-- newPos--
} }
@ -357,7 +359,7 @@ func (n *node) insertChild(numParams uint8, path string, fullPath string, handle
n.handlers = handlers n.handlers = handlers
} }
// getValue returns the handle registered with the given path (key). The values of // Returns the handle registered with the given path (key). The values of
// wildcards are saved to a map. // wildcards are saved to a map.
// If no handle can be found, a TSR (trailing slash redirect) recommendation is // If no handle can be found, a TSR (trailing slash redirect) recommendation is
// made if a handle exists with an extra (without the) trailing slash for the // made if a handle exists with an extra (without the) trailing slash for the
@ -499,7 +501,7 @@ walk: // Outer loop for walking the tree
} }
} }
// findCaseInsensitivePath makes a case-insensitive lookup of the given path and tries to find a handler. // Makes a case-insensitive lookup of the given path and tries to find a handler.
// It can optionally also fix trailing slashes. // It can optionally also fix trailing slashes.
// It returns the case-corrected path and a bool indicating whether the lookup // It returns the case-corrected path and a bool indicating whether the lookup
// was successful. // was successful.

View File

@ -100,10 +100,12 @@ func parseAccept(acceptHeader string) []string {
parts := strings.Split(acceptHeader, ",") parts := strings.Split(acceptHeader, ",")
out := make([]string, 0, len(parts)) out := make([]string, 0, len(parts))
for _, part := range parts { for _, part := range parts {
if index := strings.IndexByte(part, ';'); index >= 0 { index := strings.IndexByte(part, ';')
if index >= 0 {
part = part[0:index] part = part[0:index]
} }
if part = strings.TrimSpace(part); len(part) > 0 { part = strings.TrimSpace(part)
if len(part) > 0 {
out = append(out, part) out = append(out, part)
} }
} }

8
vendor/vendor.json vendored
View File

@ -129,10 +129,12 @@
"revisionTime": "2017-01-09T09:34:21Z" "revisionTime": "2017-01-09T09:34:21Z"
}, },
{ {
"checksumSHA1": "YYaHHK72ywsjJG11nEnz6JdGqSg=", "checksumSHA1": "cpELhz30Sco7IBwvI6FyuShnjnQ=",
"path": "github.com/gin-gonic/gin", "path": "github.com/gin-gonic/gin",
"revision": "5cb25a6410a299dcc31e7f31b41c60c90e30b3f6", "revision": "d459835d2b077e44f7c9b453505ee29881d5d12d",
"revisionTime": "2017-07-14T17:28:16Z" "revisionTime": "2017-07-02T09:28:26Z",
"version": "v1.2",
"versionExact": "v1.2"
}, },
{ {
"checksumSHA1": "A09l4+1MIuaXhh3Nn6aoOm+rr3Q=", "checksumSHA1": "A09l4+1MIuaXhh3Nn6aoOm+rr3Q=",