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