Parser body_limit is optional (API Change):

API Changes:

The signature of basic_parser<>::body_limit(n) has changed. It now accepts an
optional std::uint64_t. The caller may indicate that no body limit is required
by calling body_limit(boost::none). The default limits remain in place in order
to maintain 'safe by default' behaviour.

closes #1897
closes #1965
This commit is contained in:
Richard Hodges
2020-05-26 09:56:16 +02:00
parent d7f1426f34
commit 0fdf9cb4df
5 changed files with 151 additions and 14 deletions

View File

@@ -1,9 +1,15 @@
* Parser body_limit is optional (API Change)
* Fix basic_stream expires_after (API Change)
* Fix FILE namespace qualification
API Changes:
basic_stream::expires_after used to take a nanosecond duration type argument. This
* The signature of basic_parser<>::body_limit(n) has changed. It now accepts an
optional std::uint64_t. The caller may indicate that no body limit is required
by calling body_limit(boost::none). The default limits remain in place in order
to maintain 'safe by default' behaviour.
* basic_stream::expires_after used to take a nanosecond duration type argument. This
required users on systems where the steady_clock::duration_type was less accurate
to explicity duration_cast when calling this function, making code non-portable.
The duration type is now that of the embedded steady_clock.

View File

@@ -69,8 +69,9 @@ template<bool isRequest>
class basic_parser
: private detail::basic_parser_base
{
std::uint64_t body_limit_ =
default_body_limit(is_request{}); // max payload body
boost::optional<std::uint64_t>
body_limit_ =
default_body_limit(is_request{}); // max payload body
std::uint64_t len_ = 0; // size of chunk or body
std::uint64_t len0_ = 0; // content length if known
std::unique_ptr<char[]> buf_; // temp storage
@@ -289,10 +290,11 @@ public:
The default limit is 1MB for requests and 8MB for responses.
@param v The payload body limit to set
@param v An optional integral value representing the body limit.
If this is equal to `boost::none`, then the body limit is disabled.
*/
void
body_limit(std::uint64_t v)
body_limit(boost::optional<std::uint64_t> v)
{
body_limit_ = v;
}

View File

@@ -573,12 +573,15 @@ basic_parser<isRequest>::
parse_body_to_eof(char const*& p,
std::size_t n, error_code& ec)
{
if(n > body_limit_)
if(body_limit_.has_value())
{
ec = error::body_limit;
return;
if (n > *body_limit_)
{
ec = error::body_limit;
return;
}
*body_limit_ -= n;
}
body_limit_ = body_limit_ - n;
ec = {};
n = this->on_body_impl(string_view{p, n}, ec);
p += n;
@@ -648,12 +651,15 @@ parse_chunk_header(char const*& p0,
}
if(size != 0)
{
if(size > body_limit_)
if (body_limit_.has_value())
{
ec = error::body_limit;
return;
if (size > *body_limit_)
{
ec = error::body_limit;
return;
}
*body_limit_ -= size;
}
body_limit_ -= size;
auto const start = p;
parse_chunk_extensions(p, pend, ec);
if(ec)

View File

@@ -17,6 +17,7 @@
#include <boost/beast/core/buffers_cat.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/buffers_suffix.hpp>
#include <boost/beast/core/flat_buffer.hpp>
#include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/core/ostream.hpp>
#include <boost/beast/http/parser.hpp>
@@ -1378,6 +1379,127 @@ public:
BEAST_EXPECT(p.is_done());
}
void
testChunkedOverflow()
{
{
const std::string hdr =
"HTTP/1.1 200 OK" "\r\n"
"Server: test" "\r\n"
"Transfer-Encoding: chunked" "\r\n"
"\r\n";
const std::string chunk1 =
"10000000000000000" "\r\n"
"data...";
test_parser<false> p;
error_code ec;
p.put(net::buffer(hdr), ec);
BEAST_EXPECT(!ec);
BEAST_EXPECT(p.is_header_done());
auto bt = p.put(net::buffer(chunk1), ec);
BEAST_EXPECT(bt == 0);
BEAST_EXPECT(ec == error::bad_chunk);
}
{
const std::string hdr =
"HTTP/1.1 200 OK" "\r\n"
"Server: test" "\r\n"
"Transfer-Encoding: chunked" "\r\n"
"\r\n"
"1" "\r\n"
"x" "\r\n";
const std::string chunk2 =
"FFFFFFFFFFFFFFFF" "\r\n"
"data...";
test_parser<false> p;
p.eager(true);
error_code ec;
flat_buffer fb;
fb.commit(net::buffer_copy(fb.prepare(10000), net::buffer(hdr)));
fb.consume(p.put(fb.data(), ec));
BEAST_EXPECT(p.is_header_done());
BEAST_EXPECT(ec = error::need_more);
fb.commit(net::buffer_copy(fb.prepare(10000), net::buffer(chunk2)));
auto bt = p.put(fb.data(), ec);
BEAST_EXPECT(bt == 0);
BEAST_EXPECT(ec == error::body_limit);
}
{
const std::string hdr =
"HTTP/1.1 200 OK" "\r\n"
"Server: test" "\r\n"
"Transfer-Encoding: chunked" "\r\n"
"\r\n"
"1" "\r\n"
"x" "\r\n";
const std::string chunk2 =
"FFFFFFFFFFFFFFFF" "\r\n"
"data...";
test_parser<false> p;
p.eager(true);
p.body_limit(boost::none);
error_code ec;
flat_buffer fb;
fb.commit(net::buffer_copy(fb.prepare(10000), net::buffer(hdr)));
fb.consume(p.put(fb.data(), ec));
BEAST_EXPECT(p.is_header_done());
BEAST_EXPECTS(ec = error::need_more, ec.message());
fb.commit(net::buffer_copy(fb.prepare(10000), net::buffer(chunk2)));
auto bt = p.put(fb.data(), ec);
BEAST_EXPECT(bt == 27);
BEAST_EXPECT(!ec);
}
}
void testChunkedBodySize()
{
string_view resp =
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
// chunk 1
"4\r\n"
"Wiki\r\n"
// chunk 2
"5\r\n"
"pedia\r\n"
// chunk 3
"E\r\n"
" in\r\n"
"\r\n"
"chunks.\r\n"
// end
"0\r\n"
"\r\n";
{ // body limit not exceeded
test_parser<false> p;
p.eager(true);
p.body_limit(23);
error_code ec;
p.put(net::buffer(resp.data(), resp.size()), ec);
BEAST_EXPECT(!ec);
p.put_eof(ec);
BEAST_EXPECT(!ec);
}
{ // body limit exceeded
test_parser<false> p;
p.eager(true);
p.body_limit(22);
error_code ec;
p.put(net::buffer(resp.data(), resp.size()), ec);
BEAST_EXPECT(ec == error::body_limit);
p.put_eof(ec);
BEAST_EXPECT(ec == error::partial_message);
}
}
//--------------------------------------------------------------------------
void
@@ -1404,6 +1526,8 @@ public:
testRegression1();
testIssue1211();
testIssue1267();
testChunkedOverflow();
testChunkedBodySize();
}
};

View File

@@ -18,7 +18,6 @@
#include <boost/beast/core/flat_buffer.hpp>
#include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/core/ostream.hpp>
#include <boost/beast/http/read.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/system/system_error.hpp>
#include <algorithm>