v / vlib / net / http / request_receive_test.v
133 lines · 121 sloc · 3.94 KB · 2c62c6d0fe270138d8905050d13502c3b5246d8c
Raw
1module http
2
3import io
4import net
5import strings
6
7fn receive_all_data_timeout_cb(_ voidptr, _ &u8, _ int) !int {
8 return error_with_code('read timed out', net.err_timed_out_code)
9}
10
11fn receive_all_data_eof_cb(_ voidptr, _ &u8, _ int) !int {
12 return io.Eof{}
13}
14
15struct ReceiveAllDataFixture {
16 parts []string
17mut:
18 index int
19}
20
21fn receive_all_data_fixture_cb(con voidptr, buf &u8, bufsize int) !int {
22 mut fixture := unsafe { &ReceiveAllDataFixture(con) }
23 if fixture.index >= fixture.parts.len {
24 return io.Eof{}
25 }
26 part := fixture.parts[fixture.index].bytes()
27 fixture.index++
28 assert part.len <= bufsize
29 mut out := unsafe { buf.vbytes(bufsize) }
30 return copy(mut out, part)
31}
32
33struct ProgressBodyCapture {
34mut:
35 data []u8
36 reads []u64
37 expected []u64
38 statuses []int
39}
40
41fn receive_all_data_progress_body_cb(request &Request, chunk []u8, body_so_far u64, expected_size u64, status_code int) ! {
42 mut capture := unsafe { &ProgressBodyCapture(request.user_ptr) }
43 capture.data << chunk
44 capture.reads << body_so_far
45 capture.expected << expected_size
46 capture.statuses << status_code
47}
48
49fn test_receive_all_data_from_cb_in_builder_propagates_non_eof_errors() {
50 mut req := Request{}
51 mut content := strings.new_builder(64)
52 req.receive_all_data_from_cb_in_builder(mut content, unsafe { nil },
53 receive_all_data_timeout_cb) or {
54 assert err.code() == net.err_timed_out_code
55 return
56 }
57 panic('expected a timeout error')
58}
59
60fn test_receive_all_data_from_cb_in_builder_stops_on_eof() {
61 mut req := Request{}
62 mut content := strings.new_builder(64)
63 req.receive_all_data_from_cb_in_builder(mut content, unsafe { nil }, receive_all_data_eof_cb) or {
64 panic('unexpected error: ${err}')
65 }
66 assert content.str() == ''
67}
68
69fn test_receive_all_data_from_cb_in_builder_dechunks_progress_body_and_parses_truncated_chunked_response() {
70 parts := [
71 'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nContent-Type: text/plain\r\n\r\n4\r\nWi',
72 'ki\r\n6',
73 '\r\nped',
74 'ia!\r\n0\r',
75 '\n\r\n',
76 ]
77 full_response := parts.join('')
78 mut fixture := ReceiveAllDataFixture{
79 parts: parts
80 }
81 mut capture := ProgressBodyCapture{}
82 mut req := Request{
83 on_progress_body: receive_all_data_progress_body_cb
84 stop_copying_limit: i64(full_response.len - 1)
85 user_ptr: voidptr(&capture)
86 }
87 mut content := strings.new_builder(64)
88 response_info := req.receive_all_data_from_cb_in_builder(mut content, voidptr(&fixture),
89 receive_all_data_fixture_cb)!
90 assert response_info.is_chunked_transfer
91 assert response_info.has_truncated_body
92 assert capture.data.bytestr() == 'Wikipedia!'
93 assert capture.reads == [u64(2), 4, 7, 10]
94 assert capture.expected == [u64(0), 0, 0, 0]
95 assert capture.statuses == [200, 200, 200, 200]
96 resp := parse_received_response(content.str(), response_info)!
97 assert resp.status_code == 200
98 assert resp.body == ''
99}
100
101fn test_receive_all_data_from_cb_in_builder_errors_on_premature_eof_with_content_length() {
102 mut fixture := ReceiveAllDataFixture{
103 parts: [
104 'HTTP/1.1 200 OK\r\nContent-Length: 10\r\nContent-Type: text/plain\r\n\r\nhello',
105 ]
106 }
107 mut req := Request{}
108 mut content := strings.new_builder(64)
109 req.receive_all_data_from_cb_in_builder(mut content, voidptr(&fixture),
110 receive_all_data_fixture_cb) or {
111 assert err.msg().contains('response body ended early')
112 assert err.msg().contains('5 of 10 bytes')
113 return
114 }
115 panic('expected an early EOF error for a truncated fixed-length response')
116}
117
118fn test_receive_all_data_from_cb_in_builder_errors_on_incomplete_chunked_response() {
119 mut fixture := ReceiveAllDataFixture{
120 parts: [
121 'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nContent-Type: text/plain\r\n\r\n4\r\nWi',
122 'ki\r\n6\r\nped',
123 ]
124 }
125 mut req := Request{}
126 mut content := strings.new_builder(64)
127 req.receive_all_data_from_cb_in_builder(mut content, voidptr(&fixture),
128 receive_all_data_fixture_cb) or {
129 assert err.msg() == 'http.request: incomplete chunked response'
130 return
131 }
132 panic('expected an early EOF error for an incomplete chunked response')
133}
134