mirror of
https://github.com/boostorg/beast.git
synced 2025-08-01 05:44:38 +02:00
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:
@@ -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.
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -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>
|
||||
|
Reference in New Issue
Block a user