|
|
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
|
|
|
|
|
|
/*
|
|
|
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()
|
|
|
}
|