Cleaning up performance branch
This commit is contained in:
		| @ -6,7 +6,6 @@ package binding | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| @ -27,8 +26,6 @@ func mapForm(ptr interface{}, form map[string][]string) error { | ||||
| 			inputFieldName = typeField.Name | ||||
| 		} | ||||
| 		inputValue, exists := form[inputFieldName] | ||||
| 		fmt.Println("Field: "+inputFieldName+" Value: ", inputValue) | ||||
|  | ||||
| 		if !exists { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
							
								
								
									
										12
									
								
								context.go
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								context.go
									
									
									
									
									
								
							| @ -20,7 +20,6 @@ const AbortIndex = math.MaxInt8 / 2 | ||||
| // Context is the most important part of gin. It allows us to pass variables between middleware, | ||||
| // manage the flow, validate the JSON of a request and render a JSON response for example. | ||||
| type Context struct { | ||||
| 	Engine    *Engine | ||||
| 	writermem responseWriter | ||||
| 	Request   *http.Request | ||||
| 	Writer    ResponseWriter | ||||
| @ -30,6 +29,7 @@ type Context struct { | ||||
| 	handlers []HandlerFunc | ||||
| 	index    int8 | ||||
|  | ||||
| 	Engine   *Engine | ||||
| 	Keys     map[string]interface{} | ||||
| 	Errors   errorMsgs | ||||
| 	accepted []string | ||||
| @ -40,10 +40,13 @@ type Context struct { | ||||
| /************************************/ | ||||
|  | ||||
| func (c *Context) reset() { | ||||
| 	c.Keys = nil | ||||
| 	c.Writer = &c.writermem | ||||
| 	c.Params = c.Params[0:0] | ||||
| 	c.handlers = nil | ||||
| 	c.index = -1 | ||||
| 	c.accepted = nil | ||||
| 	c.Keys = nil | ||||
| 	c.Errors = c.Errors[0:0] | ||||
| 	c.accepted = nil | ||||
| } | ||||
|  | ||||
| func (c *Context) Copy() *Context { | ||||
| @ -114,9 +117,8 @@ func (c *Context) LastError() error { | ||||
| 	nuErrors := len(c.Errors) | ||||
| 	if nuErrors > 0 { | ||||
| 		return errors.New(c.Errors[nuErrors-1].Err) | ||||
| 	} else { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| /************************************/ | ||||
|  | ||||
							
								
								
									
										177
									
								
								gin.go
									
									
									
									
									
								
							
							
						
						
									
										177
									
								
								gin.go
									
									
									
									
									
								
							| @ -27,9 +27,9 @@ type Params []Param | ||||
| // 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) string { | ||||
| 	for i := range ps { | ||||
| 		if ps[i].Key == name { | ||||
| 			return ps[i].Value | ||||
| 	for _, entry := range ps { | ||||
| 		if entry.Key == name { | ||||
| 			return entry.Value | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| @ -43,7 +43,7 @@ type ( | ||||
|  | ||||
| 	// Represents the web framework, it wraps the blazing fast httprouter multiplexer and a list of global middlewares. | ||||
| 	Engine struct { | ||||
| 		*RouterGroup | ||||
| 		RouterGroup | ||||
| 		HTMLRender  render.Render | ||||
| 		pool        sync.Pool | ||||
| 		allNoRoute  []HandlerFunc | ||||
| @ -84,16 +84,16 @@ type ( | ||||
| // The most basic configuration | ||||
| func New() *Engine { | ||||
| 	engine := &Engine{ | ||||
| 		RouterGroup: RouterGroup{ | ||||
| 			Handlers:     nil, | ||||
| 			absolutePath: "/", | ||||
| 		}, | ||||
| 		RedirectTrailingSlash:  true, | ||||
| 		RedirectFixedPath:      true, | ||||
| 		HandleMethodNotAllowed: true, | ||||
| 		trees: make(map[string]*node), | ||||
| 	} | ||||
| 	engine.RouterGroup = &RouterGroup{ | ||||
| 		Handlers:     nil, | ||||
| 		absolutePath: "/", | ||||
| 		engine:       engine, | ||||
| 	} | ||||
| 	engine.RouterGroup.engine = engine | ||||
| 	engine.pool.New = func() interface{} { | ||||
| 		return engine.allocateContext() | ||||
| 	} | ||||
| @ -109,23 +109,10 @@ func Default() *Engine { | ||||
|  | ||||
| func (engine *Engine) allocateContext() (context *Context) { | ||||
| 	context = &Context{Engine: engine} | ||||
| 	context.Writer = &context.writermem | ||||
| 	context.Input = inputHolder{context: context} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (engine *Engine) createContext(w http.ResponseWriter, req *http.Request) *Context { | ||||
| 	c := engine.pool.Get().(*Context) | ||||
| 	c.reset() | ||||
| 	c.writermem.reset(w) | ||||
| 	c.Request = req | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| func (engine *Engine) reuseContext(c *Context) { | ||||
| 	engine.pool.Put(c) | ||||
| } | ||||
|  | ||||
| func (engine *Engine) LoadHTMLGlob(pattern string) { | ||||
| 	if IsDebugging() { | ||||
| 		r := &render.HTMLDebugRender{Glob: pattern} | ||||
| @ -177,40 +164,10 @@ func (engine *Engine) rebuild405Handlers() { | ||||
| 	engine.allNoMethod = engine.combineHandlers(engine.noMethod) | ||||
| } | ||||
|  | ||||
| func (engine *Engine) handle404(c *Context) { | ||||
| 	// set 404 by default, useful for logging | ||||
| 	c.handlers = engine.allNoRoute | ||||
| 	c.Writer.WriteHeader(404) | ||||
| 	c.Next() | ||||
| 	if !c.Writer.Written() { | ||||
| 		if c.Writer.Status() == 404 { | ||||
| 			c.Data(-1, binding.MIMEPlain, default404Body) | ||||
| 		} else { | ||||
| 			c.Writer.WriteHeaderNow() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (engine *Engine) handle405(c *Context) { | ||||
| 	// set 405 by default, useful for logging | ||||
| 	c.handlers = engine.allNoMethod | ||||
| 	c.Writer.WriteHeader(405) | ||||
| 	c.Next() | ||||
| 	if !c.Writer.Written() { | ||||
| 		if c.Writer.Status() == 405 { | ||||
| 			c.Data(-1, binding.MIMEPlain, default405Body) | ||||
| 		} else { | ||||
| 			c.Writer.WriteHeaderNow() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (engine *Engine) handle(method, path string, handlers []HandlerFunc) { | ||||
| 	if path[0] != '/' { | ||||
| 		panic("path must begin with '/'") | ||||
| 	} | ||||
|  | ||||
| 	//methodCode := codeForHTTPMethod(method) | ||||
| 	root := engine.trees[method] | ||||
| 	if root == nil { | ||||
| 		root = new(node) | ||||
| @ -219,27 +176,6 @@ func (engine *Engine) handle(method, path string, handlers []HandlerFunc) { | ||||
| 	root.addRoute(path, handlers) | ||||
| } | ||||
|  | ||||
| // ServeHTTP makes the router implement the http.Handler interface. | ||||
| func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { | ||||
| 	c := engine.createContext(w, req) | ||||
| 	//methodCode := codeForHTTPMethod(req.Method) | ||||
| 	if root := engine.trees[req.Method]; root != nil { | ||||
| 		path := req.URL.Path | ||||
| 		if handlers, params, _ := root.getValue(path, c.Params); handlers != nil { | ||||
| 			c.handlers = handlers | ||||
| 			c.Params = params | ||||
| 			c.Next() | ||||
| 			c.Writer.WriteHeaderNow() | ||||
| 			engine.reuseContext(c) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Handle 404 | ||||
| 	engine.handle404(c) | ||||
| 	engine.reuseContext(c) | ||||
| } | ||||
|  | ||||
| func (engine *Engine) Run(addr string) error { | ||||
| 	debugPrint("Listening and serving HTTP on %s\n", addr) | ||||
| 	return http.ListenAndServe(addr, engine) | ||||
| @ -249,3 +185,98 @@ func (engine *Engine) RunTLS(addr string, cert string, key string) error { | ||||
| 	debugPrint("Listening and serving HTTPS on %s\n", addr) | ||||
| 	return http.ListenAndServeTLS(addr, cert, key, engine) | ||||
| } | ||||
|  | ||||
| // ServeHTTP makes the router implement the http.Handler interface. | ||||
| func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { | ||||
| 	context := engine.pool.Get().(*Context) | ||||
| 	context.writermem.reset(w) | ||||
| 	context.Request = req | ||||
| 	context.reset() | ||||
|  | ||||
| 	engine.serveHTTPRequest(context) | ||||
|  | ||||
| 	engine.pool.Put(context) | ||||
| } | ||||
|  | ||||
| func (engine *Engine) serveHTTPRequest(context *Context) { | ||||
| 	httpMethod := context.Request.Method | ||||
| 	path := context.Request.URL.Path | ||||
|  | ||||
| 	// Find root of the tree for the given HTTP method | ||||
| 	if root := engine.trees[httpMethod]; root != nil { | ||||
| 		// Find route in tree | ||||
| 		handlers, params, tsr := root.getValue(path, context.Params) | ||||
| 		// Dispatch if we found any handlers | ||||
| 		if handlers != nil { | ||||
| 			context.handlers = handlers | ||||
| 			context.Params = params | ||||
| 			context.Next() | ||||
| 			context.writermem.WriteHeaderNow() | ||||
| 			return | ||||
|  | ||||
| 		} else if httpMethod != "CONNECT" && path != "/" { | ||||
| 			if engine.serveAutoRedirect(context, root, tsr) { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if engine.HandleMethodNotAllowed { | ||||
| 		for method, root := range engine.trees { | ||||
| 			if method != httpMethod { | ||||
| 				if handlers, _, _ := root.getValue(path, nil); handlers != nil { | ||||
| 					context.handlers = engine.allNoMethod | ||||
| 					serveError(context, 405, default405Body) | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	context.handlers = engine.allNoMethod | ||||
| 	serveError(context, 404, default404Body) | ||||
| } | ||||
|  | ||||
| func (engine *Engine) serveAutoRedirect(c *Context, root *node, tsr bool) bool { | ||||
| 	req := c.Request | ||||
| 	path := req.URL.Path | ||||
| 	code := 301 // Permanent redirect, request with GET method | ||||
| 	if req.Method != "GET" { | ||||
| 		code = 307 | ||||
| 	} | ||||
|  | ||||
| 	if tsr && engine.RedirectTrailingSlash { | ||||
| 		if len(path) > 1 && path[len(path)-1] == '/' { | ||||
| 			req.URL.Path = path[:len(path)-1] | ||||
| 		} else { | ||||
| 			req.URL.Path = path + "/" | ||||
| 		} | ||||
| 		http.Redirect(c.Writer, req, req.URL.String(), code) | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// Try to fix the request path | ||||
| 	if engine.RedirectFixedPath { | ||||
| 		fixedPath, found := root.findCaseInsensitivePath( | ||||
| 			CleanPath(path), | ||||
| 			engine.RedirectTrailingSlash, | ||||
| 		) | ||||
| 		if found { | ||||
| 			req.URL.Path = string(fixedPath) | ||||
| 			http.Redirect(c.Writer, req, req.URL.String(), code) | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func serveError(c *Context, code int, defaultMessage []byte) { | ||||
| 	c.writermem.status = code | ||||
| 	c.Next() | ||||
| 	if !c.Writer.Written() { | ||||
| 		if c.Writer.Status() == code { | ||||
| 			c.Data(-1, binding.MIMEPlain, defaultMessage) | ||||
| 		} else { | ||||
| 			c.Writer.WriteHeaderNow() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -125,13 +125,5 @@ func (group *RouterGroup) combineHandlers(handlers []HandlerFunc) []HandlerFunc | ||||
| } | ||||
|  | ||||
| func (group *RouterGroup) calculateAbsolutePath(relativePath string) string { | ||||
| 	if len(relativePath) == 0 { | ||||
| 		return group.absolutePath | ||||
| 	} | ||||
| 	absolutePath := path.Join(group.absolutePath, relativePath) | ||||
| 	appendSlash := lastChar(relativePath) == '/' && lastChar(absolutePath) != '/' | ||||
| 	if appendSlash { | ||||
| 		return absolutePath + "/" | ||||
| 	} | ||||
| 	return absolutePath | ||||
| 	return joinPaths(group.absolutePath, relativePath) | ||||
| } | ||||
|  | ||||
							
								
								
									
										14
									
								
								tree.go
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								tree.go
									
									
									
									
									
								
							| @ -312,6 +312,7 @@ func (n *node) insertChild(numParams uint8, path string, handlers []HandlerFunc) | ||||
| // made if a handle exists with an extra (without the) trailing slash for the | ||||
| // given path. | ||||
| func (n *node) getValue(path string, po Params) (handlers []HandlerFunc, p Params, tsr bool) { | ||||
| 	p = po | ||||
| walk: // Outer loop for walking the tree | ||||
| 	for { | ||||
| 		if len(path) > len(n.path) { | ||||
| @ -334,7 +335,6 @@ walk: // Outer loop for walking the tree | ||||
| 					// trailing slash if a leaf exists for that path. | ||||
| 					tsr = (path == "/" && n.handlers != nil) | ||||
| 					return | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 				// handle wildcard child | ||||
| @ -348,12 +348,8 @@ walk: // Outer loop for walking the tree | ||||
| 					} | ||||
|  | ||||
| 					// save param value | ||||
| 					if p == nil { | ||||
| 						if cap(po) < int(n.maxParams) { | ||||
| 					if cap(p) < int(n.maxParams) { | ||||
| 						p = make(Params, 0, n.maxParams) | ||||
| 						} else { | ||||
| 							p = po[0:0] | ||||
| 						} | ||||
| 					} | ||||
| 					i := len(p) | ||||
| 					p = p[:i+1] // expand slice within preallocated capacity | ||||
| @ -386,12 +382,8 @@ walk: // Outer loop for walking the tree | ||||
|  | ||||
| 				case catchAll: | ||||
| 					// save param value | ||||
| 					if p == nil { | ||||
| 						if cap(po) < int(n.maxParams) { | ||||
| 					if cap(p) < int(n.maxParams) { | ||||
| 						p = make(Params, 0, n.maxParams) | ||||
| 						} else { | ||||
| 							p = po[0:0] | ||||
| 						} | ||||
| 					} | ||||
| 					i := len(p) | ||||
| 					p = p[:i+1] // expand slice within preallocated capacity | ||||
|  | ||||
							
								
								
									
										42
									
								
								utils.go
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								utils.go
									
									
									
									
									
								
							| @ -7,23 +7,12 @@ package gin | ||||
| import ( | ||||
| 	"encoding/xml" | ||||
| 	"log" | ||||
| 	"path" | ||||
| 	"reflect" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	methodGET     = iota | ||||
| 	methodPOST    = iota | ||||
| 	methodPUT     = iota | ||||
| 	methodAHEAD   = iota | ||||
| 	methodOPTIONS = iota | ||||
| 	methodDELETE  = iota | ||||
| 	methodCONNECT = iota | ||||
| 	methodTRACE   = iota | ||||
| 	methodUnknown = iota | ||||
| ) | ||||
|  | ||||
| type H map[string]interface{} | ||||
|  | ||||
| // Allows type H to be used with xml.Marshal | ||||
| @ -93,25 +82,14 @@ func nameOfFunction(f interface{}) string { | ||||
| 	return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() | ||||
| } | ||||
|  | ||||
| func codeForHTTPMethod(method string) int { | ||||
| 	switch method { | ||||
| 	case "GET": | ||||
| 		return methodGET | ||||
| 	case "POST": | ||||
| 		return methodPOST | ||||
| 	case "PUT": | ||||
| 		return methodPUT | ||||
| 	case "AHEAD": | ||||
| 		return methodAHEAD | ||||
| 	case "OPTIONS": | ||||
| 		return methodOPTIONS | ||||
| 	case "DELETE": | ||||
| 		return methodDELETE | ||||
| 	case "TRACE": | ||||
| 		return methodTRACE | ||||
| 	case "CONNECT": | ||||
| 		return methodCONNECT | ||||
| 	default: | ||||
| 		return methodUnknown | ||||
| func joinPaths(absolutePath, relativePath string) string { | ||||
| 	if len(relativePath) == 0 { | ||||
| 		return absolutePath | ||||
| 	} | ||||
| 	absolutePath = path.Join(absolutePath, relativePath) | ||||
| 	appendSlash := lastChar(relativePath) == '/' && lastChar(absolutePath) != '/' | ||||
| 	if appendSlash { | ||||
| 		return absolutePath + "/" | ||||
| 	} | ||||
| 	return absolutePath | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user