]>
Commit | Line | Data |
---|---|---|
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 | |
27 | namespace boost { | |
28 | namespace beast { | |
29 | namespace http { | |
30 | ||
31 | class basic_parser_test : public beast::unit_test::suite | |
32 | { | |
33 | public: | |
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 | ||
1410 | BEAST_DEFINE_TESTSUITE(beast,http,basic_parser); | |
1411 | ||
1412 | } // http | |
1413 | } // beast | |
1414 | } // boost |