]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/beast/test/beast/http/basic_parser.cpp
update source to Ceph Pacific 16.2.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>
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>
92f5a8d4 25#include <boost/beast/_experimental/unit_test/suite.hpp>
b32b8144
FG
26
27namespace boost {
28namespace beast {
29namespace http {
30
31class basic_parser_test : public beast::unit_test::suite
32{
33public:
34 enum parse_flag
35 {
36 chunked = 1,
37 connection_keep_alive = 2,
38 connection_close = 4,
39 connection_upgrade = 8,
40 upgrade = 16,
41 };
42
43 class expect_version
44 {
45 suite& s_;
46 int version_;
47
48 public:
49 expect_version(suite& s, int version)
50 : s_(s)
51 , version_(version)
52 {
53 }
54
55 template<class Parser>
56 void
57 operator()(Parser const& p) const
58 {
59 s_.BEAST_EXPECT(p.version == version_);
60 }
61 };
62
63 class expect_status
64 {
65 suite& s_;
66 int status_;
67
68 public:
69 expect_status(suite& s, int status)
70 : s_(s)
71 , status_(status)
72 {
73 }
74
75 template<class Parser>
76 void
77 operator()(Parser const& p) const
78 {
79 s_.BEAST_EXPECT(p.status == status_);
80 }
81 };
82
83 class expect_flags
84 {
85 suite& s_;
86 unsigned flags_;
87
88 public:
89 expect_flags(suite& s, unsigned flags)
90 : s_(s)
91 , flags_(flags)
92 {
93 }
94
95 template<class Parser>
96 void
97 operator()(Parser const& p) const
98 {
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());
107 }
108 };
109
110 class expect_keepalive
111 {
112 suite& s_;
113 bool v_;
114
115 public:
116 expect_keepalive(suite& s, bool v)
117 : s_(s)
118 , v_(v)
119 {
120 }
121
122 template<class Parser>
123 void
124 operator()(Parser const& p) const
125 {
126 s_.BEAST_EXPECT(p.keep_alive() == v_);
127 }
128 };
129
130 class expect_body
131 {
132 suite& s_;
133 std::string const& body_;
134
135 public:
136 expect_body(expect_body&&) = default;
137
138 expect_body(suite& s, std::string const& v)
139 : s_(s)
140 , body_(v)
141 {
142 }
143
144 template<class Parser>
145 void
146 operator()(Parser const& p) const
147 {
148 s_.BEAST_EXPECT(p.body == body_);
149 }
150 };
151
152 //--------------------------------------------------------------------------
153
154 template<class Parser, class ConstBufferSequence, class Test>
155 typename std::enable_if<
92f5a8d4 156 net::is_const_buffer_sequence<ConstBufferSequence>::value>::type
b32b8144
FG
157 parsegrind(ConstBufferSequence const& buffers,
158 Test const& test, bool skip = false)
159 {
92f5a8d4 160 auto const size = buffer_bytes(buffers);
b32b8144
FG
161 for(std::size_t i = 1; i < size - 1; ++i)
162 {
163 Parser p;
164 p.eager(true);
165 p.skip(skip);
166 error_code ec;
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()))
171 continue;
172 if(! BEAST_EXPECT(! p.is_done()))
173 continue;
174 cb.consume(n);
175 n = p.put(cb, ec);
176 if(! BEAST_EXPECTS(! ec, ec.message()))
177 continue;
92f5a8d4 178 if(! BEAST_EXPECT(n == buffer_bytes(cb)))
b32b8144
FG
179 continue;
180 if(p.need_eof())
181 {
182 p.put_eof(ec);
183 if(! BEAST_EXPECTS(! ec, ec.message()))
184 continue;
185 }
186 if(! BEAST_EXPECT(p.is_done()))
187 continue;
188 test(p);
189 }
190 for(std::size_t i = 1; i < size - 1; ++i)
191 {
192 Parser p;
193 p.eager(true);
194 error_code ec;
195 buffers_suffix<ConstBufferSequence> cb{buffers};
196 cb.consume(i);
197 auto n = p.put(buffers_cat(
198 buffers_prefix(i, buffers), cb), ec);
199 if(! BEAST_EXPECTS(! ec, ec.message()))
200 continue;
201 if(! BEAST_EXPECT(n == size))
202 continue;
203 if(p.need_eof())
204 {
205 p.put_eof(ec);
206 if(! BEAST_EXPECTS(! ec, ec.message()))
207 continue;
208 }
209 test(p);
210 }
211 }
212
213 template<class Parser, class Test>
214 void
215 parsegrind(string_view msg, Test const& test, bool skip = false)
216 {
92f5a8d4 217 parsegrind<Parser>(net::const_buffer{
b32b8144
FG
218 msg.data(), msg.size()}, test, skip);
219 }
220
221 template<class Parser, class ConstBufferSequence>
222 typename std::enable_if<
92f5a8d4 223 net::is_const_buffer_sequence<ConstBufferSequence>::value>::type
b32b8144
FG
224 parsegrind(ConstBufferSequence const& buffers)
225 {
226 parsegrind<Parser>(buffers, [](Parser const&){});
227 }
228
229 template<class Parser>
230 void
231 parsegrind(string_view msg)
232 {
233 parsegrind<Parser>(msg, [](Parser const&){});
234 }
235
236 template<class Parser>
237 void
238 failgrind(string_view msg, error_code const& result)
239 {
240 for(std::size_t i = 1; i < msg.size() - 1; ++i)
241 {
242 Parser p;
243 p.eager(true);
244 error_code ec;
92f5a8d4 245 buffers_suffix<net::const_buffer> cb{
b32b8144
FG
246 boost::in_place_init, msg.data(), msg.size()};
247 auto n = p.put(buffers_prefix(i, cb), ec);
248 if(ec == result)
249 {
250 pass();
251 continue;
252 }
253 if(! BEAST_EXPECTS(
254 ec == error::need_more, ec.message()))
255 continue;
256 if(! BEAST_EXPECT(! p.is_done()))
257 continue;
258 cb.consume(n);
259 n = p.put(cb, ec);
260 if(! ec)
261 p.put_eof(ec);
262 BEAST_EXPECTS(ec == result, ec.message());
263 }
264 for(std::size_t i = 1; i < msg.size() - 1; ++i)
265 {
266 Parser p;
267 p.eager(true);
268 error_code ec;
269 p.put(buffers_cat(
92f5a8d4
TL
270 net::const_buffer{msg.data(), i},
271 net::const_buffer{
b32b8144
FG
272 msg.data() + i, msg.size() - i}), ec);
273 if(! ec)
274 p.put_eof(ec);
275 BEAST_EXPECTS(ec == result, ec.message());
276 }
277 }
278
279 //--------------------------------------------------------------------------
280
281 void
282 testFlatten()
283 {
284 parsegrind<test_parser<true>>(
285 "GET / HTTP/1.1\r\n"
286 "\r\n"
287 );
288 parsegrind<test_parser<true>>(
289 "POST / HTTP/1.1\r\n"
290 "Content-Length: 5\r\n"
291 "\r\n"
292 "*****"
293 );
294 parsegrind<test_parser<false>>(
295 "HTTP/1.1 403 Not Found\r\n"
296 "\r\n"
297 );
298 parsegrind<test_parser<false>>(
299 "HTTP/1.1 200 OK\r\n"
300 "Content-Length: 5\r\n"
301 "\r\n"
302 "*****"
303 );
304 parsegrind<test_parser<false>>(
305 "HTTP/1.1 200 OK\r\n"
306 "Transfer-Encoding: chunked\r\n"
307 "\r\n"
308 "5;x\r\n*****\r\n"
309 "0\r\nMD5: 0xff30\r\n"
310 "\r\n"
311 );
312 parsegrind<test_parser<false>>(
313 "HTTP/1.1 200 OK\r\n"
314 "\r\n"
315 "*****"
316 );
317 }
318
319 void
320 testObsFold()
321 {
322 auto const check =
323 [&](std::string const& s, string_view value)
324 {
325 std::string m =
326 "GET / HTTP/1.1\r\n"
327 "f: " + s + "\r\n"
328 "\r\n";
329 parsegrind<request_parser<string_body>>(m,
330 [&](request_parser<string_body> const& p)
331 {
332 BEAST_EXPECT(p.get()["f"] == value);
333 });
334 };
335 check("x", "x");
336 check(" x", "x");
337 check("\tx", "x");
338 check(" \tx", "x");
339 check("\t x", "x");
340 check("x ", "x");
341 check(" x\t", "x");
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");
351 check("xy", "xy");
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");
359 }
360
361 // Check that all callbacks are invoked
362 void
363 testCallbacks()
364 {
365 parsegrind<test_parser<true>>(
366 "GET / HTTP/1.1\r\n"
367 "User-Agent: test\r\n"
368 "Content-Length: 1\r\n"
369 "\r\n"
370 "*",
371 [&](test_parser<true> const& p)
372 {
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);
379 });
380 parsegrind<test_parser<false>>(
381 "HTTP/1.1 200 OK\r\n"
382 "Server: test\r\n"
383 "Content-Length: 1\r\n"
384 "\r\n"
385 "*",
386 [&](test_parser<false> const& p)
387 {
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);
394 });
395 parsegrind<test_parser<false>>(
396 "HTTP/1.1 200 OK\r\n"
397 "Server: test\r\n"
398 "Transfer-Encoding: chunked\r\n"
399 "\r\n"
400 "1\r\n*\r\n"
401 "0\r\n\r\n",
402 [&](test_parser<false> const& p)
403 {
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);
410 });
411 parsegrind<test_parser<false>>(
412 "HTTP/1.1 200 OK\r\n"
413 "Server: test\r\n"
414 "Transfer-Encoding: chunked\r\n"
415 "\r\n"
416 "1;x\r\n*\r\n"
417 "0\r\n\r\n",
418 [&](test_parser<false> const& p)
419 {
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);
426 });
427 }
428
429 void
430 testRequestLine()
431 {
432 using P = test_parser<true>;
433
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)
439
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);
462 }
463
464 void
465 testStatusLine()
466 {
467 using P = test_parser<false>;
468
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");
481
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);
506 }
507
508 void
509 testFields()
510 {
511 auto const m =
512 [](std::string const& s)
513 {
514 return "GET / HTTP/1.1\r\n" + s + "\r\n";
515 };
516
517 using P = test_parser<true>;
518
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"));
533
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);
541 failgrind<P>(
542 "GET / HTTP/1.1\r\n"
543 "\r \n\r\n"
544 "\r\n", error::bad_line_ending);
545 }
546
547 void
548 testConnectionField()
549 {
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"; };
554 #if 0
555 auto const keepalive = [&](bool v)
556 { //return keepalive_f{*this, v}; return true; };
557 #endif
558
559 using P = test_parser<true>;
560
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
576
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});
584
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});
592
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});
598
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));
605
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});
639
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});
644
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});
651
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);
661 }
662
663 void
664 testContentLengthField()
665 {
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"; };
671 auto const check =
672 [&](std::string const& s, std::uint64_t v)
673 {
674 parsegrind<P>(c(s),
675 [&](P const& p)
676 {
677 BEAST_EXPECT(p.content_length());
678 BEAST_EXPECT(p.content_length() && *p.content_length() == v);
679 }, true);
680 };
681
682 check("0\r\n", 0);
683 check("00\r\n", 0);
684 check("1\r\n", 1);
685 check("01\r\n", 1);
686 check("9\r\n", 9);
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);
691
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});
f67539c2
TL
695 parsegrind<P>(m("Content-Length: 0\r\n"
696 "Content-Length: 0\r\n"), expect_flags{*this, 0});
b32b8144
FG
697
698 failgrind<P>(c("\r\n"), error::bad_content_length);
699 failgrind<P>(c("18446744073709551616\r\n"), error::bad_content_length);
700 failgrind<P>(c("0 0\r\n"), error::bad_content_length);
701 failgrind<P>(c("0 1\r\n"), error::bad_content_length);
702 failgrind<P>(c(",\r\n"), error::bad_content_length);
703 failgrind<P>(c("0,\r\n"), error::bad_content_length);
f67539c2
TL
704 failgrind<P>(m("Content-Length: 0\r\n"
705 "Content-Length: 100\r\n"), error::bad_content_length);
b32b8144
FG
706 }
707
708 void
709 testTransferEncodingField()
710 {
711 auto const m = [](std::string const& s)
712 { return "GET / HTTP/1.1\r\n" + s + "\r\n"; };
713 auto const ce = [](std::string const& s)
714 { return "GET / HTTP/1.1\r\nTransfer-Encoding: " + s + "\r\n0\r\n\r\n"; };
715 auto const te = [](std::string const& s)
716 { return "GET / HTTP/1.1\r\nTransfer-Encoding: " + s + "\r\n"; };
717
718 using P = test_parser<true>;
719
720 parsegrind<P>(ce("chunked\r\n"), expect_flags{*this, parse_flag::chunked});
721 parsegrind<P>(ce("chunked \r\n"), expect_flags{*this, parse_flag::chunked});
722 parsegrind<P>(ce("chunked\t\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\r\n"), expect_flags{*this, parse_flag::chunked});
725 parsegrind<P>(ce("\tchunked\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"), 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 \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("\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("gzip, 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, \r\n chunked\r\n"), expect_flags{*this, parse_flag::chunked});
740
741 // Technically invalid but beyond the parser's scope to detect
742 // VFALCO Look into this
743 //parsegrind<P>(ce("custom;key=\",chunked\r\n"), expect_flags{*this, parse_flag::chunked});
744
745 parsegrind<P>(te("gzip\r\n"), expect_flags{*this, 0});
746 parsegrind<P>(te("chunked, 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("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("bigchunked\r\n"), expect_flags{*this, 0});
751 parsegrind<P>(te("chunk\r\n ked\r\n"), expect_flags{*this, 0});
752 parsegrind<P>(te("bar\r\n ley chunked\r\n"), expect_flags{*this, 0});
753 parsegrind<P>(te("barley\r\n chunked\r\n"), expect_flags{*this, 0});
754
755 parsegrind<P>(m("Transfer-EncodinX: none\r\n"), expect_flags{*this, 0});
756 parsegrind<P>(m("Transfer-Encodings: 2\r\n"), expect_flags{*this, 0});
757 parsegrind<P>(m("Transfer-Encoded: false\r\n"), expect_flags{*this, 0});
758
759 failgrind<test_parser<false>>(
760 "HTTP/1.1 200 OK\r\n"
761 "Content-Length: 1\r\n"
762 "Transfer-Encoding: chunked\r\n"
763 "\r\n", error::bad_transfer_encoding);
764 }
765
766 void
767 testUpgradeField()
768 {
769 auto const m = [](std::string const& s)
770 { return "GET / HTTP/1.1\r\n" + s + "\r\n"; };
771
772 using P = test_parser<true>;
773
774 parsegrind<P>(m("Upgrade:\r\n"), expect_flags{*this, parse_flag::upgrade});
775 parsegrind<P>(m("Upgrade: \r\n"), expect_flags{*this, parse_flag::upgrade});
776 parsegrind<P>(m("Upgrade: yes\r\n"), expect_flags{*this, parse_flag::upgrade});
777
778 parsegrind<P>(m("Up: yes\r\n"), expect_flags{*this, 0});
779 parsegrind<P>(m("UpgradX: none\r\n"), expect_flags{*this, 0});
780 parsegrind<P>(m("Upgrades: 2\r\n"), expect_flags{*this, 0});
781 parsegrind<P>(m("Upsample: 4x\r\n"), expect_flags{*this, 0});
782
783 parsegrind<P>(
784 "GET / HTTP/1.1\r\n"
785 "Connection: upgrade\r\n"
786 "Upgrade: WebSocket\r\n"
787 "\r\n",
788 [&](P const& p)
789 {
790 BEAST_EXPECT(p.upgrade());
791 });
792 }
793
794 void
795 testPartial()
796 {
797 // Make sure the slow-loris defense works and that
798 // we don't get duplicate or missing fields on a split.
799 parsegrind<test_parser<true>>(
800 "GET / HTTP/1.1\r\n"
801 "a: 0\r\n"
802 "b: 1\r\n"
803 "c: 2\r\n"
804 "d: 3\r\n"
805 "e: 4\r\n"
806 "f: 5\r\n"
807 "g: 6\r\n"
808 "h: 7\r\n"
809 "i: 8\r\n"
810 "j: 9\r\n"
811 "\r\n",
812 [&](test_parser<true> const& p)
813 {
814 BEAST_EXPECT(p.fields.size() == 10);
815 BEAST_EXPECT(p.fields.at("a") == "0");
816 BEAST_EXPECT(p.fields.at("b") == "1");
817 BEAST_EXPECT(p.fields.at("c") == "2");
818 BEAST_EXPECT(p.fields.at("d") == "3");
819 BEAST_EXPECT(p.fields.at("e") == "4");
820 BEAST_EXPECT(p.fields.at("f") == "5");
821 BEAST_EXPECT(p.fields.at("g") == "6");
822 BEAST_EXPECT(p.fields.at("h") == "7");
823 BEAST_EXPECT(p.fields.at("i") == "8");
824 BEAST_EXPECT(p.fields.at("j") == "9");
825 });
826 }
827
828 void
829 testLimits()
830 {
831 {
832 multi_buffer b;
92f5a8d4 833 ostream(b) <<
b32b8144
FG
834 "POST / HTTP/1.1\r\n"
835 "Content-Length: 2\r\n"
836 "\r\n"
837 "**";
838 error_code ec;
839 test_parser<true> p;
840 p.header_limit(10);
841 p.eager(true);
842 p.put(b.data(), ec);
843 BEAST_EXPECTS(ec == error::header_limit, ec.message());
844 }
845 {
846 multi_buffer b;
92f5a8d4 847 ostream(b) <<
b32b8144
FG
848 "POST / HTTP/1.1\r\n"
849 "Content-Length: 2\r\n"
850 "\r\n"
851 "**";
852 error_code ec;
853 test_parser<true> p;
854 p.body_limit(1);
855 p.eager(true);
856 p.put(b.data(), ec);
857 BEAST_EXPECTS(ec == error::body_limit, ec.message());
858 }
859 {
860 multi_buffer b;
92f5a8d4 861 ostream(b) <<
b32b8144
FG
862 "HTTP/1.1 200 OK\r\n"
863 "\r\n"
864 "**";
865 error_code ec;
866 test_parser<false> p;
867 p.body_limit(1);
868 p.eager(true);
869 p.put(b.data(), ec);
870 BEAST_EXPECTS(ec == error::body_limit, ec.message());
871 }
872 {
873 multi_buffer b;
92f5a8d4 874 ostream(b) <<
b32b8144
FG
875 "POST / HTTP/1.1\r\n"
876 "Transfer-Encoding: chunked\r\n"
877 "\r\n"
878 "2\r\n"
879 "**\r\n"
880 "0\r\n\r\n";
881 error_code ec;
882 test_parser<true> p;
883 p.body_limit(1);
884 p.eager(true);
885 p.put(b.data(), ec);
886 BEAST_EXPECTS(ec == error::body_limit, ec.message());
887 }
888 }
889
890 //--------------------------------------------------------------------------
891
892 static
92f5a8d4 893 net::const_buffer
b32b8144
FG
894 buf(string_view s)
895 {
896 return {s.data(), s.size()};
897 }
898
92f5a8d4 899 template<class ConstBufferSequence, bool isRequest>
b32b8144
FG
900 std::size_t
901 feed(ConstBufferSequence const& buffers,
92f5a8d4 902 basic_parser<isRequest>& p, error_code& ec)
b32b8144
FG
903 {
904 p.eager(true);
905 return p.put(buffers, ec);
906 }
907
908 void
909 testBody()
910 {
911 parsegrind<test_parser<false>>(
912 "HTTP/1.1 200 OK\r\n"
913 "Transfer-Encoding: chunked\r\n"
914 "Content-Type: application/octet-stream\r\n"
915 "\r\n"
916 "4\r\nabcd\r\n"
917 "0\r\n\r\n"
918 ,[&](test_parser<false> const& p)
919 {
920 BEAST_EXPECT(p.body == "abcd");
921 });
922 parsegrind<test_parser<false>>(
923 "HTTP/1.1 200 OK\r\n"
924 "Server: test\r\n"
925 "Expect: Expires, MD5-Fingerprint\r\n"
926 "Transfer-Encoding: chunked\r\n"
927 "\r\n"
928 "5\r\n"
929 "*****\r\n"
930 "2;a;b=1;c=\"2\"\r\n"
931 "--\r\n"
932 "0;d;e=3;f=\"4\"\r\n"
933 "Expires: never\r\n"
934 "MD5-Fingerprint: -\r\n"
935 "\r\n"
936 ,[&](test_parser<false> const& p)
937 {
938 BEAST_EXPECT(p.body == "*****--");
939 });
940
941 parsegrind<test_parser<true>>(
942 "GET / HTTP/1.1\r\n"
943 "Content-Length: 1\r\n"
944 "\r\n"
945 "1",
946 expect_body(*this, "1"));
947
948 parsegrind<test_parser<false>>(
949 "HTTP/1.0 200 OK\r\n"
950 "\r\n"
951 "hello",
952 expect_body(*this, "hello"));
953
954 parsegrind<test_parser<true>>(buffers_cat(
955 buf("GET / HTTP/1.1\r\n"
956 "Content-Length: 10\r\n"
957 "\r\n"),
958 buf("12"),
959 buf("345"),
960 buf("67890")));
961
962 // request without Content-Length or
963 // Transfer-Encoding: chunked has no body.
964 {
965 error_code ec;
966 test_parser<true> p;
967 feed(buf(
968 "GET / HTTP/1.0\r\n"
969 "\r\n"
970 ), p, ec);
971 BEAST_EXPECTS(! ec, ec.message());
972 BEAST_EXPECT(p.is_done());
973 }
974 {
975 error_code ec;
976 test_parser<true> p;
977 feed(buf(
978 "GET / HTTP/1.1\r\n"
979 "\r\n"
980 ), p, ec);
981 BEAST_EXPECTS(! ec, ec.message());
982 BEAST_EXPECT(p.is_done());
983 }
984
985 // response without Content-Length or
986 // Transfer-Encoding: chunked requires eof.
987 {
988 error_code ec;
989 test_parser<false> p;
990 feed(buf(
991 "HTTP/1.0 200 OK\r\n"
992 "\r\n"
993 ), p, ec);
994 BEAST_EXPECTS(! ec, ec.message());
995 BEAST_EXPECT(! p.is_done());
996 BEAST_EXPECT(p.need_eof());
997 }
998
999 // 304 "Not Modified" response does not require eof
1000 {
1001 error_code ec;
1002 test_parser<false> p;
1003 feed(buf(
1004 "HTTP/1.0 304 Not Modified\r\n"
1005 "\r\n"
1006 ), p, ec);
1007 BEAST_EXPECTS(! ec, ec.message());
1008 BEAST_EXPECT(p.is_done());
1009 }
1010
1011 // Chunked response does not require eof
1012 {
1013 error_code ec;
1014 test_parser<false> p;
1015 feed(buf(
1016 "HTTP/1.1 200 OK\r\n"
1017 "Transfer-Encoding: chunked\r\n"
1018 "\r\n"
1019 ), p, ec);
1020 BEAST_EXPECTS(! ec, ec.message());
1021 BEAST_EXPECT(! p.is_done());
1022 feed(buf(
1023 "0\r\n\r\n"
1024 ), p, ec);
1025 BEAST_EXPECTS(! ec, ec.message());
1026 BEAST_EXPECT(p.is_done());
1027 }
1028
1029 // restart: 1.0 assumes Connection: close
1030 {
1031 error_code ec;
1032 test_parser<true> p;
1033 feed(buf(
1034 "GET / HTTP/1.0\r\n"
1035 "\r\n"
1036 ), p, ec);
1037 BEAST_EXPECTS(! ec, ec.message());
1038 BEAST_EXPECT(p.is_done());
1039 }
1040
1041 // restart: 1.1 assumes Connection: keep-alive
1042 {
1043 error_code ec;
1044 test_parser<true> p;
1045 feed(buf(
1046 "GET / HTTP/1.1\r\n"
1047 "\r\n"
1048 ), p, ec);
1049 BEAST_EXPECTS(! ec, ec.message());
1050 BEAST_EXPECT(p.is_done());
1051 }
1052
1053 failgrind<test_parser<true>>(
1054 "GET / HTTP/1.1\r\n"
1055 "Content-Length: 1\r\n"
1056 "\r\n",
1057 error::partial_message);
1058 }
1059
1060 //--------------------------------------------------------------------------
1061
1062 // https://github.com/boostorg/beast/issues/430
1063 void
1064 testIssue430()
1065 {
1066 parsegrind<test_parser<false>>(
1067 "HTTP/1.1 200 OK\r\n"
1068 "Transfer-Encoding: chunked\r\n"
1069 "Content-Type: application/octet-stream\r\n"
1070 "\r\n"
1071 "4\r\nabcd\r\n"
1072 "0\r\n\r\n");
1073 }
1074
1075 // https://github.com/boostorg/beast/issues/452
1076 void
1077 testIssue452()
1078 {
1079 error_code ec;
1080 test_parser<true> p;
1081 p.eager(true);
1082 string_view s =
1083 "GET / HTTP/1.1\r\n"
1084 "\r\n"
1085 "die!";
92f5a8d4 1086 p.put(net::buffer(
b32b8144
FG
1087 s.data(), s.size()), ec);
1088 if(! BEAST_EXPECTS(! ec, ec.message()))
1089 return;
1090 BEAST_EXPECT(p.is_done());
1091 }
1092
1093 // https://github.com/boostorg/beast/issues/496
1094 void
1095 testIssue496()
1096 {
1097 // The bug affected hex parsing with leading zeroes
1098 using P = test_parser<false>;
1099 parsegrind<P>(
1100 "HTTP/1.1 200 OK\r\n"
1101 "Transfer-Encoding: chunked\r\n"
1102 "Content-Type: application/octet-stream\r\n"
1103 "\r\n"
1104 "0004\r\nabcd\r\n"
1105 "0\r\n\r\n"
1106 ,[&](P const& p)
1107 {
1108 BEAST_EXPECT(p.body == "abcd");
1109 });
1110 }
1111
1112 // https://github.com/boostorg/beast/issues/692
1113 void
1114 testIssue692()
1115 {
1116 error_code ec;
1117 test_parser<false> p;
1118 p.eager(true);
1119 string_view s =
1120 "HTTP/1.1 101 Switching Protocols\r\n"
1121 "Content-Length: 2147483648\r\n"
1122 "\r\n";
92f5a8d4 1123 p.put(net::buffer(
b32b8144
FG
1124 s.data(), s.size()), ec);
1125 if(! BEAST_EXPECTS(! ec, ec.message()))
1126 return;
1127 BEAST_EXPECT(p.is_done());
1128 }
1129
1130 //--------------------------------------------------------------------------
1131
1132 void
1133 testFuzz()
1134 {
1135 auto const grind =
1136 [&](string_view s)
1137 {
1138 static_string<100> ss{s};
1139 test::fuzz_rand r;
1140 test::fuzz(ss, 4, 5, r,
1141 [&](string_view s)
1142 {
1143 error_code ec;
1144 test_parser<false> p;
1145 p.eager(true);
92f5a8d4 1146 p.put(net::const_buffer{
b32b8144
FG
1147 s.data(), s.size()}, ec);
1148 });
1149 };
1150 auto const good =
1151 [&](string_view s)
1152 {
1153 std::string msg =
1154 "HTTP/1.1 200 OK\r\n"
1155 "Transfer-Encoding: chunked\r\n"
1156 "\r\n"
92f5a8d4 1157 "0" + std::string(s) + "\r\n"
b32b8144
FG
1158 "\r\n";
1159 error_code ec;
1160 test_parser<false> p;
1161 p.eager(true);
92f5a8d4 1162 p.put(net::const_buffer{
b32b8144
FG
1163 msg.data(), msg.size()}, ec);
1164 BEAST_EXPECTS(! ec, ec.message());
1165 grind(msg);
1166 };
1167 auto const bad =
1168 [&](string_view s)
1169 {
1170 std::string msg =
1171 "HTTP/1.1 200 OK\r\n"
1172 "Transfer-Encoding: chunked\r\n"
1173 "\r\n"
92f5a8d4 1174 "0" + std::string(s) + "\r\n"
b32b8144
FG
1175 "\r\n";
1176 error_code ec;
1177 test_parser<false> p;
1178 p.eager(true);
92f5a8d4 1179 p.put(net::const_buffer{
b32b8144
FG
1180 msg.data(), msg.size()}, ec);
1181 BEAST_EXPECT(ec);
1182 grind(msg);
1183 };
1184 chunkExtensionsTest(good, bad);
1185 }
1186
1187 //--------------------------------------------------------------------------
1188
1189 void
1190 testRegression1()
1191 {
1192 // crash_00cda0b02d5166bd1039ddb3b12618cd80da75f3
1193 unsigned char buf[] ={
1194 0x4C,0x4F,0x43,0x4B,0x20,0x2F,0x25,0x65,0x37,0x6C,0x59,0x3B,0x2F,0x3B,0x3B,0x25,0x30,0x62,0x38,0x3D,0x70,0x2F,0x72,0x20,
1195 0x48,0x54,0x54,0x50,0x2F,0x31,0x2E,0x31,0x0D,0x0A,0x41,0x63,0x63,0x65,0x70,0x74,0x2D,0x45,0x6E,0x63,0x6F,0x64,0x69,0x6E,
1196 0x67,0x3A,0x0D,0x0A,0x09,0x20,0xEE,0x0D,0x0A,0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x2D,0x4D,0x65,0x73,0x73,0x61,0x67,
1197 0x65,0x2D,0x49,0x44,0x3A,0xEB,0x09,0x09,0x09,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3A,0x20,0x0D,0x0A,0x09,0x20,
1198 0xF7,0x44,0x9B,0xA5,0x06,0x9F,0x0D,0x0A,0x52,0x65,0x73,0x65,0x6E,0x74,0x2D,0x44,0x61,0x74,0x65,0x3A,0xF4,0x0D,0x0A,0x41,
1199 0x6C,0x74,0x2D,0x53,0x76,0x63,0x3A,0x20,0x0D,0x0A,0x54,0x72,0x61,0x69,0x6C,0x65,0x72,0x3A,0x20,0x20,0x09,0x20,0x20,0x20,
1200 0x0D,0x0A,0x4C,0x69,0x73,0x74,0x2D,0x49,0x44,0x3A,0xA6,0x6B,0x86,0x09,0x09,0x20,0x09,0x0D,0x0A,0x41,0x6C,0x74,0x65,0x72,
1201 0x6E,0x61,0x74,0x65,0x2D,0x52,0x65,0x63,0x69,0x70,0x69,0x65,0x6E,0x74,0x3A,0xF3,0x13,0xE3,0x22,0x9D,0xEF,0xFB,0x84,0x71,
1202 0x4A,0xCC,0xBC,0x96,0xF7,0x5B,0x72,0xF1,0xF2,0x0D,0x0A,0x4C,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E,0x3A,0x20,0x0D,0x0A,0x41,
1203 0x63,0x63,0x65,0x70,0x74,0x2D,0x41,0x64,0x64,0x69,0x74,0x69,0x6F,0x6E,0x73,0x3A,0x20,0x0D,0x0A,0x4D,0x4D,0x48,0x53,0x2D,
1204 0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x74,0x6F,0x72,0x2D,0x50,0x4C,0x41,0x44,0x3A,0x20,0x0D,0x0A,0x4F,0x72,0x69,0x67,0x69,
1205 0x6E,0x61,0x6C,0x2D,0x53,0x65,0x6E,0x64,0x65,0x72,0x3A,0x20,0x0D,0x0A,0x4F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x2D,0x53,
1206 0x65,0x6E,0x64,0x65,0x72,0x3A,0x0D,0x0A,0x50,0x49,0x43,0x53,0x2D,0x4C,0x61,0x62,0x65,0x6C,0x3A,0x0D,0x0A,0x20,0x09,0x0D,
1207 0x0A,0x49,0x66,0x3A,0x20,0x40,0xC1,0x50,0x5C,0xD6,0xC3,0x86,0xFC,0x8D,0x5C,0x7C,0x96,0x45,0x0D,0x0A,0x4D,0x4D,0x48,0x53,
1208 0x2D,0x45,0x78,0x65,0x6D,0x70,0x74,0x65,0x64,0x2D,0x41,0x64,0x64,0x72,0x65,0x73,0x73,0x3A,0x0D,0x0A,0x49,0x6E,0x6A,0x65,
1209 0x63,0x74,0x69,0x6F,0x6E,0x2D,0x49,0x6E,0x66,0x6F,0x3A,0x20,0x0D,0x0A,0x43,0x6F,0x6E,0x74,0x65,0x74,0x6E,0x2D,0x4C,0x65,
1210 0x6E,0x67,0x74,0x68,0x3A,0x20,0x30,0x0D,0x0A,0x0D,0x0A
1211 };
1212
1213 error_code ec;
1214 test_parser<true> p;
92f5a8d4 1215 feed(net::buffer(buf, sizeof(buf)), p, ec);
b32b8144
FG
1216 BEAST_EXPECT(ec);
1217 }
1218
92f5a8d4
TL
1219 void
1220 testIssue1211()
1221 {
1222 using base = detail::basic_parser_base;
1223 auto const good =
1224 [&](string_view s, std::uint32_t v0)
1225 {
1226 std::uint64_t v;
1227 auto const result =
1228 base::parse_dec(s, v);
1229 if(BEAST_EXPECTS(result, s))
1230 BEAST_EXPECTS(v == v0, s);
1231 };
1232 auto const bad =
1233 [&](string_view s)
1234 {
1235 std::uint64_t v;
1236 auto const result =
1237 base::parse_dec(s, v);
1238 BEAST_EXPECTS(! result, s);
1239 };
1240 good("0", 0);
1241 good("00", 0);
1242 good("001", 1);
1243 good("255", 255);
1244 good("65535", 65535);
1245 good("65536", 65536);
1246 good("4294967295", 4294967295);
1247 bad ("");
1248 bad (" ");
1249 bad (" 0");
1250 bad ("0 ");
1251 bad ("-1");
1252 bad ("18446744073709551616"); // max(uint64) + 1
1253 }
1254
1255 void
1256 testIssue1267()
1257 {
1258 using base = detail::basic_parser_base;
1259 auto const good =
1260 [&](string_view s, std::uint64_t v0)
1261 {
1262 std::uint64_t v;
1263 auto it = s.data();
1264 auto const result =
1265 base::parse_hex(it, v);
1266 if(BEAST_EXPECTS(result, s))
1267 BEAST_EXPECTS(v == v0, s);
1268 };
1269 auto const bad =
1270 [&](string_view s)
1271 {
1272 std::uint64_t v;
1273 auto it = s.data();
1274 auto const result =
1275 base::parse_hex(it, v);
1276 BEAST_EXPECTS(! result, s);
1277 };
1278 good("f\r\n", 15);
1279 good("ff\r\n", 255);
1280 good("ffff\r\n", 65535);
1281 good("ffffffffr\n", 4294967295);
1282 good("ffffffffffffffff\r\n", 18446744073709551615ULL);
1283 bad ("\r\n");
1284 bad ("g\r\n");
1285 bad ("10000000000000000\r\n");
1286 bad ("ffffffffffffffffffffff\r\n");
1287 }
1288
1289 //--------------------------------------------------------------------------
1290
1291 // https://github.com/boostorg/beast/issues/1734
1292
1293 void
1294 testIssue1734()
1295 {
1296 // Ensure more than one buffer, this is to avoid an optimized path in
1297 // basic_parser::put(ConstBufferSequence const&,...) which avoids
1298 // buffer flattening.
1299 auto multibufs = [](multi_buffer::const_buffers_type buffers) {
1300 std::vector<net::const_buffer> bs;
1301 for (auto b : buffers_range(buffers))
1302 bs.push_back(b);
1303 while (std::distance(bs.begin(), bs.end()) < 2) {
1304 bs.push_back({});
1305 }
1306 return bs;
1307 };
1308
1309 // Buffers must be bigger than max_stack_buffer to force flattening
1310 // in basic_parser::put(ConstBufferSequence const&,...)
1311 std::string first_chunk_data(
1312 2 * basic_parser<false>::max_stack_buffer + 1, 'x');
1313
1314 std::string second_chunk_data_part1(
1315 basic_parser<false>::max_stack_buffer + 2, 'x');
1316 std::string second_chunk_data_part2(
1317 basic_parser<false>::max_stack_buffer + 1, 'x');
1318
1319 multi_buffer b;
1320 parser<false, string_body> p;
1321 p.eager(true);
1322 error_code ec;
1323 std::size_t used;
1324
1325 ostream(b) <<
1326 "HTTP/1.1 200 OK\r\n"
1327 "Server: test\r\n"
1328 "Transfer-Encoding: chunked\r\n"
1329 "\r\n";
1330
1331 used = p.put(b.data(), ec);
1332 b.consume(used);
1333
1334 BEAST_EXPECT(net::buffer_size(b.data()) == 0);
1335 BEAST_EXPECTS(!ec, ec.message());
1336 BEAST_EXPECT(!p.is_done());
1337 BEAST_EXPECT(p.is_header_done());
1338
1339 ostream(b) <<
1340 std::hex <<
1341 first_chunk_data.size() << "\r\n" <<
1342 first_chunk_data << "\r\n";
1343
1344 // First chunk
1345 used = p.put(multibufs(b.data()), ec);
1346 b.consume(used);
1347
1348 BEAST_EXPECTS(ec == error::need_more, ec.message());
1349 BEAST_EXPECT(!p.is_done());
1350
1351 ostream(b) <<
1352 std::hex <<
1353 (second_chunk_data_part1.size() +
1354 second_chunk_data_part2.size() ) << "\r\n" <<
1355 second_chunk_data_part1;
1356
1357 // Second chunk, part 1
1358 used = p.put(multibufs(b.data()), ec);
1359 b.consume(used);
1360
1361 BEAST_EXPECTS(!ec, ec.message());
1362 BEAST_EXPECT(!p.is_done());
1363
1364 ostream(b) <<
1365 second_chunk_data_part2 << "\r\n"
1366 << "0\r\n\r\n";
1367
1368 // Second chunk, part 2
1369 used = p.put(multibufs(b.data()), ec);
1370 b.consume(used);
1371
1372 BEAST_EXPECTS(!ec, ec.message()); // <-- Error: bad chunk
1373 if(p.need_eof())
1374 {
1375 p.put_eof(ec);
1376 BEAST_EXPECTS(! ec, ec.message());
1377 }
1378 BEAST_EXPECT(p.is_done());
1379 }
1380
b32b8144
FG
1381 //--------------------------------------------------------------------------
1382
1383 void
1384 run() override
1385 {
1386 testFlatten();
1387 testObsFold();
1388 testCallbacks();
1389 testRequestLine();
1390 testStatusLine();
1391 testFields();
1392 testConnectionField();
1393 testContentLengthField();
1394 testTransferEncodingField();
1395 testUpgradeField();
1396 testPartial();
1397 testLimits();
1398 testBody();
1399 testIssue430();
1400 testIssue452();
1401 testIssue496();
1402 testIssue692();
1403 testFuzz();
1404 testRegression1();
92f5a8d4
TL
1405 testIssue1211();
1406 testIssue1267();
b32b8144
FG
1407 }
1408};
1409
1410BEAST_DEFINE_TESTSUITE(beast,http,basic_parser);
1411
1412} // http
1413} // beast
1414} // boost