Fix read_size_helper usage:

read_size_helper can return zero if the buffer reaches
its maximum size, causing infinite loops in HTTP. The
function maybe_read_size_helper is provided to throw
an exception instead of returning a value for this case.
This commit is contained in:
Vinnie Falco
2017-06-10 10:12:29 -07:00
parent e4fdeecc3b
commit 78f4858e98
6 changed files with 47 additions and 21 deletions

View File

@@ -1,6 +1,7 @@
Version 53: Version 53:
* Fix basic_parser::maybe_flatten * Fix basic_parser::maybe_flatten
* Fix read_size_helper usage
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -128,9 +128,8 @@ private:
{ {
using boost::asio::buffer_cast; using boost::asio::buffer_cast;
using boost::asio::buffer_size; using boost::asio::buffer_size;
using beast::detail::read_size_helper;
auto mbs = buf_.prepare( auto mbs = buf_.prepare(
read_size_helper(buf_, max_size)); maybe_read_size_helper(buf_, max_size));
auto const mb = *mbs.begin(); auto const mb = *mbs.begin();
auto const p = buffer_cast<CharT*>(mb); auto const p = buffer_cast<CharT*>(mb);
this->setp(p, this->setp(p,
@@ -209,9 +208,8 @@ private:
{ {
using boost::asio::buffer_cast; using boost::asio::buffer_cast;
using boost::asio::buffer_size; using boost::asio::buffer_size;
using beast::detail::read_size_helper;
auto mbs = buf_.prepare( auto mbs = buf_.prepare(
read_size_helper(buf_, max_size)); maybe_read_size_helper(buf_, max_size));
auto const mb = *mbs.begin(); auto const mb = *mbs.begin();
auto const p = buffer_cast<CharT*>(mb); auto const p = buffer_cast<CharT*>(mb);
this->setp(p, this->setp(p,

View File

@@ -17,9 +17,27 @@
namespace beast { namespace beast {
namespace detail { namespace detail {
/** Returns a natural read size.
This function inspects the capacity, size, and maximum
size of the dynamic buffer. Then it computes a natural
read size given the passed-in upper limit. It favors
a read size that does not require a reallocation, subject
to a reasonable minimum to avoid tiny reads.
Calls to @ref read_size_helper should be made without
namespace qualification, i.e. allowing argument dependent
lookup to take effect, so that overloads of this function
for specific buffer types may be found.
@param buffer The dynamic buffer to inspect.
@param max_size An upper limit on the returned value.
*/
template<class DynamicBuffer> template<class DynamicBuffer>
std::size_t std::size_t
read_size_helper(DynamicBuffer const& buffer, std::size_t max_size) read_size_helper(
DynamicBuffer const& buffer, std::size_t max_size)
{ {
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value, static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met"); "DynamicBuffer requirements not met");
@@ -34,6 +52,22 @@ read_size_helper(DynamicBuffer const& buffer, std::size_t max_size)
std::min<std::size_t>(max_size, limit)); std::min<std::size_t>(max_size, limit));
} }
/** Return a non-zero natural read size.
*/
template<class DynamicBuffer>
std::size_t
maybe_read_size_helper(
DynamicBuffer const& buffer, std::size_t max_size)
{
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
auto const n = read_size_helper(buffer, max_size);
if(n == 0)
BOOST_THROW_EXCEPTION(std::length_error{
"buffer overflow"});
return n;
}
} // detail } // detail
} // beast } // beast

View File

@@ -145,9 +145,8 @@ operator()(error_code ec, std::size_t bytes_transferred)
do_read: do_read:
try try
{ {
using beast::detail::read_size_helper;
mb_.emplace(b_.prepare( mb_.emplace(b_.prepare(
read_size_helper(b_, 65536))); maybe_read_size_helper(b_, 65536)));
} }
catch(std::length_error const&) catch(std::length_error const&)
{ {
@@ -475,9 +474,9 @@ read_some(
DynamicBuffer::mutable_buffers_type> b; DynamicBuffer::mutable_buffers_type> b;
try try
{ {
using beast::detail::read_size_helper;
b.emplace(buffer.prepare( b.emplace(buffer.prepare(
read_size_helper(buffer, 65536))); beast::detail::maybe_read_size_helper(
buffer, 65536)));
} }
catch(std::length_error const&) catch(std::length_error const&)
{ {

View File

@@ -369,9 +369,8 @@ inflate(
for(;;) for(;;)
{ {
// VFALCO we could be smarter about the size // VFALCO we could be smarter about the size
using beast::detail::read_size_helper;
auto const bs = buffer.prepare( auto const bs = buffer.prepare(
read_size_helper(buffer, 65536)); maybe_read_size_helper(buffer, 65536));
auto const out = *bs.begin(); auto const out = *bs.begin();
zs.avail_out = buffer_size(out); zs.avail_out = buffer_size(out);
zs.next_out = buffer_cast<void*>(out); zs.next_out = buffer_cast<void*>(out);

View File

@@ -143,16 +143,11 @@ public:
BEAST_EXPECT(b.size() == 1); BEAST_EXPECT(b.size() == 1);
} }
{ {
flat_buffer b{10}; flat_buffer b{20};
try ostream(b) << "12345";
{ b.consume(3);
b.reserve(11); ostream(b) << "67890123";
fail("", __FILE__, __LINE__); BEAST_EXPECT(to_string(b.data()) == "4567890123");
}
catch(std::length_error const&)
{
pass();
}
} }
} }