]> git.proxmox.com Git - ceph.git/blame - ceph/src/Beast/test/http/basic_parser.cpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / Beast / test / http / basic_parser.cpp
CommitLineData
7c673cae
FG
1//
2// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7
8// Test that header file is self-contained.
9#include <beast/http/basic_parser.hpp>
10
11#include "test_parser.hpp"
12
13#include <beast/core/buffer_cat.hpp>
14#include <beast/core/consuming_buffers.hpp>
15#include <beast/core/streambuf.hpp>
16#include <beast/unit_test/suite.hpp>
17
18namespace beast {
19namespace http {
20
21class basic_parser_test : public beast::unit_test::suite
22{
23public:
24 enum parse_flag
25 {
26 chunked = 1,
27 connection_keep_alive = 2,
28 connection_close = 4,
29 connection_upgrade = 8,
30 upgrade = 16,
31 };
32
33 class expect_version
34 {
35 suite& s_;
36 int version_;
37
38 public:
39 expect_version(suite& s, int version)
40 : s_(s)
41 , version_(version)
42 {
43 }
44
45 template<class Parser>
46 void
47 operator()(Parser const& p) const
48 {
49 s_.BEAST_EXPECT(p.version == version_);
50 }
51 };
52
53 class expect_status
54 {
55 suite& s_;
56 int status_;
57
58 public:
59 expect_status(suite& s, int status)
60 : s_(s)
61 , status_(status)
62 {
63 }
64
65 template<class Parser>
66 void
67 operator()(Parser const& p) const
68 {
69 s_.BEAST_EXPECT(p.status == status_);
70 }
71 };
72
73 class expect_flags
74 {
75 suite& s_;
76 unsigned flags_;
77
78 public:
79 expect_flags(suite& s, unsigned flags)
80 : s_(s)
81 , flags_(flags)
82 {
83 }
84
85 template<class Parser>
86 void
87 operator()(Parser const& p) const
88 {
89 if(flags_ & parse_flag::chunked)
90 s_.BEAST_EXPECT(p.is_chunked());
91 if(flags_ & parse_flag::connection_keep_alive)
92 s_.BEAST_EXPECT(p.is_keep_alive());
93 if(flags_ & parse_flag::connection_close)
94 s_.BEAST_EXPECT(! p.is_keep_alive());
95 if(flags_ & parse_flag::upgrade)
96 s_.BEAST_EXPECT(! p.is_upgrade());
97 }
98 };
99
100 class expect_keepalive
101 {
102 suite& s_;
103 bool v_;
104
105 public:
106 expect_keepalive(suite& s, bool v)
107 : s_(s)
108 , v_(v)
109 {
110 }
111
112 template<class Parser>
113 void
114 operator()(Parser const& p) const
115 {
116 s_.BEAST_EXPECT(p.is_keep_alive() == v_);
117 }
118 };
119
120 class expect_body
121 {
122 suite& s_;
123 std::string const& body_;
124
125 public:
126 expect_body(expect_body&&) = default;
127
128 expect_body(suite& s, std::string const& v)
129 : s_(s)
130 , body_(v)
131 {
132 }
133
134 template<class Parser>
135 void
136 operator()(Parser const& p) const
137 {
138 s_.BEAST_EXPECT(p.body == body_);
139 }
140 };
141
142 template<std::size_t N>
143 static
144 boost::asio::const_buffers_1
145 buf(char const (&s)[N])
146 {
147 return {s, N-1};
148 }
149
150 template<
151 bool isRequest, bool isDirect, class Derived>
152 static
153 std::size_t
154 feed(boost::asio::const_buffer buffer,
155 basic_parser<isRequest, isDirect, Derived>& parser,
156 error_code& ec)
157 {
158 using boost::asio::const_buffers_1;
159 std::size_t used = 0;
160 for(;;)
161 {
162 auto const n = parser.write(
163 const_buffers_1{buffer}, ec);
164 if(ec)
165 return 0;
166 if(n == 0)
167 break;
168 buffer = buffer + n;
169 used += n;
170 if(parser.is_complete())
171 break;
172 if(buffer_size(buffer) == 0)
173 break;
174 }
175 return used;
176 }
177
178 template<class ConstBufferSequence,
179 bool isRequest, bool isDirect, class Derived>
180 static
181 std::size_t
182 feed(ConstBufferSequence const& buffers,
183 basic_parser<isRequest, isDirect, Derived>& parser,
184 error_code& ec)
185 {
186 using boost::asio::buffer_size;
187 consuming_buffers<
188 ConstBufferSequence> cb{buffers};
189 std::size_t used = 0;
190 for(;;)
191 {
192 auto const n =
193 parser.write(cb, ec);
194 if(ec)
195 return 0;
196 if(n == 0)
197 break;
198 cb.consume(n);
199 used += n;
200 if(parser.is_complete())
201 break;
202 if(buffer_size(cb) == 0)
203 break;
204 }
205 return used;
206 }
207
208 template<
209 bool isRequest, bool isDirect, class Derived>
210 static
211 std::size_t
212 feed(boost::asio::const_buffers_1 buffers,
213 basic_parser<isRequest, isDirect, Derived>& parser,
214 error_code& ec)
215 {
216 return feed(*buffers.begin(), parser, ec);
217 }
218
219 template<bool isRequest, class Pred>
220 void
221 good(boost::string_ref const& s,
222 Pred const& pred, bool skipBody = false)
223 {
224 using boost::asio::buffer;
225 test_parser<isRequest> p;
226 if(skipBody)
227 p.skip_body();
228 error_code ec;
229 auto const n = feed(buffer(
230 s.data(), s.size()), p, ec);
231 if(! BEAST_EXPECTS(! ec, ec.message()))
232 return;
233 if(! BEAST_EXPECT(n == s.size()))
234 return;
235 if(p.state() == parse_state::body_to_eof)
236 p.write_eof(ec);
237 if(BEAST_EXPECTS(! ec, ec.message()))
238 pred(p);
239 }
240
241 template<bool isRequest>
242 void
243 good(boost::string_ref const& s)
244 {
245 good<isRequest>(s,
246 [](test_parser<isRequest> const&)
247 {
248 });
249 }
250
251 template<bool isRequest>
252 void
253 bad(boost::string_ref const& s,
254 error_code const& ev, bool skipBody = false)
255 {
256 using boost::asio::buffer;
257 test_parser<isRequest> p;
258 if(skipBody)
259 p.skip_body();
260 error_code ec;
261 feed(buffer(
262 s.data(), s.size()), p, ec);
263 if(! ec && ev)
264 p.write_eof(ec);
265 BEAST_EXPECTS(ec == ev, ec.message());
266 }
267
268 void
269 testFlatten()
270 {
271 using boost::asio::buffer;
272 {
273 std::string const s =
274 "GET / HTTP/1.1\r\n"
275 "Content-Length: 1\r\n"
276 "\r\n"
277 "*";
278 for(std::size_t i = 1;
279 i < s.size() - 1; ++i)
280 {
281 auto const b1 =
282 buffer(s.data(), i);
283 auto const b2 = buffer(
284 s.data() + i, s.size() - i);
285 test_parser<true> p;
286 error_code ec;
287 feed(b1, p, ec);
288 BEAST_EXPECTS(! ec, ec.message());
289 feed(buffer_cat(b1, b2), p, ec);
290 BEAST_EXPECTS(! ec, ec.message());
291 BEAST_EXPECT(p.is_complete());
292 }
293 }
294 {
295 std::string const s =
296 "HTTP/1.1 200 OK\r\n"
297 "\r\n";
298 for(std::size_t i = 1;
299 i < s.size() - 1; ++i)
300 {
301 auto const b1 =
302 buffer(s.data(), i);
303 auto const b2 = buffer(
304 s.data() + i, s.size() - i);
305 test_parser<false> p;
306 error_code ec;
307 feed(b1, p, ec);
308 BEAST_EXPECTS(! ec, ec.message());
309 ec = {};
310 feed(buffer_cat(b1, b2), p, ec);
311 BEAST_EXPECTS(! ec, ec.message());
312 p.write_eof(ec);
313 }
314 }
315 }
316
317 // Check that all callbacks are invoked
318 void
319 testCallbacks()
320 {
321 using boost::asio::buffer;
322 {
323 test_parser<true> p;
324 error_code ec;
325 std::string const s =
326 "GET / HTTP/1.1\r\n"
327 "User-Agent: test\r\n"
328 "Content-Length: 1\r\n"
329 "\r\n"
330 "*";
331 feed(buffer(s), p, ec);
332 BEAST_EXPECTS(! ec, ec.message());
333 BEAST_EXPECT(p.is_complete());
334 BEAST_EXPECT(p.got_on_begin);
335 BEAST_EXPECT(p.got_on_field);
336 BEAST_EXPECT(p.got_on_header);
337 BEAST_EXPECT(p.got_on_body);
338 BEAST_EXPECT(! p.got_on_chunk);
339 BEAST_EXPECT(p.got_on_complete);
340 }
341 {
342 test_parser<false> p;
343 error_code ec;
344 std::string const s =
345 "HTTP/1.1 200 OK\r\n"
346 "Server: test\r\n"
347 "Content-Length: 1\r\n"
348 "\r\n"
349 "*";
350 feed(buffer(s), p, ec);
351 BEAST_EXPECTS(! ec, ec.message());
352 BEAST_EXPECT(p.is_complete());
353 BEAST_EXPECT(p.got_on_begin);
354 BEAST_EXPECT(p.got_on_field);
355 BEAST_EXPECT(p.got_on_header);
356 BEAST_EXPECT(p.got_on_body);
357 BEAST_EXPECT(! p.got_on_chunk);
358 BEAST_EXPECT(p.got_on_complete);
359 }
360 }
361
362 void
363 testRequestLine()
364 {
365 good<true>("GET /x HTTP/1.0\r\n\r\n");
366 good<true>("!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz / HTTP/1.0\r\n\r\n");
367 good<true>("GET / HTTP/1.0\r\n\r\n", expect_version{*this, 10});
368 good<true>("G / HTTP/1.1\r\n\r\n", expect_version{*this, 11});
369 // VFALCO TODO various forms of good request-target (uri)
370 good<true>("GET / HTTP/0.1\r\n\r\n", expect_version{*this, 1});
371 good<true>("GET / HTTP/2.3\r\n\r\n", expect_version{*this, 23});
372 good<true>("GET / HTTP/4.5\r\n\r\n", expect_version{*this, 45});
373 good<true>("GET / HTTP/6.7\r\n\r\n", expect_version{*this, 67});
374 good<true>("GET / HTTP/8.9\r\n\r\n", expect_version{*this, 89});
375
376 bad<true>("\tGET / HTTP/1.0\r\n" "\r\n", error::bad_method);
377 bad<true>("GET\x01 / HTTP/1.0\r\n" "\r\n", error::bad_method);
378 bad<true>("GET / HTTP/1.0\r\n" "\r\n", error::bad_path);
379 bad<true>("GET \x01 HTTP/1.0\r\n" "\r\n", error::bad_path);
380 bad<true>("GET /\x01 HTTP/1.0\r\n" "\r\n", error::bad_path);
381 // VFALCO TODO various forms of bad request-target (uri)
382 bad<true>("GET / HTTP/1.0\r\n" "\r\n", error::bad_version);
383 bad<true>("GET / _TTP/1.0\r\n" "\r\n", error::bad_version);
384 bad<true>("GET / H_TP/1.0\r\n" "\r\n", error::bad_version);
385 bad<true>("GET / HT_P/1.0\r\n" "\r\n", error::bad_version);
386 bad<true>("GET / HTT_/1.0\r\n" "\r\n", error::bad_version);
387 bad<true>("GET / HTTP_1.0\r\n" "\r\n", error::bad_version);
388 bad<true>("GET / HTTP/01.2\r\n" "\r\n", error::bad_version);
389 bad<true>("GET / HTTP/3.45\r\n" "\r\n", error::bad_version);
390 bad<true>("GET / HTTP/67.89\r\n" "\r\n", error::bad_version);
391 bad<true>("GET / HTTP/x.0\r\n" "\r\n", error::bad_version);
392 bad<true>("GET / HTTP/1.x\r\n" "\r\n", error::bad_version);
393 bad<true>("GET / HTTP/1.0 \r\n" "\r\n", error::bad_version);
394 bad<true>("GET / HTTP/1_0\r\n" "\r\n", error::bad_version);
395 bad<true>("GET / HTTP/1.0\n\r\n" "\r\n", error::bad_version);
396 bad<true>("GET / HTTP/1.0\n\r\r\n" "\r\n", error::bad_line_ending);
397 bad<true>("GET / HTTP/1.0\r\r\n" "\r\n", error::bad_line_ending);
398 }
399
400 void
401 testStatusLine()
402 {
403 good<false>("HTTP/0.1 200 OK\r\n" "\r\n", expect_version{*this, 1});
404 good<false>("HTTP/2.3 200 OK\r\n" "\r\n", expect_version{*this, 23});
405 good<false>("HTTP/4.5 200 OK\r\n" "\r\n", expect_version{*this, 45});
406 good<false>("HTTP/6.7 200 OK\r\n" "\r\n", expect_version{*this, 67});
407 good<false>("HTTP/8.9 200 OK\r\n" "\r\n", expect_version{*this, 89});
408 good<false>("HTTP/1.0 000 OK\r\n" "\r\n", expect_status{*this, 0});
409 good<false>("HTTP/1.1 012 OK\r\n" "\r\n", expect_status{*this, 12});
410 good<false>("HTTP/1.0 345 OK\r\n" "\r\n", expect_status{*this, 345});
411 good<false>("HTTP/1.0 678 OK\r\n" "\r\n", expect_status{*this, 678});
412 good<false>("HTTP/1.0 999 OK\r\n" "\r\n", expect_status{*this, 999});
413 good<false>("HTTP/1.0 200 \tX\r\n" "\r\n", expect_version{*this, 10});
414 good<false>("HTTP/1.1 200 X\r\n" "\r\n", expect_version{*this, 11});
415 good<false>("HTTP/1.0 200 \r\n" "\r\n");
416 good<false>("HTTP/1.1 200 X \r\n" "\r\n");
417 good<false>("HTTP/1.1 200 X\t\r\n" "\r\n");
418 good<false>("HTTP/1.1 200 \x80\x81...\xfe\xff\r\n\r\n");
419 good<false>("HTTP/1.1 200 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\r\n\r\n");
420
421 bad<false>("\rHTTP/1.0 200 OK\r\n" "\r\n", error::bad_line_ending);
422 bad<false>("\nHTTP/1.0 200 OK\r\n" "\r\n", error::bad_version);
423 bad<false>(" HTTP/1.0 200 OK\r\n" "\r\n", error::bad_version);
424 bad<false>("_TTP/1.0 200 OK\r\n" "\r\n", error::bad_version);
425 bad<false>("H_TP/1.0 200 OK\r\n" "\r\n", error::bad_version);
426 bad<false>("HT_P/1.0 200 OK\r\n" "\r\n", error::bad_version);
427 bad<false>("HTT_/1.0 200 OK\r\n" "\r\n", error::bad_version);
428 bad<false>("HTTP_1.0 200 OK\r\n" "\r\n", error::bad_version);
429 bad<false>("HTTP/01.2 200 OK\r\n" "\r\n", error::bad_version);
430 bad<false>("HTTP/3.45 200 OK\r\n" "\r\n", error::bad_version);
431 bad<false>("HTTP/67.89 200 OK\r\n" "\r\n", error::bad_version);
432 bad<false>("HTTP/x.0 200 OK\r\n" "\r\n", error::bad_version);
433 bad<false>("HTTP/1.x 200 OK\r\n" "\r\n", error::bad_version);
434 bad<false>("HTTP/1_0 200 OK\r\n" "\r\n", error::bad_version);
435 bad<false>("HTTP/1.0 200 OK\r\n" "\r\n", error::bad_status);
436 bad<false>("HTTP/1.0 0 OK\r\n" "\r\n", error::bad_status);
437 bad<false>("HTTP/1.0 12 OK\r\n" "\r\n", error::bad_status);
438 bad<false>("HTTP/1.0 3456 OK\r\n" "\r\n", error::bad_status);
439 bad<false>("HTTP/1.0 200\r\n" "\r\n", error::bad_status);
440 bad<false>("HTTP/1.0 200 \n\r\n" "\r\n", error::bad_reason);
441 bad<false>("HTTP/1.0 200 \x01\r\n" "\r\n", error::bad_reason);
442 bad<false>("HTTP/1.0 200 \x7f\r\n" "\r\n", error::bad_reason);
443 bad<false>("HTTP/1.0 200 OK\n\r\n" "\r\n", error::bad_reason);
444 bad<false>("HTTP/1.0 200 OK\r\r\n" "\r\n", error::bad_line_ending);
445 }
446
447 void
448 testFields()
449 {
450 auto const m =
451 [](std::string const& s)
452 {
453 return "GET / HTTP/1.1\r\n" + s + "\r\n";
454 };
455 good<true>(m("f:\r\n"));
456 good<true>(m("f: \r\n"));
457 good<true>(m("f:\t\r\n"));
458 good<true>(m("f: \t\r\n"));
459 good<true>(m("f: v\r\n"));
460 good<true>(m("f:\tv\r\n"));
461 good<true>(m("f:\tv \r\n"));
462 good<true>(m("f:\tv\t\r\n"));
463 good<true>(m("f:\tv\t \r\n"));
464 good<true>(m("f:\r\n \r\n"));
465 good<true>(m("f:v\r\n"));
466 good<true>(m("f: v\r\n u\r\n"));
467 good<true>(m("!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz: v\r\n"));
468 good<true>(m("f: !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x80\x81...\xfe\xff\r\n"));
469
470 bad<true>(m(" f: v\r\n"), error::bad_field);
471 bad<true>(m("\tf: v\r\n"), error::bad_field);
472 bad<true>(m("f : v\r\n"), error::bad_field);
473 bad<true>(m("f\t: v\r\n"), error::bad_field);
474 bad<true>(m("f: \n\r\n"), error::bad_value);
475 bad<true>(m("f: v\r \r\n"), error::bad_line_ending);
476 bad<true>(m("f: \r v\r\n"), error::bad_line_ending);
477 bad<true>("GET / HTTP/1.1\r\n\r \n\r\n\r\n",error::bad_line_ending);
478 }
479
480 void
481 testConnectionField()
482 {
483 auto const m =
484 [](std::string const& s)
485 {
486 return "GET / HTTP/1.1\r\n" + s + "\r\n";
487 };
488 auto const cn =
489 [](std::string const& s)
490 {
491 return "GET / HTTP/1.1\r\nConnection: " + s + "\r\n";
492 };
493 #if 0
494 auto const keepalive =
495 [&](bool v)
496 {
497 //return keepalive_f{*this, v};
498 return true;
499 };
500 #endif
501
502 good<true>(cn("close\r\n"), expect_flags{*this, parse_flag::connection_close});
503 good<true>(cn(",close\r\n"), expect_flags{*this, parse_flag::connection_close});
504 good<true>(cn(" close\r\n"), expect_flags{*this, parse_flag::connection_close});
505 good<true>(cn("\tclose\r\n"), expect_flags{*this, parse_flag::connection_close});
506 good<true>(cn("close,\r\n"), expect_flags{*this, parse_flag::connection_close});
507 good<true>(cn("close\t\r\n"), expect_flags{*this, parse_flag::connection_close});
508 good<true>(cn("close\r\n"), expect_flags{*this, parse_flag::connection_close});
509 good<true>(cn(" ,\t,,close,, ,\t,,\r\n"), expect_flags{*this, parse_flag::connection_close});
510 good<true>(cn("\r\n close\r\n"), expect_flags{*this, parse_flag::connection_close});
511 good<true>(cn("close\r\n \r\n"), expect_flags{*this, parse_flag::connection_close});
512 good<true>(cn("any,close\r\n"), expect_flags{*this, parse_flag::connection_close});
513 good<true>(cn("close,any\r\n"), expect_flags{*this, parse_flag::connection_close});
514 good<true>(cn("any\r\n ,close\r\n"), expect_flags{*this, parse_flag::connection_close});
515 good<true>(cn("close\r\n ,any\r\n"), expect_flags{*this, parse_flag::connection_close});
516 good<true>(cn("close,close\r\n"), expect_flags{*this, parse_flag::connection_close}); // weird but allowed
517
518 good<true>(cn("keep-alive\r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
519 good<true>(cn("keep-alive \r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
520 good<true>(cn("keep-alive\t \r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
521 good<true>(cn("keep-alive\t ,x\r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
522 good<true>(cn("\r\n keep-alive \t\r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
523 good<true>(cn("keep-alive \r\n \t \r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
524 good<true>(cn("keep-alive\r\n \r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
525
526 good<true>(cn("upgrade\r\n"), expect_flags{*this, parse_flag::connection_upgrade});
527 good<true>(cn("upgrade \r\n"), expect_flags{*this, parse_flag::connection_upgrade});
528 good<true>(cn("upgrade\t \r\n"), expect_flags{*this, parse_flag::connection_upgrade});
529 good<true>(cn("upgrade\t ,x\r\n"), expect_flags{*this, parse_flag::connection_upgrade});
530 good<true>(cn("\r\n upgrade \t\r\n"), expect_flags{*this, parse_flag::connection_upgrade});
531 good<true>(cn("upgrade \r\n \t \r\n"), expect_flags{*this, parse_flag::connection_upgrade});
532 good<true>(cn("upgrade\r\n \r\n"), expect_flags{*this, parse_flag::connection_upgrade});
533
534 // VFALCO What's up with these?
535 //good<true>(cn("close,keep-alive\r\n"), expect_flags{*this, parse_flag::connection_close | parse_flag::connection_keep_alive});
536 good<true>(cn("upgrade,keep-alive\r\n"), expect_flags{*this, parse_flag::connection_upgrade | parse_flag::connection_keep_alive});
537 good<true>(cn("upgrade,\r\n keep-alive\r\n"), expect_flags{*this, parse_flag::connection_upgrade | parse_flag::connection_keep_alive});
538 //good<true>(cn("close,keep-alive,upgrade\r\n"), expect_flags{*this, parse_flag::connection_close | parse_flag::connection_keep_alive | parse_flag::connection_upgrade});
539
540 good<true>("GET / HTTP/1.1\r\n\r\n", expect_keepalive(*this, true));
541 good<true>("GET / HTTP/1.0\r\n\r\n", expect_keepalive(*this, false));
542 good<true>("GET / HTTP/1.0\r\n"
543 "Connection: keep-alive\r\n\r\n", expect_keepalive(*this, true));
544 good<true>("GET / HTTP/1.1\r\n"
545 "Connection: close\r\n\r\n", expect_keepalive(*this, false));
546
547 good<true>(cn("x\r\n"), expect_flags{*this, 0});
548 good<true>(cn("x,y\r\n"), expect_flags{*this, 0});
549 good<true>(cn("x ,y\r\n"), expect_flags{*this, 0});
550 good<true>(cn("x\t,y\r\n"), expect_flags{*this, 0});
551 good<true>(cn("keep\r\n"), expect_flags{*this, 0});
552 good<true>(cn(",keep\r\n"), expect_flags{*this, 0});
553 good<true>(cn(" keep\r\n"), expect_flags{*this, 0});
554 good<true>(cn("\tnone\r\n"), expect_flags{*this, 0});
555 good<true>(cn("keep,\r\n"), expect_flags{*this, 0});
556 good<true>(cn("keep\t\r\n"), expect_flags{*this, 0});
557 good<true>(cn("keep\r\n"), expect_flags{*this, 0});
558 good<true>(cn(" ,\t,,keep,, ,\t,,\r\n"), expect_flags{*this, 0});
559 good<true>(cn("\r\n keep\r\n"), expect_flags{*this, 0});
560 good<true>(cn("keep\r\n \r\n"), expect_flags{*this, 0});
561 good<true>(cn("closet\r\n"), expect_flags{*this, 0});
562 good<true>(cn(",closet\r\n"), expect_flags{*this, 0});
563 good<true>(cn(" closet\r\n"), expect_flags{*this, 0});
564 good<true>(cn("\tcloset\r\n"), expect_flags{*this, 0});
565 good<true>(cn("closet,\r\n"), expect_flags{*this, 0});
566 good<true>(cn("closet\t\r\n"), expect_flags{*this, 0});
567 good<true>(cn("closet\r\n"), expect_flags{*this, 0});
568 good<true>(cn(" ,\t,,closet,, ,\t,,\r\n"), expect_flags{*this, 0});
569 good<true>(cn("\r\n closet\r\n"), expect_flags{*this, 0});
570 good<true>(cn("closet\r\n \r\n"), expect_flags{*this, 0});
571 good<true>(cn("clog\r\n"), expect_flags{*this, 0});
572 good<true>(cn("key\r\n"), expect_flags{*this, 0});
573 good<true>(cn("uptown\r\n"), expect_flags{*this, 0});
574 good<true>(cn("keeper\r\n \r\n"), expect_flags{*this, 0});
575 good<true>(cn("keep-alively\r\n \r\n"), expect_flags{*this, 0});
576 good<true>(cn("up\r\n \r\n"), expect_flags{*this, 0});
577 good<true>(cn("upgrader\r\n \r\n"), expect_flags{*this, 0});
578 good<true>(cn("none\r\n"), expect_flags{*this, 0});
579 good<true>(cn("\r\n none\r\n"), expect_flags{*this, 0});
580
581 good<true>(m("ConnectioX: close\r\n"), expect_flags{*this, 0});
582 good<true>(m("Condor: close\r\n"), expect_flags{*this, 0});
583 good<true>(m("Connect: close\r\n"), expect_flags{*this, 0});
584 good<true>(m("Connections: close\r\n"), expect_flags{*this, 0});
585
586 good<true>(m("Proxy-Connection: close\r\n"), expect_flags{*this, parse_flag::connection_close});
587 good<true>(m("Proxy-Connection: keep-alive\r\n"), expect_flags{*this, parse_flag::connection_keep_alive});
588 good<true>(m("Proxy-Connection: upgrade\r\n"), expect_flags{*this, parse_flag::connection_upgrade});
589 good<true>(m("Proxy-ConnectioX: none\r\n"), expect_flags{*this, 0});
590 good<true>(m("Proxy-Connections: 1\r\n"), expect_flags{*this, 0});
591 good<true>(m("Proxy-Connotes: see-also\r\n"), expect_flags{*this, 0});
592
593 bad<true>(cn("[\r\n"), error::bad_value);
594 bad<true>(cn("close[\r\n"), error::bad_value);
595 bad<true>(cn("close [\r\n"), error::bad_value);
596 bad<true>(cn("close, upgrade [\r\n"), error::bad_value);
597 bad<true>(cn("upgrade[]\r\n"), error::bad_value);
598 bad<true>(cn("keep\r\n -alive\r\n"), error::bad_value);
599 bad<true>(cn("keep-alive[\r\n"), error::bad_value);
600 bad<true>(cn("keep-alive []\r\n"), error::bad_value);
601 bad<true>(cn("no[ne]\r\n"), error::bad_value);
602 }
603
604 void
605 testContentLengthField()
606 {
607 auto const length =
608 [&](std::string const& s, std::uint64_t v)
609 {
610 good<true>(s,
611 [&](test_parser<true> const& p)
612 {
613 BEAST_EXPECT(p.content_length());
614 BEAST_EXPECT(p.content_length() && *p.content_length() == v);
615 }, true);
616 };
617 auto const c =
618 [](std::string const& s)
619 {
620 return "GET / HTTP/1.1\r\nContent-Length: " + s + "\r\n";
621 };
622 auto const m =
623 [](std::string const& s)
624 {
625 return "GET / HTTP/1.1\r\n" + s + "\r\n";
626 };
627
628 length(c("0\r\n"), 0);
629 length(c("00\r\n"), 0);
630 length(c("1\r\n"), 1);
631 length(c("01\r\n"), 1);
632 length(c("9\r\n"), 9);
633 length(c("123456789\r\n"), 123456789);
634 length(c("42 \r\n"), 42);
635 length(c("42\t\r\n"), 42);
636 length(c("42 \t \r\n"), 42);
637
638 // VFALCO Investigate this failure
639 //length(c("42\r\n \t \r\n"), 42);
640
641 good<true>(m("Content-LengtX: 0\r\n"), expect_flags{*this, 0});
642 good<true>(m("Content-Lengths: many\r\n"), expect_flags{*this, 0});
643 good<true>(m("Content: full\r\n"), expect_flags{*this, 0});
644
645 bad<true>(c("\r\n"), error::bad_content_length);
646 bad<true>(c("18446744073709551616\r\n"), error::bad_content_length);
647 bad<true>(c("0 0\r\n"), error::bad_content_length);
648 bad<true>(c("0 1\r\n"), error::bad_content_length);
649 bad<true>(c(",\r\n"), error::bad_content_length);
650 bad<true>(c("0,\r\n"), error::bad_content_length);
651 bad<true>(m(
652 "Content-Length: 0\r\nContent-Length: 0\r\n"), error::bad_content_length);
653 }
654
655 void
656 testTransferEncodingField()
657 {
658 auto const m =
659 [](std::string const& s)
660 {
661 return "GET / HTTP/1.1\r\n" + s + "\r\n";
662 };
663 auto const ce =
664 [](std::string const& s)
665 {
666 return "GET / HTTP/1.1\r\nTransfer-Encoding: " + s + "\r\n0\r\n\r\n";
667 };
668 auto const te =
669 [](std::string const& s)
670 {
671 return "GET / HTTP/1.1\r\nTransfer-Encoding: " + s + "\r\n";
672 };
673 good<true>(ce("chunked\r\n"), expect_flags{*this, parse_flag::chunked});
674 good<true>(ce("chunked \r\n"), expect_flags{*this, parse_flag::chunked});
675 good<true>(ce("chunked\t\r\n"), expect_flags{*this, parse_flag::chunked});
676 good<true>(ce("chunked \t\r\n"), expect_flags{*this, parse_flag::chunked});
677 good<true>(ce(" chunked\r\n"), expect_flags{*this, parse_flag::chunked});
678 good<true>(ce("\tchunked\r\n"), expect_flags{*this, parse_flag::chunked});
679 good<true>(ce("chunked,\r\n"), expect_flags{*this, parse_flag::chunked});
680 good<true>(ce("chunked ,\r\n"), expect_flags{*this, parse_flag::chunked});
681 good<true>(ce("chunked, \r\n"), expect_flags{*this, parse_flag::chunked});
682 good<true>(ce(",chunked\r\n"), expect_flags{*this, parse_flag::chunked});
683 good<true>(ce(", chunked\r\n"), expect_flags{*this, parse_flag::chunked});
684 good<true>(ce(" ,chunked\r\n"), expect_flags{*this, parse_flag::chunked});
685 good<true>(ce("chunked\r\n \r\n"), expect_flags{*this, parse_flag::chunked});
686 good<true>(ce("\r\n chunked\r\n"), expect_flags{*this, parse_flag::chunked});
687 good<true>(ce(",\r\n chunked\r\n"), expect_flags{*this, parse_flag::chunked});
688 good<true>(ce("\r\n ,chunked\r\n"), expect_flags{*this, parse_flag::chunked});
689 good<true>(ce(",\r\n chunked\r\n"), expect_flags{*this, parse_flag::chunked});
690 good<true>(ce("gzip, chunked\r\n"), expect_flags{*this, parse_flag::chunked});
691 good<true>(ce("gzip, chunked \r\n"), expect_flags{*this, parse_flag::chunked});
692 good<true>(ce("gzip, \r\n chunked\r\n"), expect_flags{*this, parse_flag::chunked});
693
694 // Technically invalid but beyond the parser's scope to detect
695 // VFALCO Look into this
696 //good<true>(ce("custom;key=\",chunked\r\n"), expect_flags{*this, parse_flag::chunked});
697
698 good<true>(te("gzip\r\n"), expect_flags{*this, 0});
699 good<true>(te("chunked, gzip\r\n"), expect_flags{*this, 0});
700 good<true>(te("chunked\r\n , gzip\r\n"), expect_flags{*this, 0});
701 good<true>(te("chunked,\r\n gzip\r\n"), expect_flags{*this, 0});
702 good<true>(te("chunked,\r\n ,gzip\r\n"), expect_flags{*this, 0});
703 good<true>(te("bigchunked\r\n"), expect_flags{*this, 0});
704 good<true>(te("chunk\r\n ked\r\n"), expect_flags{*this, 0});
705 good<true>(te("bar\r\n ley chunked\r\n"), expect_flags{*this, 0});
706 good<true>(te("barley\r\n chunked\r\n"), expect_flags{*this, 0});
707
708 good<true>(m("Transfer-EncodinX: none\r\n"), expect_flags{*this, 0});
709 good<true>(m("Transfer-Encodings: 2\r\n"), expect_flags{*this, 0});
710 good<true>(m("Transfer-Encoded: false\r\n"), expect_flags{*this, 0});
711
712 bad<false>(
713 "HTTP/1.1 200 OK\r\n"
714 "Content-Length: 1\r\n"
715 "Transfer-Encoding: chunked\r\n"
716 "\r\n", error::bad_transfer_encoding, true);
717 }
718
719 void
720 testUpgradeField()
721 {
722 auto const m =
723 [](std::string const& s)
724 {
725 return "GET / HTTP/1.1\r\n" + s + "\r\n";
726 };
727 good<true>(m("Upgrade:\r\n"), expect_flags{*this, parse_flag::upgrade});
728 good<true>(m("Upgrade: \r\n"), expect_flags{*this, parse_flag::upgrade});
729 good<true>(m("Upgrade: yes\r\n"), expect_flags{*this, parse_flag::upgrade});
730
731 good<true>(m("Up: yes\r\n"), expect_flags{*this, 0});
732 good<true>(m("UpgradX: none\r\n"), expect_flags{*this, 0});
733 good<true>(m("Upgrades: 2\r\n"), expect_flags{*this, 0});
734 good<true>(m("Upsample: 4x\r\n"), expect_flags{*this, 0});
735
736 good<true>(
737 "GET / HTTP/1.1\r\n"
738 "Connection: upgrade\r\n"
739 "Upgrade: WebSocket\r\n"
740 "\r\n",
741 [&](test_parser<true> const& p)
742 {
743 BEAST_EXPECT(p.is_upgrade());
744 });
745 }
746
747 void testBody()
748 {
749 using boost::asio::buffer;
750 good<true>(
751 "GET / HTTP/1.1\r\n"
752 "Content-Length: 1\r\n"
753 "\r\n"
754 "1",
755 expect_body(*this, "1"));
756
757 good<false>(
758 "HTTP/1.0 200 OK\r\n"
759 "\r\n"
760 "hello",
761 expect_body(*this, "hello"));
762
763 // write the body in 3 pieces
764 {
765 error_code ec;
766 test_parser<true> p;
767 feed(buffer_cat(
768 buf("GET / HTTP/1.1\r\n"
769 "Content-Length: 10\r\n"
770 "\r\n"),
771 buf("12"),
772 buf("345"),
773 buf("67890")),
774 p, ec);
775 BEAST_EXPECTS(! ec, ec.message());
776 BEAST_EXPECT(p.is_complete());
777 }
778
779 // request without Content-Length or
780 // Transfer-Encoding: chunked has no body.
781 {
782 error_code ec;
783 test_parser<true> p;
784 feed(buf(
785 "GET / HTTP/1.0\r\n"
786 "\r\n"
787 ), p, ec);
788 BEAST_EXPECTS(! ec, ec.message());
789 BEAST_EXPECT(p.is_complete());
790 }
791 {
792 error_code ec;
793 test_parser<true> p;
794 feed(buf(
795 "GET / HTTP/1.1\r\n"
796 "\r\n"
797 ), p, ec);
798 BEAST_EXPECTS(! ec, ec.message());
799 BEAST_EXPECT(p.is_complete());
800 }
801
802 // response without Content-Length or
803 // Transfer-Encoding: chunked requires eof.
804 {
805 error_code ec;
806 test_parser<false> p;
807 feed(buf(
808 "HTTP/1.0 200 OK\r\n"
809 "\r\n"
810 ), p, ec);
811 BEAST_EXPECTS(! ec, ec.message());
812 BEAST_EXPECT(! p.is_complete());
813 BEAST_EXPECT(p.state() == parse_state::body_to_eof);
814 feed(buf(
815 "hello"
816 ), p, ec);
817 BEAST_EXPECTS(! ec, ec.message());
818 BEAST_EXPECT(! p.is_complete());
819 BEAST_EXPECT(p.state() == parse_state::body_to_eof);
820 p.write_eof(ec);
821 BEAST_EXPECTS(! ec, ec.message());
822 BEAST_EXPECT(p.is_complete());
823 }
824
825 // 304 "Not Modified" response does not require eof
826 {
827 error_code ec;
828 test_parser<false> p;
829 feed(buf(
830 "HTTP/1.0 304 Not Modified\r\n"
831 "\r\n"
832 ), p, ec);
833 BEAST_EXPECTS(! ec, ec.message());
834 BEAST_EXPECT(p.is_complete());
835 }
836
837 // Chunked response does not require eof
838 {
839 error_code ec;
840 test_parser<false> p;
841 feed(buf(
842 "HTTP/1.1 200 OK\r\n"
843 "Transfer-Encoding: chunked\r\n"
844 "\r\n"
845 ), p, ec);
846 BEAST_EXPECTS(! ec, ec.message());
847 BEAST_EXPECT(! p.is_complete());
848 feed(buf(
849 "0\r\n\r\n"
850 ), p, ec);
851 BEAST_EXPECTS(! ec, ec.message());
852 BEAST_EXPECT(p.is_complete());
853 }
854
855 // restart: 1.0 assumes Connection: close
856 {
857 error_code ec;
858 test_parser<true> p;
859 feed(buf(
860 "GET / HTTP/1.0\r\n"
861 "\r\n"
862 ), p, ec);
863 BEAST_EXPECTS(! ec, ec.message());
864 BEAST_EXPECT(p.is_complete());
865 }
866
867 // restart: 1.1 assumes Connection: keep-alive
868 {
869 error_code ec;
870 test_parser<true> p;
871 feed(buf(
872 "GET / HTTP/1.1\r\n"
873 "\r\n"
874 ), p, ec);
875 BEAST_EXPECTS(! ec, ec.message());
876 BEAST_EXPECT(p.is_complete());
877 }
878
879 bad<true>(
880 "GET / HTTP/1.1\r\n"
881 "Content-Length: 1\r\n"
882 "\r\n",
883 error::partial_message);
884 }
885
886 template<bool isRequest>
887 void
888 check_header(
889 test_parser<isRequest> const& p)
890 {
891 BEAST_EXPECT(p.got_on_begin);
892 BEAST_EXPECT(p.got_on_field);
893 BEAST_EXPECT(p.got_on_header);
894 BEAST_EXPECT(! p.got_on_body);
895 BEAST_EXPECT(! p.got_on_chunk);
896 BEAST_EXPECT(! p.got_on_end_body);
897 BEAST_EXPECT(! p.got_on_complete);
898 BEAST_EXPECT(p.state() != parse_state::header);
899 }
900
901 void
902 testSplit()
903 {
904#if 0
905 streambuf sb;
906 sb <<
907 "POST / HTTP/1.1\r\n"
908 "Content-Length: 5\r\n"
909 "\r\n"
910 "*****";
911 error_code ec;
912 test_parser<true> p;
913 p.pause();
914 auto n = feed(sb.data(), p, ec);
915 BEAST_EXPECTS(! ec, ec.message());
916 BEAST_EXPECT(p.got_on_begin);
917 BEAST_EXPECT(p.got_on_field);
918 BEAST_EXPECT(p.got_on_header);
919 BEAST_EXPECT(! p.got_on_body);
920 BEAST_EXPECT(! p.got_on_chunk);
921 BEAST_EXPECT(! p.got_on_complete);
922 BEAST_EXPECT(p.state() != parse_state::header);
923 BEAST_EXPECT(! p.is_complete());
924 BEAST_EXPECT(p.body.empty());
925 sb.consume(n);
926 p.resume();
927 n = feed(sb.data(), p, ec);
928 BEAST_EXPECTS(! ec, ec.message());
929 BEAST_EXPECT(p.got_on_begin);
930 BEAST_EXPECT(p.got_on_field);
931 BEAST_EXPECT(p.got_on_header);
932 BEAST_EXPECT(p.got_on_body);
933 BEAST_EXPECT(! p.got_on_chunk);
934 BEAST_EXPECT(p.got_on_complete);
935 BEAST_EXPECT(p.is_complete());
936 BEAST_EXPECT(p.body == "*****");
937#endif
938 }
939
940 void
941 run() override
942 {
943 testFlatten();
944 testCallbacks();
945 testRequestLine();
946 testStatusLine();
947 testFields();
948 testConnectionField();
949 testContentLengthField();
950 testTransferEncodingField();
951 testUpgradeField();
952 testBody();
953 testSplit();
954 }
955};
956
957BEAST_DEFINE_TESTSUITE(basic_parser,http,beast);
958
959} // http
960} // beast