context.go
3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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
}