]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/beast/http/parser.cpp
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 // Test that header file is self-contained.
11 #include <boost/beast/http/parser.hpp>
13 #include "test_parser.hpp"
15 #include <boost/beast/_experimental/unit_test/suite.hpp>
16 #include <boost/beast/core/buffer_traits.hpp>
17 #include <boost/beast/core/buffers_suffix.hpp>
18 #include <boost/beast/core/flat_buffer.hpp>
19 #include <boost/beast/core/multi_buffer.hpp>
20 #include <boost/beast/core/ostream.hpp>
21 #include <boost/beast/http/read.hpp>
22 #include <boost/beast/http/string_body.hpp>
23 #include <boost/system/system_error.hpp>
31 : public beast::unit_test::suite
34 template<bool isRequest
>
36 parser
<isRequest
, string_body
>;
42 return {s
.data(), s
.size()};
45 template<class ConstBufferSequence
,
49 put(ConstBufferSequence
const& buffers
,
50 basic_parser
<isRequest
>& p
,
53 buffers_suffix
<ConstBufferSequence
> cb
{buffers
};
56 auto const used
= p
.put(cb
, ec
);
61 buffer_bytes(cb
) == 0)
72 template<bool isRequest
, class F
>
74 doMatrix(string_view s0
, F
const& f
)
76 // parse a single buffer
80 parser_type
<isRequest
> p
;
81 put(net::buffer(s
.data(), s
.size()), p
, ec
);
82 if(! BEAST_EXPECTS(! ec
, ec
.message()))
87 for(auto n
= s0
.size() - 1; n
>= 1; --n
)
91 parser_type
<isRequest
> p
;
94 p
.put(net::buffer(s
.data(), n
), ec
);
95 s
.remove_prefix(used
);
96 if(ec
== error::need_more
)
98 if(! BEAST_EXPECTS(! ec
, ec
.message()))
100 BEAST_EXPECT(! p
.is_done());
102 net::buffer(s
.data(), s
.size()), ec
);
103 s
.remove_prefix(used
);
104 if(! BEAST_EXPECTS(! ec
, ec
.message()))
106 BEAST_EXPECT(s
.empty());
110 if(! BEAST_EXPECTS(! ec
, ec
.message()))
113 if(BEAST_EXPECT(p
.is_done()))
122 "HTTP/1.0 200 OK\r\n"
126 [&](parser_type
<false> const& p
)
128 auto const& m
= p
.get();
129 BEAST_EXPECT(! p
.chunked());
130 BEAST_EXPECT(p
.need_eof());
131 BEAST_EXPECT(p
.content_length() == boost::none
);
132 BEAST_EXPECT(m
.version() == 10);
133 BEAST_EXPECT(m
.result() == status::ok
);
134 BEAST_EXPECT(m
.reason() == "OK");
135 BEAST_EXPECT(m
["Server"] == "test");
136 BEAST_EXPECT(m
.body() == "Hello, world!");
140 "HTTP/1.1 200 OK\r\n"
142 "Expect: Expires, MD5-Fingerprint\r\n"
143 "Transfer-Encoding: chunked\r\n"
147 "2;a;b=1;c=\"2\"\r\n"
149 "0;d;e=3;f=\"4\"\r\n"
151 "MD5-Fingerprint: -\r\n"
153 [&](parser_type
<false> const& p
)
155 auto const& m
= p
.get();
156 BEAST_EXPECT(! p
.need_eof());
157 BEAST_EXPECT(p
.chunked());
158 BEAST_EXPECT(p
.content_length() == boost::none
);
159 BEAST_EXPECT(m
.version() == 11);
160 BEAST_EXPECT(m
.result() == status::ok
);
161 BEAST_EXPECT(m
.reason() == "OK");
162 BEAST_EXPECT(m
["Server"] == "test");
163 BEAST_EXPECT(m
["Transfer-Encoding"] == "chunked");
164 BEAST_EXPECT(m
["Expires"] == "never");
165 BEAST_EXPECT(m
["MD5-Fingerprint"] == "-");
166 BEAST_EXPECT(m
.body() == "*****--");
170 "HTTP/1.0 200 OK\r\n"
172 "Content-Length: 5\r\n"
175 [&](parser_type
<false> const& p
)
177 auto const& m
= p
.get();
178 BEAST_EXPECT(m
.body() == "*****");
183 "User-Agent: test\r\n"
185 [&](parser_type
<true> const& p
)
187 auto const& m
= p
.get();
188 BEAST_EXPECT(m
.method() == verb::get
);
189 BEAST_EXPECT(m
.target() == "/");
190 BEAST_EXPECT(m
.version() == 11);
191 BEAST_EXPECT(! p
.need_eof());
192 BEAST_EXPECT(! p
.chunked());
193 BEAST_EXPECT(p
.content_length() == boost::none
);
198 "User-Agent: test\r\n"
201 [&](parser_type
<true> const& p
)
203 auto const& m
= p
.get();
204 BEAST_EXPECT(m
["X"] == "x");
215 "User-Agent: test\r\n"
216 "Content-Length: 1\r\n"
220 auto const& m
= p
.get();
222 BEAST_EXPECT(p
.is_done());
223 BEAST_EXPECT(p
.is_header_done());
224 BEAST_EXPECT(! p
.need_eof());
225 BEAST_EXPECT(m
.method() == verb::get
);
226 BEAST_EXPECT(m
.target() == "/");
227 BEAST_EXPECT(m
.version() == 11);
228 BEAST_EXPECT(m
["User-Agent"] == "test");
229 BEAST_EXPECT(m
.body() == "*");
232 // test partial parsing of final chunk
233 // parse through the chunk body
240 "Transfer-Encoding: chunked\r\n"
244 auto used
= p
.put(b
.data(), ec
);
247 BEAST_EXPECT(! p
.is_done());
248 BEAST_EXPECT(p
.get().body() == "*");
251 "0;d;e=3;f=\"4\"\r\n"
253 "MD5-Fingerprint: -\r\n";
254 // incomplete parse, missing the final crlf
255 used
= p
.put(b
.data(), ec
);
257 BEAST_EXPECT(ec
== error::need_more
);
259 BEAST_EXPECT(! p
.is_done());
261 "\r\n"; // final crlf to end message
262 used
= p
.put(b
.data(), ec
);
264 BEAST_EXPECTS(! ec
, ec
.message());
265 BEAST_EXPECT(p
.is_done());
270 response_parser
<string_body
> p
;
273 "HTTP/1.1 200 OK\r\n"
274 "Content-Length: 5\r\n"
278 BEAST_EXPECTS(! ec
, ec
.message());
279 BEAST_EXPECT(p
.is_done());
280 BEAST_EXPECT(p
.is_header_done());
281 BEAST_EXPECT(p
.content_length() &&
282 *p
.content_length() == 5);
286 //--------------------------------------------------------------------------
288 template<class DynamicBuffer
>
298 "GET / HTTP/1.1\r\n";
299 used
= p
.put(b
.data(), ec
);
300 BEAST_EXPECTS(ec
== error::need_more
, ec
.message());
304 "User-Agent: test\r\n"
306 used
= p
.put(b
.data(), ec
);
307 BEAST_EXPECTS(! ec
, ec
.message());
309 BEAST_EXPECT(p
.is_done());
310 BEAST_EXPECT(p
.is_header_done());
319 auto used
= p
.put(buf(""), ec
);
320 BEAST_EXPECT(ec
== error::need_more
);
321 BEAST_EXPECT(! p
.got_some());
322 BEAST_EXPECT(used
== 0);
324 used
= p
.put(buf("G"), ec
);
325 BEAST_EXPECT(ec
== error::need_more
);
326 BEAST_EXPECT(p
.got_some());
327 BEAST_EXPECT(used
== 0);
333 // Make sure that the parser clears pre-existing fields
334 request
<string_body
> m
;
335 m
.set(field::accept
, "html/text");
336 BEAST_EXPECT(std::distance(m
.begin(), m
.end()) == 1);
337 request_parser
<string_body
> p
{std::move(m
)};
338 BEAST_EXPECT(std::distance(m
.begin(), m
.end()) == 0);
340 BEAST_EXPECT(std::distance(m1
.begin(), m1
.end()) == 0);
346 // make sure parser finishes on redirect
348 parser_type
<false> p
;
351 "HTTP/1.1 301 Moved Permanently\r\n"
352 "Location: https://www.ebay.com\r\n"
354 BEAST_EXPECTS(! ec
, ec
.message());
355 BEAST_EXPECT(p
.is_header_done());
356 BEAST_EXPECT(! p
.is_done());
357 BEAST_EXPECT(p
.need_eof());
363 // A user raised the issue that multiple Content-Length fields and
364 // values are permissible provided all values are the same.
365 // See rfc7230 section-3.3.2
366 // https://tools.ietf.org/html/rfc7230#section-3.3.2
367 // Credit: Dimitry Bulsunov
369 auto checkPass
= [&](std::string
const& message
)
371 response_parser
<string_body
> parser
;
373 parser
.put(net::buffer(message
), ec
);
374 BEAST_EXPECTS(!ec
.failed(), ec
.message());
377 auto checkFail
= [&](std::string
const& message
)
379 response_parser
<string_body
> parser
;
381 parser
.put(net::buffer(message
), ec
);
382 BEAST_EXPECTS(ec
== error::bad_content_length
, ec
.message());
385 // multiple contents lengths the same
387 "HTTP/1.1 200 OK\r\n"
388 "Content-Length: 0\r\n"
389 "Content-Length: 0\r\n"
392 // multiple contents lengths different
394 "HTTP/1.1 200 OK\r\n"
395 "Content-Length: 0\r\n"
396 "Content-Length: 1\r\n"
399 // multiple content in same header
401 "HTTP/1.1 200 OK\r\n"
402 "Content-Length: 0, 0, 0\r\n"
405 // multiple content in same header but mismatch (case 1)
407 "HTTP/1.1 200 OK\r\n"
408 "Content-Length: 0, 0, 1\r\n"
411 // multiple content in same header but mismatch (case 2)
413 "HTTP/1.1 200 OK\r\n"
414 "Content-Length: 0, 0, 0\r\n"
415 "Content-Length: 1\r\n"
423 testNeedMore
<flat_buffer
>();
424 testNeedMore
<multi_buffer
>();
432 BEAST_DEFINE_TESTSUITE(beast
,http
,parser
);