From 9c6f92b16b3cf7f00ed3cd55af202040cd5b6134 Mon Sep 17 00:00:00 2001 From: 3ocene <7623873+ben-turner@users.noreply.github.com> Date: Sat, 29 Oct 2022 15:24:43 -0700 Subject: [PATCH 1/2] add GetContext and ReleaseContext methods - Add a method for retrieving a new *Context given an http.ResponseWriter and *http.Request. - Add a method for returning to the pool *Contexts which were provided by *Engine.GetRequest to the pool This allows contexts to be manipulated prior to handling whereas ServeHTTP does not provide the caller with access to the context. --- gin.go | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/gin.go b/gin.go index a2e2e67c..46cff494 100644 --- a/gin.go +++ b/gin.go @@ -562,16 +562,39 @@ func (engine *Engine) RunListener(listener net.Listener) (err error) { return } -// ServeHTTP conforms to the http.Handler interface. -func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { +// GetContext transforms a http.ResponseWriter and *http.Request into a new +// *Context without handling the request. This new context can then be passed +// to *Engine.HandleContext for handling. +// +// Any contexts created with this method are not automatically returned to the +// pool, so it is recommended that you call *Engine.ReleaseContext when you are +// done with it, though this is not required. +func (engine *Engine) GetContext(w http.ResponseWriter, req *http.Request) *Context { c := engine.pool.Get().(*Context) c.writermem.reset(w) c.Request = req c.reset() + return c +} + +// ReleaseContext releases a context created with *Engine.GetContext back into +// the pool. Releasing a context marks it as available for reuse and therefore +// must only be called once the context is no longer in use. Releasing a context +// is not required, but it is recommended to improve performance. Calling this +// method on a context that is not created with *Engine.GetContext will result +// in undefined behavior. +func (engine *Engine) ReleaseContext(c *Context) { + engine.pool.Put(c) +} + +// ServeHTTP conforms to the http.Handler interface. +func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { + c := engine.GetContext(w, req) + engine.handleHTTPRequest(c) - engine.pool.Put(c) + engine.ReleaseContext(c) } // HandleContext re-enters a context that has been rewritten. From c17ae54e64177e6e340f475a40a2eb1a7a876e89 Mon Sep 17 00:00:00 2001 From: 3ocene <7623873+ben-turner@users.noreply.github.com> Date: Sat, 29 Oct 2022 16:11:47 -0700 Subject: [PATCH 2/2] add method for handling contexts without resetting HandleContext resets contexts completely, overwriting any modifications since GetContext was called. This is undermines the purpose of being able to GetContexts separately, so this commit adds a new method which only resets the index, but leaves everything else intact. --- gin.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gin.go b/gin.go index 46cff494..ee245635 100644 --- a/gin.go +++ b/gin.go @@ -588,6 +588,16 @@ func (engine *Engine) ReleaseContext(c *Context) { engine.pool.Put(c) } +// HandleContextAsIs handles the context as is without resetting it. This means +// that all key/values, middleware, etc. will be retained. This is useful for +// handling a context that has been created with *Engine.GetContext. +func (engine *Engine) HandleContextAsIs(c *Context) { + oldIndex := c.index + c.index = -1 + engine.handleHTTPRequest(c) + c.index = oldIndex +} + // ServeHTTP conforms to the http.Handler interface. func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { c := engine.GetContext(w, req)