-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgr_head.go
More file actions
189 lines (162 loc) · 4.48 KB
/
gr_head.go
File metadata and controls
189 lines (162 loc) · 4.48 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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package gr
import (
"net/http"
)
/*
Alias of `http.Header`. Provides additional methods. Provides a chainable
builder-style API. All methods support both canonical and non-canonical
versions of header keys, able to find EXISTING non-canonical entries,
canonicalizing them when possible. Freely castable to and from `http.Header`.
*/
type Head http.Header
// If nil, returns a non-nil empty map. If already allocated, returns self.
func (self Head) Init() Head {
if self == nil {
return Head{}
}
return self
}
// Free cast to `http.Header`.
func (self Head) Header() http.Header { return http.Header(self) }
// Same as `http.Header`. Makes a deep copy.
func (self Head) Clone() Head { return Head(self.Header().Clone()) }
/*
Similar to `http.Header.Get`, but also works if the key is non-canonical.
*/
func (self Head) Get(key string) string {
if len(self) == 0 {
return ``
}
val, ok := self[key]
if ok {
if len(val) > 0 {
return val[0]
}
return ``
}
return self.Header().Get(key)
}
/*
Similar to `http.Header.Values`, but also works if the key is non-canonical.
*/
func (self Head) Values(key string) []string {
if len(self) == 0 {
return nil
}
val, ok := self[key]
if ok {
return val
}
return self.Header().Values(key)
}
/*
True if the header contains either this exact key or its canonical version.
*/
func (self Head) Has(key string) bool {
// Avoids pointless key conversion below.
if len(self) == 0 {
return false
}
_, ok := self[key]
if ok {
return true
}
_, ok = self[canonKey(key)]
return ok
}
/*
Deletes both this exact key and its canonical version. Mutates and returns the
receiver.
*/
func (self Head) Del(key string) Head {
if len(self) == 0 {
return self
}
delete(self, key)
delete(self, canonKey(key))
return self
}
/*
Similar to `http.Header.Add`, but also looks for an existing entry under this
EXACT key, as well as an entry for the canonical version of the key, combining
both under the canonical key. Internally calls `append`, which may mutate the
backing array of any existing slices for this key. Mutates and returns the
receiver. If the receiver is nil, allocates and returns a new map. For
correctness, you must always reassign the returned value.
*/
func (self Head) Add(key, val string) Head {
keyCanon := canonKey(key)
if self == nil {
return Head{keyCanon: {val}}
}
if key == keyCanon {
self[key] = append(self[key], val)
return self
}
prev := self[key]
prevCanon := self[keyCanon]
if cap(prev) > 0 {
self[keyCanon] = append(append(prev, prevCanon...), val)
} else {
self[keyCanon] = append(prevCanon, val)
}
delete(self, key)
return self
}
/*
Similar to `http.Header.Set`, but also replaces the previous entry under this
exact key, if the key is non-canonical. The resulting entry always has the
canonical key. Mutates and returns the receiver. If the receiver is nil,
allocates and returns a new map. For correctness, you must always reassign the
returned value.
*/
func (self Head) Set(key, val string) Head {
keyCanon := canonKey(key)
if self == nil {
return Head{keyCanon: {val}}
}
if key != keyCanon {
delete(self, key)
}
self[keyCanon] = []string{val}
return self
}
/*
Replaces the given key-value, canonicalizing the key. When called with no vals,
this is identical to `gr.Head.Del`, deleting the previous entry at BOTH this
exact key and its canonical version. When called with some vals, this replaces
the previous entry at the canonical version of this key, while deleting the
entry at this exact key. The received slice is set as-is, allowing you to reuse
a preallocated slice. Mutates and returns the receiver. If the receiver is nil,
allocates and returns a new map. For correctness, you must always reassign the
returned value.
*/
func (self Head) Replace(key string, vals ...string) Head {
keyCanon := canonKey(key)
if len(vals) == 0 {
delete(self, key)
delete(self, keyCanon)
return self
}
if self == nil {
return Head{keyCanon: vals}
}
if key != keyCanon {
delete(self, key)
}
self[keyCanon] = vals
return self
}
/*
Applies the patch, using `gr.Head.Replace` for each key-values entry. Mutates
and returns the receiver. If the receiver is nil, allocates and returns a new
map. For correctness, you must always reassign the returned value.
Accepts an "anonymous" type because all alias types such as `gr.Head` and
`http.Header` are automatically castable into it.
*/
func (self Head) Patch(head map[string][]string) Head {
for key, vals := range head {
self = self.Replace(key, vals...)
}
return self
}