"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "gin.go" between
gin-1.7.6.tar.gz and gin-1.7.7.tar.gz

About: Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API (with much better performance).

gin.go  (gin-1.7.6):gin.go  (gin-1.7.7)
skipping to change at line 14 skipping to change at line 14
package gin package gin
import ( import (
"fmt" "fmt"
"html/template" "html/template"
"net" "net"
"net/http" "net/http"
"os" "os"
"path" "path"
"reflect"
"strings" "strings"
"sync" "sync"
"github.com/gin-gonic/gin/internal/bytesconv" "github.com/gin-gonic/gin/internal/bytesconv"
"github.com/gin-gonic/gin/render" "github.com/gin-gonic/gin/render"
) )
const defaultMultipartMemory = 32 << 20 // 32 MB const defaultMultipartMemory = 32 << 20 // 32 MB
var ( var (
default404Body = []byte("404 page not found") default404Body = []byte("404 page not found")
default405Body = []byte("405 method not allowed") default405Body = []byte("405 method not allowed")
) )
var defaultAppEngine bool var defaultPlatform string
var defaultTrustedCIDRs = []*net.IPNet{{IP: net.IP{0x0, 0x0, 0x0, 0x0}, Mask: ne
t.IPMask{0x0, 0x0, 0x0, 0x0}}} // 0.0.0.0/0
// HandlerFunc defines the handler used by gin middleware as return value. // HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context) type HandlerFunc func(*Context)
// HandlersChain defines a HandlerFunc array. // HandlersChain defines a HandlerFunc array.
type HandlersChain []HandlerFunc type HandlersChain []HandlerFunc
// Last returns the last handler in the chain. ie. the last handler is the main one. // Last returns the last handler in the chain. ie. the last handler is the main one.
func (c HandlersChain) Last() HandlerFunc { func (c HandlersChain) Last() HandlerFunc {
if length := len(c); length > 0 { if length := len(c); length > 0 {
skipping to change at line 55 skipping to change at line 58
type RouteInfo struct { type RouteInfo struct {
Method string Method string
Path string Path string
Handler string Handler string
HandlerFunc HandlerFunc HandlerFunc HandlerFunc
} }
// RoutesInfo defines a RouteInfo array. // RoutesInfo defines a RouteInfo array.
type RoutesInfo []RouteInfo type RoutesInfo []RouteInfo
// Trusted platforms
const (
// When running on Google App Engine. Trust X-Appengine-Remote-Addr
// for determining the client's IP
PlatformGoogleAppEngine = "X-Appengine-Remote-Addr"
// When using Cloudflare's CDN. Trust CF-Connecting-IP for determining
// the client's IP
PlatformCloudflare = "CF-Connecting-IP"
)
// Engine is the framework's instance, it contains the muxer, middleware and con figuration settings. // Engine is the framework's instance, it contains the muxer, middleware and con figuration settings.
// Create an instance of Engine, by using New() or Default() // Create an instance of Engine, by using New() or Default()
type Engine struct { type Engine struct {
RouterGroup RouterGroup
// Enables automatic redirection if the current route can't be matched bu t a // Enables automatic redirection if the current route can't be matched bu t a
// handler for the path with (without) the trailing slash exists. // handler for the path with (without) the trailing slash exists.
// For example if /foo/ is requested but a route only exists for /foo, th e // For example if /foo/ is requested but a route only exists for /foo, th e
// client is redirected to /foo with http status code 301 for GET request s // client is redirected to /foo with http status code 301 for GET request s
// and 307 for all other request methods. // and 307 for all other request methods.
skipping to change at line 92 skipping to change at line 105
// If no other Method is allowed, the request is delegated to the NotFoun d // If no other Method is allowed, the request is delegated to the NotFoun d
// handler. // handler.
HandleMethodNotAllowed bool HandleMethodNotAllowed bool
// If enabled, client IP will be parsed from the request's headers that // If enabled, client IP will be parsed from the request's headers that
// match those stored at `(*gin.Engine).RemoteIPHeaders`. If no IP was // match those stored at `(*gin.Engine).RemoteIPHeaders`. If no IP was
// fetched, it falls back to the IP obtained from // fetched, it falls back to the IP obtained from
// `(*gin.Context).Request.RemoteAddr`. // `(*gin.Context).Request.RemoteAddr`.
ForwardedByClientIP bool ForwardedByClientIP bool
// List of headers used to obtain the client IP when // DEPRECATED: USE `TrustedPlatform` WITH VALUE `gin.GoogleAppEngine` INS
// `(*gin.Engine).ForwardedByClientIP` is `true` and TEAD
// `(*gin.Context).Request.RemoteAddr` is matched by at least one of the
// network origins of `(*gin.Engine).TrustedProxies`.
RemoteIPHeaders []string
// List of network origins (IPv4 addresses, IPv4 CIDRs, IPv6 addresses or
// IPv6 CIDRs) from which to trust request's headers that contain
// alternative client IP when `(*gin.Engine).ForwardedByClientIP` is
// `true`.
TrustedProxies []string
// #726 #755 If enabled, it will trust some headers starting with // #726 #755 If enabled, it will trust some headers starting with
// 'X-AppEngine...' for better integration with that PaaS. // 'X-AppEngine...' for better integration with that PaaS.
AppEngine bool AppEngine bool
// If enabled, the url.RawPath will be used to find parameters. // If enabled, the url.RawPath will be used to find parameters.
UseRawPath bool UseRawPath bool
// If true, the path value will be unescaped. // If true, the path value will be unescaped.
// If UseRawPath is false (by default), the UnescapePathValues effectivel y is true, // If UseRawPath is false (by default), the UnescapePathValues effectivel y 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
// Value of 'maxMemory' param that is given to http.Request's ParseMultip
artForm
// method call.
MaxMultipartMemory int64
// RemoveExtraSlash a parameter can be parsed from the URL even with extr a slashes. // RemoveExtraSlash a parameter can be parsed from the URL even with extr a slashes.
// See the PR #1817 and issue #1644 // See the PR #1817 and issue #1644
RemoveExtraSlash bool RemoveExtraSlash bool
// List of headers used to obtain the client IP when
// `(*gin.Engine).ForwardedByClientIP` is `true` and
// `(*gin.Context).Request.RemoteAddr` is matched by at least one of the
// network origins of list defined by `(*gin.Engine).SetTrustedProxies()`
.
RemoteIPHeaders []string
// If set to a constant of value gin.Platform*, trusts the headers set by
// that platform, for example to determine the client IP
TrustedPlatform string
// Value of 'maxMemory' param that is given to http.Request's ParseMultip
artForm
// method call.
MaxMultipartMemory int64
delims render.Delims delims render.Delims
secureJSONPrefix string secureJSONPrefix string
HTMLRender render.HTMLRender HTMLRender render.HTMLRender
FuncMap template.FuncMap FuncMap template.FuncMap
allNoRoute HandlersChain allNoRoute HandlersChain
allNoMethod HandlersChain allNoMethod HandlersChain
noRoute HandlersChain noRoute HandlersChain
noMethod HandlersChain noMethod HandlersChain
pool sync.Pool pool sync.Pool
trees methodTrees trees methodTrees
maxParams uint16 maxParams uint16
maxSections uint16
trustedProxies []string
trustedCIDRs []*net.IPNet trustedCIDRs []*net.IPNet
} }
var _ IRouter = &Engine{} var _ IRouter = &Engine{}
// New returns a new blank Engine instance without any middleware attached. // New returns a new blank Engine instance without any middleware attached.
// By default the configuration is: // By default the configuration is:
// - RedirectTrailingSlash: true // - RedirectTrailingSlash: true
// - RedirectFixedPath: false // - RedirectFixedPath: false
// - HandleMethodNotAllowed: false // - HandleMethodNotAllowed: false
skipping to change at line 162 skipping to change at line 176
Handlers: nil, Handlers: nil,
basePath: "/", basePath: "/",
root: true, root: true,
}, },
FuncMap: template.FuncMap{}, FuncMap: template.FuncMap{},
RedirectTrailingSlash: true, RedirectTrailingSlash: true,
RedirectFixedPath: false, RedirectFixedPath: false,
HandleMethodNotAllowed: false, HandleMethodNotAllowed: false,
ForwardedByClientIP: true, ForwardedByClientIP: true,
RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"}, RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"},
TrustedProxies: []string{"0.0.0.0/0"}, TrustedPlatform: defaultPlatform,
AppEngine: defaultAppEngine,
UseRawPath: false, UseRawPath: false,
RemoveExtraSlash: false, RemoveExtraSlash: false,
UnescapePathValues: true, UnescapePathValues: true,
MaxMultipartMemory: defaultMultipartMemory, MaxMultipartMemory: defaultMultipartMemory,
trees: make(methodTrees, 0, 9), trees: make(methodTrees, 0, 9),
delims: render.Delims{Left: "{{", Right: "}}"}, delims: render.Delims{Left: "{{", Right: "}}"},
secureJSONPrefix: "while(1);", secureJSONPrefix: "while(1);",
trustedProxies: []string{"0.0.0.0/0"},
trustedCIDRs: defaultTrustedCIDRs,
} }
engine.RouterGroup.engine = engine engine.RouterGroup.engine = engine
engine.pool.New = func() interface{} { engine.pool.New = func() interface{} {
return engine.allocateContext() return engine.allocateContext()
} }
return engine return engine
} }
// Default returns an Engine instance with the Logger and Recovery middleware al ready attached. // Default returns an Engine instance with the Logger and Recovery middleware al ready attached.
func Default() *Engine { func Default() *Engine {
debugPrintWARNINGDefault() debugPrintWARNINGDefault()
engine := New() engine := New()
engine.Use(Logger(), Recovery()) engine.Use(Logger(), Recovery())
return engine return engine
} }
func (engine *Engine) allocateContext() *Context { func (engine *Engine) allocateContext() *Context {
v := make(Params, 0, engine.maxParams) v := make(Params, 0, engine.maxParams)
return &Context{engine: engine, params: &v} skippedNodes := make([]skippedNode, 0, engine.maxSections)
return &Context{engine: engine, params: &v, skippedNodes: &skippedNodes}
} }
// Delims sets template left and right delims and returns a Engine instance. // Delims sets template left and right delims and returns a Engine instance.
func (engine *Engine) Delims(left, right string) *Engine { func (engine *Engine) Delims(left, right string) *Engine {
engine.delims = render.Delims{Left: left, Right: right} engine.delims = render.Delims{Left: left, Right: right}
return engine return engine
} }
// SecureJsonPrefix sets the secureJSONPrefix used in Context.SecureJSON. // SecureJsonPrefix sets the secureJSONPrefix used in Context.SecureJSON.
func (engine *Engine) SecureJsonPrefix(prefix string) *Engine { func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
skipping to change at line 252 skipping to change at line 268
func (engine *Engine) SetFuncMap(funcMap template.FuncMap) { func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
engine.FuncMap = funcMap engine.FuncMap = funcMap
} }
// NoRoute 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()
} }
// NoMethod sets the handlers called when... TODO. // NoMethod sets the handlers called when Engine.HandleMethodNotAllowed = true.
func (engine *Engine) NoMethod(handlers ...HandlerFunc) { func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
engine.noMethod = handlers engine.noMethod = handlers
engine.rebuild405Handlers() engine.rebuild405Handlers()
} }
// Use attaches a global middleware to the router. ie. the middleware attached t hough Use() will be // Use attaches a global middleware to the router. ie. the middleware attached t hough Use() will be
// included in the handlers chain for every single request. Even 404, 405, stati c files... // included in the handlers chain for every single request. Even 404, 405, stati c files...
// For example, this is the right place for a logger or error management middlew are. // For example, this is the right place for a logger or error management middlew are.
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes { func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
engine.RouterGroup.Use(middleware...) engine.RouterGroup.Use(middleware...)
skipping to change at line 295 skipping to change at line 311
root = new(node) root = new(node)
root.fullPath = "/" root.fullPath = "/"
engine.trees = append(engine.trees, methodTree{method: method, ro ot: root}) engine.trees = append(engine.trees, methodTree{method: method, ro ot: root})
} }
root.addRoute(path, handlers) root.addRoute(path, handlers)
// Update maxParams // Update maxParams
if paramsCount := countParams(path); paramsCount > engine.maxParams { if paramsCount := countParams(path); paramsCount > engine.maxParams {
engine.maxParams = paramsCount engine.maxParams = paramsCount
} }
if sectionsCount := countSections(path); sectionsCount > engine.maxSectio
ns {
engine.maxSections = sectionsCount
}
} }
// Routes returns a slice of registered routes, including some useful informatio n, such as: // Routes returns a slice of registered routes, including some useful informatio n, such as:
// the http method, path and the handler name. // the http method, path and the handler name.
func (engine *Engine) Routes() (routes RoutesInfo) { func (engine *Engine) Routes() (routes RoutesInfo) {
for _, tree := range engine.trees { for _, tree := range engine.trees {
routes = iterate("", tree.method, routes, tree.root) routes = iterate("", tree.method, routes, tree.root)
} }
return routes return routes
} }
skipping to change at line 329 skipping to change at line 349
} }
return routes return routes
} }
// Run attaches the router to a http.Server and starts listening and serving HTT P requests. // Run attaches the router to a http.Server and starts listening and serving HTT P 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 indefinitely unless an err or happens. // Note: this method will block the calling goroutine indefinitely unless an err or happens.
func (engine *Engine) Run(addr ...string) (err error) { func (engine *Engine) Run(addr ...string) (err error) {
defer func() { debugPrintError(err) }() defer func() { debugPrintError(err) }()
trustedCIDRs, err := engine.prepareTrustedCIDRs() if engine.isUnsafeTrustedProxies() {
if err != nil { debugPrint("[WARNING] You trusted all proxies, this is NOT safe.
return err We recommend you to set a value.\n" +
"Please check https://pkg.go.dev/github.com/gin-gonic/gin
#readme-don-t-trust-all-proxies for details.")
} }
engine.trustedCIDRs = trustedCIDRs
address := resolveAddress(addr) address := resolveAddress(addr)
debugPrint("Listening and serving HTTP on %s\n", address) debugPrint("Listening and serving HTTP on %s\n", address)
err = http.ListenAndServe(address, engine) err = http.ListenAndServe(address, engine)
return return
} }
func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) { func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) {
if engine.TrustedProxies == nil { if engine.trustedProxies == nil {
return nil, nil return nil, nil
} }
cidr := make([]*net.IPNet, 0, len(engine.TrustedProxies)) cidr := make([]*net.IPNet, 0, len(engine.trustedProxies))
for _, trustedProxy := range engine.TrustedProxies { for _, trustedProxy := range engine.trustedProxies {
if !strings.Contains(trustedProxy, "/") { if !strings.Contains(trustedProxy, "/") {
ip := parseIP(trustedProxy) ip := parseIP(trustedProxy)
if ip == nil { if ip == nil {
return cidr, &net.ParseError{Type: "IP address", Text: trustedProxy} return cidr, &net.ParseError{Type: "IP address", Text: trustedProxy}
} }
switch len(ip) { switch len(ip) {
case net.IPv4len: case net.IPv4len:
trustedProxy += "/32" trustedProxy += "/32"
case net.IPv6len: case net.IPv6len:
skipping to change at line 369 skipping to change at line 389
} }
_, cidrNet, err := net.ParseCIDR(trustedProxy) _, cidrNet, err := net.ParseCIDR(trustedProxy)
if err != nil { if err != nil {
return cidr, err return cidr, err
} }
cidr = append(cidr, cidrNet) cidr = append(cidr, cidrNet)
} }
return cidr, nil return cidr, nil
} }
// SetTrustedProxies set a list of network origins (IPv4 addresses,
// IPv4 CIDRs, IPv6 addresses or IPv6 CIDRs) from which to trust
// request's headers that contain alternative client IP when
// `(*gin.Engine).ForwardedByClientIP` is `true`. `TrustedProxies`
// feature is enabled by default, and it also trusts all proxies
// by default. If you want to disable this feature, use
// Engine.SetTrustedProxies(nil), then Context.ClientIP() will
// return the remote address directly.
func (engine *Engine) SetTrustedProxies(trustedProxies []string) error {
engine.trustedProxies = trustedProxies
return engine.parseTrustedProxies()
}
// isUnsafeTrustedProxies compares Engine.trustedCIDRs and defaultTrustedCIDRs,
it's not safe if equal (returns true)
func (engine *Engine) isUnsafeTrustedProxies() bool {
return reflect.DeepEqual(engine.trustedCIDRs, defaultTrustedCIDRs)
}
// parseTrustedProxies parse Engine.trustedProxies to Engine.trustedCIDRs
func (engine *Engine) parseTrustedProxies() error {
trustedCIDRs, err := engine.prepareTrustedCIDRs()
engine.trustedCIDRs = trustedCIDRs
return err
}
// parseIP parse a string representation of an IP and returns a net.IP with the // parseIP parse a string representation of an IP and returns a net.IP with the
// minimum byte representation or nil if input is invalid. // minimum byte representation or nil if input is invalid.
func parseIP(ip string) net.IP { func parseIP(ip string) net.IP {
parsedIP := net.ParseIP(ip) parsedIP := net.ParseIP(ip)
if ipv4 := parsedIP.To4(); ipv4 != nil { if ipv4 := parsedIP.To4(); ipv4 != nil {
// return ip in a 4-byte representation // return ip in a 4-byte representation
return ipv4 return ipv4
} }
skipping to change at line 390 skipping to change at line 435
return parsedIP return parsedIP
} }
// RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests. // RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) 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 indefinitely unless an err or happens. // Note: this method will block the calling goroutine indefinitely unless an err or happens.
func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) { func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) {
debugPrint("Listening and serving HTTPS on %s\n", addr) debugPrint("Listening and serving HTTPS on %s\n", addr)
defer func() { debugPrintError(err) }() defer func() { debugPrintError(err) }()
if engine.isUnsafeTrustedProxies() {
debugPrint("[WARNING] You trusted all proxies, this is NOT safe.
We recommend you to set a value.\n" +
"Please check https://pkg.go.dev/github.com/gin-gonic/gin
#readme-don-t-trust-all-proxies for details.")
}
err = http.ListenAndServeTLS(addr, certFile, keyFile, engine) err = http.ListenAndServeTLS(addr, certFile, keyFile, engine)
return return
} }
// RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests // RunUnix attaches the router 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 indefinitely unless an err or happens. // Note: this method will block the calling goroutine indefinitely unless an err or happens.
func (engine *Engine) RunUnix(file string) (err error) { func (engine *Engine) RunUnix(file string) (err error) {
debugPrint("Listening and serving HTTP on unix:/%s", file) debugPrint("Listening and serving HTTP on unix:/%s", file)
defer func() { debugPrintError(err) }() defer func() { debugPrintError(err) }()
if engine.isUnsafeTrustedProxies() {
debugPrint("[WARNING] You trusted all proxies, this is NOT safe.
We recommend you to set a value.\n" +
"Please check https://pkg.go.dev/github.com/gin-gonic/gin
#readme-don-t-trust-all-proxies for details.")
}
listener, err := net.Listen("unix", file) listener, err := net.Listen("unix", file)
if err != nil { if err != nil {
return return
} }
defer listener.Close() defer listener.Close()
defer os.Remove(file) defer os.Remove(file)
err = http.Serve(listener, engine) err = http.Serve(listener, engine)
return return
} }
// RunFd attaches the router to a http.Server and starts listening and serving H TTP requests // RunFd attaches the router to a http.Server and starts listening and serving H TTP requests
// through the specified file descriptor. // through the specified file descriptor.
// Note: this method will block the calling goroutine indefinitely unless an err or happens. // Note: this method will block the calling goroutine indefinitely unless an err or happens.
func (engine *Engine) RunFd(fd int) (err error) { func (engine *Engine) RunFd(fd int) (err error) {
debugPrint("Listening and serving HTTP on fd@%d", fd) debugPrint("Listening and serving HTTP on fd@%d", fd)
defer func() { debugPrintError(err) }() defer func() { debugPrintError(err) }()
if engine.isUnsafeTrustedProxies() {
debugPrint("[WARNING] You trusted all proxies, this is NOT safe.
We recommend you to set a value.\n" +
"Please check https://pkg.go.dev/github.com/gin-gonic/gin
#readme-don-t-trust-all-proxies for details.")
}
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd)) f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd))
listener, err := net.FileListener(f) listener, err := net.FileListener(f)
if err != nil { if err != nil {
return return
} }
defer listener.Close() defer listener.Close()
err = engine.RunListener(listener) err = engine.RunListener(listener)
return return
} }
// RunListener attaches the router to a http.Server and starts listening and ser ving HTTP requests // RunListener attaches the router to a http.Server and starts listening and ser ving HTTP requests
// through the specified net.Listener // through the specified net.Listener
func (engine *Engine) RunListener(listener net.Listener) (err error) { func (engine *Engine) RunListener(listener net.Listener) (err error) {
debugPrint("Listening and serving HTTP on listener what's bind with addre ss@%s", listener.Addr()) debugPrint("Listening and serving HTTP on listener what's bind with addre ss@%s", listener.Addr())
defer func() { debugPrintError(err) }() defer func() { debugPrintError(err) }()
if engine.isUnsafeTrustedProxies() {
debugPrint("[WARNING] You trusted all proxies, this is NOT safe.
We recommend you to set a value.\n" +
"Please check https://pkg.go.dev/github.com/gin-gonic/gin
#readme-don-t-trust-all-proxies for details.")
}
err = http.Serve(listener, engine) err = http.Serve(listener, engine)
return return
} }
// ServeHTTP conforms to the http.Handler interface. // ServeHTTP 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)
c.Request = req c.Request = req
c.reset() c.reset()
skipping to change at line 482 skipping to change at line 548
} }
// Find root of the tree for the given HTTP method // Find root of the tree for the given HTTP method
t := engine.trees t := engine.trees
for i, tl := 0, len(t); i < tl; i++ { for i, tl := 0, len(t); i < tl; i++ {
if t[i].method != httpMethod { if t[i].method != httpMethod {
continue continue
} }
root := t[i].root root := t[i].root
// Find route in tree // Find route in tree
value := root.getValue(rPath, c.params, unescape) value := root.getValue(rPath, c.params, c.skippedNodes, unescape)
if value.params != nil { if value.params != nil {
c.Params = *value.params c.Params = *value.params
} }
if value.handlers != nil { if value.handlers != nil {
c.handlers = value.handlers c.handlers = value.handlers
c.fullPath = value.fullPath c.fullPath = value.fullPath
c.Next() c.Next()
c.writermem.WriteHeaderNow() c.writermem.WriteHeaderNow()
return return
} }
skipping to change at line 510 skipping to change at line 576
} }
} }
break break
} }
if engine.HandleMethodNotAllowed { if engine.HandleMethodNotAllowed {
for _, tree := range engine.trees { for _, tree := range engine.trees {
if tree.method == httpMethod { if tree.method == httpMethod {
continue continue
} }
if value := tree.root.getValue(rPath, nil, unescape); val ue.handlers != nil { if value := tree.root.getValue(rPath, nil, c.skippedNodes , unescape); value.handlers != nil {
c.handlers = engine.allNoMethod c.handlers = engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, defaul t405Body) serveError(c, http.StatusMethodNotAllowed, defaul t405Body)
return return
} }
} }
} }
c.handlers = engine.allNoRoute c.handlers = engine.allNoRoute
serveError(c, http.StatusNotFound, default404Body) serveError(c, http.StatusNotFound, default404Body)
} }
 End of changes. 23 change blocks. 
31 lines changed or deleted 112 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)