mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-15 13:02:14 +08:00
Merge branch 'master' into export_responsewriter_app_engine
* master: Fixes bug when status code is negative Update README.md Updates CHANGELOG and AUTHORS Fixes html debug mode Using test mode Adds TestMode HTML template debug mode. Update README.md Typo in AUTHORS Adds debug mode (part 1) Updates AUTHORS.md Updates CHANGELOG Update README.md
This commit is contained in:
commit
ae4800e50f
18
AUTHORS.md
18
AUTHORS.md
@ -5,7 +5,7 @@ List of all the awesome people working to make Gin the best Web Framework in Go!
|
|||||||
##gin 0.x series authors
|
##gin 0.x series authors
|
||||||
|
|
||||||
**Lead Developer:** Manu Martinez-Almeida (@manucorporat)
|
**Lead Developer:** Manu Martinez-Almeida (@manucorporat)
|
||||||
**Stuff:**
|
**Staff:**
|
||||||
Javier Provecho (@javierprovecho)
|
Javier Provecho (@javierprovecho)
|
||||||
|
|
||||||
People and companies, who have contributed, in alphabetical order.
|
People and companies, who have contributed, in alphabetical order.
|
||||||
@ -22,10 +22,13 @@ People and companies, who have contributed, in alphabetical order.
|
|||||||
- Using template.Must to fix multiple return issue
|
- Using template.Must to fix multiple return issue
|
||||||
- ★ Added support for OPTIONS verb
|
- ★ Added support for OPTIONS verb
|
||||||
- ★ Setting response headers before calling WriteHeader
|
- ★ Setting response headers before calling WriteHeader
|
||||||
|
- Improved documentation for model binding
|
||||||
|
- ★ Added Content.Redirect()
|
||||||
|
- ★ Added tons of Unit tests
|
||||||
|
|
||||||
|
|
||||||
**@austinheap (Austin Heap)**
|
**@austinheap (Austin Heap)**
|
||||||
- Adds travis CI integration
|
- Added travis CI integration
|
||||||
|
|
||||||
|
|
||||||
**@bluele (Jun Kimura)**
|
**@bluele (Jun Kimura)**
|
||||||
@ -67,20 +70,23 @@ People and companies, who have contributed, in alphabetical order.
|
|||||||
**@mdigger (Dmitry Sedykh)**
|
**@mdigger (Dmitry Sedykh)**
|
||||||
- Fixes Form binding when content-type is x-www-form-urlencoded
|
- Fixes Form binding when content-type is x-www-form-urlencoded
|
||||||
- No repeat call c.Writer.Status() in gin.Logger
|
- No repeat call c.Writer.Status() in gin.Logger
|
||||||
- Fixed Content-Type for json render
|
- Fixes Content-Type for json render
|
||||||
|
|
||||||
|
|
||||||
**@mopemope (Yutaka Matsubara)**
|
**@mopemope (Yutaka Matsubara)**
|
||||||
- ★ Adds Godep support (Dependencies Manager)
|
- ★ Adds Godep support (Dependencies Manager)
|
||||||
- Fix variadic parameter in the flexible render API
|
- Fix variadic parameter in the flexible render API
|
||||||
- Fix Corrupted plain render
|
- Fix Corrupted plain render
|
||||||
- Fix variadic parameter in new flexible render API
|
|
||||||
|
|
||||||
|
|
||||||
**@msemenistyi (Mykyta Semenistyi)**
|
**@msemenistyi (Mykyta Semenistyi)**
|
||||||
- update Readme.md. Add code to String method
|
- update Readme.md. Add code to String method
|
||||||
|
|
||||||
|
|
||||||
|
**@msoedov (Sasha Myasoedov)**
|
||||||
|
- ★ Adds tons of unit tests.
|
||||||
|
|
||||||
|
|
||||||
**@ngerakines (Nick Gerakines)**
|
**@ngerakines (Nick Gerakines)**
|
||||||
- ★ Improves API, c.GET() doesn't panic
|
- ★ Improves API, c.GET() doesn't panic
|
||||||
- Adds MustGet() method
|
- Adds MustGet() method
|
||||||
@ -96,3 +102,7 @@ People and companies, who have contributed, in alphabetical order.
|
|||||||
|
|
||||||
**@SkuliOskarsson (Skuli Oskarsson)**
|
**@SkuliOskarsson (Skuli Oskarsson)**
|
||||||
- Fixes some texts in README II
|
- Fixes some texts in README II
|
||||||
|
|
||||||
|
|
||||||
|
**@yuyabee**
|
||||||
|
- Fixed README
|
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,6 +1,12 @@
|
|||||||
##Changelog
|
#Changelog
|
||||||
|
|
||||||
###Gin 0.4 (??)
|
###Gin 0.4 (Aug 21, 2014)
|
||||||
|
|
||||||
|
- [NEW] Development mode
|
||||||
|
- [NEW] Unit tests
|
||||||
|
- [NEW] Add Content.Redirect()
|
||||||
|
- [FIX] Deferring WriteHeader()
|
||||||
|
- [FIX] Improved documentation for model binding
|
||||||
|
|
||||||
|
|
||||||
###Gin 0.3 (Jul 18, 2014)
|
###Gin 0.3 (Jul 18, 2014)
|
||||||
|
13
README.md
13
README.md
@ -1,6 +1,6 @@
|
|||||||
#Gin Web Framework
|
#Gin Web Framework
|
||||||
|
|
||||||
[](https://godoc.org/github.com/gin-gonic/gin)
|
[](https://godoc.org/github.com/gin-gonic/gin)
|
||||||
[](https://travis-ci.org/gin-gonic/gin)
|
[](https://travis-ci.org/gin-gonic/gin)
|
||||||
|
|
||||||
Gin is a web framework written in Golang. It features a martini-like API with much better performance, up to 40 times faster. If you need performance and good productivity, you will love Gin.
|
Gin is a web framework written in Golang. It features a martini-like API with much better performance, up to 40 times faster. If you need performance and good productivity, you will love Gin.
|
||||||
@ -324,12 +324,13 @@ func main() {
|
|||||||
|
|
||||||
Issuing a HTTP redirect is easy:
|
Issuing a HTTP redirect is easy:
|
||||||
|
|
||||||
```r.GET("/test", func(c *gin.Context) {
|
```go
|
||||||
|
r.GET("/test", func(c *gin.Context) {
|
||||||
c.Redirect(301, "http://www.google.com/")
|
c.Redirect(301, "http://www.google.com/")
|
||||||
})
|
})
|
||||||
|
|
||||||
Both internal and external locations are supported.
|
|
||||||
```
|
```
|
||||||
|
Both internal and external locations are supported.
|
||||||
|
|
||||||
|
|
||||||
#### Custom Middlewares
|
#### Custom Middlewares
|
||||||
|
|
||||||
@ -425,7 +426,7 @@ func main() {
|
|||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
// note than you are using the copied context "c_cp", IMPORTANT
|
// note than you are using the copied context "c_cp", IMPORTANT
|
||||||
log.Println("Done! in path " + c_cp.Req.URL.Path)
|
log.Println("Done! in path " + c_cp.Request.URL.Path)
|
||||||
}()
|
}()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -435,7 +436,7 @@ func main() {
|
|||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
// since we are NOT using a goroutine, we do not have to copy the context
|
// since we are NOT using a goroutine, we do not have to copy the context
|
||||||
log.Println("Done! in path " + c.Req.URL.Path)
|
log.Println("Done! in path " + c.Request.URL.Path)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Listen and server on 0.0.0.0:8080
|
// Listen and server on 0.0.0.0:8080
|
||||||
|
28
gin.go
28
gin.go
@ -1,6 +1,7 @@
|
|||||||
package gin
|
package gin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin/render"
|
"github.com/gin-gonic/gin/render"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"html/template"
|
"html/template"
|
||||||
@ -73,13 +74,21 @@ func Default() *Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) LoadHTMLGlob(pattern string) {
|
func (engine *Engine) LoadHTMLGlob(pattern string) {
|
||||||
templ := template.Must(template.ParseGlob(pattern))
|
if gin_mode == debugCode {
|
||||||
engine.SetHTMLTemplate(templ)
|
engine.HTMLRender = render.HTMLDebug
|
||||||
|
} else {
|
||||||
|
templ := template.Must(template.ParseGlob(pattern))
|
||||||
|
engine.SetHTMLTemplate(templ)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) LoadHTMLFiles(files ...string) {
|
func (engine *Engine) LoadHTMLFiles(files ...string) {
|
||||||
templ := template.Must(template.ParseFiles(files...))
|
if gin_mode == debugCode {
|
||||||
engine.SetHTMLTemplate(templ)
|
engine.HTMLRender = render.HTMLDebug
|
||||||
|
} else {
|
||||||
|
templ := template.Must(template.ParseFiles(files...))
|
||||||
|
engine.SetHTMLTemplate(templ)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
|
func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
|
||||||
@ -105,12 +114,18 @@ func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) Run(addr string) {
|
func (engine *Engine) Run(addr string) {
|
||||||
|
if gin_mode == debugCode {
|
||||||
|
fmt.Println("[GIN-debug] Listening and serving HTTP on " + addr)
|
||||||
|
}
|
||||||
if err := http.ListenAndServe(addr, engine); err != nil {
|
if err := http.ListenAndServe(addr, engine); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) RunTLS(addr string, cert string, key string) {
|
func (engine *Engine) RunTLS(addr string, cert string, key string) {
|
||||||
|
if gin_mode == debugCode {
|
||||||
|
fmt.Println("[GIN-debug] Listening and serving HTTPS on " + addr)
|
||||||
|
}
|
||||||
if err := http.ListenAndServeTLS(addr, cert, key, engine); err != nil {
|
if err := http.ListenAndServeTLS(addr, cert, key, engine); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -160,6 +175,11 @@ func (group *RouterGroup) pathFor(p string) string {
|
|||||||
func (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
|
func (group *RouterGroup) Handle(method, p string, handlers []HandlerFunc) {
|
||||||
p = group.pathFor(p)
|
p = group.pathFor(p)
|
||||||
handlers = group.combineHandlers(handlers)
|
handlers = group.combineHandlers(handlers)
|
||||||
|
if gin_mode == debugCode {
|
||||||
|
nuHandlers := len(handlers)
|
||||||
|
name := funcName(handlers[nuHandlers-1])
|
||||||
|
fmt.Printf("[GIN-debug] %-5s %-25s --> %s (%d handlers)\n", method, p, name, nuHandlers)
|
||||||
|
}
|
||||||
group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
|
group.engine.router.Handle(method, p, func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
|
||||||
c := group.engine.createContext(w, req, params, handlers)
|
c := group.engine.createContext(w, req, params, handlers)
|
||||||
c.Next()
|
c.Next()
|
||||||
|
@ -10,6 +10,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SetMode(TestMode)
|
||||||
|
}
|
||||||
|
|
||||||
func PerformRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
|
func PerformRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
|
||||||
req, _ := http.NewRequest(method, path, nil)
|
req, _ := http.NewRequest(method, path, nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
42
mode.go
Normal file
42
mode.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const GIN_MODE = "GIN_MODE"
|
||||||
|
|
||||||
|
const (
|
||||||
|
DebugMode string = "debug"
|
||||||
|
ReleaseMode string = "release"
|
||||||
|
TestMode string = "test"
|
||||||
|
)
|
||||||
|
const (
|
||||||
|
debugCode = iota
|
||||||
|
releaseCode = iota
|
||||||
|
testCode = iota
|
||||||
|
)
|
||||||
|
|
||||||
|
var gin_mode int = debugCode
|
||||||
|
|
||||||
|
func SetMode(value string) {
|
||||||
|
switch value {
|
||||||
|
case DebugMode:
|
||||||
|
gin_mode = debugCode
|
||||||
|
case ReleaseMode:
|
||||||
|
gin_mode = releaseCode
|
||||||
|
case TestMode:
|
||||||
|
gin_mode = testCode
|
||||||
|
default:
|
||||||
|
panic("gin mode unknown, the allowed modes are: " + DebugMode + " and " + ReleaseMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
value := os.Getenv(GIN_MODE)
|
||||||
|
if len(value) == 0 {
|
||||||
|
SetMode(DebugMode)
|
||||||
|
} else {
|
||||||
|
SetMode(value)
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,9 @@ type (
|
|||||||
// Redirects
|
// Redirects
|
||||||
redirectRender struct{}
|
redirectRender struct{}
|
||||||
|
|
||||||
|
// Redirects
|
||||||
|
htmlDebugRender struct{}
|
||||||
|
|
||||||
// form binding
|
// form binding
|
||||||
HTMLRender struct {
|
HTMLRender struct {
|
||||||
Template *template.Template
|
Template *template.Template
|
||||||
@ -32,10 +35,11 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
JSON = jsonRender{}
|
JSON = jsonRender{}
|
||||||
XML = xmlRender{}
|
XML = xmlRender{}
|
||||||
Plain = plainRender{}
|
Plain = plainRender{}
|
||||||
Redirect = redirectRender{}
|
Redirect = redirectRender{}
|
||||||
|
HTMLDebug = htmlDebugRender{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func writeHeader(w http.ResponseWriter, code int, contentType string) {
|
func writeHeader(w http.ResponseWriter, code int, contentType string) {
|
||||||
@ -61,13 +65,6 @@ func (_ xmlRender) Render(w http.ResponseWriter, code int, data ...interface{})
|
|||||||
return encoder.Encode(data[0])
|
return encoder.Encode(data[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (html HTMLRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
|
|
||||||
writeHeader(w, code, "text/html")
|
|
||||||
file := data[0].(string)
|
|
||||||
obj := data[1]
|
|
||||||
return html.Template.ExecuteTemplate(w, file, obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ plainRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
|
func (_ plainRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
|
||||||
writeHeader(w, code, "text/plain")
|
writeHeader(w, code, "text/plain")
|
||||||
format := data[0].(string)
|
format := data[0].(string)
|
||||||
@ -80,3 +77,21 @@ func (_ plainRender) Render(w http.ResponseWriter, code int, data ...interface{}
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (_ htmlDebugRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
|
||||||
|
writeHeader(w, code, "text/html")
|
||||||
|
file := data[0].(string)
|
||||||
|
obj := data[1]
|
||||||
|
t, err := template.ParseFiles(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return t.ExecuteTemplate(w, file, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (html HTMLRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
|
||||||
|
writeHeader(w, code, "text/html")
|
||||||
|
file := data[0].(string)
|
||||||
|
obj := data[1]
|
||||||
|
return html.Template.ExecuteTemplate(w, file, obj)
|
||||||
|
}
|
||||||
|
@ -27,7 +27,7 @@ func (w *responseWriter) reset(writer http.ResponseWriter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *responseWriter) WriteHeader(code int) {
|
func (w *responseWriter) WriteHeader(code int) {
|
||||||
if code != 0 {
|
if code > 0 {
|
||||||
w.status = code
|
w.status = code
|
||||||
if w.written {
|
if w.written {
|
||||||
log.Println("[GIN] WARNING. Headers were already written!")
|
log.Println("[GIN] WARNING. Headers were already written!")
|
||||||
|
6
utils.go
6
utils.go
@ -2,6 +2,8 @@ package gin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
type H map[string]interface{}
|
type H map[string]interface{}
|
||||||
@ -38,3 +40,7 @@ func filterFlags(content string) string {
|
|||||||
}
|
}
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func funcName(f interface{}) string {
|
||||||
|
return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user