add FromContext API for macaron and reqcontext, add API for standard middleware in macaron (#37057)

This commit is contained in:
Serge Zaitsev
2021-07-26 06:11:43 +02:00
committed by GitHub
parent f78452be30
commit 827a5b7021
2 changed files with 52 additions and 1 deletions

View File

@@ -18,6 +18,7 @@
package macaron // import "gopkg.in/macaron.v1"
import (
"context"
"log"
"net/http"
"os"
@@ -151,6 +152,41 @@ func (m *Macaron) Handlers(handlers ...Handler) {
// Macaron stops future process when it returns true.
type BeforeHandler func(rw http.ResponseWriter, req *http.Request) bool
// macaronContextKey is used to store/fetch macaron.Context inside context.Context
type macaronContextKey struct{}
// FromContext returns the macaron context stored in a context.Context, if any.
func FromContext(c context.Context) *Context {
if mc, ok := c.Value(macaronContextKey{}).(*Context); ok {
return mc
}
return nil
}
// UseMiddleware is a traditional approach to writing middleware in Go.
// A middleware is a function that has a reference to the next handler in the chain
// and returns the actual middleware handler, that may do its job and optionally
// call next.
// Due to how Macaron handles/injects requests and responses we patch the macaron.Context
// to use the new ResponseWriter and http.Request here. The caller may only call
// `next.ServeHTTP(rw, req)` to pass a modified response writer and/or a request to the
// further middlewares in the chain.
func (m *Macaron) UseMiddleware(middleware func(http.Handler) http.Handler) {
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
c := FromContext(req.Context())
c.Req.Request = req
if mrw, ok := rw.(*responseWriter); ok {
c.Resp = mrw
} else {
c.Resp = NewResponseWriter(req.Method, rw)
}
c.Map(req)
c.MapTo(rw, (*http.ResponseWriter)(nil))
c.Next()
})
m.handlers = append(m.handlers, Handler(middleware(next)))
}
// Use adds a middleware Handler to the stack,
// and panics if the handler is not a callable func.
// Middleware Handlers are invoked in the order that they are added.
@@ -165,15 +201,16 @@ func (m *Macaron) createContext(rw http.ResponseWriter, req *http.Request) *Cont
handlers: m.handlers,
index: 0,
Router: m.Router,
Req: Request{req},
Resp: NewResponseWriter(req.Method, rw),
Render: &DummyRender{rw},
Data: make(map[string]interface{}),
}
req = req.WithContext(context.WithValue(req.Context(), macaronContextKey{}, c))
c.SetParent(m)
c.Map(c)
c.MapTo(c.Resp, (*http.ResponseWriter)(nil))
c.Map(req)
c.Req = Request{req}
return c
}

View File

@@ -62,6 +62,16 @@ func (h *ContextHandler) Init() error {
return nil
}
type reqContextKey struct{}
// FromContext returns the ReqContext value stored in a context.Context, if any.
func FromContext(c context.Context) *models.ReqContext {
if reqCtx, ok := c.Value(reqContextKey{}).(*models.ReqContext); ok {
return reqCtx
}
return nil
}
// Middleware provides a middleware to initialize the Macaron context.
func (h *ContextHandler) Middleware(mContext *macaron.Context) {
span, _ := opentracing.StartSpanFromContext(mContext.Req.Context(), "Auth - Middleware")
@@ -76,6 +86,10 @@ func (h *ContextHandler) Middleware(mContext *macaron.Context) {
Logger: log.New("context"),
}
// Inject ReqContext into a request context and replace the request instance in the macaron context
mContext.Req.Request = mContext.Req.WithContext(context.WithValue(mContext.Req.Context(), reqContextKey{}, reqContext))
mContext.Map(mContext.Req.Request)
traceID, exists := cw.ExtractTraceID(mContext.Req.Request.Context())
if exists {
reqContext.Logger = reqContext.Logger.New("traceID", traceID)