diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cda050b..0cbd8ba3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/include/boost/beast/http/basic_parser.hpp b/include/boost/beast/http/basic_parser.hpp index 9cff88b8..4703f4e8 100644 --- a/include/boost/beast/http/basic_parser.hpp +++ b/include/boost/beast/http/basic_parser.hpp @@ -69,8 +69,9 @@ template class basic_parser : private detail::basic_parser_base { - std::uint64_t body_limit_ = - default_body_limit(is_request{}); // max payload body + boost::optional + 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 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 v) { body_limit_ = v; } diff --git a/include/boost/beast/http/impl/basic_parser.ipp b/include/boost/beast/http/impl/basic_parser.ipp index bc9870b7..485a999e 100644 --- a/include/boost/beast/http/impl/basic_parser.ipp +++ b/include/boost/beast/http/impl/basic_parser.ipp @@ -573,12 +573,15 @@ basic_parser:: 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) diff --git a/test/beast/http/basic_parser.cpp b/test/beast/http/basic_parser.cpp index f4073b74..5f221f9f 100644 --- a/test/beast/http/basic_parser.cpp +++ b/test/beast/http/basic_parser.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -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 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 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 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 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 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(); } }; diff --git a/test/beast/http/parser.cpp b/test/beast/http/parser.cpp index d6842622..9d59511d 100644 --- a/test/beast/http/parser.cpp +++ b/test/beast/http/parser.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include