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