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