1
2
3
4
5 package http
6
7
8
9 func isSeparator(c byte) bool {
10 switch c {
11 case '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t':
12 return true
13 }
14 return false
15 }
16
17 func isSpace(c byte) bool {
18 switch c {
19 case ' ', '\t', '\r', '\n':
20 return true
21 }
22 return false
23 }
24
25 func isCtl(c byte) bool { return (0 <= c && c <= 31) || c == 127 }
26
27 func isChar(c byte) bool { return 0 <= c && c <= 127 }
28
29 func isAnyText(c byte) bool { return !isCtl(c) }
30
31 func isQdText(c byte) bool { return isAnyText(c) && c != '"' }
32
33 func isToken(c byte) bool { return isChar(c) && !isCtl(c) && !isSeparator(c) }
34
35
36
37
38
39 func httpUnquotePair(b byte) byte {
40
41 switch b {
42 case 'a':
43 return '\a'
44 case 'b':
45 return '\b'
46 case 'f':
47 return '\f'
48 case 'n':
49 return '\n'
50 case 'r':
51 return '\r'
52 case 't':
53 return '\t'
54 case 'v':
55 return '\v'
56 case '\\':
57 return '\\'
58 case '\'':
59 return '\''
60 case '"':
61 return '"'
62 }
63 return '?'
64 }
65
66
67
68
69 func httpUnquote(raw []byte) (eaten int, result string) {
70 buf := make([]byte, len(raw))
71 if raw[0] != '"' {
72 return -1, ""
73 }
74 eaten = 1
75 j := 0
76 for i := 1; i < len(raw); i++ {
77 switch b := raw[i]; b {
78 case '"':
79 eaten++
80 buf = buf[0:j]
81 return i + 1, string(buf)
82 case '\\':
83 if len(raw) < i+2 {
84 return -1, ""
85 }
86 buf[j] = httpUnquotePair(raw[i+1])
87 eaten += 2
88 j++
89 i++
90 default:
91 if isQdText(b) {
92 buf[j] = b
93 } else {
94 buf[j] = '?'
95 }
96 eaten++
97 j++
98 }
99 }
100 return -1, ""
101 }
102
103
104
105 func httpSplitFieldValue(fv string) (eaten int, result []string) {
106 result = make([]string, 0, len(fv))
107 raw := []byte(fv)
108 i := 0
109 chunk := ""
110 for i < len(raw) {
111 b := raw[i]
112 switch {
113 case b == '"':
114 eaten, unq := httpUnquote(raw[i:len(raw)])
115 if eaten < 0 {
116 return i, result
117 } else {
118 i += eaten
119 chunk += unq
120 }
121 case isSeparator(b):
122 if chunk != "" {
123 result = result[0 : len(result)+1]
124 result[len(result)-1] = chunk
125 chunk = ""
126 }
127 i++
128 case isToken(b):
129 chunk += string(b)
130 i++
131 case b == '\n' || b == '\r':
132 i++
133 default:
134 chunk += "?"
135 i++
136 }
137 }
138 if chunk != "" {
139 result = result[0 : len(result)+1]
140 result[len(result)-1] = chunk
141 chunk = ""
142 }
143 return i, result
144 }