-
-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from guregu/newctx
Support 1.7 context package
- Loading branch information
Showing
16 changed files
with
1,263 additions
and
332 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package kami | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/dimfeld/httptreemux" | ||
) | ||
|
||
var ( | ||
routes = newRouter() | ||
enable405 = true | ||
) | ||
|
||
func init() { | ||
// set up the default 404/405 handlers | ||
NotFound(nil) | ||
MethodNotAllowed(nil) | ||
} | ||
|
||
func newRouter() *httptreemux.TreeMux { | ||
r := httptreemux.New() | ||
r.PathSource = httptreemux.URLPath | ||
r.RedirectBehavior = httptreemux.Redirect307 | ||
r.RedirectMethodBehavior = map[string]httptreemux.RedirectBehavior{ | ||
"GET": httptreemux.Redirect301, | ||
} | ||
return r | ||
} | ||
|
||
// Handler returns an http.Handler serving registered routes. | ||
func Handler() http.Handler { | ||
return routes | ||
} | ||
|
||
// Handle registers an arbitrary method handler under the given path. | ||
func Handle(method, path string, handler HandlerType) { | ||
routes.Handle(method, path, bless(wrap(handler))) | ||
} | ||
|
||
// Get registers a GET handler under the given path. | ||
func Get(path string, handler HandlerType) { | ||
Handle("GET", path, handler) | ||
} | ||
|
||
// Post registers a POST handler under the given path. | ||
func Post(path string, handler HandlerType) { | ||
Handle("POST", path, handler) | ||
} | ||
|
||
// Put registers a PUT handler under the given path. | ||
func Put(path string, handler HandlerType) { | ||
Handle("PUT", path, handler) | ||
} | ||
|
||
// Patch registers a PATCH handler under the given path. | ||
func Patch(path string, handler HandlerType) { | ||
Handle("PATCH", path, handler) | ||
} | ||
|
||
// Head registers a HEAD handler under the given path. | ||
func Head(path string, handler HandlerType) { | ||
Handle("HEAD", path, handler) | ||
} | ||
|
||
// Head registers a OPTIONS handler under the given path. | ||
func Options(path string, handler HandlerType) { | ||
Handle("OPTIONS", path, handler) | ||
} | ||
|
||
// Delete registers a DELETE handler under the given path. | ||
func Delete(path string, handler HandlerType) { | ||
Handle("DELETE", path, handler) | ||
} | ||
|
||
// EnableMethodNotAllowed enables or disables automatic Method Not Allowed handling. | ||
// Note that this is enabled by default. | ||
func EnableMethodNotAllowed(enabled bool) { | ||
enable405 = enabled | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// +build go1.7 | ||
|
||
package kami | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
|
||
"github.com/dimfeld/httptreemux" | ||
"github.com/zenazn/goji/web/mutil" | ||
) | ||
|
||
var ( | ||
// Context is the root "god object" from which every request's context will derive. | ||
Context = context.Background() | ||
|
||
// PanicHandler will, if set, be called on panics. | ||
// You can use kami.Exception(ctx) within the panic handler to get panic details. | ||
PanicHandler HandlerType | ||
// LogHandler will, if set, wrap every request and be called at the very end. | ||
LogHandler func(context.Context, mutil.WriterProxy, *http.Request) | ||
) | ||
|
||
// NotFound registers a special handler for unregistered (404) paths. | ||
// If handle is nil, use the default http.NotFound behavior. | ||
func NotFound(handler HandlerType) { | ||
// set up the default handler if needed | ||
// we need to bless this so middleware will still run for a 404 request | ||
if handler == nil { | ||
handler = HandlerFunc(func(_ context.Context, w http.ResponseWriter, r *http.Request) { | ||
http.NotFound(w, r) | ||
}) | ||
} | ||
|
||
h := bless(wrap(handler)) | ||
routes.NotFoundHandler = func(w http.ResponseWriter, r *http.Request) { | ||
h(w, r, nil) | ||
} | ||
} | ||
|
||
// MethodNotAllowed registers a special handler for automatically responding | ||
// to invalid method requests (405). | ||
func MethodNotAllowed(handler HandlerType) { | ||
if handler == nil { | ||
handler = HandlerFunc(func(_ context.Context, w http.ResponseWriter, r *http.Request) { | ||
http.Error(w, | ||
http.StatusText(http.StatusMethodNotAllowed), | ||
http.StatusMethodNotAllowed, | ||
) | ||
}) | ||
} | ||
|
||
h := bless(wrap(handler)) | ||
routes.MethodNotAllowedHandler = func(w http.ResponseWriter, r *http.Request, methods map[string]httptreemux.HandlerFunc) { | ||
if !enable405 { | ||
routes.NotFoundHandler(w, r) | ||
return | ||
} | ||
h(w, r, nil) | ||
} | ||
} | ||
|
||
// bless creates a new kamified handler using the global mux and middleware. | ||
func bless(h ContextHandler) httptreemux.HandlerFunc { | ||
k := kami{ | ||
handler: h, | ||
base: &Context, | ||
middleware: defaultMW, | ||
panicHandler: &PanicHandler, | ||
logHandler: &LogHandler, | ||
} | ||
return k.handle | ||
} | ||
|
||
// Reset changes the root Context to context.Background(). | ||
// It removes every handler and all middleware. | ||
func Reset() { | ||
Context = context.Background() | ||
PanicHandler = nil | ||
LogHandler = nil | ||
defaultMW = newWares() | ||
routes = newRouter() | ||
NotFound(nil) | ||
MethodNotAllowed(nil) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// +build !go1.7 | ||
|
||
package kami | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/dimfeld/httptreemux" | ||
"github.com/zenazn/goji/web/mutil" | ||
"golang.org/x/net/context" | ||
) | ||
|
||
var ( | ||
// Context is the root "god object" from which every request's context will derive. | ||
Context = context.Background() | ||
|
||
// PanicHandler will, if set, be called on panics. | ||
// You can use kami.Exception(ctx) within the panic handler to get panic details. | ||
PanicHandler HandlerType | ||
// LogHandler will, if set, wrap every request and be called at the very end. | ||
LogHandler func(context.Context, mutil.WriterProxy, *http.Request) | ||
) | ||
|
||
// NotFound registers a special handler for unregistered (404) paths. | ||
// If handle is nil, use the default http.NotFound behavior. | ||
func NotFound(handler HandlerType) { | ||
// set up the default handler if needed | ||
// we need to bless this so middleware will still run for a 404 request | ||
if handler == nil { | ||
handler = HandlerFunc(func(_ context.Context, w http.ResponseWriter, r *http.Request) { | ||
http.NotFound(w, r) | ||
}) | ||
} | ||
|
||
h := bless(wrap(handler)) | ||
routes.NotFoundHandler = func(w http.ResponseWriter, r *http.Request) { | ||
h(w, r, nil) | ||
} | ||
} | ||
|
||
// MethodNotAllowed registers a special handler for automatically responding | ||
// to invalid method requests (405). | ||
func MethodNotAllowed(handler HandlerType) { | ||
if handler == nil { | ||
handler = HandlerFunc(func(_ context.Context, w http.ResponseWriter, r *http.Request) { | ||
http.Error(w, | ||
http.StatusText(http.StatusMethodNotAllowed), | ||
http.StatusMethodNotAllowed, | ||
) | ||
}) | ||
} | ||
|
||
h := bless(wrap(handler)) | ||
routes.MethodNotAllowedHandler = func(w http.ResponseWriter, r *http.Request, methods map[string]httptreemux.HandlerFunc) { | ||
if !enable405 { | ||
routes.NotFoundHandler(w, r) | ||
return | ||
} | ||
h(w, r, nil) | ||
} | ||
} | ||
|
||
// bless creates a new kamified handler using the global mux and middleware. | ||
func bless(h ContextHandler) httptreemux.HandlerFunc { | ||
k := kami{ | ||
handler: h, | ||
base: &Context, | ||
middleware: defaultMW, | ||
panicHandler: &PanicHandler, | ||
logHandler: &LogHandler, | ||
} | ||
return k.handle | ||
} | ||
|
||
// Reset changes the root Context to context.Background(). | ||
// It removes every handler and all middleware. | ||
func Reset() { | ||
Context = context.Background() | ||
PanicHandler = nil | ||
LogHandler = nil | ||
defaultMW = newWares() | ||
routes = newRouter() | ||
NotFound(nil) | ||
MethodNotAllowed(nil) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// +build go1.7 | ||
|
||
package kami | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
|
||
netcontext "golang.org/x/net/context" | ||
) | ||
|
||
// HandlerType is the type of Handlers and types that kami internally converts to | ||
// ContextHandler. In order to provide an expressive API, this type is an alias for | ||
// interface{} that is named for the purposes of documentation, however only the | ||
// following concrete types are accepted: | ||
// - types that implement http.Handler | ||
// - types that implement ContextHandler | ||
// - func(http.ResponseWriter, *http.Request) | ||
// - func(context.Context, http.ResponseWriter, *http.Request) | ||
type HandlerType interface{} | ||
|
||
// ContextHandler is like http.Handler but supports context. | ||
type ContextHandler interface { | ||
ServeHTTPContext(context.Context, http.ResponseWriter, *http.Request) | ||
} | ||
|
||
// OldContextHandler is like ContextHandler but uses the old x/net/context. | ||
type OldContextHandler interface { | ||
ServeHTTPContext(netcontext.Context, http.ResponseWriter, *http.Request) | ||
} | ||
|
||
// HandlerFunc is like http.HandlerFunc with context. | ||
type HandlerFunc func(context.Context, http.ResponseWriter, *http.Request) | ||
|
||
func (h HandlerFunc) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) { | ||
h(ctx, w, r) | ||
} | ||
|
||
// wrap tries to turn a HandlerType into a ContextHandler | ||
func wrap(h HandlerType) ContextHandler { | ||
switch x := h.(type) { | ||
case ContextHandler: | ||
return x | ||
case func(context.Context, http.ResponseWriter, *http.Request): | ||
return HandlerFunc(x) | ||
case func(netcontext.Context, http.ResponseWriter, *http.Request): | ||
return HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { | ||
x(ctx, w, r) | ||
}) | ||
case http.Handler: | ||
return HandlerFunc(func(_ context.Context, w http.ResponseWriter, r *http.Request) { | ||
x.ServeHTTP(w, r) | ||
}) | ||
case func(http.ResponseWriter, *http.Request): | ||
return HandlerFunc(func(_ context.Context, w http.ResponseWriter, r *http.Request) { | ||
x(w, r) | ||
}) | ||
} | ||
panic(fmt.Errorf("unsupported HandlerType: %T", h)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
// +build !go1.7 | ||
|
||
package kami | ||
|
||
import ( | ||
|
Oops, something went wrong.