]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/beast/test/beast/http/read.cpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / libs / beast / test / beast / http / read.cpp
CommitLineData
b32b8144
FG
1//
2// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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>
21#include <boost/beast/test/stream.hpp>
22#include <boost/beast/test/yield_to.hpp>
23#include <boost/beast/unit_test/suite.hpp>
11fdf7f2
TL
24#include <boost/asio/io_service.hpp>
25#include <boost/asio/strand.hpp>
b32b8144
FG
26#include <atomic>
27
28namespace boost {
29namespace beast {
30namespace http {
31
32class read_test
33 : public beast::unit_test::suite
34 , public test::enable_yield_to
35{
36public:
37 template<bool isRequest>
38 void
39 failMatrix(char const* s, yield_context do_yield)
40 {
41 using boost::asio::buffer;
42 using boost::asio::buffer_copy;
43 static std::size_t constexpr limit = 100;
44 std::size_t n;
45 auto const len = strlen(s);
46 for(n = 0; n < limit; ++n)
47 {
48 multi_buffer b;
49 b.commit(buffer_copy(
50 b.prepare(len), buffer(s, len)));
51 test::fail_counter fc(n);
52 test::stream ts{ioc_, fc};
53 test_parser<isRequest> p(fc);
54 error_code ec = test::error::fail_error;
55 ts.close_remote();
56 read(ts, b, p, ec);
57 if(! ec)
58 break;
59 }
60 BEAST_EXPECT(n < limit);
61 for(n = 0; n < limit; ++n)
62 {
63 static std::size_t constexpr pre = 10;
64 multi_buffer b;
65 b.commit(buffer_copy(
66 b.prepare(pre), buffer(s, pre)));
67 test::fail_counter fc(n);
68 test::stream ts{ioc_, fc,
69 std::string(s + pre, len - pre)};
70 test_parser<isRequest> p(fc);
71 error_code ec = test::error::fail_error;
72 ts.close_remote();
73 read(ts, b, p, ec);
74 if(! ec)
75 break;
76 }
77 BEAST_EXPECT(n < limit);
78 for(n = 0; n < limit; ++n)
79 {
80 multi_buffer b;
81 b.commit(buffer_copy(
82 b.prepare(len), buffer(s, len)));
83 test::fail_counter fc(n);
84 test::stream ts{ioc_, fc};
85 test_parser<isRequest> p(fc);
86 error_code ec = test::error::fail_error;
87 ts.close_remote();
88 async_read(ts, b, p, do_yield[ec]);
89 if(! ec)
90 break;
91 }
92 BEAST_EXPECT(n < limit);
93 for(n = 0; n < limit; ++n)
94 {
95 multi_buffer b;
96 b.commit(buffer_copy(
97 b.prepare(len), buffer(s, len)));
98 test::fail_counter fc(n);
99 test::stream ts{ioc_, fc};
100 test_parser<isRequest> p(fc);
101 error_code ec = test::error::fail_error;
102 ts.close_remote();
103 async_read_header(ts, b, p, do_yield[ec]);
104 if(! ec)
105 break;
106 }
107 BEAST_EXPECT(n < limit);
108 for(n = 0; n < limit; ++n)
109 {
110 static std::size_t constexpr pre = 10;
111 multi_buffer b;
112 b.commit(buffer_copy(
113 b.prepare(pre), buffer(s, pre)));
114 test::fail_counter fc(n);
115 test::stream ts(ioc_, fc,
116 std::string{s + pre, len - pre});
117 test_parser<isRequest> p(fc);
118 error_code ec = test::error::fail_error;
119 ts.close_remote();
120 async_read(ts, b, p, do_yield[ec]);
121 if(! ec)
122 break;
123 }
124 BEAST_EXPECT(n < limit);
125 }
126
127 void testThrow()
128 {
129 try
130 {
131 multi_buffer b;
132 test::stream c{ioc_, "GET / X"};
133 c.close_remote();
134 request_parser<dynamic_body> p;
135 read(c, b, p);
136 fail();
137 }
138 catch(std::exception const&)
139 {
140 pass();
141 }
142 }
143
144 void
145 testBufferOverflow()
146 {
147 {
148 test::stream c{ioc_};
149 ostream(c.buffer()) <<
150 "GET / HTTP/1.1\r\n"
151 "Host: localhost\r\n"
152 "User-Agent: test\r\n"
153 "Transfer-Encoding: chunked\r\n"
154 "\r\n"
155 "10\r\n"
156 "****************\r\n"
157 "0\r\n\r\n";
158 flat_static_buffer<1024> b;
159 request<string_body> req;
160 try
161 {
162 read(c, b, req);
163 pass();
164 }
165 catch(std::exception const& e)
166 {
167 fail(e.what(), __FILE__, __LINE__);
168 }
169 }
170 {
171 test::stream c{ioc_};
172 ostream(c.buffer()) <<
173 "GET / HTTP/1.1\r\n"
174 "Host: localhost\r\n"
175 "User-Agent: test\r\n"
176 "Transfer-Encoding: chunked\r\n"
177 "\r\n"
178 "10\r\n"
179 "****************\r\n"
180 "0\r\n\r\n";
181 error_code ec = test::error::fail_error;
182 flat_static_buffer<10> b;
183 request<string_body> req;
184 read(c, b, req, ec);
185 BEAST_EXPECTS(ec == error::buffer_overflow,
186 ec.message());
187 }
188 }
189
190 void testFailures(yield_context do_yield)
191 {
192 char const* req[] = {
193 "GET / HTTP/1.0\r\n"
194 "Host: localhost\r\n"
195 "User-Agent: test\r\n"
196 "Empty:\r\n"
197 "\r\n"
198 ,
199 "GET / HTTP/1.1\r\n"
200 "Host: localhost\r\n"
201 "User-Agent: test\r\n"
202 "Content-Length: 2\r\n"
203 "\r\n"
204 "**"
205 ,
206 "GET / HTTP/1.1\r\n"
207 "Host: localhost\r\n"
208 "User-Agent: test\r\n"
209 "Transfer-Encoding: chunked\r\n"
210 "\r\n"
211 "10\r\n"
212 "****************\r\n"
213 "0\r\n\r\n"
214 ,
215 nullptr
216 };
217
218 char const* res[] = {
219 "HTTP/1.0 200 OK\r\n"
220 "Server: test\r\n"
221 "\r\n"
222 ,
223 "HTTP/1.0 200 OK\r\n"
224 "Server: test\r\n"
225 "\r\n"
226 "***"
227 ,
228 "HTTP/1.1 200 OK\r\n"
229 "Server: test\r\n"
230 "Content-Length: 3\r\n"
231 "\r\n"
232 "***"
233 ,
234 "HTTP/1.1 200 OK\r\n"
235 "Server: test\r\n"
236 "Transfer-Encoding: chunked\r\n"
237 "\r\n"
238 "10\r\n"
239 "****************\r\n"
240 "0\r\n\r\n"
241 ,
242 nullptr
243 };
244 for(std::size_t i = 0; req[i]; ++i)
245 failMatrix<true>(req[i], do_yield);
246 for(std::size_t i = 0; res[i]; ++i)
247 failMatrix<false>(res[i], do_yield);
248 }
249
250 void testRead(yield_context do_yield)
251 {
252 static std::size_t constexpr limit = 100;
253 std::size_t n;
254
255 for(n = 0; n < limit; ++n)
256 {
257 test::fail_counter fc{n};
258 test::stream c{ioc_, fc,
259 "GET / HTTP/1.1\r\n"
260 "Host: localhost\r\n"
261 "User-Agent: test\r\n"
262 "Content-Length: 0\r\n"
263 "\r\n"
264 };
265 request<dynamic_body> m;
266 try
267 {
268 multi_buffer b;
269 read(c, b, m);
270 break;
271 }
272 catch(std::exception const&)
273 {
274 }
275 }
276 BEAST_EXPECT(n < limit);
277
278 for(n = 0; n < limit; ++n)
279 {
280 test::fail_counter fc{n};
281 test::stream ts{ioc_, fc,
282 "GET / HTTP/1.1\r\n"
283 "Host: localhost\r\n"
284 "User-Agent: test\r\n"
285 "Content-Length: 0\r\n"
286 "\r\n"
287 };
288 request<dynamic_body> m;
289 error_code ec = test::error::fail_error;
290 multi_buffer b;
291 read(ts, b, m, ec);
292 if(! ec)
293 break;
294 }
295 BEAST_EXPECT(n < limit);
296
297 for(n = 0; n < limit; ++n)
298 {
299 test::fail_counter fc{n};
300 test::stream c{ioc_, fc,
301 "GET / HTTP/1.1\r\n"
302 "Host: localhost\r\n"
303 "User-Agent: test\r\n"
304 "Content-Length: 0\r\n"
305 "\r\n"
306 };
307 request<dynamic_body> m;
308 error_code ec = test::error::fail_error;
309 multi_buffer b;
310 async_read(c, b, m, do_yield[ec]);
311 if(! ec)
312 break;
313 }
314 BEAST_EXPECT(n < limit);
315
316 for(n = 0; n < limit; ++n)
317 {
318 test::fail_counter fc{n};
319 test::stream c{ioc_, fc,
320 "GET / HTTP/1.1\r\n"
321 "Host: localhost\r\n"
322 "User-Agent: test\r\n"
323 "Content-Length: 0\r\n"
324 "\r\n"
325 };
326 request_parser<dynamic_body> m;
327 error_code ec = test::error::fail_error;
328 multi_buffer b;
329 async_read_some(c, b, m, do_yield[ec]);
330 if(! ec)
331 break;
332 }
333 BEAST_EXPECT(n < limit);
334 }
335
336 void
337 testEof(yield_context do_yield)
338 {
339 {
340 multi_buffer b;
341 test::stream ts{ioc_};
342 request_parser<dynamic_body> p;
343 error_code ec;
344 ts.close_remote();
345 read(ts, b, p, ec);
346 BEAST_EXPECT(ec == http::error::end_of_stream);
347 }
348 {
349 multi_buffer b;
350 test::stream ts{ioc_};
351 request_parser<dynamic_body> p;
352 error_code ec;
353 ts.close_remote();
354 async_read(ts, b, p, do_yield[ec]);
355 BEAST_EXPECT(ec == http::error::end_of_stream);
356 }
357 }
358
359 // Ensure completion handlers are not leaked
360 struct handler
361 {
362 static std::atomic<std::size_t>&
363 count() { static std::atomic<std::size_t> n; return n; }
364 handler() { ++count(); }
365 ~handler() { --count(); }
366 handler(handler const&) { ++count(); }
367 void operator()(error_code const&, std::size_t) const {}
368 };
369
370 void
371 testIoService()
372 {
373 {
374 // Make sure handlers are not destroyed
375 // after calling io_context::stop
376 boost::asio::io_context ioc;
377 test::stream ts{ioc,
378 "GET / HTTP/1.1\r\n\r\n"};
379 BEAST_EXPECT(handler::count() == 0);
380 multi_buffer b;
381 request<dynamic_body> m;
382 async_read(ts, b, m, handler{});
383 BEAST_EXPECT(handler::count() > 0);
384 ioc.stop();
385 BEAST_EXPECT(handler::count() > 0);
386 ioc.restart();
387 BEAST_EXPECT(handler::count() > 0);
388 ioc.run_one();
389 BEAST_EXPECT(handler::count() == 0);
390 }
391 {
392 // Make sure uninvoked handlers are
393 // destroyed when calling ~io_context
394 {
395 boost::asio::io_context ioc;
396 test::stream ts{ioc,
397 "GET / HTTP/1.1\r\n\r\n"};
398 BEAST_EXPECT(handler::count() == 0);
399 multi_buffer b;
400 request<dynamic_body> m;
401 async_read(ts, b, m, handler{});
402 BEAST_EXPECT(handler::count() > 0);
403 }
404 BEAST_EXPECT(handler::count() == 0);
405 }
406 }
407
408 // https://github.com/boostorg/beast/issues/430
409 void
410 testRegression430()
411 {
412 test::stream ts{ioc_};
413 ts.read_size(1);
414 ostream(ts.buffer()) <<
415 "HTTP/1.1 200 OK\r\n"
416 "Transfer-Encoding: chunked\r\n"
417 "Content-Type: application/octet-stream\r\n"
418 "\r\n"
419 "4\r\nabcd\r\n"
420 "0\r\n\r\n";
421 error_code ec;
422 flat_buffer fb;
423 response_parser<dynamic_body> p;
424 read(ts, fb, p, ec);
425 BEAST_EXPECTS(! ec, ec.message());
426 }
427
428 //--------------------------------------------------------------------------
429
430 template<class Parser, class Pred>
431 void
432 readgrind(string_view s, Pred&& pred)
433 {
434 using boost::asio::buffer;
435 for(std::size_t n = 1; n < s.size() - 1; ++n)
436 {
437 Parser p;
438 error_code ec = test::error::fail_error;
439 flat_buffer b;
440 test::stream ts{ioc_};
441 ostream(ts.buffer()) << s;
442 ts.read_size(n);
443 read(ts, b, p, ec);
444 if(! BEAST_EXPECTS(! ec, ec.message()))
445 continue;
446 pred(p);
447 }
448 }
449
450 void
451 testReadGrind()
452 {
453 readgrind<test_parser<false>>(
454 "HTTP/1.1 200 OK\r\n"
455 "Transfer-Encoding: chunked\r\n"
456 "Content-Type: application/octet-stream\r\n"
457 "\r\n"
458 "4\r\nabcd\r\n"
459 "0\r\n\r\n"
460 ,[&](test_parser<false> const& p)
461 {
462 BEAST_EXPECT(p.body == "abcd");
463 });
464 readgrind<test_parser<false>>(
465 "HTTP/1.1 200 OK\r\n"
466 "Server: test\r\n"
467 "Expect: Expires, MD5-Fingerprint\r\n"
468 "Transfer-Encoding: chunked\r\n"
469 "\r\n"
470 "5\r\n"
471 "*****\r\n"
472 "2;a;b=1;c=\"2\"\r\n"
473 "--\r\n"
474 "0;d;e=3;f=\"4\"\r\n"
475 "Expires: never\r\n"
476 "MD5-Fingerprint: -\r\n"
477 "\r\n"
478 ,[&](test_parser<false> const& p)
479 {
480 BEAST_EXPECT(p.body == "*****--");
481 });
482 }
483
11fdf7f2
TL
484 struct copyable_handler
485 {
486 template<class... Args>
487 void
488 operator()(Args&&...) const
489 {
490 }
491 };
492
493 void
494 testAsioHandlerInvoke()
495 {
496 // make sure things compile, also can set a
497 // breakpoint in asio_handler_invoke to make sure
498 // it is instantiated.
499 {
500 boost::asio::io_context ioc;
501 boost::asio::io_service::strand s{ioc};
502 test::stream ts{ioc};
503 flat_buffer b;
504 request_parser<dynamic_body> p;
505 async_read_some(ts, b, p, s.wrap(copyable_handler{}));
506 }
507 {
508 boost::asio::io_context ioc;
509 boost::asio::io_service::strand s{ioc};
510 test::stream ts{ioc};
511 flat_buffer b;
512 request_parser<dynamic_body> p;
513 async_read(ts, b, p, s.wrap(copyable_handler{}));
514 }
515 {
516 boost::asio::io_context ioc;
517 boost::asio::io_service::strand s{ioc};
518 test::stream ts{ioc};
519 flat_buffer b;
520 request<dynamic_body> m;
521 async_read(ts, b, m, s.wrap(copyable_handler{}));
522 }
523 }
524
b32b8144
FG
525 void
526 run() override
527 {
528 testThrow();
529 testBufferOverflow();
530
531 yield_to([&](yield_context yield)
532 {
533 testFailures(yield);
534 });
535 yield_to([&](yield_context yield)
536 {
537 testRead(yield);
538 });
539 yield_to([&](yield_context yield)
540 {
541 testEof(yield);
542 });
543
544 testIoService();
545 testRegression430();
546 testReadGrind();
11fdf7f2 547 testAsioHandlerInvoke();
b32b8144
FG
548 }
549};
550
551BEAST_DEFINE_TESTSUITE(beast,http,read);
552
553} // http
554} // beast
555} // boost