-
-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathparams_writer.go
145 lines (120 loc) · 3.81 KB
/
params_writer.go
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
139
140
141
142
143
144
145
package muxie
import "net/http"
// GetParam returns the path parameter value based on its key, i.e
// "/hello/:name", the parameter key is the "name".
// For example if a route with pattern of "/hello/:name" is inserted to the `Trie` or handlded by the `Mux`
// and the path "/hello/kataras" is requested through the `Mux#ServeHTTP -> Trie#Search`
// then the `GetParam("name")` will return the value of "kataras".
// If not associated value with that key is found then it will return an empty string.
//
// The function will do its job only if the given "w" http.ResponseWriter interface is an `ResponseWriter`.
func GetParam(w http.ResponseWriter, key string) string {
if store, ok := w.(ResponseWriter); ok {
return store.Get(key)
}
return ""
}
// GetParams returns all the available parameters based on the "w" http.ResponseWriter which should be a ResponseWriter.
//
// The function will do its job only if the given "w" http.ResponseWriter interface is an `ResponseWriter`.
func GetParams(w http.ResponseWriter) []ParamEntry {
if store, ok := w.(ResponseWriter); ok {
return store.GetAll()
}
return nil
}
// SetParam sets manually a parameter to the "w" http.ResponseWriter which should be a ResponseWriter.
// This is not commonly used by the end-developers,
// unless sharing values(string messages only) between handlers is absolutely necessary.
func SetParam(w http.ResponseWriter, key, value string) bool {
if store, ok := w.(ResponseWriter); ok {
store.Set(key, value)
return true
}
return false
}
// ParamEntry holds the Key and the Value of a named path parameter.
type ParamEntry struct {
Key string
Value string
}
// ResponseWriter is the muxie's specific ResponseWriter to hold the path parameters.
// Usage: use this to cast a handler's `http.ResponseWriter` and pass it as an embedded parameter to custom response writer
// that will be passed to the next handler in the chain.
type ResponseWriter interface {
http.ResponseWriter
http.Flusher
http.Pusher
http.Hijacker
http.CloseNotifier
ParamsSetter
Get(string) string
GetAll() []ParamEntry
}
type paramsWriter struct {
http.ResponseWriter
http.Flusher
http.Pusher
http.Hijacker
http.CloseNotifier
params []ParamEntry
}
var _ ResponseWriter = (*paramsWriter)(nil)
// Set implements the `ParamsSetter` which `Trie#Search` needs to store the parameters, if any.
// These are decoupled because end-developers may want to use the trie to design a new Mux of their own
// or to store different kind of data inside it.
func (pw *paramsWriter) Set(key, value string) {
if ln := len(pw.params); cap(pw.params) > ln {
pw.params = pw.params[:ln+1]
p := &pw.params[ln]
p.Key = key
p.Value = value
return
}
pw.params = append(pw.params, ParamEntry{
Key: key,
Value: value,
})
}
// Get returns the value of the associated parameter based on its key/name.
func (pw *paramsWriter) Get(key string) string {
n := len(pw.params)
for i := 0; i < n; i++ {
if kv := pw.params[i]; kv.Key == key {
return kv.Value
}
}
return ""
}
// GetAll returns all the path parameters keys-values.
func (pw *paramsWriter) GetAll() []ParamEntry {
return pw.params
}
func (pw *paramsWriter) reset(w http.ResponseWriter) {
pw.ResponseWriter = w
flusher, ok := w.(http.Flusher)
if !ok {
flusher = nil // make sure interface value is nil.
}
pusher, ok := w.(http.Pusher)
if !ok {
pusher = nil
}
hijacker, ok := w.(http.Hijacker)
if !ok {
hijacker = nil
}
// This interface is obselete by Go authors
// and we only capture it
// for compatible reasons. End-developers SHOULD replace
// the use of CloseNotifier with the: Request.Context().Done() channel.
closeNotifier, ok := w.(http.CloseNotifier)
if !ok {
closeNotifier = nil
}
pw.Flusher = flusher
pw.Pusher = pusher
pw.Hijacker = hijacker
pw.CloseNotifier = closeNotifier
pw.params = pw.params[0:0]
}