mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-24 02:32:17 +08:00
Merge branch 'master' into example3332
This commit is contained in:
commit
75f42a40b8
4
auth.go
4
auth.go
@ -24,7 +24,7 @@ type authPair struct {
|
||||
type authPairs []authPair
|
||||
|
||||
func (a authPairs) searchCredential(authValue string) (string, bool) {
|
||||
if len(authValue) == 0 {
|
||||
if authValue == "" {
|
||||
return "", false
|
||||
}
|
||||
for _, pair := range a {
|
||||
@ -71,7 +71,7 @@ func processAccounts(accounts Accounts) authPairs {
|
||||
assert1(len(accounts) > 0, "Empty list of authorized credentials")
|
||||
pairs := make(authPairs, 0, len(accounts))
|
||||
for user, password := range accounts {
|
||||
assert1(len(user) > 0, "User can not be empty")
|
||||
assert1(user != "", "User can not be empty")
|
||||
value := authorizationHeader(user, password)
|
||||
pairs = append(pairs, authPair{
|
||||
Value: value,
|
||||
|
@ -163,6 +163,14 @@ func setTimeField(val string, structField reflect.StructField, value reflect.Val
|
||||
l = time.UTC
|
||||
}
|
||||
|
||||
if locTag := structField.Tag.Get("time_location"); locTag != "" {
|
||||
loc, err := time.LoadLocation(locTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = loc
|
||||
}
|
||||
|
||||
t, err := time.ParseInLocation(timeFormat, val, l)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -45,6 +45,7 @@ func createMultipartRequest() *http.Request {
|
||||
must(mw.WriteField("id", ""))
|
||||
must(mw.WriteField("time_local", "31/12/2016 14:55"))
|
||||
must(mw.WriteField("time_utc", "31/12/2016 14:55"))
|
||||
must(mw.WriteField("time_location", "31/12/2016 14:55"))
|
||||
req, err := http.NewRequest("POST", "/", body)
|
||||
must(err)
|
||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
||||
@ -451,6 +452,7 @@ func TestContextPostFormMultipart(t *testing.T) {
|
||||
ID string `form:"id"`
|
||||
TimeLocal time.Time `form:"time_local" time_format:"02/01/2006 15:04"`
|
||||
TimeUTC time.Time `form:"time_utc" time_format:"02/01/2006 15:04" time_utc:"1"`
|
||||
TimeLocation time.Time `form:"time_location" time_format:"02/01/2006 15:04" time_location:"Asia/Tokyo"`
|
||||
BlankTime time.Time `form:"blank_time" time_format:"02/01/2006 15:04"`
|
||||
}
|
||||
assert.NoError(t, c.Bind(&obj))
|
||||
@ -463,6 +465,9 @@ func TestContextPostFormMultipart(t *testing.T) {
|
||||
assert.Equal(t, obj.TimeLocal.Location(), time.Local)
|
||||
assert.Equal(t, obj.TimeUTC.Format("02/01/2006 15:04"), "31/12/2016 14:55")
|
||||
assert.Equal(t, obj.TimeUTC.Location(), time.UTC)
|
||||
loc, _ := time.LoadLocation("Asia/Tokyo")
|
||||
assert.Equal(t, obj.TimeLocation.Format("02/01/2006 15:04"), "31/12/2016 14:55")
|
||||
assert.Equal(t, obj.TimeLocation.Location(), loc)
|
||||
assert.True(t, obj.BlankTime.IsZero())
|
||||
|
||||
value, ok := c.GetQuery("foo")
|
||||
|
6
debug.go
6
debug.go
@ -46,6 +46,12 @@ func debugPrint(format string, values ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func debugPrintWARNINGDefault() {
|
||||
debugPrint(`[WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
|
||||
|
||||
`)
|
||||
}
|
||||
|
||||
func debugPrintWARNINGNew() {
|
||||
debugPrint(`[WARNING] Running in "debug" mode. Switch to "release" mode in production.
|
||||
- using env: export GIN_MODE=release
|
||||
|
@ -86,6 +86,24 @@ func TestDebugPrintWARNINGSetHTMLTemplate(t *testing.T) {
|
||||
assert.Equal(t, "[GIN-debug] [WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called\nat initialization. ie. before any route is registered or the router is listening in a socket:\n\n\trouter := gin.Default()\n\trouter.SetHTMLTemplate(template) // << good place\n\n", w.String())
|
||||
}
|
||||
|
||||
func TestDebugPrintWARNINGDefault(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
setup(&w)
|
||||
defer teardown()
|
||||
|
||||
debugPrintWARNINGDefault()
|
||||
assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", w.String())
|
||||
}
|
||||
|
||||
func TestDebugPrintWARNINGNew(t *testing.T) {
|
||||
var w bytes.Buffer
|
||||
setup(&w)
|
||||
defer teardown()
|
||||
|
||||
debugPrintWARNINGNew()
|
||||
assert.Equal(t, "[GIN-debug] [WARNING] Running in \"debug\" mode. Switch to \"release\" mode in production.\n - using env:\texport GIN_MODE=release\n - using code:\tgin.SetMode(gin.ReleaseMode)\n\n", w.String())
|
||||
}
|
||||
|
||||
func setup(w io.Writer) {
|
||||
SetMode(DebugMode)
|
||||
log.SetOutput(w)
|
||||
|
51
gin.go
51
gin.go
@ -20,9 +20,11 @@ const (
|
||||
defaultMultipartMemory = 32 << 20 // 32 MB
|
||||
)
|
||||
|
||||
var default404Body = []byte("404 page not found")
|
||||
var default405Body = []byte("405 method not allowed")
|
||||
var defaultAppEngine bool
|
||||
var (
|
||||
default404Body = []byte("404 page not found")
|
||||
default405Body = []byte("405 method not allowed")
|
||||
defaultAppEngine bool
|
||||
)
|
||||
|
||||
type HandlerFunc func(*Context)
|
||||
type HandlersChain []HandlerFunc
|
||||
@ -91,6 +93,7 @@ type Engine struct {
|
||||
|
||||
// If enabled, the url.RawPath will be used to find parameters.
|
||||
UseRawPath bool
|
||||
|
||||
// If true, the path value will be unescaped.
|
||||
// If UseRawPath is false (by default), the UnescapePathValues effectively is true,
|
||||
// as url.Path gonna be used, which is already unescaped.
|
||||
@ -141,6 +144,7 @@ func New() *Engine {
|
||||
|
||||
// Default returns an Engine instance with the Logger and Recovery middleware already attached.
|
||||
func Default() *Engine {
|
||||
debugPrintWARNINGDefault()
|
||||
engine := New()
|
||||
engine.Use(Logger(), Recovery())
|
||||
return engine
|
||||
@ -161,13 +165,16 @@ func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
|
||||
}
|
||||
|
||||
func (engine *Engine) LoadHTMLGlob(pattern string) {
|
||||
left := engine.delims.Left
|
||||
right := engine.delims.Right
|
||||
|
||||
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(left, right).Funcs(engine.FuncMap).ParseGlob(pattern)))
|
||||
engine.HTMLRender = render.HTMLDebug{Glob: pattern, FuncMap: engine.FuncMap, Delims: engine.delims}
|
||||
return
|
||||
}
|
||||
|
||||
templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseGlob(pattern))
|
||||
templ := template.Must(template.New("").Delims(left, right).Funcs(engine.FuncMap).ParseGlob(pattern))
|
||||
engine.SetHTMLTemplate(templ)
|
||||
}
|
||||
|
||||
@ -225,7 +232,7 @@ func (engine *Engine) rebuild405Handlers() {
|
||||
|
||||
func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
|
||||
assert1(path[0] == '/', "path must begin with '/'")
|
||||
assert1(len(method) > 0, "HTTP method can not be empty")
|
||||
assert1(method != "", "HTTP method can not be empty")
|
||||
assert1(len(handlers) > 0, "there must be at least one handler")
|
||||
|
||||
debugPrintRoute(method, path, handlers)
|
||||
@ -322,12 +329,12 @@ func (engine *Engine) HandleContext(c *Context) {
|
||||
engine.pool.Put(c)
|
||||
}
|
||||
|
||||
func (engine *Engine) handleHTTPRequest(context *Context) {
|
||||
httpMethod := context.Request.Method
|
||||
path := context.Request.URL.Path
|
||||
func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||
httpMethod := c.Request.Method
|
||||
path := c.Request.URL.Path
|
||||
unescape := false
|
||||
if engine.UseRawPath && len(context.Request.URL.RawPath) > 0 {
|
||||
path = context.Request.URL.RawPath
|
||||
if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
|
||||
path = c.Request.URL.RawPath
|
||||
unescape = engine.UnescapePathValues
|
||||
}
|
||||
|
||||
@ -337,20 +344,20 @@ func (engine *Engine) handleHTTPRequest(context *Context) {
|
||||
if t[i].method == httpMethod {
|
||||
root := t[i].root
|
||||
// Find route in tree
|
||||
handlers, params, tsr := root.getValue(path, context.Params, unescape)
|
||||
handlers, params, tsr := root.getValue(path, c.Params, unescape)
|
||||
if handlers != nil {
|
||||
context.handlers = handlers
|
||||
context.Params = params
|
||||
context.Next()
|
||||
context.writermem.WriteHeaderNow()
|
||||
c.handlers = handlers
|
||||
c.Params = params
|
||||
c.Next()
|
||||
c.writermem.WriteHeaderNow()
|
||||
return
|
||||
}
|
||||
if httpMethod != "CONNECT" && path != "/" {
|
||||
if tsr && engine.RedirectTrailingSlash {
|
||||
redirectTrailingSlash(context)
|
||||
redirectTrailingSlash(c)
|
||||
return
|
||||
}
|
||||
if engine.RedirectFixedPath && redirectFixedPath(context, root, engine.RedirectFixedPath) {
|
||||
if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -362,15 +369,15 @@ func (engine *Engine) handleHTTPRequest(context *Context) {
|
||||
for _, tree := range engine.trees {
|
||||
if tree.method != httpMethod {
|
||||
if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil {
|
||||
context.handlers = engine.allNoMethod
|
||||
serveError(context, 405, default405Body)
|
||||
c.handlers = engine.allNoMethod
|
||||
serveError(c, 405, default405Body)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
context.handlers = engine.allNoRoute
|
||||
serveError(context, 404, default404Body)
|
||||
c.handlers = engine.allNoRoute
|
||||
serveError(c, 404, default404Body)
|
||||
}
|
||||
|
||||
var mimePlain = []string{MIMEPlain}
|
||||
|
2
mode.go
2
mode.go
@ -39,7 +39,7 @@ var modeName = DebugMode
|
||||
|
||||
func init() {
|
||||
mode := os.Getenv(ENV_GIN_MODE)
|
||||
if len(mode) == 0 {
|
||||
if mode == "" {
|
||||
SetMode(DebugMode)
|
||||
} else {
|
||||
SetMode(mode)
|
||||
|
@ -60,7 +60,7 @@ func (r HTMLDebug) loadTemplate() *template.Template {
|
||||
if len(r.Files) > 0 {
|
||||
return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseFiles(r.Files...))
|
||||
}
|
||||
if len(r.Glob) > 0 {
|
||||
if r.Glob != "" {
|
||||
return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseGlob(r.Glob))
|
||||
}
|
||||
panic("the HTML debug render was created without files or glob pattern")
|
||||
@ -69,7 +69,7 @@ func (r HTMLDebug) loadTemplate() *template.Template {
|
||||
func (r HTML) Render(w http.ResponseWriter) error {
|
||||
r.WriteContentType(w)
|
||||
|
||||
if len(r.Name) == 0 {
|
||||
if r.Name == "" {
|
||||
return r.Template.Execute(w, r.Data)
|
||||
}
|
||||
return r.Template.ExecuteTemplate(w, r.Name, r.Data)
|
||||
|
11
utils.go
11
utils.go
@ -103,7 +103,7 @@ func parseAccept(acceptHeader string) []string {
|
||||
if index := strings.IndexByte(part, ';'); index >= 0 {
|
||||
part = part[0:index]
|
||||
}
|
||||
if part = strings.TrimSpace(part); len(part) > 0 {
|
||||
if part = strings.TrimSpace(part); part != "" {
|
||||
out = append(out, part)
|
||||
}
|
||||
}
|
||||
@ -111,11 +111,10 @@ func parseAccept(acceptHeader string) []string {
|
||||
}
|
||||
|
||||
func lastChar(str string) uint8 {
|
||||
size := len(str)
|
||||
if size == 0 {
|
||||
if str == "" {
|
||||
panic("The length of the string can't be 0")
|
||||
}
|
||||
return str[size-1]
|
||||
return str[len(str)-1]
|
||||
}
|
||||
|
||||
func nameOfFunction(f interface{}) string {
|
||||
@ -123,7 +122,7 @@ func nameOfFunction(f interface{}) string {
|
||||
}
|
||||
|
||||
func joinPaths(absolutePath, relativePath string) string {
|
||||
if len(relativePath) == 0 {
|
||||
if relativePath == "" {
|
||||
return absolutePath
|
||||
}
|
||||
|
||||
@ -138,7 +137,7 @@ func joinPaths(absolutePath, relativePath string) string {
|
||||
func resolveAddress(addr []string) string {
|
||||
switch len(addr) {
|
||||
case 0:
|
||||
if port := os.Getenv("PORT"); len(port) > 0 {
|
||||
if port := os.Getenv("PORT"); port != "" {
|
||||
debugPrint("Environment variable PORT=\"%s\"", port)
|
||||
return ":" + port
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user