123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- package chi
-
- import (
- "context"
- "net/http"
- "strings"
- )
-
- // 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.URLParam(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.URLParam(key)
- }
- return ""
- }
-
- // RouteContext returns chi's routing Context object from a
- // http.Request Context.
- func RouteContext(ctx context.Context) *Context {
- val, _ := ctx.Value(RouteCtxKey).(*Context)
- return val
- }
-
- // NewRouteContext returns a new routing Context object.
- func NewRouteContext() *Context {
- return &Context{}
- }
-
- var (
- // RouteCtxKey is the context.Context key to store the request context.
- RouteCtxKey = &contextKey{"RouteContext"}
- )
-
- // Context is the default routing context set on the root node of a
- // request context to track route patterns, URL parameters and
- // an optional routing path.
- type Context struct {
- Routes Routes
-
- // parentCtx is the parent of this one, for using Context as a
- // context.Context directly. This is an optimization that saves
- // 1 allocation.
- parentCtx context.Context
-
- // Routing path/method override used during the route search.
- // See Mux#routeHTTP method.
- RoutePath string
- RouteMethod string
-
- // URLParams are the stack of routeParams captured during the
- // routing lifecycle across a stack of sub-routers.
- URLParams RouteParams
-
- // Route parameters matched for the current sub-router. It is
- // intentionally unexported so it cant be tampered.
- routeParams RouteParams
-
- // The endpoint routing pattern that matched the request URI path
- // or `RoutePath` of the current sub-router. This value will update
- // during the lifecycle of a request passing through a stack of
- // sub-routers.
- routePattern string
-
- // Routing pattern stack throughout the lifecycle of the request,
- // across all connected routers. It is a record of all matching
- // patterns across a stack of sub-routers.
- RoutePatterns []string
-
- // methodNotAllowed hint
- methodNotAllowed bool
- }
-
- // Reset a routing context to its initial state.
- func (x *Context) Reset() {
- x.Routes = nil
- x.RoutePath = ""
- x.RouteMethod = ""
- x.RoutePatterns = x.RoutePatterns[:0]
- x.URLParams.Keys = x.URLParams.Keys[:0]
- x.URLParams.Values = x.URLParams.Values[:0]
-
- x.routePattern = ""
- x.routeParams.Keys = x.routeParams.Keys[:0]
- x.routeParams.Values = x.routeParams.Values[:0]
- x.methodNotAllowed = false
- x.parentCtx = nil
- }
-
- // URLParam returns the corresponding URL parameter value from the request
- // routing context.
- func (x *Context) URLParam(key string) string {
- for k := len(x.URLParams.Keys) - 1; k >= 0; k-- {
- if x.URLParams.Keys[k] == key {
- return x.URLParams.Values[k]
- }
- }
- return ""
- }
-
- // RoutePattern builds the routing pattern string for the particular
- // request, at the particular point during routing. This means, the value
- // will change throughout the execution of a request in a router. That is
- // why its advised to only use this value after calling the next handler.
- //
- // For example,
- //
- // func Instrument(next http.Handler) http.Handler {
- // return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- // next.ServeHTTP(w, r)
- // routePattern := chi.RouteContext(r.Context()).RoutePattern()
- // measure(w, r, routePattern)
- // })
- // }
- func (x *Context) RoutePattern() string {
- routePattern := strings.Join(x.RoutePatterns, "")
- return replaceWildcards(routePattern)
- }
-
- // replaceWildcards takes a route pattern and recursively replaces all
- // occurrences of "/*/" to "/".
- func replaceWildcards(p string) string {
- if strings.Contains(p, "/*/") {
- return replaceWildcards(strings.Replace(p, "/*/", "/", -1))
- }
-
- return p
- }
-
- // RouteParams is a structure to track URL routing parameters efficiently.
- type RouteParams struct {
- Keys, Values []string
- }
-
- // Add will append a URL parameter to the end of the route param
- func (s *RouteParams) Add(key, value string) {
- s.Keys = append(s.Keys, key)
- s.Values = append(s.Values, value)
- }
-
- // 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
- }
|