]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // |
92f5a8d4 | 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) |
b32b8144 FG |
3 | // |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // Official repository: https://github.com/boostorg/beast | |
8 | // | |
9 | ||
10 | // Test that header file is self-contained. | |
11 | #include <boost/beast/http/read.hpp> | |
12 | ||
13 | #include "test_parser.hpp" | |
14 | ||
15 | #include <boost/beast/core/ostream.hpp> | |
16 | #include <boost/beast/core/flat_static_buffer.hpp> | |
17 | #include <boost/beast/http/fields.hpp> | |
18 | #include <boost/beast/http/dynamic_body.hpp> | |
19 | #include <boost/beast/http/parser.hpp> | |
20 | #include <boost/beast/http/string_body.hpp> | |
92f5a8d4 TL |
21 | #include <boost/beast/_experimental/test/stream.hpp> |
22 | #include <boost/beast/_experimental/unit_test/suite.hpp> | |
b32b8144 | 23 | #include <boost/beast/test/yield_to.hpp> |
92f5a8d4 | 24 | #include <boost/asio/io_context.hpp> |
92f5a8d4 | 25 | #include <boost/asio/ip/tcp.hpp> |
20effc67 TL |
26 | #include <boost/asio/strand.hpp> |
27 | #include <boost/asio/write.hpp> | |
b32b8144 FG |
28 | #include <atomic> |
29 | ||
20effc67 TL |
30 | #if BOOST_ASIO_HAS_CO_AWAIT |
31 | #include <boost/asio/use_awaitable.hpp> | |
32 | #endif | |
33 | ||
b32b8144 FG |
34 | namespace boost { |
35 | namespace beast { | |
36 | namespace http { | |
37 | ||
38 | class read_test | |
39 | : public beast::unit_test::suite | |
40 | , public test::enable_yield_to | |
41 | { | |
42 | public: | |
43 | template<bool isRequest> | |
44 | void | |
45 | failMatrix(char const* s, yield_context do_yield) | |
46 | { | |
b32b8144 FG |
47 | static std::size_t constexpr limit = 100; |
48 | std::size_t n; | |
49 | auto const len = strlen(s); | |
50 | for(n = 0; n < limit; ++n) | |
51 | { | |
52 | multi_buffer b; | |
92f5a8d4 TL |
53 | b.commit(net::buffer_copy( |
54 | b.prepare(len), net::buffer(s, len))); | |
55 | test::fail_count fc(n); | |
b32b8144 FG |
56 | test::stream ts{ioc_, fc}; |
57 | test_parser<isRequest> p(fc); | |
92f5a8d4 | 58 | error_code ec = test::error::test_failure; |
b32b8144 FG |
59 | ts.close_remote(); |
60 | read(ts, b, p, ec); | |
61 | if(! ec) | |
62 | break; | |
63 | } | |
64 | BEAST_EXPECT(n < limit); | |
65 | for(n = 0; n < limit; ++n) | |
66 | { | |
67 | static std::size_t constexpr pre = 10; | |
68 | multi_buffer b; | |
92f5a8d4 TL |
69 | b.commit(net::buffer_copy( |
70 | b.prepare(pre), net::buffer(s, pre))); | |
71 | test::fail_count fc(n); | |
b32b8144 FG |
72 | test::stream ts{ioc_, fc, |
73 | std::string(s + pre, len - pre)}; | |
74 | test_parser<isRequest> p(fc); | |
92f5a8d4 | 75 | error_code ec = test::error::test_failure; |
b32b8144 FG |
76 | ts.close_remote(); |
77 | read(ts, b, p, ec); | |
78 | if(! ec) | |
79 | break; | |
80 | } | |
81 | BEAST_EXPECT(n < limit); | |
82 | for(n = 0; n < limit; ++n) | |
83 | { | |
84 | multi_buffer b; | |
92f5a8d4 TL |
85 | b.commit(net::buffer_copy( |
86 | b.prepare(len), net::buffer(s, len))); | |
87 | test::fail_count fc(n); | |
b32b8144 FG |
88 | test::stream ts{ioc_, fc}; |
89 | test_parser<isRequest> p(fc); | |
92f5a8d4 | 90 | error_code ec = test::error::test_failure; |
b32b8144 FG |
91 | ts.close_remote(); |
92 | async_read(ts, b, p, do_yield[ec]); | |
93 | if(! ec) | |
94 | break; | |
95 | } | |
96 | BEAST_EXPECT(n < limit); | |
97 | for(n = 0; n < limit; ++n) | |
98 | { | |
99 | multi_buffer b; | |
92f5a8d4 TL |
100 | b.commit(net::buffer_copy( |
101 | b.prepare(len), net::buffer(s, len))); | |
102 | test::fail_count fc(n); | |
b32b8144 FG |
103 | test::stream ts{ioc_, fc}; |
104 | test_parser<isRequest> p(fc); | |
92f5a8d4 | 105 | error_code ec = test::error::test_failure; |
b32b8144 FG |
106 | ts.close_remote(); |
107 | async_read_header(ts, b, p, do_yield[ec]); | |
108 | if(! ec) | |
109 | break; | |
110 | } | |
111 | BEAST_EXPECT(n < limit); | |
112 | for(n = 0; n < limit; ++n) | |
113 | { | |
114 | static std::size_t constexpr pre = 10; | |
115 | multi_buffer b; | |
92f5a8d4 TL |
116 | b.commit(net::buffer_copy( |
117 | b.prepare(pre), net::buffer(s, pre))); | |
118 | test::fail_count fc(n); | |
b32b8144 FG |
119 | test::stream ts(ioc_, fc, |
120 | std::string{s + pre, len - pre}); | |
121 | test_parser<isRequest> p(fc); | |
92f5a8d4 | 122 | error_code ec = test::error::test_failure; |
b32b8144 FG |
123 | ts.close_remote(); |
124 | async_read(ts, b, p, do_yield[ec]); | |
125 | if(! ec) | |
126 | break; | |
127 | } | |
128 | BEAST_EXPECT(n < limit); | |
129 | } | |
130 | ||
131 | void testThrow() | |
132 | { | |
133 | try | |
134 | { | |
135 | multi_buffer b; | |
136 | test::stream c{ioc_, "GET / X"}; | |
137 | c.close_remote(); | |
138 | request_parser<dynamic_body> p; | |
139 | read(c, b, p); | |
140 | fail(); | |
141 | } | |
142 | catch(std::exception const&) | |
143 | { | |
144 | pass(); | |
145 | } | |
146 | } | |
147 | ||
148 | void | |
149 | testBufferOverflow() | |
150 | { | |
151 | { | |
152 | test::stream c{ioc_}; | |
153 | ostream(c.buffer()) << | |
154 | "GET / HTTP/1.1\r\n" | |
155 | "Host: localhost\r\n" | |
156 | "User-Agent: test\r\n" | |
157 | "Transfer-Encoding: chunked\r\n" | |
158 | "\r\n" | |
159 | "10\r\n" | |
160 | "****************\r\n" | |
161 | "0\r\n\r\n"; | |
162 | flat_static_buffer<1024> b; | |
163 | request<string_body> req; | |
164 | try | |
165 | { | |
166 | read(c, b, req); | |
167 | pass(); | |
168 | } | |
169 | catch(std::exception const& e) | |
170 | { | |
171 | fail(e.what(), __FILE__, __LINE__); | |
172 | } | |
173 | } | |
174 | { | |
175 | test::stream c{ioc_}; | |
176 | ostream(c.buffer()) << | |
177 | "GET / HTTP/1.1\r\n" | |
178 | "Host: localhost\r\n" | |
179 | "User-Agent: test\r\n" | |
180 | "Transfer-Encoding: chunked\r\n" | |
181 | "\r\n" | |
182 | "10\r\n" | |
183 | "****************\r\n" | |
184 | "0\r\n\r\n"; | |
92f5a8d4 | 185 | error_code ec = test::error::test_failure; |
b32b8144 FG |
186 | flat_static_buffer<10> b; |
187 | request<string_body> req; | |
188 | read(c, b, req, ec); | |
189 | BEAST_EXPECTS(ec == error::buffer_overflow, | |
190 | ec.message()); | |
191 | } | |
192 | } | |
193 | ||
194 | void testFailures(yield_context do_yield) | |
195 | { | |
196 | char const* req[] = { | |
197 | "GET / HTTP/1.0\r\n" | |
198 | "Host: localhost\r\n" | |
199 | "User-Agent: test\r\n" | |
200 | "Empty:\r\n" | |
201 | "\r\n" | |
202 | , | |
203 | "GET / HTTP/1.1\r\n" | |
204 | "Host: localhost\r\n" | |
205 | "User-Agent: test\r\n" | |
206 | "Content-Length: 2\r\n" | |
207 | "\r\n" | |
208 | "**" | |
209 | , | |
210 | "GET / HTTP/1.1\r\n" | |
211 | "Host: localhost\r\n" | |
212 | "User-Agent: test\r\n" | |
213 | "Transfer-Encoding: chunked\r\n" | |
214 | "\r\n" | |
215 | "10\r\n" | |
216 | "****************\r\n" | |
217 | "0\r\n\r\n" | |
218 | , | |
219 | nullptr | |
220 | }; | |
221 | ||
222 | char const* res[] = { | |
223 | "HTTP/1.0 200 OK\r\n" | |
224 | "Server: test\r\n" | |
225 | "\r\n" | |
226 | , | |
227 | "HTTP/1.0 200 OK\r\n" | |
228 | "Server: test\r\n" | |
229 | "\r\n" | |
230 | "***" | |
231 | , | |
232 | "HTTP/1.1 200 OK\r\n" | |
233 | "Server: test\r\n" | |
234 | "Content-Length: 3\r\n" | |
235 | "\r\n" | |
236 | "***" | |
237 | , | |
238 | "HTTP/1.1 200 OK\r\n" | |
239 | "Server: test\r\n" | |
240 | "Transfer-Encoding: chunked\r\n" | |
241 | "\r\n" | |
242 | "10\r\n" | |
243 | "****************\r\n" | |
244 | "0\r\n\r\n" | |
245 | , | |
246 | nullptr | |
247 | }; | |
248 | for(std::size_t i = 0; req[i]; ++i) | |
249 | failMatrix<true>(req[i], do_yield); | |
250 | for(std::size_t i = 0; res[i]; ++i) | |
251 | failMatrix<false>(res[i], do_yield); | |
252 | } | |
253 | ||
254 | void testRead(yield_context do_yield) | |
255 | { | |
256 | static std::size_t constexpr limit = 100; | |
257 | std::size_t n; | |
258 | ||
259 | for(n = 0; n < limit; ++n) | |
260 | { | |
92f5a8d4 | 261 | test::fail_count fc{n}; |
b32b8144 FG |
262 | test::stream c{ioc_, fc, |
263 | "GET / HTTP/1.1\r\n" | |
264 | "Host: localhost\r\n" | |
265 | "User-Agent: test\r\n" | |
266 | "Content-Length: 0\r\n" | |
267 | "\r\n" | |
268 | }; | |
269 | request<dynamic_body> m; | |
270 | try | |
271 | { | |
272 | multi_buffer b; | |
273 | read(c, b, m); | |
274 | break; | |
275 | } | |
276 | catch(std::exception const&) | |
277 | { | |
278 | } | |
279 | } | |
280 | BEAST_EXPECT(n < limit); | |
281 | ||
282 | for(n = 0; n < limit; ++n) | |
283 | { | |
92f5a8d4 | 284 | test::fail_count fc{n}; |
b32b8144 FG |
285 | test::stream ts{ioc_, fc, |
286 | "GET / HTTP/1.1\r\n" | |
287 | "Host: localhost\r\n" | |
288 | "User-Agent: test\r\n" | |
289 | "Content-Length: 0\r\n" | |
290 | "\r\n" | |
291 | }; | |
292 | request<dynamic_body> m; | |
92f5a8d4 | 293 | error_code ec = test::error::test_failure; |
b32b8144 FG |
294 | multi_buffer b; |
295 | read(ts, b, m, ec); | |
296 | if(! ec) | |
297 | break; | |
298 | } | |
299 | BEAST_EXPECT(n < limit); | |
300 | ||
301 | for(n = 0; n < limit; ++n) | |
302 | { | |
92f5a8d4 | 303 | test::fail_count fc{n}; |
b32b8144 FG |
304 | test::stream c{ioc_, fc, |
305 | "GET / HTTP/1.1\r\n" | |
306 | "Host: localhost\r\n" | |
307 | "User-Agent: test\r\n" | |
308 | "Content-Length: 0\r\n" | |
309 | "\r\n" | |
310 | }; | |
311 | request<dynamic_body> m; | |
92f5a8d4 | 312 | error_code ec = test::error::test_failure; |
b32b8144 FG |
313 | multi_buffer b; |
314 | async_read(c, b, m, do_yield[ec]); | |
315 | if(! ec) | |
316 | break; | |
317 | } | |
318 | BEAST_EXPECT(n < limit); | |
319 | ||
320 | for(n = 0; n < limit; ++n) | |
321 | { | |
92f5a8d4 | 322 | test::fail_count fc{n}; |
b32b8144 FG |
323 | test::stream c{ioc_, fc, |
324 | "GET / HTTP/1.1\r\n" | |
325 | "Host: localhost\r\n" | |
326 | "User-Agent: test\r\n" | |
327 | "Content-Length: 0\r\n" | |
328 | "\r\n" | |
329 | }; | |
330 | request_parser<dynamic_body> m; | |
92f5a8d4 | 331 | error_code ec = test::error::test_failure; |
b32b8144 FG |
332 | multi_buffer b; |
333 | async_read_some(c, b, m, do_yield[ec]); | |
334 | if(! ec) | |
335 | break; | |
336 | } | |
337 | BEAST_EXPECT(n < limit); | |
338 | } | |
339 | ||
340 | void | |
341 | testEof(yield_context do_yield) | |
342 | { | |
343 | { | |
344 | multi_buffer b; | |
345 | test::stream ts{ioc_}; | |
346 | request_parser<dynamic_body> p; | |
347 | error_code ec; | |
348 | ts.close_remote(); | |
349 | read(ts, b, p, ec); | |
350 | BEAST_EXPECT(ec == http::error::end_of_stream); | |
351 | } | |
352 | { | |
353 | multi_buffer b; | |
354 | test::stream ts{ioc_}; | |
355 | request_parser<dynamic_body> p; | |
356 | error_code ec; | |
357 | ts.close_remote(); | |
358 | async_read(ts, b, p, do_yield[ec]); | |
359 | BEAST_EXPECT(ec == http::error::end_of_stream); | |
360 | } | |
361 | } | |
362 | ||
363 | // Ensure completion handlers are not leaked | |
364 | struct handler | |
365 | { | |
366 | static std::atomic<std::size_t>& | |
367 | count() { static std::atomic<std::size_t> n; return n; } | |
368 | handler() { ++count(); } | |
369 | ~handler() { --count(); } | |
370 | handler(handler const&) { ++count(); } | |
371 | void operator()(error_code const&, std::size_t) const {} | |
372 | }; | |
373 | ||
374 | void | |
375 | testIoService() | |
376 | { | |
377 | { | |
378 | // Make sure handlers are not destroyed | |
379 | // after calling io_context::stop | |
92f5a8d4 | 380 | net::io_context ioc; |
b32b8144 FG |
381 | test::stream ts{ioc, |
382 | "GET / HTTP/1.1\r\n\r\n"}; | |
383 | BEAST_EXPECT(handler::count() == 0); | |
384 | multi_buffer b; | |
385 | request<dynamic_body> m; | |
386 | async_read(ts, b, m, handler{}); | |
387 | BEAST_EXPECT(handler::count() > 0); | |
388 | ioc.stop(); | |
389 | BEAST_EXPECT(handler::count() > 0); | |
390 | ioc.restart(); | |
391 | BEAST_EXPECT(handler::count() > 0); | |
392 | ioc.run_one(); | |
393 | BEAST_EXPECT(handler::count() == 0); | |
394 | } | |
395 | { | |
396 | // Make sure uninvoked handlers are | |
397 | // destroyed when calling ~io_context | |
398 | { | |
92f5a8d4 | 399 | net::io_context ioc; |
b32b8144 FG |
400 | test::stream ts{ioc, |
401 | "GET / HTTP/1.1\r\n\r\n"}; | |
402 | BEAST_EXPECT(handler::count() == 0); | |
403 | multi_buffer b; | |
404 | request<dynamic_body> m; | |
405 | async_read(ts, b, m, handler{}); | |
406 | BEAST_EXPECT(handler::count() > 0); | |
407 | } | |
408 | BEAST_EXPECT(handler::count() == 0); | |
409 | } | |
410 | } | |
411 | ||
412 | // https://github.com/boostorg/beast/issues/430 | |
413 | void | |
414 | testRegression430() | |
415 | { | |
416 | test::stream ts{ioc_}; | |
417 | ts.read_size(1); | |
418 | ostream(ts.buffer()) << | |
419 | "HTTP/1.1 200 OK\r\n" | |
420 | "Transfer-Encoding: chunked\r\n" | |
421 | "Content-Type: application/octet-stream\r\n" | |
422 | "\r\n" | |
423 | "4\r\nabcd\r\n" | |
424 | "0\r\n\r\n"; | |
425 | error_code ec; | |
426 | flat_buffer fb; | |
427 | response_parser<dynamic_body> p; | |
428 | read(ts, fb, p, ec); | |
429 | BEAST_EXPECTS(! ec, ec.message()); | |
430 | } | |
431 | ||
432 | //-------------------------------------------------------------------------- | |
433 | ||
434 | template<class Parser, class Pred> | |
435 | void | |
436 | readgrind(string_view s, Pred&& pred) | |
437 | { | |
b32b8144 FG |
438 | for(std::size_t n = 1; n < s.size() - 1; ++n) |
439 | { | |
440 | Parser p; | |
92f5a8d4 | 441 | error_code ec = test::error::test_failure; |
b32b8144 FG |
442 | flat_buffer b; |
443 | test::stream ts{ioc_}; | |
444 | ostream(ts.buffer()) << s; | |
445 | ts.read_size(n); | |
446 | read(ts, b, p, ec); | |
447 | if(! BEAST_EXPECTS(! ec, ec.message())) | |
448 | continue; | |
449 | pred(p); | |
450 | } | |
451 | } | |
452 | ||
453 | void | |
454 | testReadGrind() | |
455 | { | |
456 | readgrind<test_parser<false>>( | |
457 | "HTTP/1.1 200 OK\r\n" | |
458 | "Transfer-Encoding: chunked\r\n" | |
459 | "Content-Type: application/octet-stream\r\n" | |
460 | "\r\n" | |
461 | "4\r\nabcd\r\n" | |
462 | "0\r\n\r\n" | |
463 | ,[&](test_parser<false> const& p) | |
464 | { | |
465 | BEAST_EXPECT(p.body == "abcd"); | |
466 | }); | |
467 | readgrind<test_parser<false>>( | |
468 | "HTTP/1.1 200 OK\r\n" | |
469 | "Server: test\r\n" | |
470 | "Expect: Expires, MD5-Fingerprint\r\n" | |
471 | "Transfer-Encoding: chunked\r\n" | |
472 | "\r\n" | |
473 | "5\r\n" | |
474 | "*****\r\n" | |
475 | "2;a;b=1;c=\"2\"\r\n" | |
476 | "--\r\n" | |
477 | "0;d;e=3;f=\"4\"\r\n" | |
478 | "Expires: never\r\n" | |
479 | "MD5-Fingerprint: -\r\n" | |
480 | "\r\n" | |
481 | ,[&](test_parser<false> const& p) | |
482 | { | |
483 | BEAST_EXPECT(p.body == "*****--"); | |
484 | }); | |
485 | } | |
486 | ||
11fdf7f2 TL |
487 | struct copyable_handler |
488 | { | |
489 | template<class... Args> | |
490 | void | |
491 | operator()(Args&&...) const | |
492 | { | |
493 | } | |
494 | }; | |
495 | ||
496 | void | |
497 | testAsioHandlerInvoke() | |
498 | { | |
92f5a8d4 TL |
499 | using strand = net::strand< |
500 | net::io_context::executor_type>; | |
501 | ||
11fdf7f2 TL |
502 | // make sure things compile, also can set a |
503 | // breakpoint in asio_handler_invoke to make sure | |
504 | // it is instantiated. | |
505 | { | |
92f5a8d4 TL |
506 | net::io_context ioc; |
507 | strand s{ioc.get_executor()}; | |
11fdf7f2 TL |
508 | test::stream ts{ioc}; |
509 | flat_buffer b; | |
510 | request_parser<dynamic_body> p; | |
92f5a8d4 TL |
511 | async_read_some(ts, b, p, |
512 | net::bind_executor( | |
513 | s, copyable_handler{})); | |
11fdf7f2 TL |
514 | } |
515 | { | |
92f5a8d4 TL |
516 | net::io_context ioc; |
517 | strand s{ioc.get_executor()}; | |
11fdf7f2 TL |
518 | test::stream ts{ioc}; |
519 | flat_buffer b; | |
520 | request_parser<dynamic_body> p; | |
92f5a8d4 TL |
521 | async_read(ts, b, p, |
522 | net::bind_executor( | |
523 | s, copyable_handler{})); | |
11fdf7f2 TL |
524 | } |
525 | { | |
92f5a8d4 TL |
526 | net::io_context ioc; |
527 | strand s{ioc.get_executor()}; | |
11fdf7f2 TL |
528 | test::stream ts{ioc}; |
529 | flat_buffer b; | |
530 | request<dynamic_body> m; | |
92f5a8d4 TL |
531 | async_read(ts, b, m, |
532 | net::bind_executor( | |
533 | s, copyable_handler{})); | |
11fdf7f2 TL |
534 | } |
535 | } | |
536 | ||
20effc67 TL |
537 | #if BOOST_ASIO_HAS_CO_AWAIT |
538 | void testAwaitableCompiles( | |
539 | test::stream& stream, | |
540 | flat_buffer& dynbuf, | |
541 | parser<true, string_body>& request_parser, | |
542 | request<http::string_body>& request, | |
543 | parser<false, string_body>& response_parser, | |
544 | response<http::string_body>& response) | |
545 | { | |
546 | static_assert(std::is_same_v< | |
547 | net::awaitable<std::size_t>, decltype( | |
548 | http::async_read(stream, dynbuf, request, net::use_awaitable))>); | |
549 | ||
550 | static_assert(std::is_same_v< | |
551 | net::awaitable<std::size_t>, decltype( | |
552 | http::async_read(stream, dynbuf, request_parser, net::use_awaitable))>); | |
553 | ||
554 | static_assert(std::is_same_v< | |
555 | net::awaitable<std::size_t>, decltype( | |
556 | http::async_read(stream, dynbuf, response, net::use_awaitable))>); | |
557 | ||
558 | static_assert(std::is_same_v< | |
559 | net::awaitable<std::size_t>, decltype( | |
560 | http::async_read(stream, dynbuf, response_parser, net::use_awaitable))>); | |
561 | ||
562 | static_assert(std::is_same_v< | |
563 | net::awaitable<std::size_t>, decltype( | |
564 | http::async_read_some(stream, dynbuf, request_parser, net::use_awaitable))>); | |
565 | ||
566 | static_assert(std::is_same_v< | |
567 | net::awaitable<std::size_t>, decltype( | |
568 | http::async_read_some(stream, dynbuf, response_parser, net::use_awaitable))>); | |
569 | ||
570 | static_assert(std::is_same_v< | |
571 | net::awaitable<std::size_t>, decltype( | |
572 | http::async_read_header(stream, dynbuf, request_parser, net::use_awaitable))>); | |
573 | ||
574 | static_assert(std::is_same_v< | |
575 | net::awaitable<std::size_t>, decltype( | |
576 | http::async_read_header(stream, dynbuf, response_parser, net::use_awaitable))>); | |
577 | } | |
578 | #endif | |
579 | ||
580 | void testReadSomeHeader(net::yield_context yield) | |
581 | { | |
582 | std::string hdr = | |
583 | "GET /foo HTTP/1.1" "\r\n" | |
584 | "Connection: Keep-Alive" "\r\n" | |
585 | "Content-Length: 6" | |
586 | "\r\n" | |
587 | "\r\n"; | |
588 | std::string body = | |
589 | "Hello!"; | |
590 | ||
591 | { | |
592 | // bytes_transferred returns length of header | |
593 | request_parser<string_body> p; | |
594 | test::stream s(ioc_); | |
595 | ||
596 | s.append(string_view(hdr)); | |
597 | s.append(string_view(body)); | |
598 | flat_buffer fb; | |
599 | error_code ec; | |
600 | auto bt = async_read_header(s, fb, p, yield[ec]); | |
601 | BEAST_EXPECTS(!ec, ec.message()); | |
602 | BEAST_EXPECT(bt == hdr.size()); | |
603 | ||
604 | // next read should be zero-size, success | |
605 | bt = async_read_header(s, fb, p, yield[ec]); | |
606 | BEAST_EXPECTS(!ec, ec.message()); | |
607 | BEAST_EXPECTS(bt == 0, std::to_string(0)); | |
608 | } | |
609 | ||
610 | { | |
611 | // incomplete header consumes all parsable header bytes | |
612 | request_parser<string_body> p; | |
613 | test::stream s(ioc_); | |
614 | ||
615 | s.append(hdr.substr(0, hdr.size() - 1)); | |
616 | s.close(); | |
617 | flat_buffer fb; | |
618 | error_code ec; | |
619 | auto bt = async_read_header(s, fb, p, yield[ec]); | |
620 | BEAST_EXPECTS(ec == error::partial_message, ec.message()); | |
621 | BEAST_EXPECTS(bt + fb.size() == hdr.size() - 1, | |
622 | std::to_string(bt + fb.size()) + | |
623 | " expected " + | |
624 | std::to_string(hdr.size() - 1)); | |
625 | } | |
626 | ||
627 | { | |
628 | // read consumes and reports correct number of bytes | |
629 | request_parser<string_body> p; | |
630 | test::stream s(ioc_); | |
631 | ||
632 | s.append(hdr); | |
633 | s.append(body); | |
634 | s.append(hdr); | |
635 | s.append(body); | |
636 | s.append(hdr); | |
637 | s.append(body); | |
638 | ||
639 | flat_buffer fb; | |
640 | error_code ec; | |
641 | auto bt = async_read_header(s, fb, p, yield[ec]); | |
642 | BEAST_EXPECTS("ec", ec.message()); | |
643 | BEAST_EXPECT(bt == hdr.size()); | |
644 | auto bt2 = async_read_some(s, fb, p, yield[ec]); | |
645 | BEAST_EXPECTS(!ec, ec.message()); | |
646 | BEAST_EXPECT(bt2 == body.size()); | |
647 | BEAST_EXPECTS(fb.size() / 2 == hdr.size() + body.size(), | |
648 | std::to_string(fb.size() / 2) + " != " + std::to_string(hdr.size() + body.size())); | |
649 | ||
650 | request_parser<string_body> p2; | |
651 | bt = async_read(s, fb, p2, yield[ec]); | |
652 | BEAST_EXPECTS(!ec, ec.message()); | |
653 | BEAST_EXPECTS(bt == hdr.size() + body.size(), | |
654 | std::to_string(bt) + | |
655 | " expected " + | |
656 | std::to_string(hdr.size() + body.size())); | |
657 | BEAST_EXPECTS(fb.size() == hdr.size() + body.size(), | |
658 | std::to_string(fb.size()) + " != " + std::to_string(hdr.size() + body.size())); | |
659 | ||
660 | ||
661 | } | |
662 | } | |
663 | ||
664 | void testReadSomeHeader() | |
665 | { | |
666 | net::io_context ioc; | |
667 | ||
668 | std::string hdr = | |
669 | "GET /foo HTTP/1.1" "\r\n" | |
670 | "Connection: Keep-Alive" "\r\n" | |
671 | "Content-Length: 6" | |
672 | "\r\n" | |
673 | "\r\n"; | |
674 | std::string body = | |
675 | "Hello!"; | |
676 | ||
677 | { | |
678 | // bytes_transferred returns length of header | |
679 | request_parser<string_body> p; | |
680 | test::stream s(ioc); | |
681 | s.append(string_view(hdr)); | |
682 | s.append(string_view(body)); | |
683 | flat_buffer fb; | |
684 | error_code ec; | |
685 | auto bt = read_header(s, fb, p, ec); | |
686 | BEAST_EXPECTS(!ec, ec.message()); | |
687 | BEAST_EXPECT(bt == hdr.size()); | |
688 | ||
689 | // next read should be zero-size, success | |
690 | bt = read_header(s, fb, p, ec); | |
691 | BEAST_EXPECTS(!ec, ec.message()); | |
692 | BEAST_EXPECTS(bt == 0, std::to_string(0)); | |
693 | } | |
694 | ||
695 | { | |
696 | // incomplete header consumes all parsable header bytes | |
697 | request_parser<string_body> p; | |
698 | test::stream s(ioc); | |
699 | ||
700 | s.append(hdr.substr(0, hdr.size() - 1)); | |
701 | s.close(); | |
702 | flat_buffer fb; | |
703 | error_code ec; | |
704 | auto bt = read_header(s, fb, p, ec); | |
705 | BEAST_EXPECTS(ec == error::partial_message, ec.message()); | |
706 | BEAST_EXPECTS(bt + fb.size() == hdr.size() - 1, | |
707 | std::to_string(bt + fb.size()) + | |
708 | " expected " + | |
709 | std::to_string(hdr.size() - 1)); | |
710 | } | |
711 | } | |
712 | ||
713 | ||
b32b8144 FG |
714 | void |
715 | run() override | |
716 | { | |
717 | testThrow(); | |
718 | testBufferOverflow(); | |
719 | ||
720 | yield_to([&](yield_context yield) | |
721 | { | |
722 | testFailures(yield); | |
723 | }); | |
724 | yield_to([&](yield_context yield) | |
725 | { | |
726 | testRead(yield); | |
727 | }); | |
728 | yield_to([&](yield_context yield) | |
729 | { | |
730 | testEof(yield); | |
731 | }); | |
732 | ||
733 | testIoService(); | |
734 | testRegression430(); | |
735 | testReadGrind(); | |
11fdf7f2 | 736 | testAsioHandlerInvoke(); |
20effc67 TL |
737 | #if BOOST_ASIO_HAS_CO_AWAIT |
738 | boost::ignore_unused(&read_test::testAwaitableCompiles); | |
739 | #endif | |
740 | yield_to([&](yield_context yield) | |
741 | { | |
742 | testReadSomeHeader(yield); | |
743 | }); | |
744 | testReadSomeHeader(); | |
b32b8144 | 745 | } |
20effc67 TL |
746 | |
747 | ||
b32b8144 FG |
748 | }; |
749 | ||
750 | BEAST_DEFINE_TESTSUITE(beast,http,read); | |
751 | ||
752 | } // http | |
753 | } // beast | |
754 | } // boost |