nyx/vendor/github.com/pressly/chi/context.go

139 lines
3.1 KiB
Go

package chi
import (
"context"
"net"
"net/http"
)
var (
RouteCtxKey = &contextKey{"RouteContext"}
)
// Context is the default routing context set on the root node of a
// request context to track URL parameters and an optional routing path.
type Context struct {
// URL routing parameter key and values.
URLParams params
// Routing path override used by subrouters.
RoutePath string
// Routing pattern matching the path.
RoutePattern string
// Routing patterns throughout the lifecycle of the request,
// across all connected routers.
RoutePatterns []string
}
// NewRouteContext returns a new routing Context object.
func NewRouteContext() *Context {
return &Context{}
}
// reset a routing context to its initial state.
func (x *Context) reset() {
x.URLParams = x.URLParams[:0]
x.RoutePath = ""
x.RoutePattern = ""
x.RoutePatterns = x.RoutePatterns[:0]
}
// RouteContext returns chi's routing Context object from a
// http.Request Context.
func RouteContext(ctx context.Context) *Context {
return ctx.Value(RouteCtxKey).(*Context)
}
// URLParam returns the url parameter from a http.Request object.
func URLParam(r *http.Request, key string) string {
if rctx := RouteContext(r.Context()); rctx != nil {
return rctx.URLParams.Get(key)
}
return ""
}
// URLParamFromCtx returns the url parameter from a http.Request Context.
func URLParamFromCtx(ctx context.Context, key string) string {
if rctx := RouteContext(ctx); rctx != nil {
return rctx.URLParams.Get(key)
}
return ""
}
type param struct {
Key, Value string
}
type params []param
func (ps *params) Add(key string, value string) {
*ps = append(*ps, param{key, value})
}
func (ps params) Get(key string) string {
for _, p := range ps {
if p.Key == key {
return p.Value
}
}
return ""
}
func (ps *params) Set(key string, value string) {
idx := -1
for i, p := range *ps {
if p.Key == key {
idx = i
break
}
}
if idx < 0 {
(*ps).Add(key, value)
} else {
(*ps)[idx] = param{key, value}
}
}
func (ps *params) Del(key string) string {
for i, p := range *ps {
if p.Key == key {
*ps = append((*ps)[:i], (*ps)[i+1:]...)
return p.Value
}
}
return ""
}
// ServerBaseContext wraps an http.Handler to set the request context to the
// `baseCtx`.
func ServerBaseContext(h http.Handler, baseCtx context.Context) http.Handler {
fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
baseCtx := baseCtx
// Copy over default net/http server context keys
if v, ok := ctx.Value(http.ServerContextKey).(*http.Server); ok {
baseCtx = context.WithValue(baseCtx, http.ServerContextKey, v)
}
if v, ok := ctx.Value(http.LocalAddrContextKey).(net.Addr); ok {
baseCtx = context.WithValue(baseCtx, http.LocalAddrContextKey, v)
}
h.ServeHTTP(w, r.WithContext(baseCtx))
})
return fn
}
// contextKey is a value for use with context.WithValue. It's used as
// a pointer so it fits in an interface{} without allocation. This technique
// for defining context keys was copied from Go 1.7's new use of context in net/http.
type contextKey struct {
name string
}
func (k *contextKey) String() string {
return "chi context value " + k.name
}