mirror of
https://github.com/rls-moe/nyx
synced 2024-11-14 22:12:24 +00:00
139 lines
3.1 KiB
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
|
||
|
}
|