package handlers import ( "net/http" ) // Structure that holds the context map and exposes the ResponseWriter interface. type contextResponseWriter struct { http.ResponseWriter m map[interface{}]interface{} } // Implement the WrapWriter interface. func (this *contextResponseWriter) WrappedWriter() http.ResponseWriter { return this.ResponseWriter } // ContextHandlerFunc is the same as ContextHandler, it is just a convenience // signature that accepts a func(http.ResponseWriter, *http.Request) instead of // a http.Handler interface. It saves the boilerplate http.HandlerFunc() cast. func ContextHandlerFunc(h http.HandlerFunc, cap int) http.HandlerFunc { return ContextHandler(h, cap) } // ContextHandler gives a context storage that lives only for the duration of // the request, with no locking involved. func ContextHandler(h http.Handler, cap int) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if _, ok := GetContext(w); ok { // Self-awareness, context handler is already set up h.ServeHTTP(w, r) return } // Create the context-providing ResponseWriter replacement. ctxw := &contextResponseWriter{ w, make(map[interface{}]interface{}, cap), } // Call the wrapped handler with the context-aware writer h.ServeHTTP(ctxw, r) } } // Helper function to retrieve the context map from the ResponseWriter interface. func GetContext(w http.ResponseWriter) (map[interface{}]interface{}, bool) { ctxw, ok := GetResponseWriter(w, func(tst http.ResponseWriter) bool { _, ok := tst.(*contextResponseWriter) return ok }) if ok { return ctxw.(*contextResponseWriter).m, true } return nil, false }