v / vlib / net / http / header_test.v
392 lines · 346 sloc · 10.21 KB · d7cac2df6d5a31b72c82807bed0715b9c8b2ba70
Raw
1module http
2
3fn test_header_new() {
4 h := new_header(HeaderConfig{ key: .accept, value: 'nothing' },
5 key: .expires
6 value: 'yesterday'
7 )
8 assert h.contains(.accept)
9 assert h.contains(.expires)
10 accept := h.get(.accept) or { '' }
11 expires := h.get(.expires) or { '' }
12 assert accept == 'nothing'
13 assert expires == 'yesterday'
14}
15
16fn test_header_invalid_key() {
17 mut h := new_header()
18 h.add_custom('space is invalid', ':(') or { return }
19 panic('should have returned')
20}
21
22fn test_header_adds_multiple() {
23 mut h := new_header()
24 h.add(.accept, 'one')
25 h.add(.accept, 'two')
26
27 assert h.values(.accept) == ['one', 'two']
28}
29
30/*
31fn test_same_key() {
32 mut h := new_header()
33 h.add_custom('accept', 'foo')!
34 h.add_custom('Accept', 'bar')!
35 // h.add(.accept, 'bar')
36 println(h)
37 exit(0)
38}
39*/
40
41fn test_header_get() {
42 // .dnt is all cap ("DNT"), test this
43 mut h := new_header(key: .dnt, value: 'one')
44 h.add_custom('dnt', 'two')!
45 dnt := h.get_custom('dnt') or { '' }
46 exact := h.get_custom('dnt', exact: true) or { '' }
47 assert dnt == 'one'
48 assert exact == 'two'
49}
50
51fn test_header_set() {
52 mut h := new_header(HeaderConfig{ key: .dnt, value: 'one' },
53 key: .dnt
54 value: 'two'
55 )
56 assert h.values(.dnt) == ['one', 'two']
57 h.set_custom('DNT', 'three')!
58 assert h.values(.dnt) == ['three']
59}
60
61fn test_header_delete() {
62 mut h := new_header(HeaderConfig{ key: .dnt, value: 'one' },
63 key: .dnt
64 value: 'two'
65 )
66 assert h.values(.dnt) == ['one', 'two']
67 h.delete(.dnt)
68 assert h.values(.dnt) == []
69}
70
71fn test_header_delete_not_existing() {
72 mut h := new_header()
73 assert h.data.len == max_headers
74 assert h.values(.dnt).len == 0
75 // assert h.keys.len == 0
76 h.delete(.dnt)
77 assert h.data.len == max_headers
78 assert h.values(.dnt).len == 0
79 // assert h.keys.len == 0
80}
81
82fn test_delete_header() {
83 mut r := new_request(.get, '', '')
84 r.header.set(.authorization, 'foo')
85 r.header.delete(.authorization)
86 assert r.header.get(.authorization)? == ''
87}
88
89fn test_custom_header() {
90 mut h := new_header()
91 h.add_custom('AbC', 'dEf')!
92 h.add_custom('aBc', 'GhI')!
93 assert h.custom_values('AbC', exact: true) == ['dEf']
94 assert h.custom_values('aBc', exact: true) == ['GhI']
95 assert h.custom_values('ABC') == ['dEf', 'GhI']
96 assert h.custom_values('abc') == ['dEf', 'GhI']
97 assert h.keys() == ['AbC', 'aBc']
98 h.delete_custom('AbC')
99 h.delete_custom('aBc')
100
101 h.add_custom('abc', 'def')!
102 assert h.custom_values('abc') == ['def']
103 assert h.custom_values('ABC') == ['def']
104 assert h.keys() == ['abc']
105 h.delete_custom('abc')
106
107 h.add_custom('accEPT', '*/*')!
108 assert h.custom_values('ACCept') == ['*/*']
109 assert h.values(.accept) == ['*/*']
110 assert h.keys() == ['accEPT']
111}
112
113fn test_contains_custom() {
114 mut h := new_header()
115 h.add_custom('Hello', 'world')!
116 assert h.contains_custom('hello')
117 assert h.contains_custom('HELLO')
118 assert h.contains_custom('Hello', exact: true)
119 assert h.contains_custom('hello', exact: true) == false
120 assert h.contains_custom('HELLO', exact: true) == false
121}
122
123fn test_get_custom() {
124 mut h := new_header()
125 h.add_custom('Hello', 'world')!
126 assert h.get_custom('hello')? == 'world'
127 assert h.get_custom('HELLO')? == 'world'
128 assert h.get_custom('Hello', exact: true)? == 'world'
129 if _ := h.get_custom('hello', exact: true) {
130 // should be none
131 assert false
132 }
133 if _ := h.get_custom('HELLO', exact: true) {
134 // should be none
135 assert false
136 }
137}
138
139fn test_starting_with() {
140 mut h := new_header()
141 h.add_custom('Hello-1', 'world')!
142 h.add_custom('Hello-21', 'world')!
143 assert h.starting_with('Hello-')! == 'Hello-1'
144 assert h.starting_with('Hello-2')! == 'Hello-21'
145}
146
147fn test_custom_values() {
148 mut h := new_header()
149 h.add_custom('Hello', 'world')!
150 assert h.custom_values('hello') == ['world']
151 assert h.custom_values('HELLO') == ['world']
152 assert h.custom_values('Hello', exact: true) == ['world']
153 assert h.custom_values('hello', exact: true) == []
154 assert h.custom_values('HELLO', exact: true) == []
155}
156
157fn test_coerce_canonicalize() {
158 mut h := new_header()
159 h.add_custom('accept', 'foo')!
160 h.add(.accept, 'bar')
161 assert h.values(.accept) == ['foo', 'bar']
162 assert h.keys().len == 2
163}
164
165fn test_coerce_custom() {
166 mut h := new_header()
167 h.add_custom('Hello', 'foo')!
168 h.add_custom('hello', 'bar')!
169 h.add_custom('HELLO', 'baz')!
170 assert h.custom_values('hello') == ['foo', 'bar', 'baz']
171 assert h.keys().len == 3
172}
173
174fn test_coerce_canonicalize_custom() {
175 mut h := new_header()
176 h.add_custom('foo-BAR', 'foo')!
177 h.add_custom('FOO-bar', 'bar')!
178 assert h.custom_values('foo-bar') == ['foo', 'bar']
179 assert h.keys().len == 2
180}
181
182fn test_render_version() {
183 mut h := new_header()
184 h.add_custom('accept', 'foo')!
185 h.add_custom('Accept', 'bar')!
186 h.add(.accept, 'baz')
187
188 s1_0 := h.render(version: .v1_0)
189 assert s1_0.contains('accept: foo\r\n')
190 assert s1_0.contains('Accept: bar\r\n')
191 assert s1_0.contains('Accept: baz\r\n')
192
193 s1_1 := h.render(version: .v1_1)
194 assert s1_1.contains('accept: foo\r\n')
195 assert s1_1.contains('Accept: bar\r\n')
196 assert s1_1.contains('Accept: baz\r\n')
197
198 s2_0 := h.render(version: .v2_0)
199 assert s2_0.contains('accept: foo\r\n')
200 assert s2_0.contains('accept: bar\r\n')
201 assert s2_0.contains('accept: baz\r\n')
202}
203
204/*
205fn test_render_coerce() {
206 mut h := new_header()
207 h.add_custom('accept', 'foo')!
208 h.add_custom('Accept', 'bar')!
209 h.add(.accept, 'baz')
210 h.add(.host, 'host')
211
212 s1_0 := h.render(version: .v1_1, coerce: true)
213 println('<<<<<<<<<<<<')
214 println(s1_0)
215 println('>>>>>>>>>>>>>>')
216 assert s1_0.contains('accept: foo\r\n')
217 assert s1_0.contains('accept: bar\r\n')
218 assert s1_0.contains('accept: baz\r\n')
219 assert s1_0.contains('Host: host\r\n')
220
221 s1_1 := h.render(version: .v1_1, coerce: true)
222 assert s1_1.contains('accept: foo\r\n')
223 assert s1_1.contains('accept: bar\r\n')
224 assert s1_1.contains('accept: baz\r\n')
225 assert s1_1.contains('Host: host\r\n')
226
227 s2_0 := h.render(version: .v2_0, coerce: true)
228 assert s2_0.contains('accept: foo\r\n')
229 assert s2_0.contains('accept: bar\r\n')
230 assert s2_0.contains('accept: baz\r\n')
231 assert s2_0.contains('host: host\r\n')
232}
233*/
234
235fn test_render_canonicalize() {
236 mut h := new_header()
237 h.add_custom('accept', 'foo')!
238 h.add_custom('Accept', 'bar')!
239 h.add(.accept, 'baz')
240 h.add(.host, 'host')
241
242 s1_0 := h.render(version: .v1_1, canonicalize: true)
243 assert s1_0.contains('Accept: foo\r\n')
244 assert s1_0.contains('Accept: bar\r\n')
245 assert s1_0.contains('Accept: baz\r\n')
246 assert s1_0.contains('Host: host\r\n')
247
248 s1_1 := h.render(version: .v1_1, canonicalize: true)
249 assert s1_1.contains('Accept: foo\r\n')
250 assert s1_1.contains('Accept: bar\r\n')
251 assert s1_1.contains('Accept: baz\r\n')
252 assert s1_1.contains('Host: host\r\n')
253
254 s2_0 := h.render(version: .v2_0, canonicalize: true)
255 assert s2_0.contains('accept: foo\r\n')
256 assert s2_0.contains('accept: bar\r\n')
257 assert s2_0.contains('accept: baz\r\n')
258 assert s2_0.contains('host: host\r\n')
259}
260
261fn test_render_coerce_canonicalize() {
262 mut h := new_header()
263 h.add_custom('accept', 'foo')!
264 h.add_custom('Accept', 'bar')!
265 h.add(.accept, 'baz')
266 h.add(.host, 'host')
267
268 s1_0 := h.render(version: .v1_1, coerce: true, canonicalize: true)
269 assert s1_0.contains('Accept: foo\r\n')
270 assert s1_0.contains('Accept: bar\r\n')
271 assert s1_0.contains('Accept: baz\r\n')
272 assert s1_0.contains('Host: host\r\n')
273
274 s1_1 := h.render(version: .v1_1, coerce: true, canonicalize: true)
275 assert s1_1.contains('Accept: foo\r\n')
276 assert s1_1.contains('Accept: bar\r\n')
277 assert s1_1.contains('Accept: baz\r\n')
278 assert s1_1.contains('Host: host\r\n')
279
280 s2_0 := h.render(version: .v2_0, coerce: true, canonicalize: true)
281 assert s2_0.contains('accept: foo\r\n')
282 assert s2_0.contains('accept: bar\r\n')
283 assert s2_0.contains('accept: baz\r\n')
284 assert s2_0.contains('host: host\r\n')
285}
286
287fn test_str() {
288 mut h := new_header()
289 h.add(.accept, 'text/html')
290 h.add_custom('Accept', 'image/jpeg')!
291 h.add_custom('X-custom', 'Hello')!
292
293 println('===========')
294 println(h.str())
295
296 // key order is not guaranteed
297 assert h.str() == 'Accept: text/html\r\nAccept: image/jpeg\r\nX-custom: Hello\r\n'
298 || h.str() == 'X-custom: Hello\r\nAccept:text/html\r\nAccept: image/jpeg\r\n'
299}
300
301fn test_header_from_map() {
302 h := new_header_from_map({
303 CommonHeader.accept: 'nothing'
304 CommonHeader.expires: 'yesterday'
305 })
306 assert h.contains(.accept)
307 assert h.contains(.expires)
308 assert h.get(.accept) or { '' } == 'nothing'
309 assert h.get(.expires) or { '' } == 'yesterday'
310}
311
312fn test_custom_header_from_map() {
313 h := new_custom_header_from_map({
314 'Server': 'Veb'
315 'foo': 'bar'
316 })!
317 assert h.contains_custom('server')
318 assert h.contains_custom('foo')
319 assert h.get_custom('server') or { '' } == 'Veb'
320 assert h.get_custom('foo') or { '' } == 'bar'
321}
322
323fn test_header_join() {
324 h1 := new_header_from_map({
325 CommonHeader.accept: 'nothing'
326 CommonHeader.expires: 'yesterday'
327 })
328 h2 := new_custom_header_from_map({
329 'Server': 'Veb'
330 'foo': 'bar'
331 })!
332 h3 := h1.join(h2)
333 // h1 is unchanged
334 assert h1.contains(.accept)
335 assert h1.contains(.expires)
336 assert !h1.contains_custom('Server')
337 assert !h1.contains_custom('foo')
338 // h2 is unchanged
339 assert !h2.contains(.accept)
340 assert !h2.contains(.expires)
341 assert h2.contains_custom('Server')
342 assert h2.contains_custom('foo')
343 // h3 has all four headers
344 assert h3.contains(.accept)
345 assert h3.contains(.expires)
346 assert h3.contains_custom('Server')
347 assert h3.contains_custom('foo')
348}
349
350fn parse_headers_test(s string, expected map[string]string) ! {
351 assert parse_headers(s)! == new_custom_header_from_map(expected)!
352}
353
354fn test_parse_headers() ! {
355 parse_headers_test('foo: bar', {
356 'foo': 'bar'
357 })!
358 parse_headers_test('foo: \t bar', {
359 'foo': 'bar'
360 })!
361 parse_headers_test('foo: bar\r\n\tbaz', {
362 'foo': 'bar baz'
363 })!
364 parse_headers_test('foo: bar \r\n\tbaz\r\n buzz', {
365 'foo': 'bar baz buzz'
366 })!
367 parse_headers_test('foo: bar\r\nbar:baz', {
368 'foo': 'bar'
369 'bar': 'baz'
370 })!
371 parse_headers_test('foo: bar\r\nbar:baz\r\n', {
372 'foo': 'bar'
373 'bar': 'baz'
374 })!
375 parse_headers_test('foo: bar\r\nbar:baz\r\n\r\n', {
376 'foo': 'bar'
377 'bar': 'baz'
378 })!
379 assert parse_headers('foo: bar\r\nfoo:baz')!.custom_values('foo') == ['bar', 'baz']
380
381 if x := parse_headers(' oops: oh no') {
382 return error('should have errored, but got ${x}')
383 }
384}
385
386fn test_set_cookie() {
387 // multiple Set-Cookie headers should be sent when rendered
388 mut h := new_header()
389 h.add(.set_cookie, 'foo')
390 h.add(.set_cookie, 'bar')
391 assert h.render() == 'Set-Cookie: foo\r\nSet-Cookie: bar\r\n'
392}
393