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