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