2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 // Test that header file is self-contained.
11 #include <boost/beast/http/basic_parser.hpp>
13 #include "message_fuzz.hpp"
14 #include "test_parser.hpp"
16 #include <boost/beast/core/buffer_traits.hpp>
17 #include <boost/beast/core/buffers_cat.hpp>
18 #include <boost/beast/core/buffers_prefix.hpp>
19 #include <boost/beast/core/buffers_suffix.hpp>
20 #include <boost/beast/core/multi_buffer.hpp>
21 #include <boost/beast/core/ostream.hpp>
22 #include <boost/beast/http/parser.hpp>
23 #include <boost/beast/http/string_body.hpp>
24 #include <boost/beast/test/fuzz.hpp>
25 #include <boost/beast/_experimental/unit_test/suite.hpp>
31 class basic_parser_test
: public beast::unit_test::suite
37 connection_keep_alive
= 2,
39 connection_upgrade
= 8,
49 expect_version(suite
& s
, int version
)
55 template<class Parser
>
57 operator()(Parser
const& p
) const
59 s_
.BEAST_EXPECT(p
.version
== version_
);
69 expect_status(suite
& s
, int status
)
75 template<class Parser
>
77 operator()(Parser
const& p
) const
79 s_
.BEAST_EXPECT(p
.status
== status_
);
89 expect_flags(suite
& s
, unsigned flags
)
95 template<class Parser
>
97 operator()(Parser
const& p
) const
99 if(flags_
& parse_flag::chunked
)
100 s_
.BEAST_EXPECT(p
.chunked());
101 if(flags_
& parse_flag::connection_keep_alive
)
102 s_
.BEAST_EXPECT(p
.keep_alive());
103 if(flags_
& parse_flag::connection_close
)
104 s_
.BEAST_EXPECT(! p
.keep_alive());
105 if(flags_
& parse_flag::upgrade
)
106 s_
.BEAST_EXPECT(! p
.upgrade());
110 class expect_keepalive
116 expect_keepalive(suite
& s
, bool v
)
122 template<class Parser
>
124 operator()(Parser
const& p
) const
126 s_
.BEAST_EXPECT(p
.keep_alive() == v_
);
133 std::string
const& body_
;
136 expect_body(expect_body
&&) = default;
138 expect_body(suite
& s
, std::string
const& v
)
144 template<class Parser
>
146 operator()(Parser
const& p
) const
148 s_
.BEAST_EXPECT(p
.body
== body_
);
152 //--------------------------------------------------------------------------
154 template<class Parser
, class ConstBufferSequence
, class Test
>
155 typename
std::enable_if
<
156 net::is_const_buffer_sequence
<ConstBufferSequence
>::value
>::type
157 parsegrind(ConstBufferSequence
const& buffers
,
158 Test
const& test
, bool skip
= false)
160 auto const size
= buffer_bytes(buffers
);
161 for(std::size_t i
= 1; i
< size
- 1; ++i
)
167 buffers_suffix
<ConstBufferSequence
> cb
{buffers
};
168 auto n
= p
.put(buffers_prefix(i
, cb
), ec
);
169 if(! BEAST_EXPECTS(! ec
||
170 ec
== error::need_more
, ec
.message()))
172 if(! BEAST_EXPECT(! p
.is_done()))
176 if(! BEAST_EXPECTS(! ec
, ec
.message()))
178 if(! BEAST_EXPECT(n
== buffer_bytes(cb
)))
183 if(! BEAST_EXPECTS(! ec
, ec
.message()))
186 if(! BEAST_EXPECT(p
.is_done()))
190 for(std::size_t i
= 1; i
< size
- 1; ++i
)
195 buffers_suffix
<ConstBufferSequence
> cb
{buffers
};
197 auto n
= p
.put(buffers_cat(
198 buffers_prefix(i
, buffers
), cb
), ec
);
199 if(! BEAST_EXPECTS(! ec
, ec
.message()))
201 if(! BEAST_EXPECT(n
== size
))
206 if(! BEAST_EXPECTS(! ec
, ec
.message()))
213 template<class Parser
, class Test
>
215 parsegrind(string_view msg
, Test
const& test
, bool skip
= false)
217 parsegrind
<Parser
>(net::const_buffer
{
218 msg
.data(), msg
.size()}, test
, skip
);
221 template<class Parser
, class ConstBufferSequence
>
222 typename
std::enable_if
<
223 net::is_const_buffer_sequence
<ConstBufferSequence
>::value
>::type
224 parsegrind(ConstBufferSequence
const& buffers
)
226 parsegrind
<Parser
>(buffers
, [](Parser
const&){});
229 template<class Parser
>
231 parsegrind(string_view msg
)
233 parsegrind
<Parser
>(msg
, [](Parser
const&){});
236 template<class Parser
>
238 failgrind(string_view msg
, error_code
const& result
)
240 for(std::size_t i
= 1; i
< msg
.size() - 1; ++i
)
245 buffers_suffix
<net::const_buffer
> cb
{
246 boost::in_place_init
, msg
.data(), msg
.size()};
247 auto n
= p
.put(buffers_prefix(i
, cb
), ec
);
254 ec
== error::need_more
, ec
.message()))
256 if(! BEAST_EXPECT(! p
.is_done()))
262 BEAST_EXPECTS(ec
== result
, ec
.message());
264 for(std::size_t i
= 1; i
< msg
.size() - 1; ++i
)
270 net::const_buffer
{msg
.data(), i
},
272 msg
.data() + i
, msg
.size() - i
}), ec
);
275 BEAST_EXPECTS(ec
== result
, ec
.message());
279 //--------------------------------------------------------------------------
284 parsegrind
<test_parser
<true>>(
288 parsegrind
<test_parser
<true>>(
289 "POST / HTTP/1.1\r\n"
290 "Content-Length: 5\r\n"
294 parsegrind
<test_parser
<false>>(
295 "HTTP/1.1 403 Not Found\r\n"
298 parsegrind
<test_parser
<false>>(
299 "HTTP/1.1 200 OK\r\n"
300 "Content-Length: 5\r\n"
304 parsegrind
<test_parser
<false>>(
305 "HTTP/1.1 200 OK\r\n"
306 "Transfer-Encoding: chunked\r\n"
309 "0\r\nMD5: 0xff30\r\n"
312 parsegrind
<test_parser
<false>>(
313 "HTTP/1.1 200 OK\r\n"
323 [&](std::string
const& s
, string_view value
)
329 parsegrind
<request_parser
<string_body
>>(m
,
330 [&](request_parser
<string_body
> const& p
)
332 BEAST_EXPECT(p
.get()["f"] == value
);
342 check("\tx \t", "x");
343 check(" \tx\t ", "x");
344 check("\t x \t ", "x");
345 check("\r\n x", "x");
346 check(" \r\n x", "x");
347 check(" \r\n\tx", "x");
348 check(" \r\n\t x", "x");
349 check(" \r\n \tx", "x");
350 check(" \r\n \r\n \r\n x \t", "x");
352 check("\r\n x", "x");
353 check("\r\n x", "x");
354 check("\r\n xy", "xy");
355 check("\r\n \r\n \r\n x", "x");
356 check("\r\n \r\n \r\n xy", "xy");
357 check("x\r\n y", "x y");
358 check("x\r\n y\r\n z ", "x y z");
361 // Check that all callbacks are invoked
365 parsegrind
<test_parser
<true>>(
367 "User-Agent: test\r\n"
368 "Content-Length: 1\r\n"
371 [&](test_parser
<true> const& p
)
373 BEAST_EXPECT(p
.got_on_begin
== 1);
374 BEAST_EXPECT(p
.got_on_field
== 2);
375 BEAST_EXPECT(p
.got_on_header
== 1);
376 BEAST_EXPECT(p
.got_on_body
== 1);
377 BEAST_EXPECT(p
.got_on_chunk
== 0);
378 BEAST_EXPECT(p
.got_on_complete
== 1);
380 parsegrind
<test_parser
<false>>(
381 "HTTP/1.1 200 OK\r\n"
383 "Content-Length: 1\r\n"
386 [&](test_parser
<false> const& p
)
388 BEAST_EXPECT(p
.got_on_begin
== 1);
389 BEAST_EXPECT(p
.got_on_field
== 2);
390 BEAST_EXPECT(p
.got_on_header
== 1);
391 BEAST_EXPECT(p
.got_on_body
== 1);
392 BEAST_EXPECT(p
.got_on_chunk
== 0);
393 BEAST_EXPECT(p
.got_on_complete
== 1);
395 parsegrind
<test_parser
<false>>(
396 "HTTP/1.1 200 OK\r\n"
398 "Transfer-Encoding: chunked\r\n"
402 [&](test_parser
<false> const& p
)
404 BEAST_EXPECT(p
.got_on_begin
== 1);
405 BEAST_EXPECT(p
.got_on_field
== 2);
406 BEAST_EXPECT(p
.got_on_header
== 1);
407 BEAST_EXPECT(p
.got_on_body
== 1);
408 BEAST_EXPECT(p
.got_on_chunk
== 2);
409 BEAST_EXPECT(p
.got_on_complete
== 1);
411 parsegrind
<test_parser
<false>>(
412 "HTTP/1.1 200 OK\r\n"
414 "Transfer-Encoding: chunked\r\n"
418 [&](test_parser
<false> const& p
)
420 BEAST_EXPECT(p
.got_on_begin
== 1);
421 BEAST_EXPECT(p
.got_on_field
== 2);
422 BEAST_EXPECT(p
.got_on_header
== 1);
423 BEAST_EXPECT(p
.got_on_body
== 1);
424 BEAST_EXPECT(p
.got_on_chunk
== 2);
425 BEAST_EXPECT(p
.got_on_complete
== 1);
432 using P
= test_parser
<true>;
434 parsegrind
<P
>("GET /x HTTP/1.0\r\n\r\n");
435 parsegrind
<P
>("!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz / HTTP/1.0\r\n\r\n");
436 parsegrind
<P
>("GET / HTTP/1.0\r\n\r\n", expect_version
{*this, 10});
437 parsegrind
<P
>("G / HTTP/1.1\r\n\r\n", expect_version
{*this, 11});
438 // VFALCO TODO various forms of good request-target (uri)
440 failgrind
<P
>("\tGET / HTTP/1.0\r\n" "\r\n", error::bad_method
);
441 failgrind
<P
>("GET\x01 / HTTP/1.0\r\n" "\r\n", error::bad_method
);
442 failgrind
<P
>("GET / HTTP/1.0\r\n" "\r\n", error::bad_target
);
443 failgrind
<P
>("GET \x01 HTTP/1.0\r\n" "\r\n", error::bad_target
);
444 failgrind
<P
>("GET /\x01 HTTP/1.0\r\n" "\r\n", error::bad_target
);
445 // VFALCO TODO various forms of bad request-target (uri)
446 failgrind
<P
>("GET / HTTP/1.0\r\n" "\r\n", error::bad_version
);
447 failgrind
<P
>("GET / _TTP/1.0\r\n" "\r\n", error::bad_version
);
448 failgrind
<P
>("GET / H_TP/1.0\r\n" "\r\n", error::bad_version
);
449 failgrind
<P
>("GET / HT_P/1.0\r\n" "\r\n", error::bad_version
);
450 failgrind
<P
>("GET / HTT_/1.0\r\n" "\r\n", error::bad_version
);
451 failgrind
<P
>("GET / HTTP_1.0\r\n" "\r\n", error::bad_version
);
452 failgrind
<P
>("GET / HTTP/01.2\r\n" "\r\n", error::bad_version
);
453 failgrind
<P
>("GET / HTTP/3.45\r\n" "\r\n", error::bad_version
);
454 failgrind
<P
>("GET / HTTP/67.89\r\n" "\r\n", error::bad_version
);
455 failgrind
<P
>("GET / HTTP/x.0\r\n" "\r\n", error::bad_version
);
456 failgrind
<P
>("GET / HTTP/1.x\r\n" "\r\n", error::bad_version
);
457 failgrind
<P
>("GET / HTTP/1.0 \r\n" "\r\n", error::bad_version
);
458 failgrind
<P
>("GET / HTTP/1_0\r\n" "\r\n", error::bad_version
);
459 failgrind
<P
>("GET / HTTP/1.0\n\r\n" "\r\n", error::bad_version
);
460 failgrind
<P
>("GET / HTTP/1.0\n\r\r\n" "\r\n", error::bad_version
);
461 failgrind
<P
>("GET / HTTP/1.0\r\r\n" "\r\n", error::bad_version
);
467 using P
= test_parser
<false>;
469 parsegrind
<P
>("HTTP/1.0 000 OK\r\n" "\r\n", expect_status
{*this, 0});
470 parsegrind
<P
>("HTTP/1.1 012 OK\r\n" "\r\n", expect_status
{*this, 12});
471 parsegrind
<P
>("HTTP/1.0 345 OK\r\n" "\r\n", expect_status
{*this, 345});
472 parsegrind
<P
>("HTTP/1.0 678 OK\r\n" "\r\n", expect_status
{*this, 678});
473 parsegrind
<P
>("HTTP/1.0 999 OK\r\n" "\r\n", expect_status
{*this, 999});
474 parsegrind
<P
>("HTTP/1.0 200 \tX\r\n" "\r\n", expect_version
{*this, 10});
475 parsegrind
<P
>("HTTP/1.1 200 X\r\n" "\r\n", expect_version
{*this, 11});
476 parsegrind
<P
>("HTTP/1.0 200 \r\n" "\r\n");
477 parsegrind
<P
>("HTTP/1.1 200 X \r\n" "\r\n");
478 parsegrind
<P
>("HTTP/1.1 200 X\t\r\n" "\r\n");
479 parsegrind
<P
>("HTTP/1.1 200 \x80\x81...\xfe\xff\r\n\r\n");
480 parsegrind
<P
>("HTTP/1.1 200 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\r\n\r\n");
482 failgrind
<P
>("\rHTTP/1.0 200 OK\r\n" "\r\n", error::bad_version
);
483 failgrind
<P
>("\nHTTP/1.0 200 OK\r\n" "\r\n", error::bad_version
);
484 failgrind
<P
>(" HTTP/1.0 200 OK\r\n" "\r\n", error::bad_version
);
485 failgrind
<P
>("_TTP/1.0 200 OK\r\n" "\r\n", error::bad_version
);
486 failgrind
<P
>("H_TP/1.0 200 OK\r\n" "\r\n", error::bad_version
);
487 failgrind
<P
>("HT_P/1.0 200 OK\r\n" "\r\n", error::bad_version
);
488 failgrind
<P
>("HTT_/1.0 200 OK\r\n" "\r\n", error::bad_version
);
489 failgrind
<P
>("HTTP_1.0 200 OK\r\n" "\r\n", error::bad_version
);
490 failgrind
<P
>("HTTP/01.2 200 OK\r\n" "\r\n", error::bad_version
);
491 failgrind
<P
>("HTTP/3.45 200 OK\r\n" "\r\n", error::bad_version
);
492 failgrind
<P
>("HTTP/67.89 200 OK\r\n" "\r\n", error::bad_version
);
493 failgrind
<P
>("HTTP/x.0 200 OK\r\n" "\r\n", error::bad_version
);
494 failgrind
<P
>("HTTP/1.x 200 OK\r\n" "\r\n", error::bad_version
);
495 failgrind
<P
>("HTTP/1_0 200 OK\r\n" "\r\n", error::bad_version
);
496 failgrind
<P
>("HTTP/1.0 200 OK\r\n" "\r\n", error::bad_status
);
497 failgrind
<P
>("HTTP/1.0 0 OK\r\n" "\r\n", error::bad_status
);
498 failgrind
<P
>("HTTP/1.0 12 OK\r\n" "\r\n", error::bad_status
);
499 failgrind
<P
>("HTTP/1.0 3456 OK\r\n" "\r\n", error::bad_status
);
500 failgrind
<P
>("HTTP/1.0 200\r\n" "\r\n", error::bad_status
);
501 failgrind
<P
>("HTTP/1.0 200 \n\r\n" "\r\n", error::bad_reason
);
502 failgrind
<P
>("HTTP/1.0 200 \x01\r\n" "\r\n", error::bad_reason
);
503 failgrind
<P
>("HTTP/1.0 200 \x7f\r\n" "\r\n", error::bad_reason
);
504 failgrind
<P
>("HTTP/1.0 200 OK\n\r\n" "\r\n", error::bad_reason
);
505 failgrind
<P
>("HTTP/1.0 200 OK\r\r\n" "\r\n", error::bad_line_ending
);
512 [](std::string
const& s
)
514 return "GET / HTTP/1.1\r\n" + s
+ "\r\n";
517 using P
= test_parser
<true>;
519 parsegrind
<P
>(m("f:\r\n"));
520 parsegrind
<P
>(m("f: \r\n"));
521 parsegrind
<P
>(m("f:\t\r\n"));
522 parsegrind
<P
>(m("f: \t\r\n"));
523 parsegrind
<P
>(m("f: v\r\n"));
524 parsegrind
<P
>(m("f:\tv\r\n"));
525 parsegrind
<P
>(m("f:\tv \r\n"));
526 parsegrind
<P
>(m("f:\tv\t\r\n"));
527 parsegrind
<P
>(m("f:\tv\t \r\n"));
528 parsegrind
<P
>(m("f:\r\n \r\n"));
529 parsegrind
<P
>(m("f:v\r\n"));
530 parsegrind
<P
>(m("f: v\r\n u\r\n"));
531 parsegrind
<P
>(m("!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz: v\r\n"));
532 parsegrind
<P
>(m("f: !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x80\x81...\xfe\xff\r\n"));
534 failgrind
<P
>(m(" f: v\r\n"), error::bad_field
);
535 failgrind
<P
>(m("\tf: v\r\n"), error::bad_field
);
536 failgrind
<P
>(m("f : v\r\n"), error::bad_field
);
537 failgrind
<P
>(m("f\t: v\r\n"), error::bad_field
);
538 failgrind
<P
>(m("f: \n\r\n"), error::bad_value
);
539 failgrind
<P
>(m("f: v\r \r\n"), error::bad_line_ending
);
540 failgrind
<P
>(m("f: \r v\r\n"), error::bad_line_ending
);
544 "\r\n", error::bad_line_ending
);
548 testConnectionField()
550 auto const m
= [](std::string
const& s
)
551 { return "GET / HTTP/1.1\r\n" + s
+ "\r\n"; };
552 auto const cn
= [](std::string
const& s
)
553 { return "GET / HTTP/1.1\r\nConnection: " + s
+ "\r\n"; };
555 auto const keepalive
= [&](bool v
)
556 { //return keepalive_f{*this, v}; return true; };
559 using P
= test_parser
<true>;
561 parsegrind
<P
>(cn("close\r\n"), expect_flags
{*this, parse_flag::connection_close
});
562 parsegrind
<P
>(cn(",close\r\n"), expect_flags
{*this, parse_flag::connection_close
});
563 parsegrind
<P
>(cn(" close\r\n"), expect_flags
{*this, parse_flag::connection_close
});
564 parsegrind
<P
>(cn("\tclose\r\n"), expect_flags
{*this, parse_flag::connection_close
});
565 parsegrind
<P
>(cn("close,\r\n"), expect_flags
{*this, parse_flag::connection_close
});
566 parsegrind
<P
>(cn("close\t\r\n"), expect_flags
{*this, parse_flag::connection_close
});
567 parsegrind
<P
>(cn("close\r\n"), expect_flags
{*this, parse_flag::connection_close
});
568 parsegrind
<P
>(cn(" ,\t,,close,, ,\t,,\r\n"), expect_flags
{*this, parse_flag::connection_close
});
569 parsegrind
<P
>(cn("\r\n close\r\n"), expect_flags
{*this, parse_flag::connection_close
});
570 parsegrind
<P
>(cn("close\r\n \r\n"), expect_flags
{*this, parse_flag::connection_close
});
571 parsegrind
<P
>(cn("any,close\r\n"), expect_flags
{*this, parse_flag::connection_close
});
572 parsegrind
<P
>(cn("close,any\r\n"), expect_flags
{*this, parse_flag::connection_close
});
573 parsegrind
<P
>(cn("any\r\n ,close\r\n"), expect_flags
{*this, parse_flag::connection_close
});
574 parsegrind
<P
>(cn("close\r\n ,any\r\n"), expect_flags
{*this, parse_flag::connection_close
});
575 parsegrind
<P
>(cn("close,close\r\n"), expect_flags
{*this, parse_flag::connection_close
}); // weird but allowed
577 parsegrind
<P
>(cn("keep-alive\r\n"), expect_flags
{*this, parse_flag::connection_keep_alive
});
578 parsegrind
<P
>(cn("keep-alive \r\n"), expect_flags
{*this, parse_flag::connection_keep_alive
});
579 parsegrind
<P
>(cn("keep-alive\t \r\n"), expect_flags
{*this, parse_flag::connection_keep_alive
});
580 parsegrind
<P
>(cn("keep-alive\t ,x\r\n"), expect_flags
{*this, parse_flag::connection_keep_alive
});
581 parsegrind
<P
>(cn("\r\n keep-alive \t\r\n"), expect_flags
{*this, parse_flag::connection_keep_alive
});
582 parsegrind
<P
>(cn("keep-alive \r\n \t \r\n"), expect_flags
{*this, parse_flag::connection_keep_alive
});
583 parsegrind
<P
>(cn("keep-alive\r\n \r\n"), expect_flags
{*this, parse_flag::connection_keep_alive
});
585 parsegrind
<P
>(cn("upgrade\r\n"), expect_flags
{*this, parse_flag::connection_upgrade
});
586 parsegrind
<P
>(cn("upgrade \r\n"), expect_flags
{*this, parse_flag::connection_upgrade
});
587 parsegrind
<P
>(cn("upgrade\t \r\n"), expect_flags
{*this, parse_flag::connection_upgrade
});
588 parsegrind
<P
>(cn("upgrade\t ,x\r\n"), expect_flags
{*this, parse_flag::connection_upgrade
});
589 parsegrind
<P
>(cn("\r\n upgrade \t\r\n"), expect_flags
{*this, parse_flag::connection_upgrade
});
590 parsegrind
<P
>(cn("upgrade \r\n \t \r\n"), expect_flags
{*this, parse_flag::connection_upgrade
});
591 parsegrind
<P
>(cn("upgrade\r\n \r\n"), expect_flags
{*this, parse_flag::connection_upgrade
});
593 // VFALCO What's up with these?
594 //parsegrind<P>(cn("close,keep-alive\r\n"), expect_flags{*this, parse_flag::connection_close | parse_flag::connection_keep_alive});
595 parsegrind
<P
>(cn("upgrade,keep-alive\r\n"), expect_flags
{*this, parse_flag::connection_upgrade
| parse_flag::connection_keep_alive
});
596 parsegrind
<P
>(cn("upgrade,\r\n keep-alive\r\n"), expect_flags
{*this, parse_flag::connection_upgrade
| parse_flag::connection_keep_alive
});
597 //parsegrind<P>(cn("close,keep-alive,upgrade\r\n"), expect_flags{*this, parse_flag::connection_close | parse_flag::connection_keep_alive | parse_flag::connection_upgrade});
599 parsegrind
<P
>("GET / HTTP/1.1\r\n\r\n", expect_keepalive(*this, true));
600 parsegrind
<P
>("GET / HTTP/1.0\r\n\r\n", expect_keepalive(*this, false));
601 parsegrind
<P
>("GET / HTTP/1.0\r\n"
602 "Connection: keep-alive\r\n\r\n", expect_keepalive(*this, true));
603 parsegrind
<P
>("GET / HTTP/1.1\r\n"
604 "Connection: close\r\n\r\n", expect_keepalive(*this, false));
606 parsegrind
<P
>(cn("x\r\n"), expect_flags
{*this, 0});
607 parsegrind
<P
>(cn("x,y\r\n"), expect_flags
{*this, 0});
608 parsegrind
<P
>(cn("x ,y\r\n"), expect_flags
{*this, 0});
609 parsegrind
<P
>(cn("x\t,y\r\n"), expect_flags
{*this, 0});
610 parsegrind
<P
>(cn("keep\r\n"), expect_flags
{*this, 0});
611 parsegrind
<P
>(cn(",keep\r\n"), expect_flags
{*this, 0});
612 parsegrind
<P
>(cn(" keep\r\n"), expect_flags
{*this, 0});
613 parsegrind
<P
>(cn("\tnone\r\n"), expect_flags
{*this, 0});
614 parsegrind
<P
>(cn("keep,\r\n"), expect_flags
{*this, 0});
615 parsegrind
<P
>(cn("keep\t\r\n"), expect_flags
{*this, 0});
616 parsegrind
<P
>(cn("keep\r\n"), expect_flags
{*this, 0});
617 parsegrind
<P
>(cn(" ,\t,,keep,, ,\t,,\r\n"), expect_flags
{*this, 0});
618 parsegrind
<P
>(cn("\r\n keep\r\n"), expect_flags
{*this, 0});
619 parsegrind
<P
>(cn("keep\r\n \r\n"), expect_flags
{*this, 0});
620 parsegrind
<P
>(cn("closet\r\n"), expect_flags
{*this, 0});
621 parsegrind
<P
>(cn(",closet\r\n"), expect_flags
{*this, 0});
622 parsegrind
<P
>(cn(" closet\r\n"), expect_flags
{*this, 0});
623 parsegrind
<P
>(cn("\tcloset\r\n"), expect_flags
{*this, 0});
624 parsegrind
<P
>(cn("closet,\r\n"), expect_flags
{*this, 0});
625 parsegrind
<P
>(cn("closet\t\r\n"), expect_flags
{*this, 0});
626 parsegrind
<P
>(cn("closet\r\n"), expect_flags
{*this, 0});
627 parsegrind
<P
>(cn(" ,\t,,closet,, ,\t,,\r\n"), expect_flags
{*this, 0});
628 parsegrind
<P
>(cn("\r\n closet\r\n"), expect_flags
{*this, 0});
629 parsegrind
<P
>(cn("closet\r\n \r\n"), expect_flags
{*this, 0});
630 parsegrind
<P
>(cn("clog\r\n"), expect_flags
{*this, 0});
631 parsegrind
<P
>(cn("key\r\n"), expect_flags
{*this, 0});
632 parsegrind
<P
>(cn("uptown\r\n"), expect_flags
{*this, 0});
633 parsegrind
<P
>(cn("keeper\r\n \r\n"), expect_flags
{*this, 0});
634 parsegrind
<P
>(cn("keep-alively\r\n \r\n"), expect_flags
{*this, 0});
635 parsegrind
<P
>(cn("up\r\n \r\n"), expect_flags
{*this, 0});
636 parsegrind
<P
>(cn("upgrader\r\n \r\n"), expect_flags
{*this, 0});
637 parsegrind
<P
>(cn("none\r\n"), expect_flags
{*this, 0});
638 parsegrind
<P
>(cn("\r\n none\r\n"), expect_flags
{*this, 0});
640 parsegrind
<P
>(m("ConnectioX: close\r\n"), expect_flags
{*this, 0});
641 parsegrind
<P
>(m("Condor: close\r\n"), expect_flags
{*this, 0});
642 parsegrind
<P
>(m("Connect: close\r\n"), expect_flags
{*this, 0});
643 parsegrind
<P
>(m("Connections: close\r\n"), expect_flags
{*this, 0});
645 parsegrind
<P
>(m("Proxy-Connection: close\r\n"), expect_flags
{*this, parse_flag::connection_close
});
646 parsegrind
<P
>(m("Proxy-Connection: keep-alive\r\n"), expect_flags
{*this, parse_flag::connection_keep_alive
});
647 parsegrind
<P
>(m("Proxy-Connection: upgrade\r\n"), expect_flags
{*this, parse_flag::connection_upgrade
});
648 parsegrind
<P
>(m("Proxy-ConnectioX: none\r\n"), expect_flags
{*this, 0});
649 parsegrind
<P
>(m("Proxy-Connections: 1\r\n"), expect_flags
{*this, 0});
650 parsegrind
<P
>(m("Proxy-Connotes: see-also\r\n"), expect_flags
{*this, 0});
652 failgrind
<P
>(cn("[\r\n"), error::bad_value
);
653 failgrind
<P
>(cn("close[\r\n"), error::bad_value
);
654 failgrind
<P
>(cn("close [\r\n"), error::bad_value
);
655 failgrind
<P
>(cn("close, upgrade [\r\n"), error::bad_value
);
656 failgrind
<P
>(cn("upgrade[]\r\n"), error::bad_value
);
657 failgrind
<P
>(cn("keep\r\n -alive\r\n"), error::bad_value
);
658 failgrind
<P
>(cn("keep-alive[\r\n"), error::bad_value
);
659 failgrind
<P
>(cn("keep-alive []\r\n"), error::bad_value
);
660 failgrind
<P
>(cn("no[ne]\r\n"), error::bad_value
);
664 testContentLengthField()
666 using P
= test_parser
<true>;
667 auto const c
= [](std::string
const& s
)
668 { return "GET / HTTP/1.1\r\nContent-Length: " + s
+ "\r\n"; };
669 auto const m
= [](std::string
const& s
)
670 { return "GET / HTTP/1.1\r\n" + s
+ "\r\n"; };
672 [&](std::string
const& s
, std::uint64_t v
)
677 BEAST_EXPECT(p
.content_length());
678 BEAST_EXPECT(p
.content_length() && *p
.content_length() == v
);
687 check("42 \r\n", 42);
688 check("42\t\r\n", 42);
689 check("42 \t \r\n", 42);
690 check("42\r\n \t \r\n", 42);
692 parsegrind
<P
>(m("Content-LengtX: 0\r\n"), expect_flags
{*this, 0});
693 parsegrind
<P
>(m("Content-Lengths: many\r\n"), expect_flags
{*this, 0});
694 parsegrind
<P
>(m("Content: full\r\n"), expect_flags
{*this, 0});
696 failgrind
<P
>(c("\r\n"), error::bad_content_length
);
697 failgrind
<P
>(c("18446744073709551616\r\n"), error::bad_content_length
);
698 failgrind
<P
>(c("0 0\r\n"), error::bad_content_length
);
699 failgrind
<P
>(c("0 1\r\n"), error::bad_content_length
);
700 failgrind
<P
>(c(",\r\n"), error::bad_content_length
);
701 failgrind
<P
>(c("0,\r\n"), error::bad_content_length
);
703 "Content-Length: 0\r\nContent-Length: 0\r\n"), error::bad_content_length
);
707 testTransferEncodingField()
709 auto const m
= [](std::string
const& s
)
710 { return "GET / HTTP/1.1\r\n" + s
+ "\r\n"; };
711 auto const ce
= [](std::string
const& s
)
712 { return "GET / HTTP/1.1\r\nTransfer-Encoding: " + s
+ "\r\n0\r\n\r\n"; };
713 auto const te
= [](std::string
const& s
)
714 { return "GET / HTTP/1.1\r\nTransfer-Encoding: " + s
+ "\r\n"; };
716 using P
= test_parser
<true>;
718 parsegrind
<P
>(ce("chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
719 parsegrind
<P
>(ce("chunked \r\n"), expect_flags
{*this, parse_flag::chunked
});
720 parsegrind
<P
>(ce("chunked\t\r\n"), expect_flags
{*this, parse_flag::chunked
});
721 parsegrind
<P
>(ce("chunked \t\r\n"), expect_flags
{*this, parse_flag::chunked
});
722 parsegrind
<P
>(ce(" chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
723 parsegrind
<P
>(ce("\tchunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
724 parsegrind
<P
>(ce("chunked,\r\n"), expect_flags
{*this, parse_flag::chunked
});
725 parsegrind
<P
>(ce("chunked ,\r\n"), expect_flags
{*this, parse_flag::chunked
});
726 parsegrind
<P
>(ce("chunked, \r\n"), expect_flags
{*this, parse_flag::chunked
});
727 parsegrind
<P
>(ce(",chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
728 parsegrind
<P
>(ce(", chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
729 parsegrind
<P
>(ce(" ,chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
730 parsegrind
<P
>(ce("chunked\r\n \r\n"), expect_flags
{*this, parse_flag::chunked
});
731 parsegrind
<P
>(ce("\r\n chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
732 parsegrind
<P
>(ce(",\r\n chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
733 parsegrind
<P
>(ce("\r\n ,chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
734 parsegrind
<P
>(ce(",\r\n chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
735 parsegrind
<P
>(ce("gzip, chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
736 parsegrind
<P
>(ce("gzip, chunked \r\n"), expect_flags
{*this, parse_flag::chunked
});
737 parsegrind
<P
>(ce("gzip, \r\n chunked\r\n"), expect_flags
{*this, parse_flag::chunked
});
739 // Technically invalid but beyond the parser's scope to detect
740 // VFALCO Look into this
741 //parsegrind<P>(ce("custom;key=\",chunked\r\n"), expect_flags{*this, parse_flag::chunked});
743 parsegrind
<P
>(te("gzip\r\n"), expect_flags
{*this, 0});
744 parsegrind
<P
>(te("chunked, gzip\r\n"), expect_flags
{*this, 0});
745 parsegrind
<P
>(te("chunked\r\n , gzip\r\n"), expect_flags
{*this, 0});
746 parsegrind
<P
>(te("chunked,\r\n gzip\r\n"), expect_flags
{*this, 0});
747 parsegrind
<P
>(te("chunked,\r\n ,gzip\r\n"), expect_flags
{*this, 0});
748 parsegrind
<P
>(te("bigchunked\r\n"), expect_flags
{*this, 0});
749 parsegrind
<P
>(te("chunk\r\n ked\r\n"), expect_flags
{*this, 0});
750 parsegrind
<P
>(te("bar\r\n ley chunked\r\n"), expect_flags
{*this, 0});
751 parsegrind
<P
>(te("barley\r\n chunked\r\n"), expect_flags
{*this, 0});
753 parsegrind
<P
>(m("Transfer-EncodinX: none\r\n"), expect_flags
{*this, 0});
754 parsegrind
<P
>(m("Transfer-Encodings: 2\r\n"), expect_flags
{*this, 0});
755 parsegrind
<P
>(m("Transfer-Encoded: false\r\n"), expect_flags
{*this, 0});
757 failgrind
<test_parser
<false>>(
758 "HTTP/1.1 200 OK\r\n"
759 "Content-Length: 1\r\n"
760 "Transfer-Encoding: chunked\r\n"
761 "\r\n", error::bad_transfer_encoding
);
767 auto const m
= [](std::string
const& s
)
768 { return "GET / HTTP/1.1\r\n" + s
+ "\r\n"; };
770 using P
= test_parser
<true>;
772 parsegrind
<P
>(m("Upgrade:\r\n"), expect_flags
{*this, parse_flag::upgrade
});
773 parsegrind
<P
>(m("Upgrade: \r\n"), expect_flags
{*this, parse_flag::upgrade
});
774 parsegrind
<P
>(m("Upgrade: yes\r\n"), expect_flags
{*this, parse_flag::upgrade
});
776 parsegrind
<P
>(m("Up: yes\r\n"), expect_flags
{*this, 0});
777 parsegrind
<P
>(m("UpgradX: none\r\n"), expect_flags
{*this, 0});
778 parsegrind
<P
>(m("Upgrades: 2\r\n"), expect_flags
{*this, 0});
779 parsegrind
<P
>(m("Upsample: 4x\r\n"), expect_flags
{*this, 0});
783 "Connection: upgrade\r\n"
784 "Upgrade: WebSocket\r\n"
788 BEAST_EXPECT(p
.upgrade());
795 // Make sure the slow-loris defense works and that
796 // we don't get duplicate or missing fields on a split.
797 parsegrind
<test_parser
<true>>(
810 [&](test_parser
<true> const& p
)
812 BEAST_EXPECT(p
.fields
.size() == 10);
813 BEAST_EXPECT(p
.fields
.at("a") == "0");
814 BEAST_EXPECT(p
.fields
.at("b") == "1");
815 BEAST_EXPECT(p
.fields
.at("c") == "2");
816 BEAST_EXPECT(p
.fields
.at("d") == "3");
817 BEAST_EXPECT(p
.fields
.at("e") == "4");
818 BEAST_EXPECT(p
.fields
.at("f") == "5");
819 BEAST_EXPECT(p
.fields
.at("g") == "6");
820 BEAST_EXPECT(p
.fields
.at("h") == "7");
821 BEAST_EXPECT(p
.fields
.at("i") == "8");
822 BEAST_EXPECT(p
.fields
.at("j") == "9");
832 "POST / HTTP/1.1\r\n"
833 "Content-Length: 2\r\n"
841 BEAST_EXPECTS(ec
== error::header_limit
, ec
.message());
846 "POST / HTTP/1.1\r\n"
847 "Content-Length: 2\r\n"
855 BEAST_EXPECTS(ec
== error::body_limit
, ec
.message());
860 "HTTP/1.1 200 OK\r\n"
864 test_parser
<false> p
;
868 BEAST_EXPECTS(ec
== error::body_limit
, ec
.message());
873 "POST / HTTP/1.1\r\n"
874 "Transfer-Encoding: chunked\r\n"
884 BEAST_EXPECTS(ec
== error::body_limit
, ec
.message());
888 //--------------------------------------------------------------------------
894 return {s
.data(), s
.size()};
897 template<class ConstBufferSequence
, bool isRequest
>
899 feed(ConstBufferSequence
const& buffers
,
900 basic_parser
<isRequest
>& p
, error_code
& ec
)
903 return p
.put(buffers
, ec
);
909 parsegrind
<test_parser
<false>>(
910 "HTTP/1.1 200 OK\r\n"
911 "Transfer-Encoding: chunked\r\n"
912 "Content-Type: application/octet-stream\r\n"
916 ,[&](test_parser
<false> const& p
)
918 BEAST_EXPECT(p
.body
== "abcd");
920 parsegrind
<test_parser
<false>>(
921 "HTTP/1.1 200 OK\r\n"
923 "Expect: Expires, MD5-Fingerprint\r\n"
924 "Transfer-Encoding: chunked\r\n"
928 "2;a;b=1;c=\"2\"\r\n"
930 "0;d;e=3;f=\"4\"\r\n"
932 "MD5-Fingerprint: -\r\n"
934 ,[&](test_parser
<false> const& p
)
936 BEAST_EXPECT(p
.body
== "*****--");
939 parsegrind
<test_parser
<true>>(
941 "Content-Length: 1\r\n"
944 expect_body(*this, "1"));
946 parsegrind
<test_parser
<false>>(
947 "HTTP/1.0 200 OK\r\n"
950 expect_body(*this, "hello"));
952 parsegrind
<test_parser
<true>>(buffers_cat(
953 buf("GET / HTTP/1.1\r\n"
954 "Content-Length: 10\r\n"
960 // request without Content-Length or
961 // Transfer-Encoding: chunked has no body.
969 BEAST_EXPECTS(! ec
, ec
.message());
970 BEAST_EXPECT(p
.is_done());
979 BEAST_EXPECTS(! ec
, ec
.message());
980 BEAST_EXPECT(p
.is_done());
983 // response without Content-Length or
984 // Transfer-Encoding: chunked requires eof.
987 test_parser
<false> p
;
989 "HTTP/1.0 200 OK\r\n"
992 BEAST_EXPECTS(! ec
, ec
.message());
993 BEAST_EXPECT(! p
.is_done());
994 BEAST_EXPECT(p
.need_eof());
997 // 304 "Not Modified" response does not require eof
1000 test_parser
<false> p
;
1002 "HTTP/1.0 304 Not Modified\r\n"
1005 BEAST_EXPECTS(! ec
, ec
.message());
1006 BEAST_EXPECT(p
.is_done());
1009 // Chunked response does not require eof
1012 test_parser
<false> p
;
1014 "HTTP/1.1 200 OK\r\n"
1015 "Transfer-Encoding: chunked\r\n"
1018 BEAST_EXPECTS(! ec
, ec
.message());
1019 BEAST_EXPECT(! p
.is_done());
1023 BEAST_EXPECTS(! ec
, ec
.message());
1024 BEAST_EXPECT(p
.is_done());
1027 // restart: 1.0 assumes Connection: close
1030 test_parser
<true> p
;
1032 "GET / HTTP/1.0\r\n"
1035 BEAST_EXPECTS(! ec
, ec
.message());
1036 BEAST_EXPECT(p
.is_done());
1039 // restart: 1.1 assumes Connection: keep-alive
1042 test_parser
<true> p
;
1044 "GET / HTTP/1.1\r\n"
1047 BEAST_EXPECTS(! ec
, ec
.message());
1048 BEAST_EXPECT(p
.is_done());
1051 failgrind
<test_parser
<true>>(
1052 "GET / HTTP/1.1\r\n"
1053 "Content-Length: 1\r\n"
1055 error::partial_message
);
1058 //--------------------------------------------------------------------------
1060 // https://github.com/boostorg/beast/issues/430
1064 parsegrind
<test_parser
<false>>(
1065 "HTTP/1.1 200 OK\r\n"
1066 "Transfer-Encoding: chunked\r\n"
1067 "Content-Type: application/octet-stream\r\n"
1073 // https://github.com/boostorg/beast/issues/452
1078 test_parser
<true> p
;
1081 "GET / HTTP/1.1\r\n"
1085 s
.data(), s
.size()), ec
);
1086 if(! BEAST_EXPECTS(! ec
, ec
.message()))
1088 BEAST_EXPECT(p
.is_done());
1091 // https://github.com/boostorg/beast/issues/496
1095 // The bug affected hex parsing with leading zeroes
1096 using P
= test_parser
<false>;
1098 "HTTP/1.1 200 OK\r\n"
1099 "Transfer-Encoding: chunked\r\n"
1100 "Content-Type: application/octet-stream\r\n"
1106 BEAST_EXPECT(p
.body
== "abcd");
1110 // https://github.com/boostorg/beast/issues/692
1115 test_parser
<false> p
;
1118 "HTTP/1.1 101 Switching Protocols\r\n"
1119 "Content-Length: 2147483648\r\n"
1122 s
.data(), s
.size()), ec
);
1123 if(! BEAST_EXPECTS(! ec
, ec
.message()))
1125 BEAST_EXPECT(p
.is_done());
1128 //--------------------------------------------------------------------------
1136 static_string
<100> ss
{s
};
1138 test::fuzz(ss
, 4, 5, r
,
1142 test_parser
<false> p
;
1144 p
.put(net::const_buffer
{
1145 s
.data(), s
.size()}, ec
);
1152 "HTTP/1.1 200 OK\r\n"
1153 "Transfer-Encoding: chunked\r\n"
1155 "0" + std::string(s
) + "\r\n"
1158 test_parser
<false> p
;
1160 p
.put(net::const_buffer
{
1161 msg
.data(), msg
.size()}, ec
);
1162 BEAST_EXPECTS(! ec
, ec
.message());
1169 "HTTP/1.1 200 OK\r\n"
1170 "Transfer-Encoding: chunked\r\n"
1172 "0" + std::string(s
) + "\r\n"
1175 test_parser
<false> p
;
1177 p
.put(net::const_buffer
{
1178 msg
.data(), msg
.size()}, ec
);
1182 chunkExtensionsTest(good
, bad
);
1185 //--------------------------------------------------------------------------
1190 // crash_00cda0b02d5166bd1039ddb3b12618cd80da75f3
1191 unsigned char buf
[] ={
1192 0x4C,0x4F,0x43,0x4B,0x20,0x2F,0x25,0x65,0x37,0x6C,0x59,0x3B,0x2F,0x3B,0x3B,0x25,0x30,0x62,0x38,0x3D,0x70,0x2F,0x72,0x20,
1193 0x48,0x54,0x54,0x50,0x2F,0x31,0x2E,0x31,0x0D,0x0A,0x41,0x63,0x63,0x65,0x70,0x74,0x2D,0x45,0x6E,0x63,0x6F,0x64,0x69,0x6E,
1194 0x67,0x3A,0x0D,0x0A,0x09,0x20,0xEE,0x0D,0x0A,0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x2D,0x4D,0x65,0x73,0x73,0x61,0x67,
1195 0x65,0x2D,0x49,0x44,0x3A,0xEB,0x09,0x09,0x09,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3A,0x20,0x0D,0x0A,0x09,0x20,
1196 0xF7,0x44,0x9B,0xA5,0x06,0x9F,0x0D,0x0A,0x52,0x65,0x73,0x65,0x6E,0x74,0x2D,0x44,0x61,0x74,0x65,0x3A,0xF4,0x0D,0x0A,0x41,
1197 0x6C,0x74,0x2D,0x53,0x76,0x63,0x3A,0x20,0x0D,0x0A,0x54,0x72,0x61,0x69,0x6C,0x65,0x72,0x3A,0x20,0x20,0x09,0x20,0x20,0x20,
1198 0x0D,0x0A,0x4C,0x69,0x73,0x74,0x2D,0x49,0x44,0x3A,0xA6,0x6B,0x86,0x09,0x09,0x20,0x09,0x0D,0x0A,0x41,0x6C,0x74,0x65,0x72,
1199 0x6E,0x61,0x74,0x65,0x2D,0x52,0x65,0x63,0x69,0x70,0x69,0x65,0x6E,0x74,0x3A,0xF3,0x13,0xE3,0x22,0x9D,0xEF,0xFB,0x84,0x71,
1200 0x4A,0xCC,0xBC,0x96,0xF7,0x5B,0x72,0xF1,0xF2,0x0D,0x0A,0x4C,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E,0x3A,0x20,0x0D,0x0A,0x41,
1201 0x63,0x63,0x65,0x70,0x74,0x2D,0x41,0x64,0x64,0x69,0x74,0x69,0x6F,0x6E,0x73,0x3A,0x20,0x0D,0x0A,0x4D,0x4D,0x48,0x53,0x2D,
1202 0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x74,0x6F,0x72,0x2D,0x50,0x4C,0x41,0x44,0x3A,0x20,0x0D,0x0A,0x4F,0x72,0x69,0x67,0x69,
1203 0x6E,0x61,0x6C,0x2D,0x53,0x65,0x6E,0x64,0x65,0x72,0x3A,0x20,0x0D,0x0A,0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x2D,0x53,
1204 0x65,0x6E,0x64,0x65,0x72,0x3A,0x0D,0x0A,0x50,0x49,0x43,0x53,0x2D,0x4C,0x61,0x62,0x65,0x6C,0x3A,0x0D,0x0A,0x20,0x09,0x0D,
1205 0x0A,0x49,0x66,0x3A,0x20,0x40,0xC1,0x50,0x5C,0xD6,0xC3,0x86,0xFC,0x8D,0x5C,0x7C,0x96,0x45,0x0D,0x0A,0x4D,0x4D,0x48,0x53,
1206 0x2D,0x45,0x78,0x65,0x6D,0x70,0x74,0x65,0x64,0x2D,0x41,0x64,0x64,0x72,0x65,0x73,0x73,0x3A,0x0D,0x0A,0x49,0x6E,0x6A,0x65,
1207 0x63,0x74,0x69,0x6F,0x6E,0x2D,0x49,0x6E,0x66,0x6F,0x3A,0x20,0x0D,0x0A,0x43,0x6F,0x6E,0x74,0x65,0x74,0x6E,0x2D,0x4C,0x65,
1208 0x6E,0x67,0x74,0x68,0x3A,0x20,0x30,0x0D,0x0A,0x0D,0x0A
1212 test_parser
<true> p
;
1213 feed(net::buffer(buf
, sizeof(buf
)), p
, ec
);
1220 using base
= detail::basic_parser_base
;
1222 [&](string_view s
, std::uint32_t v0
)
1226 base::parse_dec(s
, v
);
1227 if(BEAST_EXPECTS(result
, s
))
1228 BEAST_EXPECTS(v
== v0
, s
);
1235 base::parse_dec(s
, v
);
1236 BEAST_EXPECTS(! result
, s
);
1242 good("65535", 65535);
1243 good("65536", 65536);
1244 good("4294967295", 4294967295);
1250 bad ("18446744073709551616"); // max(uint64) + 1
1256 using base
= detail::basic_parser_base
;
1258 [&](string_view s
, std::uint64_t v0
)
1263 base::parse_hex(it
, v
);
1264 if(BEAST_EXPECTS(result
, s
))
1265 BEAST_EXPECTS(v
== v0
, s
);
1273 base::parse_hex(it
, v
);
1274 BEAST_EXPECTS(! result
, s
);
1277 good("ff\r\n", 255);
1278 good("ffff\r\n", 65535);
1279 good("ffffffffr\n", 4294967295);
1280 good("ffffffffffffffff\r\n", 18446744073709551615ULL);
1283 bad ("10000000000000000\r\n");
1284 bad ("ffffffffffffffffffffff\r\n");
1287 //--------------------------------------------------------------------------
1289 // https://github.com/boostorg/beast/issues/1734
1294 // Ensure more than one buffer, this is to avoid an optimized path in
1295 // basic_parser::put(ConstBufferSequence const&,...) which avoids
1296 // buffer flattening.
1297 auto multibufs
= [](multi_buffer::const_buffers_type buffers
) {
1298 std::vector
<net::const_buffer
> bs
;
1299 for (auto b
: buffers_range(buffers
))
1301 while (std::distance(bs
.begin(), bs
.end()) < 2) {
1307 // Buffers must be bigger than max_stack_buffer to force flattening
1308 // in basic_parser::put(ConstBufferSequence const&,...)
1309 std::string
first_chunk_data(
1310 2 * basic_parser
<false>::max_stack_buffer
+ 1, 'x');
1312 std::string
second_chunk_data_part1(
1313 basic_parser
<false>::max_stack_buffer
+ 2, 'x');
1314 std::string
second_chunk_data_part2(
1315 basic_parser
<false>::max_stack_buffer
+ 1, 'x');
1318 parser
<false, string_body
> p
;
1324 "HTTP/1.1 200 OK\r\n"
1326 "Transfer-Encoding: chunked\r\n"
1329 used
= p
.put(b
.data(), ec
);
1332 BEAST_EXPECT(net::buffer_size(b
.data()) == 0);
1333 BEAST_EXPECTS(!ec
, ec
.message());
1334 BEAST_EXPECT(!p
.is_done());
1335 BEAST_EXPECT(p
.is_header_done());
1339 first_chunk_data
.size() << "\r\n" <<
1340 first_chunk_data
<< "\r\n";
1343 used
= p
.put(multibufs(b
.data()), ec
);
1346 BEAST_EXPECTS(ec
== error::need_more
, ec
.message());
1347 BEAST_EXPECT(!p
.is_done());
1351 (second_chunk_data_part1
.size() +
1352 second_chunk_data_part2
.size() ) << "\r\n" <<
1353 second_chunk_data_part1
;
1355 // Second chunk, part 1
1356 used
= p
.put(multibufs(b
.data()), ec
);
1359 BEAST_EXPECTS(!ec
, ec
.message());
1360 BEAST_EXPECT(!p
.is_done());
1363 second_chunk_data_part2
<< "\r\n"
1366 // Second chunk, part 2
1367 used
= p
.put(multibufs(b
.data()), ec
);
1370 BEAST_EXPECTS(!ec
, ec
.message()); // <-- Error: bad chunk
1374 BEAST_EXPECTS(! ec
, ec
.message());
1376 BEAST_EXPECT(p
.is_done());
1379 //--------------------------------------------------------------------------
1390 testConnectionField();
1391 testContentLengthField();
1392 testTransferEncodingField();
1408 BEAST_DEFINE_TESTSUITE(beast
,http
,basic_parser
);