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