1
2
3
4
5
6
7
8
9
10 package header
11
12 import (
13 "net/http"
14 "strings"
15 "time"
16 )
17
18
19 var octetTypes [256]octetType
20
21 type octetType byte
22
23 const (
24 isToken octetType = 1 << iota
25 isSpace
26 )
27
28 func init() {
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 for c := 0; c < 256; c++ {
46 var t octetType
47 isCtl := c <= 31 || c == 127
48 isChar := 0 <= c && c <= 127
49 isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
50 if strings.ContainsRune(" \t\r\n", rune(c)) {
51 t |= isSpace
52 }
53 if isChar && !isCtl && !isSeparator {
54 t |= isToken
55 }
56 octetTypes[c] = t
57 }
58 }
59
60
61 func Copy(header http.Header) http.Header {
62 h := make(http.Header)
63 for k, vs := range header {
64 h[k] = vs
65 }
66 return h
67 }
68
69 var timeLayouts = []string{"Mon, 02 Jan 2006 15:04:05 GMT", time.RFC850, time.ANSIC}
70
71
72
73
74 func ParseTime(header http.Header, key string) time.Time {
75 if s := header.Get(key); s != "" {
76 for _, layout := range timeLayouts {
77 if t, err := time.Parse(layout, s); err == nil {
78 return t.UTC()
79 }
80 }
81 }
82 return time.Time{}
83 }
84
85
86
87
88 func ParseList(header http.Header, key string) []string {
89 var result []string
90 for _, s := range header[http.CanonicalHeaderKey(key)] {
91 begin := 0
92 end := 0
93 escape := false
94 quote := false
95 for i := 0; i < len(s); i++ {
96 b := s[i]
97 switch {
98 case escape:
99 escape = false
100 end = i + 1
101 case quote:
102 switch b {
103 case '\\':
104 escape = true
105 case '"':
106 quote = false
107 }
108 end = i + 1
109 case b == '"':
110 quote = true
111 end = i + 1
112 case octetTypes[b]&isSpace != 0:
113 if begin == end {
114 begin = i + 1
115 end = begin
116 }
117 case b == ',':
118 if begin < end {
119 result = append(result, s[begin:end])
120 }
121 begin = i + 1
122 end = begin
123 default:
124 end = i + 1
125 }
126 }
127 if begin < end {
128 result = append(result, s[begin:end])
129 }
130 }
131 return result
132 }
133
134
135
136
137 func ParseValueAndParams(header http.Header, key string) (string, map[string]string) {
138 return parseValueAndParams(header.Get(key))
139 }
140
141 func parseValueAndParams(s string) (value string, params map[string]string) {
142 params = make(map[string]string)
143 value, s = expectTokenSlash(s)
144 if value == "" {
145 return
146 }
147 value = strings.ToLower(value)
148 s = skipSpace(s)
149 for strings.HasPrefix(s, ";") {
150 var pkey string
151 pkey, s = expectToken(skipSpace(s[1:]))
152 if pkey == "" {
153 return
154 }
155 if !strings.HasPrefix(s, "=") {
156 return
157 }
158 var pvalue string
159 pvalue, s = expectTokenOrQuoted(s[1:])
160 if pvalue == "" {
161 return
162 }
163 pkey = strings.ToLower(pkey)
164 params[pkey] = pvalue
165 s = skipSpace(s)
166 }
167 return
168 }
169
170
171 type AcceptSpec struct {
172 Value string
173 Q float64
174 }
175
176
177 func ParseAccept2(header http.Header, key string) (specs []AcceptSpec) {
178 for _, en := range ParseList(header, key) {
179 v, p := parseValueAndParams(en)
180 var spec AcceptSpec
181 spec.Value = v
182 spec.Q = 1.0
183 if p != nil {
184 if q, ok := p["q"]; ok {
185 spec.Q, _ = expectQuality(q)
186 }
187 }
188 if spec.Q < 0.0 {
189 continue
190 }
191 specs = append(specs, spec)
192 }
193
194 return
195 }
196
197
198 func ParseAccept(header http.Header, key string) []AcceptSpec {
199 var specs []AcceptSpec
200 loop:
201 for _, s := range header[key] {
202 for {
203 var spec AcceptSpec
204 spec.Value, s = expectTokenSlash(s)
205 if spec.Value == "" {
206 continue loop
207 }
208 spec.Q = 1.0
209 s = skipSpace(s)
210 if strings.HasPrefix(s, ";") {
211 s = skipSpace(s[1:])
212 for !strings.HasPrefix(s, "q=") && s != "" && !strings.HasPrefix(s, ",") {
213 s = skipSpace(s[1:])
214 }
215 if strings.HasPrefix(s, "q=") {
216 spec.Q, s = expectQuality(s[2:])
217 if spec.Q < 0.0 {
218 continue loop
219 }
220 }
221 }
222
223 specs = append(specs, spec)
224 s = skipSpace(s)
225 if !strings.HasPrefix(s, ",") {
226 continue loop
227 }
228 s = skipSpace(s[1:])
229 }
230 }
231
232 return specs
233 }
234
235 func skipSpace(s string) (rest string) {
236 i := 0
237 for ; i < len(s); i++ {
238 if octetTypes[s[i]]&isSpace == 0 {
239 break
240 }
241 }
242 return s[i:]
243 }
244
245 func expectToken(s string) (token, rest string) {
246 i := 0
247 for ; i < len(s); i++ {
248 if octetTypes[s[i]]&isToken == 0 {
249 break
250 }
251 }
252 return s[:i], s[i:]
253 }
254
255 func expectTokenSlash(s string) (token, rest string) {
256 i := 0
257 for ; i < len(s); i++ {
258 b := s[i]
259 if (octetTypes[b]&isToken == 0) && b != '/' {
260 break
261 }
262 }
263 return s[:i], s[i:]
264 }
265
266 func expectQuality(s string) (q float64, rest string) {
267 switch {
268 case len(s) == 0:
269 return -1, ""
270 case s[0] == '0':
271
272 s = s[1:]
273 case s[0] == '1':
274 s = s[1:]
275 q = 1
276 case s[0] == '.':
277
278 default:
279 return -1, ""
280 }
281 if !strings.HasPrefix(s, ".") {
282 return q, s
283 }
284 s = s[1:]
285 i := 0
286 n := 0
287 d := 1
288 for ; i < len(s); i++ {
289 b := s[i]
290 if b < '0' || b > '9' {
291 break
292 }
293 n = n*10 + int(b) - '0'
294 d *= 10
295 }
296 return q + float64(n)/float64(d), s[i:]
297 }
298
299 func expectTokenOrQuoted(s string) (value string, rest string) {
300 if !strings.HasPrefix(s, "\"") {
301 return expectToken(s)
302 }
303 s = s[1:]
304 for i := 0; i < len(s); i++ {
305 switch s[i] {
306 case '"':
307 return s[:i], s[i+1:]
308 case '\\':
309 p := make([]byte, len(s)-1)
310 j := copy(p, s[:i])
311 escape := true
312 for i++; i < len(s); i++ {
313 b := s[i]
314 switch {
315 case escape:
316 escape = false
317 p[j] = b
318 j++
319 case b == '\\':
320 escape = true
321 case b == '"':
322 return string(p[:j]), s[i+1:]
323 default:
324 p[j] = b
325 j++
326 }
327 }
328 return "", ""
329 }
330 }
331 return "", ""
332 }
333
View as plain text