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