Source file src/vendor/golang.org/x/net/http/httpguts/httplex.go
1
2
3
4
5 package httpguts
6
7 import (
8 "net"
9 "strings"
10 "unicode/utf8"
11
12 "golang.org/x/net/idna"
13 )
14
15 var isTokenTable = [127]bool{
16 '!': true,
17 '#': true,
18 '$': true,
19 '%': true,
20 '&': true,
21 '\'': true,
22 '*': true,
23 '+': true,
24 '-': true,
25 '.': true,
26 '0': true,
27 '1': true,
28 '2': true,
29 '3': true,
30 '4': true,
31 '5': true,
32 '6': true,
33 '7': true,
34 '8': true,
35 '9': true,
36 'A': true,
37 'B': true,
38 'C': true,
39 'D': true,
40 'E': true,
41 'F': true,
42 'G': true,
43 'H': true,
44 'I': true,
45 'J': true,
46 'K': true,
47 'L': true,
48 'M': true,
49 'N': true,
50 'O': true,
51 'P': true,
52 'Q': true,
53 'R': true,
54 'S': true,
55 'T': true,
56 'U': true,
57 'W': true,
58 'V': true,
59 'X': true,
60 'Y': true,
61 'Z': true,
62 '^': true,
63 '_': true,
64 '`': true,
65 'a': true,
66 'b': true,
67 'c': true,
68 'd': true,
69 'e': true,
70 'f': true,
71 'g': true,
72 'h': true,
73 'i': true,
74 'j': true,
75 'k': true,
76 'l': true,
77 'm': true,
78 'n': true,
79 'o': true,
80 'p': true,
81 'q': true,
82 'r': true,
83 's': true,
84 't': true,
85 'u': true,
86 'v': true,
87 'w': true,
88 'x': true,
89 'y': true,
90 'z': true,
91 '|': true,
92 '~': true,
93 }
94
95 func IsTokenRune(r rune) bool {
96 i := int(r)
97 return i < len(isTokenTable) && isTokenTable[i]
98 }
99
100 func isNotToken(r rune) bool {
101 return !IsTokenRune(r)
102 }
103
104
105
106 func HeaderValuesContainsToken(values []string, token string) bool {
107 for _, v := range values {
108 if headerValueContainsToken(v, token) {
109 return true
110 }
111 }
112 return false
113 }
114
115
116
117 func isOWS(b byte) bool { return b == ' ' || b == '\t' }
118
119
120
121 func trimOWS(x string) string {
122
123
124
125
126 for len(x) > 0 && isOWS(x[0]) {
127 x = x[1:]
128 }
129 for len(x) > 0 && isOWS(x[len(x)-1]) {
130 x = x[:len(x)-1]
131 }
132 return x
133 }
134
135
136
137
138
139 func headerValueContainsToken(v string, token string) bool {
140 v = trimOWS(v)
141 if comma := strings.IndexByte(v, ','); comma != -1 {
142 return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token)
143 }
144 return tokenEqual(v, token)
145 }
146
147
148 func lowerASCII(b byte) byte {
149 if 'A' <= b && b <= 'Z' {
150 return b + ('a' - 'A')
151 }
152 return b
153 }
154
155
156 func tokenEqual(t1, t2 string) bool {
157 if len(t1) != len(t2) {
158 return false
159 }
160 for i, b := range t1 {
161 if b >= utf8.RuneSelf {
162
163 return false
164 }
165 if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
166 return false
167 }
168 }
169 return true
170 }
171
172
173
174
175 func isLWS(b byte) bool { return b == ' ' || b == '\t' }
176
177
178
179
180
181 func isCTL(b byte) bool {
182 const del = 0x7f
183 return b < ' ' || b == del
184 }
185
186
187
188
189
190
191
192
193
194
195
196 func ValidHeaderFieldName(v string) bool {
197 if len(v) == 0 {
198 return false
199 }
200 for _, r := range v {
201 if !IsTokenRune(r) {
202 return false
203 }
204 }
205 return true
206 }
207
208
209 func ValidHostHeader(h string) bool {
210
211
212
213
214
215
216
217
218
219
220
221 for i := 0; i < len(h); i++ {
222 if !validHostByte[h[i]] {
223 return false
224 }
225 }
226 return true
227 }
228
229
230 var validHostByte = [256]bool{
231 '0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true,
232 '8': true, '9': true,
233
234 'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true,
235 'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true,
236 'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
237 'y': true, 'z': true,
238
239 'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true,
240 'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true,
241 'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
242 'Y': true, 'Z': true,
243
244 '!': true,
245 '$': true,
246 '%': true,
247 '&': true,
248 '(': true,
249 ')': true,
250 '*': true,
251 '+': true,
252 ',': true,
253 '-': true,
254 '.': true,
255 ':': true,
256 ';': true,
257 '=': true,
258 '[': true,
259 '\'': true,
260 ']': true,
261 '_': true,
262 '~': true,
263 }
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302 func ValidHeaderFieldValue(v string) bool {
303 for i := 0; i < len(v); i++ {
304 b := v[i]
305 if isCTL(b) && !isLWS(b) {
306 return false
307 }
308 }
309 return true
310 }
311
312 func isASCII(s string) bool {
313 for i := 0; i < len(s); i++ {
314 if s[i] >= utf8.RuneSelf {
315 return false
316 }
317 }
318 return true
319 }
320
321
322
323 func PunycodeHostPort(v string) (string, error) {
324 if isASCII(v) {
325 return v, nil
326 }
327
328 host, port, err := net.SplitHostPort(v)
329 if err != nil {
330
331
332
333 host = v
334 port = ""
335 }
336 host, err = idna.ToASCII(host)
337 if err != nil {
338
339
340 return "", err
341 }
342 if port == "" {
343 return host, nil
344 }
345 return net.JoinHostPort(host, port), nil
346 }
347
View as plain text