Source file
src/net/http/header.go
1
2
3
4
5 package http
6
7 import (
8 "io"
9 "net/http/httptrace"
10 "net/http/internal/ascii"
11 "net/textproto"
12 "sort"
13 "strings"
14 "sync"
15 "time"
16
17 "golang.org/x/net/http/httpguts"
18 )
19
20
21
22
23
24 type Header map[string][]string
25
26
27
28
29
30 func (h Header) Add(key, value string) {
31 textproto.MIMEHeader(h).Add(key, value)
32 }
33
34
35
36
37
38
39 func (h Header) Set(key, value string) {
40 textproto.MIMEHeader(h).Set(key, value)
41 }
42
43
44
45
46
47
48
49 func (h Header) Get(key string) string {
50 return textproto.MIMEHeader(h).Get(key)
51 }
52
53
54
55
56
57
58 func (h Header) Values(key string) []string {
59 return textproto.MIMEHeader(h).Values(key)
60 }
61
62
63 func (h Header) get(key string) string {
64 if v := h[key]; len(v) > 0 {
65 return v[0]
66 }
67 return ""
68 }
69
70
71
72 func (h Header) has(key string) bool {
73 _, ok := h[key]
74 return ok
75 }
76
77
78
79
80 func (h Header) Del(key string) {
81 textproto.MIMEHeader(h).Del(key)
82 }
83
84
85 func (h Header) Write(w io.Writer) error {
86 return h.write(w, nil)
87 }
88
89 func (h Header) write(w io.Writer, trace *httptrace.ClientTrace) error {
90 return h.writeSubset(w, nil, trace)
91 }
92
93
94 func (h Header) Clone() Header {
95 if h == nil {
96 return nil
97 }
98
99
100 nv := 0
101 for _, vv := range h {
102 nv += len(vv)
103 }
104 sv := make([]string, nv)
105 h2 := make(Header, len(h))
106 for k, vv := range h {
107 if vv == nil {
108
109
110 h2[k] = nil
111 continue
112 }
113 n := copy(sv, vv)
114 h2[k] = sv[:n:n]
115 sv = sv[n:]
116 }
117 return h2
118 }
119
120 var timeFormats = []string{
121 TimeFormat,
122 time.RFC850,
123 time.ANSIC,
124 }
125
126
127
128
129 func ParseTime(text string) (t time.Time, err error) {
130 for _, layout := range timeFormats {
131 t, err = time.Parse(layout, text)
132 if err == nil {
133 return
134 }
135 }
136 return
137 }
138
139 var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")
140
141
142 type stringWriter struct {
143 w io.Writer
144 }
145
146 func (w stringWriter) WriteString(s string) (n int, err error) {
147 return w.w.Write([]byte(s))
148 }
149
150 type keyValues struct {
151 key string
152 values []string
153 }
154
155
156
157
158 type headerSorter struct {
159 kvs []keyValues
160 }
161
162 func (s *headerSorter) Len() int { return len(s.kvs) }
163 func (s *headerSorter) Swap(i, j int) { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
164 func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key }
165
166 var headerSorterPool = sync.Pool{
167 New: func() any { return new(headerSorter) },
168 }
169
170
171
172
173 func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *headerSorter) {
174 hs = headerSorterPool.Get().(*headerSorter)
175 if cap(hs.kvs) < len(h) {
176 hs.kvs = make([]keyValues, 0, len(h))
177 }
178 kvs = hs.kvs[:0]
179 for k, vv := range h {
180 if !exclude[k] {
181 kvs = append(kvs, keyValues{k, vv})
182 }
183 }
184 hs.kvs = kvs
185 sort.Sort(hs)
186 return kvs, hs
187 }
188
189
190
191
192 func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
193 return h.writeSubset(w, exclude, nil)
194 }
195
196 func (h Header) writeSubset(w io.Writer, exclude map[string]bool, trace *httptrace.ClientTrace) error {
197 ws, ok := w.(io.StringWriter)
198 if !ok {
199 ws = stringWriter{w}
200 }
201 kvs, sorter := h.sortedKeyValues(exclude)
202 var formattedVals []string
203 for _, kv := range kvs {
204 if !httpguts.ValidHeaderFieldName(kv.key) {
205
206
207
208
209 continue
210 }
211 for _, v := range kv.values {
212 v = headerNewlineToSpace.Replace(v)
213 v = textproto.TrimString(v)
214 for _, s := range []string{kv.key, ": ", v, "\r\n"} {
215 if _, err := ws.WriteString(s); err != nil {
216 headerSorterPool.Put(sorter)
217 return err
218 }
219 }
220 if trace != nil && trace.WroteHeaderField != nil {
221 formattedVals = append(formattedVals, v)
222 }
223 }
224 if trace != nil && trace.WroteHeaderField != nil {
225 trace.WroteHeaderField(kv.key, formattedVals)
226 formattedVals = nil
227 }
228 }
229 headerSorterPool.Put(sorter)
230 return nil
231 }
232
233
234
235
236
237
238
239
240 func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) }
241
242
243
244
245
246 func hasToken(v, token string) bool {
247 if len(token) > len(v) || token == "" {
248 return false
249 }
250 if v == token {
251 return true
252 }
253 for sp := 0; sp <= len(v)-len(token); sp++ {
254
255
256
257
258
259
260 if b := v[sp]; b != token[0] && b|0x20 != token[0] {
261 continue
262 }
263
264 if sp > 0 && !isTokenBoundary(v[sp-1]) {
265 continue
266 }
267
268 if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) {
269 continue
270 }
271 if ascii.EqualFold(v[sp:sp+len(token)], token) {
272 return true
273 }
274 }
275 return false
276 }
277
278 func isTokenBoundary(b byte) bool {
279 return b == ' ' || b == ',' || b == '\t'
280 }
281
View as plain text