]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/beast/test/beast/http/basic_parser.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / beast / test / beast / http / basic_parser.cpp
CommitLineData
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/basic_parser.hpp>
12
13#include "message_fuzz.hpp"
14#include "test_parser.hpp"
15
92f5a8d4 16#include <boost/beast/core/buffer_traits.hpp>
b32b8144
FG
17#include <boost/beast/core/buffers_cat.hpp>
18#include <boost/beast/core/buffers_prefix.hpp>
19#include <boost/beast/core/buffers_suffix.hpp>
20effc67 20#include <boost/beast/core/flat_buffer.hpp>
b32b8144
FG
21#include <boost/beast/core/multi_buffer.hpp>
22#include <boost/beast/core/ostream.hpp>
23#include <boost/beast/http/parser.hpp>
24#include <boost/beast/http/string_body.hpp>
25#include <boost/beast/test/fuzz.hpp>
92f5a8d4 26#include <boost/beast/_experimental/unit_test/suite.hpp>
b32b8144
FG
27
28namespace boost {
29namespace beast {
30namespace http {
31
32class basic_parser_test : public beast::unit_test::suite
33{
34public:
35 enum parse_flag
36 {
37 chunked = 1,
38 connection_keep_alive = 2,
39 connection_close = 4,
40 connection_upgrade = 8,
41 upgrade = 16,
42 };
43
44 class expect_version
45 {
46 suite& s_;
47 int version_;
48
49 public:
50 expect_version(suite& s, int version)
51 : s_(s)
52 , version_(version)
53 {
54 }
55
56 template<class Parser>
57 void
58 operator()(Parser const& p) const
59 {
60 s_.BEAST_EXPECT(p.version == version_);
61 }
62 };
63
64 class expect_status
65 {
66 suite& s_;
67 int status_;
68
69 public:
70 expect_status(suite& s, int status)
71 : s_(s)
72 , status_(status)
73 {
74 }
75
76 template<class Parser>
77 void
78 operator()(Parser const& p) const
79 {
80 s_.BEAST_EXPECT(p.status == status_);
81 }
82 };
83
84 class expect_flags
85 {
86 suite& s_;
87 unsigned flags_;
88
89 public:
90 expect_flags(suite& s, unsigned flags)
91 : s_(s)
92 , flags_(flags)
93 {
94 }
95
96 template<class Parser>
97 void
98 operator()(Parser const& p) const
99 {
100 if(flags_ & parse_flag::chunked)
101 s_.BEAST_EXPECT(p.chunked());
102 if(flags_ & parse_flag::connection_keep_alive)
103 s_.BEAST_EXPECT(p.keep_alive());
104 if(flags_ & parse_flag::connection_close)
105 s_.BEAST_EXPECT(! p.keep_alive());
106 if(flags_ & parse_flag::upgrade)
107 s_.BEAST_EXPECT(! p.upgrade());
108 }
109 };
110
111 class expect_keepalive
112 {
113 suite& s_;
114 bool v_;
115
116 public:
117 expect_keepalive(suite& s, bool v)
118 : s_(s)
119 , v_(v)
120 {
121 }
122
123 template<class Parser>
124 void
125 operator()(Parser const& p) const
126 {
127 s_.BEAST_EXPECT(p.keep_alive() == v_);
128 }
129 };
130
131 class expect_body
132 {
133 suite& s_;
134 std::string const& body_;
135
136 public:
137 expect_body(expect_body&&) = default;
138
139 expect_body(suite& s, std::string const& v)
140 : s_(s)
141 , body_(v)
142 {
143 }
144
145 template<class Parser>
146 void
147 operator()(Parser const& p) const
148 {
149 s_.BEAST_EXPECT(p.body == body_);
150 }
151 };
152
153 //--------------------------------------------------------------------------
154
155 template<class Parser, class ConstBufferSequence, class Test>
156 typename std::enable_if<
92f5a8d4 157 net::is_const_buffer_sequence<ConstBufferSequence>::value>::type
b32b8144
FG
158 parsegrind(ConstBufferSequence const& buffers,
159 Test const& test, bool skip = false)
160 {
92f5a8d4 161 auto const size = buffer_bytes(buffers);
b32b8144
FG
162 for(std::size_t i = 1; i < size - 1; ++i)
163 {
164 Parser p;
165 p.eager(true);
166 p.skip(skip);
167 error_code ec;
168 buffers_suffix<ConstBufferSequence> cb{buffers};
169 auto n = p.put(buffers_prefix(i, cb), ec);
170 if(! BEAST_EXPECTS(! ec ||
171 ec == error::need_more, ec.message()))
172 continue;
173 if(! BEAST_EXPECT(! p.is_done()))
174 continue;
175 cb.consume(n);
176 n = p.put(cb, ec);
177 if(! BEAST_EXPECTS(! ec, ec.message()))
178 continue;
92f5a8d4 179 if(! BEAST_EXPECT(n == buffer_bytes(cb)))
b32b8144
FG
180 continue;
181 if(p.need_eof())
182 {
183 p.put_eof(ec);
184 if(! BEAST_EXPECTS(! ec, ec.message()))
185 continue;
186 }
187 if(! BEAST_EXPECT(p.is_done()))
188 continue;
189 test(p);
190 }
191 for(std::size_t i = 1; i < size - 1; ++i)
192 {
193 Parser p;
194 p.eager(true);
195 error_code ec;
196 buffers_suffix<ConstBufferSequence> cb{buffers};
197 cb.consume(i);
198 auto n = p.put(buffers_cat(
199 buffers_prefix(i, buffers), cb), ec);
200 if(! BEAST_EXPECTS(! ec, ec.message()))
201 continue;
202 if(! BEAST_EXPECT(n == size))
203 continue;
204 if(p.need_eof())
205 {
206 p.put_eof(ec);
207 if(! BEAST_EXPECTS(! ec, ec.message()))
208 continue;
209 }
210 test(p);
211 }
212 }
213
214 template<class Parser, class Test>
215 void
216 parsegrind(string_view msg, Test const& test, bool skip = false)
217 {
92f5a8d4 218 parsegrind<Parser>(net::const_buffer{
b32b8144
FG
219 msg.data(), msg.size()}, test, skip);
220 }
221
222 template<class Parser, class ConstBufferSequence>
223 typename std::enable_if<
92f5a8d4 224 net::is_const_buffer_sequence<ConstBufferSequence>::value>::type
b32b8144
FG
225 parsegrind(ConstBufferSequence const& buffers)
226 {
227 parsegrind<Parser>(buffers, [](Parser const&){});
228 }
229
230 template<class Parser>
231 void
232 parsegrind(string_view msg)
233 {
234 parsegrind<Parser>(msg, [](Parser const&){});
235 }
236
237 template<class Parser>
238 void
239 failgrind(string_view msg, error_code const& result)
240 {
241 for(std::size_t i = 1; i < msg.size() - 1; ++i)
242 {
243 Parser p;
244 p.eager(true);
245 error_code ec;
92f5a8d4 246 buffers_suffix<net::const_buffer> cb{
b32b8144
FG
247 boost::in_place_init, msg.data(), msg.size()};
248 auto n = p.put(buffers_prefix(i, cb), ec);
249 if(ec == result)
250 {
251 pass();
252 continue;
253 }
254 if(! BEAST_EXPECTS(
255 ec == error::need_more, ec.message()))
256 continue;
257 if(! BEAST_EXPECT(! p.is_done()))
258 continue;
259 cb.consume(n);
260 n = p.put(cb, ec);
261 if(! ec)
262 p.put_eof(ec);
263 BEAST_EXPECTS(ec == result, ec.message());
264 }
265 for(std::size_t i = 1; i < msg.size() - 1; ++i)
266 {
267 Parser p;
268 p.eager(true);
269 error_code ec;
270 p.put(buffers_cat(
92f5a8d4
TL
271 net::const_buffer{msg.data(), i},
272 net::const_buffer{
b32b8144
FG
273 msg.data() + i, msg.size() - i}), ec);
274 if(! ec)
275 p.put_eof(ec);
276 BEAST_EXPECTS(ec == result, ec.message());
277 }
278 }
279
280 //--------------------------------------------------------------------------
281
282 void
283 testFlatten()
284 {
285 parsegrind<test_parser<true>>(
286 "GET / HTTP/1.1\r\n"
287 "\r\n"
288 );
289 parsegrind<test_parser<true>>(
290 "POST / HTTP/1.1\r\n"
291 "Content-Length: 5\r\n"
292 "\r\n"
293 "*****"
294 );
295 parsegrind<test_parser<false>>(
296 "HTTP/1.1 403 Not Found\r\n"
297 "\r\n"
298 );
299 parsegrind<test_parser<false>>(
300 "HTTP/1.1 200 OK\r\n"
301 "Content-Length: 5\r\n"
302 "\r\n"
303 "*****"
304 );
305 parsegrind<test_parser<false>>(
306 "HTTP/1.1 200 OK\r\n"
307 "Transfer-Encoding: chunked\r\n"
308 "\r\n"
309 "5;x\r\n*****\r\n"
310 "0\r\nMD5: 0xff30\r\n"
311 "\r\n"
312 );
313 parsegrind<test_parser<false>>(
314 "HTTP/1.1 200 OK\r\n"
315 "\r\n"
316 "*****"
317 );
318 }
319
320 void
321 testObsFold()
322 {
323 auto const check =
324 [&](std::string const& s, string_view value)
325 {
326 std::string m =
327 "GET / HTTP/1.1\r\n"
328 "f: " + s + "\r\n"
329 "\r\n";
330 parsegrind<request_parser<string_body>>(m,
331 [&](request_parser<string_body> const& p)
332 {
333 BEAST_EXPECT(p.get()["f"] == value);
334 });
335 };
336 check("x", "x");
337 check(" x", "x");
338 check("\tx", "x");
339 check(" \tx", "x");
340 check("\t x", "x");
341 check("x ", "x");
342 check(" x\t", "x");
343 check("\tx \t", "x");
344 check(" \tx\t ", "x");
345 check("\t x \t ", "x");
346 check("\r\n x", "x");
347 check(" \r\n x", "x");
348 check(" \r\n\tx", "x");
349 check(" \r\n\t x", "x");
350 check(" \r\n \tx", "x");
351 check(" \r\n \r\n \r\n x \t", "x");
352 check("xy", "xy");
353 check("\r\n x", "x");
354 check("\r\n x", "x");
355 check("\r\n xy", "xy");
356 check("\r\n \r\n \r\n x", "x");
357 check("\r\n \r\n \r\n xy", "xy");
358 check("x\r\n y", "x y");
359 check("x\r\n y\r\n z ", "x y z");
360 }
361
362 // Check that all callbacks are invoked
363 void
364 testCallbacks()
365 {
366 parsegrind<test_parser<true>>(
367 "GET / HTTP/1.1\r\n"
368 "User-Agent: test\r\n"
369 "Content-Length: 1\r\n"
370 "\r\n"
371 "*",
372 [&](test_parser<true> const& p)
373 {
374 BEAST_EXPECT(p.got_on_begin == 1);
375 BEAST_EXPECT(p.got_on_field == 2);
376 BEAST_EXPECT(p.got_on_header == 1);
377 BEAST_EXPECT(p.got_on_body == 1);
378 BEAST_EXPECT(p.got_on_chunk == 0);
379 BEAST_EXPECT(p.got_on_complete == 1);
380 });
381 parsegrind<test_parser<false>>(
382 "HTTP/1.1 200 OK\r\n"
383 "Server: test\r\n"
384 "Content-Length: 1\r\n"
385 "\r\n"
386 "*",
387 [&](test_parser<false> const& p)
388 {
389 BEAST_EXPECT(p.got_on_begin == 1);
390 BEAST_EXPECT(p.got_on_field == 2);
391 BEAST_EXPECT(p.got_on_header == 1);
392 BEAST_EXPECT(p.got_on_body == 1);
393 BEAST_EXPECT(p.got_on_chunk == 0);
394 BEAST_EXPECT(p.got_on_complete == 1);
395 });
396 parsegrind<test_parser<false>>(
397 "HTTP/1.1 200 OK\r\n"
398 "Server: test\r\n"
399 "Transfer-Encoding: chunked\r\n"
400 "\r\n"
401 "1\r\n*\r\n"
402 "0\r\n\r\n",
403 [&](test_parser<false> const& p)
404 {
405 BEAST_EXPECT(p.got_on_begin == 1);
406 BEAST_EXPECT(p.got_on_field == 2);
407 BEAST_EXPECT(p.got_on_header == 1);
408 BEAST_EXPECT(p.got_on_body == 1);
409 BEAST_EXPECT(p.got_on_chunk == 2);
410 BEAST_EXPECT(p.got_on_complete == 1);
411 });
412 parsegrind<test_parser<false>>(
413 "HTTP/1.1 200 OK\r\n"
414 "Server: test\r\n"
415 "Transfer-Encoding: chunked\r\n"
416 "\r\n"
417 "1;x\r\n*\r\n"
418 "0\r\n\r\n",
419 [&](test_parser<false> const& p)
420 {
421 BEAST_EXPECT(p.got_on_begin == 1);
422 BEAST_EXPECT(p.got_on_field == 2);
423 BEAST_EXPECT(p.got_on_header == 1);
424 BEAST_EXPECT(p.got_on_body == 1);
425 BEAST_EXPECT(p.got_on_chunk == 2);
426 BEAST_EXPECT(p.got_on_complete == 1);
427 });
428 }
429
430 void
431 testRequestLine()
432 {
433 using P = test_parser<true>;
434
435 parsegrind<P>("GET /x HTTP/1.0\r\n\r\n");
436 parsegrind<P>("!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz / HTTP/1.0\r\n\r\n");
437 parsegrind<P>("GET / HTTP/1.0\r\n\r\n", expect_version{*this, 10});
438 parsegrind<P>("G / HTTP/1.1\r\n\r\n", expect_version{*this, 11});
439 // VFALCO TODO various forms of good request-target (uri)
440
441 failgrind<P>("\tGET / HTTP/1.0\r\n" "\r\n", error::bad_method);
442 failgrind<P>("GET\x01 / HTTP/1.0\r\n" "\r\n", error::bad_method);
443 failgrind<P>("GET / 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 failgrind<P>("GET /\x01 HTTP/1.0\r\n" "\r\n", error::bad_target);
446 // VFALCO TODO various forms of bad request-target (uri)
447 failgrind<P>("GET / HTTP/1.0\r\n" "\r\n", error::bad_version);
448 failgrind<P>("GET / _TTP/1.0\r\n" "\r\n", error::bad_version);
449 failgrind<P>("GET / H_TP/1.0\r\n" "\r\n", error::bad_version);
450 failgrind<P>("GET / HT_P/1.0\r\n" "\r\n", error::bad_version);
451 failgrind<P>("GET / HTT_/1.0\r\n" "\r\n", error::bad_version);
452 failgrind<P>("GET / HTTP_1.0\r\n" "\r\n", error::bad_version);
453 failgrind<P>("GET / HTTP/01.2\r\n" "\r\n", error::bad_version);
454 failgrind<P>("GET / HTTP/3.45\r\n" "\r\n", error::bad_version);
455 failgrind<P>("GET / HTTP/67.89\r\n" "\r\n", error::bad_version);
456 failgrind<P>("GET / HTTP/x.0\r\n" "\r\n", error::bad_version);
457 failgrind<P>("GET / HTTP/1.x\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\r\n" "\r\n", error::bad_version);
460 failgrind<P>("GET / HTTP/1.0\n\r\n" "\r\n", error::bad_version);
461 failgrind<P>("GET / HTTP/1.0\n\r\r\n" "\r\n", error::bad_version);
462 failgrind<P>("GET / HTTP/1.0\r\r\n" "\r\n", error::bad_version);
463 }
464
465 void
466 testStatusLine()
467 {
468 using P = test_parser<false>;
469
470 parsegrind<P>("HTTP/1.0 000 OK\r\n" "\r\n", expect_status{*this, 0});
471 parsegrind<P>("HTTP/1.1 012 OK\r\n" "\r\n", expect_status{*this, 12});
472 parsegrind<P>("HTTP/1.0 345 OK\r\n" "\r\n", expect_status{*this, 345});
473 parsegrind<P>("HTTP/1.0 678 OK\r\n" "\r\n", expect_status{*this, 678});
474 parsegrind<P>("HTTP/1.0 999 OK\r\n" "\r\n", expect_status{*this, 999});
475 parsegrind<P>("HTTP/1.0 200 \tX\r\n" "\r\n", expect_version{*this, 10});
476 parsegrind<P>("HTTP/1.1 200 X\r\n" "\r\n", expect_version{*this, 11});
477 parsegrind<P>("HTTP/1.0 200 \r\n" "\r\n");
478 parsegrind<P>("HTTP/1.1 200 X \r\n" "\r\n");
479 parsegrind<P>("HTTP/1.1 200 X\t\r\n" "\r\n");
480 parsegrind<P>("HTTP/1.1 200 \x80\x81...\xfe\xff\r\n\r\n");
481 parsegrind<P>("HTTP/1.1 200 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\r\n\r\n");
482
483 failgrind<P>("\rHTTP/1.0 200 OK\r\n" "\r\n", error::bad_version);
484 failgrind<P>("\nHTTP/1.0 200 OK\r\n" "\r\n", error::bad_version);
485 failgrind<P>(" HTTP/1.0 200 OK\r\n" "\r\n", error::bad_version);
486 failgrind<P>("_TTP/1.0 200 OK\r\n" "\r\n", error::bad_version);
487 failgrind<P>("H_TP/1.0 200 OK\r\n" "\r\n", error::bad_version);
488 failgrind<P>("HT_P/1.0 200 OK\r\n" "\r\n", error::bad_version);
489 failgrind<P>("HTT_/1.0 200 OK\r\n" "\r\n", error::bad_version);
490 failgrind<P>("HTTP_1.0 200 OK\r\n" "\r\n", error::bad_version);
491 failgrind<P>("HTTP/01.2 200 OK\r\n" "\r\n", error::bad_version);
492 failgrind<P>("HTTP/3.45 200 OK\r\n" "\r\n", error::bad_version);
493 failgrind<P>("HTTP/67.89 200 OK\r\n" "\r\n", error::bad_version);
494 failgrind<P>("HTTP/x.0 200 OK\r\n" "\r\n", error::bad_version);
495 failgrind<P>("HTTP/1.x 200 OK\r\n" "\r\n", error::bad_version);
496 failgrind<P>("HTTP/1_0 200 OK\r\n" "\r\n", error::bad_version);
497 failgrind<P>("HTTP/1.0 200 OK\r\n" "\r\n", error::bad_status);
498 failgrind<P>("HTTP/1.0 0 OK\r\n" "\r\n", error::bad_status);
499 failgrind<P>("HTTP/1.0 12 OK\r\n" "\r\n", error::bad_status);
500 failgrind<P>("HTTP/1.0 3456 OK\r\n" "\r\n", error::bad_status);
501 failgrind<P>("HTTP/1.0 200\r\n" "\r\n", error::bad_status);
502 failgrind<P>("HTTP/1.0 200 \n\r\n" "\r\n", error::bad_reason);
503 failgrind<P>("HTTP/1.0 200 \x01\r\n" "\r\n", error::bad_reason);
504 failgrind<P>("HTTP/1.0 200 \x7f\r\n" "\r\n", error::bad_reason);
505 failgrind<P>("HTTP/1.0 200 OK\n\r\n" "\r\n", error::bad_reason);
506 failgrind<P>("HTTP/1.0 200 OK\r\r\n" "\r\n", error::bad_line_ending);
507 }
508
509 void
510 testFields()
511 {
512 auto const m =
513 [](std::string const& s)
514 {
515 return "GET / HTTP/1.1\r\n" + s + "\r\n";
516 };
517
518 using P = test_parser<true>;
519
520 parsegrind<P>(m("f:\r\n"));
521 parsegrind<P>(m("f: \r\n"));
522 parsegrind<P>(m("f:\t\r\n"));
523 parsegrind<P>(m("f: \t\r\n"));
524 parsegrind<P>(m("f: v\r\n"));
525 parsegrind<P>(m("f:\tv\r\n"));
526 parsegrind<P>(m("f:\tv \r\n"));
527 parsegrind<P>(m("f:\tv\t\r\n"));
528 parsegrind<P>(m("f:\tv\t \r\n"));
529 parsegrind<P>(m("f:\r\n \r\n"));
530 parsegrind<P>(m("f:v\r\n"));
531 parsegrind<P>(m("f: v\r\n u\r\n"));
532 parsegrind<P>(m("!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz: v\r\n"));
533 parsegrind<P>(m("f: !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x80\x81...\xfe\xff\r\n"));
534
535 failgrind<P>(m(" f: v\r\n"), error::bad_field);
536 failgrind<P>(m("\tf: v\r\n"), error::bad_field);
537 failgrind<P>(m("f : v\r\n"), error::bad_field);
538 failgrind<P>(m("f\t: v\r\n"), error::bad_field);
539 failgrind<P>(m("f: \n\r\n"), error::bad_value);
540 failgrind<P>(m("f: v\r \r\n"), error::bad_line_ending);
541 failgrind<P>(m("f: \r v\r\n"), error::bad_line_ending);
542 failgrind<P>(
543 "GET / HTTP/1.1\r\n"
544 "\r \n\r\n"
545 "\r\n", error::bad_line_ending);
546 }
547
548 void
549 testConnectionField()
550 {
551 auto const m = [](std::string const& s)
552 { return "GET / HTTP/1.1\r\n" + s + "\r\n"; };
553 auto const cn = [](std::string const& s)
554 { return "GET / HTTP/1.1\r\nConnection: " + s + "\r\n"; };
555 #if 0
556 auto const keepalive = [&](bool v)
557 { //return keepalive_f{*this, v}; return true; };
558 #endif
559
560 using P = test_parser<true>;
561
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(" close\r\n"), expect_flags{*this, parse_flag::connection_close});
565 parsegrind<P>(cn("\tclose\r\n"), expect_flags{*this, parse_flag::connection_close});
566 parsegrind<P>(cn("close,\r\n"), expect_flags{*this, parse_flag::connection_close});
567 parsegrind<P>(cn("close\t\r\n"), expect_flags{*this, parse_flag::connection_close});
568 parsegrind<P>(cn("close\r\n"), expect_flags{*this, parse_flag::connection_close});
569 parsegrind<P>(cn(" ,\t,,close,, ,\t,,\r\n"), expect_flags{*this, parse_flag::connection_close});
570 parsegrind<P>(cn("\r\n close\r\n"), expect_flags{*this, parse_flag::connection_close});
571 parsegrind<P>(cn("close\r\n \r\n"), expect_flags{*this, parse_flag::connection_close});
572 parsegrind<P>(cn("any,close\r\n"), expect_flags{*this, parse_flag::connection_close});
573 parsegrind<P>(cn("close,any\r\n"), expect_flags{*this, parse_flag::connection_close});
574 parsegrind<P>(cn("any\r\n ,close\r\n"), expect_flags{*this, parse_flag::connection_close});
575 parsegrind<P>(cn("close\r\n ,any\r\n"), expect_flags{*this, parse_flag::connection_close});
576 parsegrind<P>(cn("close,close\r\n"), expect_flags{*this, parse_flag::connection_close}); // weird but allowed
577
578 parsegrind<P>(cn("keep-alive\r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
579 parsegrind<P>(cn("keep-alive \r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
580 parsegrind<P>(cn("keep-alive\t \r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
581 parsegrind<P>(cn("keep-alive\t ,x\r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
582 parsegrind<P>(cn("\r\n keep-alive \t\r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
583 parsegrind<P>(cn("keep-alive \r\n \t \r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
584 parsegrind<P>(cn("keep-alive\r\n \r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
585
586 parsegrind<P>(cn("upgrade\r\n"), expect_flags{*this, parse_flag::connection_upgrade});
587 parsegrind<P>(cn("upgrade \r\n"), expect_flags{*this, parse_flag::connection_upgrade});
588 parsegrind<P>(cn("upgrade\t \r\n"), expect_flags{*this, parse_flag::connection_upgrade});
589 parsegrind<P>(cn("upgrade\t ,x\r\n"), expect_flags{*this, parse_flag::connection_upgrade});
590 parsegrind<P>(cn("\r\n upgrade \t\r\n"), expect_flags{*this, parse_flag::connection_upgrade});
591 parsegrind<P>(cn("upgrade \r\n \t \r\n"), expect_flags{*this, parse_flag::connection_upgrade});
592 parsegrind<P>(cn("upgrade\r\n \r\n"), expect_flags{*this, parse_flag::connection_upgrade});
593
594 // VFALCO What's up with these?
595 //parsegrind<P>(cn("close,keep-alive\r\n"), expect_flags{*this, parse_flag::connection_close | parse_flag::connection_keep_alive});
596 parsegrind<P>(cn("upgrade,keep-alive\r\n"), expect_flags{*this, parse_flag::connection_upgrade | parse_flag::connection_keep_alive});
597 parsegrind<P>(cn("upgrade,\r\n keep-alive\r\n"), expect_flags{*this, parse_flag::connection_upgrade | parse_flag::connection_keep_alive});
598 //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
600 parsegrind<P>("GET / HTTP/1.1\r\n\r\n", expect_keepalive(*this, true));
601 parsegrind<P>("GET / HTTP/1.0\r\n\r\n", expect_keepalive(*this, false));
602 parsegrind<P>("GET / HTTP/1.0\r\n"
603 "Connection: keep-alive\r\n\r\n", expect_keepalive(*this, true));
604 parsegrind<P>("GET / HTTP/1.1\r\n"
605 "Connection: close\r\n\r\n", expect_keepalive(*this, false));
606
607 parsegrind<P>(cn("x\r\n"), expect_flags{*this, 0});
608 parsegrind<P>(cn("x,y\r\n"), expect_flags{*this, 0});
609 parsegrind<P>(cn("x ,y\r\n"), expect_flags{*this, 0});
610 parsegrind<P>(cn("x\t,y\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(" keep\r\n"), expect_flags{*this, 0});
614 parsegrind<P>(cn("\tnone\r\n"), expect_flags{*this, 0});
615 parsegrind<P>(cn("keep,\r\n"), expect_flags{*this, 0});
616 parsegrind<P>(cn("keep\t\r\n"), expect_flags{*this, 0});
617 parsegrind<P>(cn("keep\r\n"), expect_flags{*this, 0});
618 parsegrind<P>(cn(" ,\t,,keep,, ,\t,,\r\n"), expect_flags{*this, 0});
619 parsegrind<P>(cn("\r\n keep\r\n"), expect_flags{*this, 0});
620 parsegrind<P>(cn("keep\r\n \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(" closet\r\n"), expect_flags{*this, 0});
624 parsegrind<P>(cn("\tcloset\r\n"), expect_flags{*this, 0});
625 parsegrind<P>(cn("closet,\r\n"), expect_flags{*this, 0});
626 parsegrind<P>(cn("closet\t\r\n"), expect_flags{*this, 0});
627 parsegrind<P>(cn("closet\r\n"), expect_flags{*this, 0});
628 parsegrind<P>(cn(" ,\t,,closet,, ,\t,,\r\n"), expect_flags{*this, 0});
629 parsegrind<P>(cn("\r\n closet\r\n"), expect_flags{*this, 0});
630 parsegrind<P>(cn("closet\r\n \r\n"), expect_flags{*this, 0});
631 parsegrind<P>(cn("clog\r\n"), expect_flags{*this, 0});
632 parsegrind<P>(cn("key\r\n"), expect_flags{*this, 0});
633 parsegrind<P>(cn("uptown\r\n"), expect_flags{*this, 0});
634 parsegrind<P>(cn("keeper\r\n \r\n"), expect_flags{*this, 0});
635 parsegrind<P>(cn("keep-alively\r\n \r\n"), expect_flags{*this, 0});
636 parsegrind<P>(cn("up\r\n \r\n"), expect_flags{*this, 0});
637 parsegrind<P>(cn("upgrader\r\n \r\n"), expect_flags{*this, 0});
638 parsegrind<P>(cn("none\r\n"), expect_flags{*this, 0});
639 parsegrind<P>(cn("\r\n none\r\n"), expect_flags{*this, 0});
640
641 parsegrind<P>(m("ConnectioX: close\r\n"), expect_flags{*this, 0});
642 parsegrind<P>(m("Condor: close\r\n"), expect_flags{*this, 0});
643 parsegrind<P>(m("Connect: close\r\n"), expect_flags{*this, 0});
644 parsegrind<P>(m("Connections: close\r\n"), expect_flags{*this, 0});
645
646 parsegrind<P>(m("Proxy-Connection: close\r\n"), expect_flags{*this, parse_flag::connection_close});
647 parsegrind<P>(m("Proxy-Connection: keep-alive\r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
648 parsegrind<P>(m("Proxy-Connection: upgrade\r\n"), expect_flags{*this, parse_flag::connection_upgrade});
649 parsegrind<P>(m("Proxy-ConnectioX: none\r\n"), expect_flags{*this, 0});
650 parsegrind<P>(m("Proxy-Connections: 1\r\n"), expect_flags{*this, 0});
651 parsegrind<P>(m("Proxy-Connotes: see-also\r\n"), expect_flags{*this, 0});
652
653 failgrind<P>(cn("[\r\n"), error::bad_value);
654 failgrind<P>(cn("close[\r\n"), error::bad_value);
655 failgrind<P>(cn("close [\r\n"), error::bad_value);
656 failgrind<P>(cn("close, upgrade [\r\n"), error::bad_value);
657 failgrind<P>(cn("upgrade[]\r\n"), error::bad_value);
658 failgrind<P>(cn("keep\r\n -alive\r\n"), error::bad_value);
659 failgrind<P>(cn("keep-alive[\r\n"), error::bad_value);
660 failgrind<P>(cn("keep-alive []\r\n"), error::bad_value);
661 failgrind<P>(cn("no[ne]\r\n"), error::bad_value);
662 }
663
664 void
665 testContentLengthField()
666 {
667 using P = test_parser<true>;
668 auto const c = [](std::string const& s)
669 { return "GET / HTTP/1.1\r\nContent-Length: " + s + "\r\n"; };
670 auto const m = [](std::string const& s)
671 { return "GET / HTTP/1.1\r\n" + s + "\r\n"; };
672 auto const check =
673 [&](std::string const& s, std::uint64_t v)
674 {
675 parsegrind<P>(c(s),
676 [&](P const& p)
677 {
678 BEAST_EXPECT(p.content_length());
679 BEAST_EXPECT(p.content_length() && *p.content_length() == v);
680 }, true);
681 };
682
683 check("0\r\n", 0);
684 check("00\r\n", 0);
685 check("1\r\n", 1);
686 check("01\r\n", 1);
687 check("9\r\n", 9);
688 check("42 \r\n", 42);
689 check("42\t\r\n", 42);
690 check("42 \t \r\n", 42);
691 check("42\r\n \t \r\n", 42);
692
693 parsegrind<P>(m("Content-LengtX: 0\r\n"), expect_flags{*this, 0});
694 parsegrind<P>(m("Content-Lengths: many\r\n"), expect_flags{*this, 0});
695 parsegrind<P>(m("Content: full\r\n"), expect_flags{*this, 0});
f67539c2
TL
696 parsegrind<P>(m("Content-Length: 0\r\n"
697 "Content-Length: 0\r\n"), expect_flags{*this, 0});
b32b8144
FG
698
699 failgrind<P>(c("\r\n"), error::bad_content_length);
700 failgrind<P>(c("18446744073709551616\r\n"), error::bad_content_length);
701 failgrind<P>(c("0 0\r\n"), error::bad_content_length);
702 failgrind<P>(c("0 1\r\n"), error::bad_content_length);
703 failgrind<P>(c(",\r\n"), error::bad_content_length);
704 failgrind<P>(c("0,\r\n"), error::bad_content_length);
f67539c2
TL
705 failgrind<P>(m("Content-Length: 0\r\n"
706 "Content-Length: 100\r\n"), error::bad_content_length);
b32b8144
FG
707 }
708
709 void
710 testTransferEncodingField()
711 {
712 auto const m = [](std::string const& s)
713 { return "GET / HTTP/1.1\r\n" + s + "\r\n"; };
714 auto const ce = [](std::string const& s)
715 { return "GET / HTTP/1.1\r\nTransfer-Encoding: " + s + "\r\n0\r\n\r\n"; };
716 auto const te = [](std::string const& s)
717 { return "GET / HTTP/1.1\r\nTransfer-Encoding: " + s + "\r\n"; };
718
719 using P = test_parser<true>;
720
721 parsegrind<P>(ce("chunked\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("chunked\t\r\n"), expect_flags{*this, parse_flag::chunked});
724 parsegrind<P>(ce("chunked \t\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("\tchunked\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"), expect_flags{*this, parse_flag::chunked});
731 parsegrind<P>(ce(", chunked\r\n"), expect_flags{*this, parse_flag::chunked});
732 parsegrind<P>(ce(" ,chunked\r\n"), expect_flags{*this, parse_flag::chunked});
733 parsegrind<P>(ce("chunked\r\n \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(",\r\n chunked\r\n"), expect_flags{*this, parse_flag::chunked});
736 parsegrind<P>(ce("\r\n ,chunked\r\n"), expect_flags{*this, parse_flag::chunked});
737 parsegrind<P>(ce(",\r\n chunked\r\n"), expect_flags{*this, parse_flag::chunked});
738 parsegrind<P>(ce("gzip, chunked\r\n"), expect_flags{*this, parse_flag::chunked});
739 parsegrind<P>(ce("gzip, chunked \r\n"), expect_flags{*this, parse_flag::chunked});
740 parsegrind<P>(ce("gzip, \r\n chunked\r\n"), expect_flags{*this, parse_flag::chunked});
741
742 // Technically invalid but beyond the parser's scope to detect
743 // VFALCO Look into this
744 //parsegrind<P>(ce("custom;key=\",chunked\r\n"), expect_flags{*this, parse_flag::chunked});
745
746 parsegrind<P>(te("gzip\r\n"), expect_flags{*this, 0});
747 parsegrind<P>(te("chunked, gzip\r\n"), expect_flags{*this, 0});
748 parsegrind<P>(te("chunked\r\n , gzip\r\n"), expect_flags{*this, 0});
749 parsegrind<P>(te("chunked,\r\n gzip\r\n"), expect_flags{*this, 0});
750 parsegrind<P>(te("chunked,\r\n ,gzip\r\n"), expect_flags{*this, 0});
751 parsegrind<P>(te("bigchunked\r\n"), expect_flags{*this, 0});
752 parsegrind<P>(te("chunk\r\n ked\r\n"), expect_flags{*this, 0});
753 parsegrind<P>(te("bar\r\n ley chunked\r\n"), expect_flags{*this, 0});
754 parsegrind<P>(te("barley\r\n chunked\r\n"), expect_flags{*this, 0});
755
756 parsegrind<P>(m("Transfer-EncodinX: none\r\n"), expect_flags{*this, 0});
757 parsegrind<P>(m("Transfer-Encodings: 2\r\n"), expect_flags{*this, 0});
758 parsegrind<P>(m("Transfer-Encoded: false\r\n"), expect_flags{*this, 0});
759
760 failgrind<test_parser<false>>(
761 "HTTP/1.1 200 OK\r\n"
762 "Content-Length: 1\r\n"
763 "Transfer-Encoding: chunked\r\n"
764 "\r\n", error::bad_transfer_encoding);
765 }
766
767 void
768 testUpgradeField()
769 {
770 auto const m = [](std::string const& s)
771 { return "GET / HTTP/1.1\r\n" + s + "\r\n"; };
772
773 using P = test_parser<true>;
774
775 parsegrind<P>(m("Upgrade:\r\n"), expect_flags{*this, parse_flag::upgrade});
776 parsegrind<P>(m("Upgrade: \r\n"), expect_flags{*this, parse_flag::upgrade});
777 parsegrind<P>(m("Upgrade: yes\r\n"), expect_flags{*this, parse_flag::upgrade});
778
779 parsegrind<P>(m("Up: yes\r\n"), expect_flags{*this, 0});
780 parsegrind<P>(m("UpgradX: none\r\n"), expect_flags{*this, 0});
781 parsegrind<P>(m("Upgrades: 2\r\n"), expect_flags{*this, 0});
782 parsegrind<P>(m("Upsample: 4x\r\n"), expect_flags{*this, 0});
783
784 parsegrind<P>(
785 "GET / HTTP/1.1\r\n"
786 "Connection: upgrade\r\n"
787 "Upgrade: WebSocket\r\n"
788 "\r\n",
789 [&](P const& p)
790 {
791 BEAST_EXPECT(p.upgrade());
792 });
793 }
794
795 void
796 testPartial()
797 {
798 // Make sure the slow-loris defense works and that
799 // we don't get duplicate or missing fields on a split.
800 parsegrind<test_parser<true>>(
801 "GET / HTTP/1.1\r\n"
802 "a: 0\r\n"
803 "b: 1\r\n"
804 "c: 2\r\n"
805 "d: 3\r\n"
806 "e: 4\r\n"
807 "f: 5\r\n"
808 "g: 6\r\n"
809 "h: 7\r\n"
810 "i: 8\r\n"
811 "j: 9\r\n"
812 "\r\n",
813 [&](test_parser<true> const& p)
814 {
815 BEAST_EXPECT(p.fields.size() == 10);
816 BEAST_EXPECT(p.fields.at("a") == "0");
817 BEAST_EXPECT(p.fields.at("b") == "1");
818 BEAST_EXPECT(p.fields.at("c") == "2");
819 BEAST_EXPECT(p.fields.at("d") == "3");
820 BEAST_EXPECT(p.fields.at("e") == "4");
821 BEAST_EXPECT(p.fields.at("f") == "5");
822 BEAST_EXPECT(p.fields.at("g") == "6");
823 BEAST_EXPECT(p.fields.at("h") == "7");
824 BEAST_EXPECT(p.fields.at("i") == "8");
825 BEAST_EXPECT(p.fields.at("j") == "9");
826 });
827 }
828
829 void
830 testLimits()
831 {
832 {
833 multi_buffer b;
92f5a8d4 834 ostream(b) <<
b32b8144
FG
835 "POST / HTTP/1.1\r\n"
836 "Content-Length: 2\r\n"
837 "\r\n"
838 "**";
839 error_code ec;
840 test_parser<true> p;
841 p.header_limit(10);
842 p.eager(true);
843 p.put(b.data(), ec);
844 BEAST_EXPECTS(ec == error::header_limit, ec.message());
845 }
846 {
847 multi_buffer b;
92f5a8d4 848 ostream(b) <<
b32b8144
FG
849 "POST / HTTP/1.1\r\n"
850 "Content-Length: 2\r\n"
851 "\r\n"
852 "**";
853 error_code ec;
854 test_parser<true> p;
855 p.body_limit(1);
856 p.eager(true);
857 p.put(b.data(), ec);
858 BEAST_EXPECTS(ec == error::body_limit, ec.message());
859 }
860 {
861 multi_buffer b;
92f5a8d4 862 ostream(b) <<
b32b8144
FG
863 "HTTP/1.1 200 OK\r\n"
864 "\r\n"
865 "**";
866 error_code ec;
867 test_parser<false> p;
868 p.body_limit(1);
869 p.eager(true);
870 p.put(b.data(), ec);
871 BEAST_EXPECTS(ec == error::body_limit, ec.message());
872 }
873 {
874 multi_buffer b;
92f5a8d4 875 ostream(b) <<
b32b8144
FG
876 "POST / HTTP/1.1\r\n"
877 "Transfer-Encoding: chunked\r\n"
878 "\r\n"
879 "2\r\n"
880 "**\r\n"
881 "0\r\n\r\n";
882 error_code ec;
883 test_parser<true> p;
884 p.body_limit(1);
885 p.eager(true);
886 p.put(b.data(), ec);
887 BEAST_EXPECTS(ec == error::body_limit, ec.message());
888 }
889 }
890
891 //--------------------------------------------------------------------------
892
893 static
92f5a8d4 894 net::const_buffer
b32b8144
FG
895 buf(string_view s)
896 {
897 return {s.data(), s.size()};
898 }
899
92f5a8d4 900 template<class ConstBufferSequence, bool isRequest>
b32b8144
FG
901 std::size_t
902 feed(ConstBufferSequence const& buffers,
92f5a8d4 903 basic_parser<isRequest>& p, error_code& ec)
b32b8144
FG
904 {
905 p.eager(true);
906 return p.put(buffers, ec);
907 }
908
909 void
910 testBody()
911 {
912 parsegrind<test_parser<false>>(
913 "HTTP/1.1 200 OK\r\n"
914 "Transfer-Encoding: chunked\r\n"
915 "Content-Type: application/octet-stream\r\n"
916 "\r\n"
917 "4\r\nabcd\r\n"
918 "0\r\n\r\n"
919 ,[&](test_parser<false> const& p)
920 {
921 BEAST_EXPECT(p.body == "abcd");
922 });
923 parsegrind<test_parser<false>>(
924 "HTTP/1.1 200 OK\r\n"
925 "Server: test\r\n"
926 "Expect: Expires, MD5-Fingerprint\r\n"
927 "Transfer-Encoding: chunked\r\n"
928 "\r\n"
929 "5\r\n"
930 "*****\r\n"
931 "2;a;b=1;c=\"2\"\r\n"
932 "--\r\n"
933 "0;d;e=3;f=\"4\"\r\n"
934 "Expires: never\r\n"
935 "MD5-Fingerprint: -\r\n"
936 "\r\n"
937 ,[&](test_parser<false> const& p)
938 {
939 BEAST_EXPECT(p.body == "*****--");
940 });
941
942 parsegrind<test_parser<true>>(
943 "GET / HTTP/1.1\r\n"
944 "Content-Length: 1\r\n"
945 "\r\n"
946 "1",
947 expect_body(*this, "1"));
948
949 parsegrind<test_parser<false>>(
950 "HTTP/1.0 200 OK\r\n"
951 "\r\n"
952 "hello",
953 expect_body(*this, "hello"));
954
955 parsegrind<test_parser<true>>(buffers_cat(
956 buf("GET / HTTP/1.1\r\n"
957 "Content-Length: 10\r\n"
958 "\r\n"),
959 buf("12"),
960 buf("345"),
961 buf("67890")));
962
963 // request without Content-Length or
964 // Transfer-Encoding: chunked has no body.
965 {
966 error_code ec;
967 test_parser<true> p;
968 feed(buf(
969 "GET / HTTP/1.0\r\n"
970 "\r\n"
971 ), p, ec);
972 BEAST_EXPECTS(! ec, ec.message());
973 BEAST_EXPECT(p.is_done());
974 }
975 {
976 error_code ec;
977 test_parser<true> p;
978 feed(buf(
979 "GET / HTTP/1.1\r\n"
980 "\r\n"
981 ), p, ec);
982 BEAST_EXPECTS(! ec, ec.message());
983 BEAST_EXPECT(p.is_done());
984 }
985
986 // response without Content-Length or
987 // Transfer-Encoding: chunked requires eof.
988 {
989 error_code ec;
990 test_parser<false> p;
991 feed(buf(
992 "HTTP/1.0 200 OK\r\n"
993 "\r\n"
994 ), p, ec);
995 BEAST_EXPECTS(! ec, ec.message());
996 BEAST_EXPECT(! p.is_done());
997 BEAST_EXPECT(p.need_eof());
998 }
999
1000 // 304 "Not Modified" response does not require eof
1001 {
1002 error_code ec;
1003 test_parser<false> p;
1004 feed(buf(
1005 "HTTP/1.0 304 Not Modified\r\n"
1006 "\r\n"
1007 ), p, ec);
1008 BEAST_EXPECTS(! ec, ec.message());
1009 BEAST_EXPECT(p.is_done());
1010 }
1011
1012 // Chunked response does not require eof
1013 {
1014 error_code ec;
1015 test_parser<false> p;
1016 feed(buf(
1017 "HTTP/1.1 200 OK\r\n"
1018 "Transfer-Encoding: chunked\r\n"
1019 "\r\n"
1020 ), p, ec);
1021 BEAST_EXPECTS(! ec, ec.message());
1022 BEAST_EXPECT(! p.is_done());
1023 feed(buf(
1024 "0\r\n\r\n"
1025 ), p, ec);
1026 BEAST_EXPECTS(! ec, ec.message());
1027 BEAST_EXPECT(p.is_done());
1028 }
1029
1030 // restart: 1.0 assumes Connection: close
1031 {
1032 error_code ec;
1033 test_parser<true> p;
1034 feed(buf(
1035 "GET / HTTP/1.0\r\n"
1036 "\r\n"
1037 ), p, ec);
1038 BEAST_EXPECTS(! ec, ec.message());
1039 BEAST_EXPECT(p.is_done());
1040 }
1041
1042 // restart: 1.1 assumes Connection: keep-alive
1043 {
1044 error_code ec;
1045 test_parser<true> p;
1046 feed(buf(
1047 "GET / HTTP/1.1\r\n"
1048 "\r\n"
1049 ), p, ec);
1050 BEAST_EXPECTS(! ec, ec.message());
1051 BEAST_EXPECT(p.is_done());
1052 }
1053
1054 failgrind<test_parser<true>>(
1055 "GET / HTTP/1.1\r\n"
1056 "Content-Length: 1\r\n"
1057 "\r\n",
1058 error::partial_message);
1059 }
1060
1061 //--------------------------------------------------------------------------
1062
1063 // https://github.com/boostorg/beast/issues/430
1064 void
1065 testIssue430()
1066 {
1067 parsegrind<test_parser<false>>(
1068 "HTTP/1.1 200 OK\r\n"
1069 "Transfer-Encoding: chunked\r\n"
1070 "Content-Type: application/octet-stream\r\n"
1071 "\r\n"
1072 "4\r\nabcd\r\n"
1073 "0\r\n\r\n");
1074 }
1075
1076 // https://github.com/boostorg/beast/issues/452
1077 void
1078 testIssue452()
1079 {
1080 error_code ec;
1081 test_parser<true> p;
1082 p.eager(true);
1083 string_view s =
1084 "GET / HTTP/1.1\r\n"
1085 "\r\n"
1086 "die!";
92f5a8d4 1087 p.put(net::buffer(
b32b8144
FG
1088 s.data(), s.size()), ec);
1089 if(! BEAST_EXPECTS(! ec, ec.message()))
1090 return;
1091 BEAST_EXPECT(p.is_done());
1092 }
1093
1094 // https://github.com/boostorg/beast/issues/496
1095 void
1096 testIssue496()
1097 {
1098 // The bug affected hex parsing with leading zeroes
1099 using P = test_parser<false>;
1100 parsegrind<P>(
1101 "HTTP/1.1 200 OK\r\n"
1102 "Transfer-Encoding: chunked\r\n"
1103 "Content-Type: application/octet-stream\r\n"
1104 "\r\n"
1105 "0004\r\nabcd\r\n"
1106 "0\r\n\r\n"
1107 ,[&](P const& p)
1108 {
1109 BEAST_EXPECT(p.body == "abcd");
1110 });
1111 }
1112
1113 // https://github.com/boostorg/beast/issues/692
1114 void
1115 testIssue692()
1116 {
1117 error_code ec;
1118 test_parser<false> p;
1119 p.eager(true);
1120 string_view s =
1121 "HTTP/1.1 101 Switching Protocols\r\n"
1122 "Content-Length: 2147483648\r\n"
1123 "\r\n";
92f5a8d4 1124 p.put(net::buffer(
b32b8144
FG
1125 s.data(), s.size()), ec);
1126 if(! BEAST_EXPECTS(! ec, ec.message()))
1127 return;
1128 BEAST_EXPECT(p.is_done());
1129 }
1130
1131 //--------------------------------------------------------------------------
1132
1133 void
1134 testFuzz()
1135 {
1136 auto const grind =
1137 [&](string_view s)
1138 {
1139 static_string<100> ss{s};
1140 test::fuzz_rand r;
1141 test::fuzz(ss, 4, 5, r,
1142 [&](string_view s)
1143 {
1144 error_code ec;
1145 test_parser<false> p;
1146 p.eager(true);
92f5a8d4 1147 p.put(net::const_buffer{
b32b8144
FG
1148 s.data(), s.size()}, ec);
1149 });
1150 };
1151 auto const good =
1152 [&](string_view s)
1153 {
1154 std::string msg =
1155 "HTTP/1.1 200 OK\r\n"
1156 "Transfer-Encoding: chunked\r\n"
1157 "\r\n"
92f5a8d4 1158 "0" + std::string(s) + "\r\n"
b32b8144
FG
1159 "\r\n";
1160 error_code ec;
1161 test_parser<false> p;
1162 p.eager(true);
92f5a8d4 1163 p.put(net::const_buffer{
b32b8144
FG
1164 msg.data(), msg.size()}, ec);
1165 BEAST_EXPECTS(! ec, ec.message());
1166 grind(msg);
1167 };
1168 auto const bad =
1169 [&](string_view s)
1170 {
1171 std::string msg =
1172 "HTTP/1.1 200 OK\r\n"
1173 "Transfer-Encoding: chunked\r\n"
1174 "\r\n"
92f5a8d4 1175 "0" + std::string(s) + "\r\n"
b32b8144
FG
1176 "\r\n";
1177 error_code ec;
1178 test_parser<false> p;
1179 p.eager(true);
92f5a8d4 1180 p.put(net::const_buffer{
b32b8144
FG
1181 msg.data(), msg.size()}, ec);
1182 BEAST_EXPECT(ec);
1183 grind(msg);
1184 };
1185 chunkExtensionsTest(good, bad);
1186 }
1187
1188 //--------------------------------------------------------------------------
1189
1190 void
1191 testRegression1()
1192 {
1193 // crash_00cda0b02d5166bd1039ddb3b12618cd80da75f3
1194 unsigned char buf[] ={
1195 0x4C,0x4F,0x43,0x4B,0x20,0x2F,0x25,0x65,0x37,0x6C,0x59,0x3B,0x2F,0x3B,0x3B,0x25,0x30,0x62,0x38,0x3D,0x70,0x2F,0x72,0x20,
1196 0x48,0x54,0x54,0x50,0x2F,0x31,0x2E,0x31,0x0D,0x0A,0x41,0x63,0x63,0x65,0x70,0x74,0x2D,0x45,0x6E,0x63,0x6F,0x64,0x69,0x6E,
1197 0x67,0x3A,0x0D,0x0A,0x09,0x20,0xEE,0x0D,0x0A,0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x2D,0x4D,0x65,0x73,0x73,0x61,0x67,
1198 0x65,0x2D,0x49,0x44,0x3A,0xEB,0x09,0x09,0x09,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3A,0x20,0x0D,0x0A,0x09,0x20,
1199 0xF7,0x44,0x9B,0xA5,0x06,0x9F,0x0D,0x0A,0x52,0x65,0x73,0x65,0x6E,0x74,0x2D,0x44,0x61,0x74,0x65,0x3A,0xF4,0x0D,0x0A,0x41,
1200 0x6C,0x74,0x2D,0x53,0x76,0x63,0x3A,0x20,0x0D,0x0A,0x54,0x72,0x61,0x69,0x6C,0x65,0x72,0x3A,0x20,0x20,0x09,0x20,0x20,0x20,
1201 0x0D,0x0A,0x4C,0x69,0x73,0x74,0x2D,0x49,0x44,0x3A,0xA6,0x6B,0x86,0x09,0x09,0x20,0x09,0x0D,0x0A,0x41,0x6C,0x74,0x65,0x72,
1202 0x6E,0x61,0x74,0x65,0x2D,0x52,0x65,0x63,0x69,0x70,0x69,0x65,0x6E,0x74,0x3A,0xF3,0x13,0xE3,0x22,0x9D,0xEF,0xFB,0x84,0x71,
1203 0x4A,0xCC,0xBC,0x96,0xF7,0x5B,0x72,0xF1,0xF2,0x0D,0x0A,0x4C,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E,0x3A,0x20,0x0D,0x0A,0x41,
1204 0x63,0x63,0x65,0x70,0x74,0x2D,0x41,0x64,0x64,0x69,0x74,0x69,0x6F,0x6E,0x73,0x3A,0x20,0x0D,0x0A,0x4D,0x4D,0x48,0x53,0x2D,
1205 0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x74,0x6F,0x72,0x2D,0x50,0x4C,0x41,0x44,0x3A,0x20,0x0D,0x0A,0x4F,0x72,0x69,0x67,0x69,
1206 0x6E,0x61,0x6C,0x2D,0x53,0x65,0x6E,0x64,0x65,0x72,0x3A,0x20,0x0D,0x0A,0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x2D,0x53,
1207 0x65,0x6E,0x64,0x65,0x72,0x3A,0x0D,0x0A,0x50,0x49,0x43,0x53,0x2D,0x4C,0x61,0x62,0x65,0x6C,0x3A,0x0D,0x0A,0x20,0x09,0x0D,
1208 0x0A,0x49,0x66,0x3A,0x20,0x40,0xC1,0x50,0x5C,0xD6,0xC3,0x86,0xFC,0x8D,0x5C,0x7C,0x96,0x45,0x0D,0x0A,0x4D,0x4D,0x48,0x53,
1209 0x2D,0x45,0x78,0x65,0x6D,0x70,0x74,0x65,0x64,0x2D,0x41,0x64,0x64,0x72,0x65,0x73,0x73,0x3A,0x0D,0x0A,0x49,0x6E,0x6A,0x65,
1210 0x63,0x74,0x69,0x6F,0x6E,0x2D,0x49,0x6E,0x66,0x6F,0x3A,0x20,0x0D,0x0A,0x43,0x6F,0x6E,0x74,0x65,0x74,0x6E,0x2D,0x4C,0x65,
1211 0x6E,0x67,0x74,0x68,0x3A,0x20,0x30,0x0D,0x0A,0x0D,0x0A
1212 };
1213
1214 error_code ec;
1215 test_parser<true> p;
92f5a8d4 1216 feed(net::buffer(buf, sizeof(buf)), p, ec);
b32b8144
FG
1217 BEAST_EXPECT(ec);
1218 }
1219
92f5a8d4
TL
1220 void
1221 testIssue1211()
1222 {
1223 using base = detail::basic_parser_base;
1224 auto const good =
1225 [&](string_view s, std::uint32_t v0)
1226 {
1227 std::uint64_t v;
1228 auto const result =
1229 base::parse_dec(s, v);
1230 if(BEAST_EXPECTS(result, s))
1231 BEAST_EXPECTS(v == v0, s);
1232 };
1233 auto const bad =
1234 [&](string_view s)
1235 {
1236 std::uint64_t v;
1237 auto const result =
1238 base::parse_dec(s, v);
1239 BEAST_EXPECTS(! result, s);
1240 };
1241 good("0", 0);
1242 good("00", 0);
1243 good("001", 1);
1244 good("255", 255);
1245 good("65535", 65535);
1246 good("65536", 65536);
1247 good("4294967295", 4294967295);
1248 bad ("");
1249 bad (" ");
1250 bad (" 0");
1251 bad ("0 ");
1252 bad ("-1");
1253 bad ("18446744073709551616"); // max(uint64) + 1
1254 }
1255
1256 void
1257 testIssue1267()
1258 {
1259 using base = detail::basic_parser_base;
1260 auto const good =
1261 [&](string_view s, std::uint64_t v0)
1262 {
1263 std::uint64_t v;
1264 auto it = s.data();
1265 auto const result =
1266 base::parse_hex(it, v);
1267 if(BEAST_EXPECTS(result, s))
1268 BEAST_EXPECTS(v == v0, s);
1269 };
1270 auto const bad =
1271 [&](string_view s)
1272 {
1273 std::uint64_t v;
1274 auto it = s.data();
1275 auto const result =
1276 base::parse_hex(it, v);
1277 BEAST_EXPECTS(! result, s);
1278 };
1279 good("f\r\n", 15);
1280 good("ff\r\n", 255);
1281 good("ffff\r\n", 65535);
1282 good("ffffffffr\n", 4294967295);
1283 good("ffffffffffffffff\r\n", 18446744073709551615ULL);
1284 bad ("\r\n");
1285 bad ("g\r\n");
1286 bad ("10000000000000000\r\n");
1287 bad ("ffffffffffffffffffffff\r\n");
1288 }
1289
1290 //--------------------------------------------------------------------------
1291
1292 // https://github.com/boostorg/beast/issues/1734
1293
1294 void
1295 testIssue1734()
1296 {
1297 // Ensure more than one buffer, this is to avoid an optimized path in
1298 // basic_parser::put(ConstBufferSequence const&,...) which avoids
1299 // buffer flattening.
1300 auto multibufs = [](multi_buffer::const_buffers_type buffers) {
1301 std::vector<net::const_buffer> bs;
1302 for (auto b : buffers_range(buffers))
1303 bs.push_back(b);
1304 while (std::distance(bs.begin(), bs.end()) < 2) {
1305 bs.push_back({});
1306 }
1307 return bs;
1308 };
1309
1310 // Buffers must be bigger than max_stack_buffer to force flattening
1311 // in basic_parser::put(ConstBufferSequence const&,...)
1312 std::string first_chunk_data(
1313 2 * basic_parser<false>::max_stack_buffer + 1, 'x');
1314
1315 std::string second_chunk_data_part1(
1316 basic_parser<false>::max_stack_buffer + 2, 'x');
1317 std::string second_chunk_data_part2(
1318 basic_parser<false>::max_stack_buffer + 1, 'x');
1319
1320 multi_buffer b;
1321 parser<false, string_body> p;
1322 p.eager(true);
1323 error_code ec;
1324 std::size_t used;
1325
1326 ostream(b) <<
1327 "HTTP/1.1 200 OK\r\n"
1328 "Server: test\r\n"
1329 "Transfer-Encoding: chunked\r\n"
1330 "\r\n";
1331
1332 used = p.put(b.data(), ec);
1333 b.consume(used);
1334
1335 BEAST_EXPECT(net::buffer_size(b.data()) == 0);
1336 BEAST_EXPECTS(!ec, ec.message());
1337 BEAST_EXPECT(!p.is_done());
1338 BEAST_EXPECT(p.is_header_done());
1339
1340 ostream(b) <<
1341 std::hex <<
1342 first_chunk_data.size() << "\r\n" <<
1343 first_chunk_data << "\r\n";
1344
1345 // First chunk
1346 used = p.put(multibufs(b.data()), ec);
1347 b.consume(used);
1348
1349 BEAST_EXPECTS(ec == error::need_more, ec.message());
1350 BEAST_EXPECT(!p.is_done());
1351
1352 ostream(b) <<
1353 std::hex <<
1354 (second_chunk_data_part1.size() +
1355 second_chunk_data_part2.size() ) << "\r\n" <<
1356 second_chunk_data_part1;
1357
1358 // Second chunk, part 1
1359 used = p.put(multibufs(b.data()), ec);
1360 b.consume(used);
1361
1362 BEAST_EXPECTS(!ec, ec.message());
1363 BEAST_EXPECT(!p.is_done());
1364
1365 ostream(b) <<
1366 second_chunk_data_part2 << "\r\n"
1367 << "0\r\n\r\n";
1368
1369 // Second chunk, part 2
1370 used = p.put(multibufs(b.data()), ec);
1371 b.consume(used);
1372
1373 BEAST_EXPECTS(!ec, ec.message()); // <-- Error: bad chunk
1374 if(p.need_eof())
1375 {
1376 p.put_eof(ec);
1377 BEAST_EXPECTS(! ec, ec.message());
1378 }
1379 BEAST_EXPECT(p.is_done());
1380 }
1381
20effc67
TL
1382 void
1383 testChunkedOverflow()
1384 {
1385 {
1386 const std::string hdr =
1387 "HTTP/1.1 200 OK" "\r\n"
1388 "Server: test" "\r\n"
1389 "Transfer-Encoding: chunked" "\r\n"
1390 "\r\n";
1391 const std::string chunk1 =
1392 "10000000000000000" "\r\n"
1393 "data...";
1394 test_parser<false> p;
1395 error_code ec;
1396 p.put(net::buffer(hdr), ec);
1397 BEAST_EXPECT(!ec);
1398 BEAST_EXPECT(p.is_header_done());
1399 auto bt = p.put(net::buffer(chunk1), ec);
1400 BEAST_EXPECT(bt == 0);
1401 BEAST_EXPECT(ec == error::bad_chunk);
1402 }
1403 {
1404 const std::string hdr =
1405 "HTTP/1.1 200 OK" "\r\n"
1406 "Server: test" "\r\n"
1407 "Transfer-Encoding: chunked" "\r\n"
1408 "\r\n"
1409 "1" "\r\n"
1410 "x" "\r\n";
1411 const std::string chunk2 =
1412 "FFFFFFFFFFFFFFFF" "\r\n"
1413 "data...";
1414 test_parser<false> p;
1415 p.eager(true);
1416 error_code ec;
1417 flat_buffer fb;
1418 fb.commit(net::buffer_copy(fb.prepare(10000), net::buffer(hdr)));
1419 fb.consume(p.put(fb.data(), ec));
1420 BEAST_EXPECT(p.is_header_done());
1421 BEAST_EXPECT(ec = error::need_more);
1422 fb.commit(net::buffer_copy(fb.prepare(10000), net::buffer(chunk2)));
1423 auto bt = p.put(fb.data(), ec);
1424 BEAST_EXPECT(bt == 0);
1425 BEAST_EXPECT(ec == error::body_limit);
1426 }
1427 {
1428 const std::string hdr =
1429 "HTTP/1.1 200 OK" "\r\n"
1430 "Server: test" "\r\n"
1431 "Transfer-Encoding: chunked" "\r\n"
1432 "\r\n"
1433 "1" "\r\n"
1434 "x" "\r\n";
1435 const std::string chunk2 =
1436 "FFFFFFFFFFFFFFFF" "\r\n"
1437 "data...";
1438 test_parser<false> p;
1439 p.eager(true);
1440 p.body_limit(boost::none);
1441 error_code ec;
1442 flat_buffer fb;
1443 fb.commit(net::buffer_copy(fb.prepare(10000), net::buffer(hdr)));
1444 fb.consume(p.put(fb.data(), ec));
1445 BEAST_EXPECT(p.is_header_done());
1446 BEAST_EXPECTS(ec = error::need_more, ec.message());
1447 fb.commit(net::buffer_copy(fb.prepare(10000), net::buffer(chunk2)));
1448 auto bt = p.put(fb.data(), ec);
1449 BEAST_EXPECT(bt == 27);
1450 BEAST_EXPECT(!ec);
1451 }
1452 }
1453
1454 void testChunkedBodySize()
1455 {
1456 string_view resp =
1457 "HTTP/1.1 200 OK\r\n"
1458 "Server: test\r\n"
1459 "Transfer-Encoding: chunked\r\n"
1460 "\r\n"
1461
1462 // chunk 1
1463 "4\r\n"
1464 "Wiki\r\n"
1465
1466 // chunk 2
1467 "5\r\n"
1468 "pedia\r\n"
1469
1470 // chunk 3
1471 "E\r\n"
1472 " in\r\n"
1473 "\r\n"
1474 "chunks.\r\n"
1475
1476 // end
1477 "0\r\n"
1478 "\r\n";
1479
1480 { // body limit not exceeded
1481 test_parser<false> p;
1482 p.eager(true);
1483 p.body_limit(23);
1484 error_code ec;
1485 p.put(net::buffer(resp.data(), resp.size()), ec);
1486 BEAST_EXPECT(!ec);
1487 p.put_eof(ec);
1488 BEAST_EXPECT(!ec);
1489 }
1490
1491 { // body limit exceeded
1492 test_parser<false> p;
1493 p.eager(true);
1494 p.body_limit(22);
1495 error_code ec;
1496 p.put(net::buffer(resp.data(), resp.size()), ec);
1497 BEAST_EXPECT(ec == error::body_limit);
1498 p.put_eof(ec);
1499 BEAST_EXPECT(ec == error::partial_message);
1500 }
1501 }
1502
1503 void
1504 testUnlimitedBody()
1505 {
1506 const char data[] =
1507 "POST / HTTP/1.1\r\n"
1508 "Content-Length: 5\r\n"
1509 "\r\n"
1510 "*****";
1511
1512 test::fail_count fc(1000);
1513 test_parser<true> p(fc);
1514 p.body_limit(none);
1515 error_code ec;
1516 p.put(net::buffer(data, strlen(data)), ec);
1517 BEAST_EXPECTS(!ec, ec.message());
1518 }
1519
1e59de90
TL
1520 void
1521 testIssue2201()
1522 {
1523 const char data[] =
1524 "HTTP/1.1 200 OK\r\n"
1525 "Content-Length: 5\r\n"
1526 "\r\n"
1527 "*****";
1528
1529 test_parser<false> p;
1530 p.eager(true);
1531 p.body_limit(3);
1532 error_code ec;
1533 p.put(net::buffer(data, strlen(data)), ec);
1534 BEAST_EXPECT(ec == error::body_limit);
1535 }
1536
b32b8144
FG
1537 //--------------------------------------------------------------------------
1538
1539 void
1540 run() override
1541 {
1542 testFlatten();
1543 testObsFold();
1544 testCallbacks();
1545 testRequestLine();
1546 testStatusLine();
1547 testFields();
1548 testConnectionField();
1549 testContentLengthField();
1550 testTransferEncodingField();
1551 testUpgradeField();
1552 testPartial();
1553 testLimits();
1554 testBody();
1555 testIssue430();
1556 testIssue452();
1557 testIssue496();
1558 testIssue692();
1559 testFuzz();
1560 testRegression1();
92f5a8d4
TL
1561 testIssue1211();
1562 testIssue1267();
20effc67
TL
1563 testChunkedOverflow();
1564 testChunkedBodySize();
1565 testUnlimitedBody();
1e59de90 1566 testIssue2201();
b32b8144
FG
1567 }
1568};
1569
1570BEAST_DEFINE_TESTSUITE(beast,http,basic_parser);
1571
1572} // http
1573} // beast
1574} // boost