package web import ( "net/http" ) /* Mux is an HTTP multiplexer, much like net/http's ServeMux. It functions as both a middleware stack and as an HTTP router. Middleware provide a great abstraction for actions that must be performed on every request, such as request logging and authentication. To append, insert, and remove middleware, you can call the Use, Insert, and Abandon functions respectively. Routes may be added using any of the HTTP verb functions (Get, Post, etc.), or through the generic Handle function. Goji's routing algorithm is very simple: routes are processed in the order they are added, and the first matching route will be executed. Routes match if their HTTP method and Pattern both match. */ type Mux struct { ms mStack rt router } // New creates a new Mux without any routes or middleware. func New() *Mux { mux := Mux{ ms: mStack{ stack: make([]mLayer, 0), pool: makeCPool(), }, rt: router{ routes: make([]route, 0), notFound: parseHandler(http.NotFound), }, } mux.ms.router = &mux.rt return &mux } // ServeHTTP processes HTTP requests. Satisfies net/http.Handler. func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { stack := m.ms.alloc() stack.ServeHTTP(w, r) m.ms.release(stack) } // ServeHTTPC creates a context dependent request with the given Mux. Satisfies // the Handler interface. func (m *Mux) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) { stack := m.ms.alloc() stack.ServeHTTPC(c, w, r) m.ms.release(stack) } // Middleware Stack functions // Append the given middleware to the middleware stack. // // No attempt is made to enforce the uniqueness of middlewares. It is illegal to // call this function concurrently with active requests. func (m *Mux) Use(middleware MiddlewareType) { m.ms.Use(middleware) } // Insert the given middleware immediately before a given existing middleware in // the stack. Returns an error if "before" cannot be found in the current stack. // // No attempt is made to enforce the uniqueness of middlewares. If the insertion // point is ambiguous, the first (outermost) one is chosen. It is illegal to // call this function concurrently with active requests. func (m *Mux) Insert(middleware, before MiddlewareType) error { return m.ms.Insert(middleware, before) } // Remove the given middleware from the middleware stack. Returns an error if // no such middleware can be found. // // If the name of the middleware to delete is ambiguous, the first (outermost) // one is chosen. It is illegal to call this function concurrently with active // requests. func (m *Mux) Abandon(middleware MiddlewareType) error { return m.ms.Abandon(middleware) } // Router functions type routerMiddleware struct { m *Mux c *C h http.Handler } func (rm routerMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { if rm.c.Env == nil { rm.c.Env = make(map[interface{}]interface{}, 1) } rm.c.Env[MatchKey] = rm.m.rt.getMatch(rm.c, w, r) rm.h.ServeHTTP(w, r) } // Router is a middleware that performs routing and stores the resulting Match // in Goji's environment. If a routing Match is present at the end of the // middleware stack, that Match is used instead of re-routing. // // This middleware is especially useful to create post-routing middleware, e.g. // a request logger which prints which pattern or handler was selected, or an // authentication middleware which only applies to certain routes. func (m *Mux) Router(c *C, h http.Handler) http.Handler { return routerMiddleware{m, c, h} } /* Dispatch to the given handler when the pattern matches, regardless of HTTP method. This method is commonly used to implement sub-routing: an admin application, for instance, can expose a single handler that is attached to the main Mux by calling Handle("/admin/*", adminHandler) or similar. Note that this function doesn't strip this prefix from the path before forwarding it on (e.g., the handler will see the full path, including the "/admin/" part), but this functionality can easily be performed by an extra middleware layer. */ func (m *Mux) Handle(pattern PatternType, handler HandlerType) { m.rt.handleUntyped(pattern, mALL, handler) } // Dispatch to the given handler when the pattern matches and the HTTP method is // CONNECT. func (m *Mux) Connect(pattern PatternType, handler HandlerType) { m.rt.handleUntyped(pattern, mCONNECT, handler) } // Dispatch to the given handler when the pattern matches and the HTTP method is // DELETE. func (m *Mux) Delete(pattern PatternType, handler HandlerType) { m.rt.handleUntyped(pattern, mDELETE, handler) } // Dispatch to the given handler when the pattern matches and the HTTP method is // GET. // // All GET handlers also transparently serve HEAD requests, since net/http will // take care of all the fiddly bits for you. If you wish to provide an alternate // implementation of HEAD, you should add a handler explicitly and place it // above your GET handler. func (m *Mux) Get(pattern PatternType, handler HandlerType) { m.rt.handleUntyped(pattern, mGET|mHEAD, handler) } // Dispatch to the given handler when the pattern matches and the HTTP method is // HEAD. func (m *Mux) Head(pattern PatternType, handler HandlerType) { m.rt.handleUntyped(pattern, mHEAD, handler) } // Dispatch to the given handler when the pattern matches and the HTTP method is // OPTIONS. func (m *Mux) Options(pattern PatternType, handler HandlerType) { m.rt.handleUntyped(pattern, mOPTIONS, handler) } // Dispatch to the given handler when the pattern matches and the HTTP method is // PATCH. func (m *Mux) Patch(pattern PatternType, handler HandlerType) { m.rt.handleUntyped(pattern, mPATCH, handler) } // Dispatch to the given handler when the pattern matches and the HTTP method is // POST. func (m *Mux) Post(pattern PatternType, handler HandlerType) { m.rt.handleUntyped(pattern, mPOST, handler) } // Dispatch to the given handler when the pattern matches and the HTTP method is // PUT. func (m *Mux) Put(pattern PatternType, handler HandlerType) { m.rt.handleUntyped(pattern, mPUT, handler) } // Dispatch to the given handler when the pattern matches and the HTTP method is // TRACE. func (m *Mux) Trace(pattern PatternType, handler HandlerType) { m.rt.handleUntyped(pattern, mTRACE, handler) } // Set the fallback (i.e., 404) handler for this mux. // // As a convenience, the context environment variable "goji.web.validMethods" // (also available as the constant ValidMethodsKey) will be set to the list of // HTTP methods that could have been routed had they been provided on an // otherwise identical request. func (m *Mux) NotFound(handler HandlerType) { m.rt.notFound = parseHandler(handler) } // Compile the list of routes into bytecode. This only needs to be done once // after all the routes have been added, and will be called automatically for // you (at some performance cost on the first request) if you do not call it // explicitly. func (m *Mux) Compile() { m.rt.compile() }