v / vlib / net / http / head_with_content_length_test.v
85 lines · 75 sloc · 2.44 KB · f40137a0ccc87676e6b78e511141988f06f51772
Raw
1module http
2
3import net
4
5// These tests cover RFC 7230 §3.3.3 / RFC 9112 §6.2: HEAD responses, and
6// 1xx/204/304 status responses, must not carry a body. Before the fix, the
7// receive loop in `receive_all_data_from_cb_in_builder` waited for
8// `Content-Length` body bytes that the server never sends, then surfaced
9// either `response body ended early` (when the connection closed) or a
10// read timeout (when the server kept the socket open).
11
12const head_resp = 'HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 1234\r\nConnection: close\r\n\r\n'
13
14const status_204_resp = 'HTTP/1.1 204 No Content\r\nContent-Length: 5\r\nConnection: close\r\n\r\n'
15
16const status_304_resp = 'HTTP/1.1 304 Not Modified\r\nContent-Length: 100\r\nConnection: close\r\n\r\n'
17
18fn serve_once(mut listener net.TcpListener, response string) {
19 mut conn := listener.accept() or { return }
20 defer {
21 conn.close() or {}
22 }
23 mut buf := []u8{len: 4096}
24 for {
25 n := conn.read(mut buf) or { return }
26 if n <= 0 {
27 return
28 }
29 if buf[..n].bytestr().contains('\r\n\r\n') {
30 break
31 }
32 }
33 conn.write(response.bytes()) or {}
34}
35
36fn start_server(response string) !int {
37 mut listener := net.listen_tcp(.ip, '127.0.0.1:0')!
38 addr := listener.addr()!
39 port := addr.port()!
40 spawn fn [mut listener, response] () {
41 serve_once(mut listener, response)
42 }()
43 return port
44}
45
46fn test_head_does_not_wait_for_body_when_content_length_is_set() {
47 port := start_server(head_resp) or {
48 assert false, 'failed to start server: ${err}'
49 return
50 }
51 resp := head('http://127.0.0.1:${port}/') or {
52 assert false, 'HEAD should not error, got: ${err}'
53 return
54 }
55 assert resp.status_code == 200
56 assert resp.body == ''
57 cl := resp.header.get(.content_length) or { '' }
58 assert cl == '1234', 'Content-Length header should still be exposed to the caller'
59}
60
61fn test_get_204_no_content_does_not_wait_for_body() {
62 port := start_server(status_204_resp) or {
63 assert false, 'failed to start server: ${err}'
64 return
65 }
66 resp := get('http://127.0.0.1:${port}/') or {
67 assert false, 'GET 204 should not error, got: ${err}'
68 return
69 }
70 assert resp.status_code == 204
71 assert resp.body == ''
72}
73
74fn test_get_304_not_modified_does_not_wait_for_body() {
75 port := start_server(status_304_resp) or {
76 assert false, 'failed to start server: ${err}'
77 return
78 }
79 resp := get('http://127.0.0.1:${port}/') or {
80 assert false, 'GET 304 should not error, got: ${err}'
81 return
82 }
83 assert resp.status_code == 304
84 assert resp.body == ''
85}
86