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