Skip to content

Commit 571adcc

Browse files
committed
Add parser::has_buffered_data()
1 parent f774a58 commit 571adcc

3 files changed

Lines changed: 136 additions & 0 deletions

File tree

include/boost/http/parser.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,28 @@ class parser
307307
core::string_view
308308
body() const;
309309

310+
/** Return true if data is buffered past the message.
311+
312+
After a complete message, returns true when the
313+
parser's buffer still holds octets that lie
314+
beyond it, such as the start of a pipelined
315+
message or data the peer sent past the message
316+
framing. Returns false before the message is
317+
complete.
318+
319+
This does not include the message body, which is
320+
retrieved separately via @ref body or
321+
@ref pull_body.
322+
323+
@return true if octets remain buffered past the
324+
completed message.
325+
326+
@see @ref is_complete, @ref release_buffered_data.
327+
*/
328+
BOOST_HTTP_DECL
329+
bool
330+
has_buffered_data() const noexcept;
331+
310332
/** Return unconsumed data past the last message.
311333
312334
Use this after an upgrade or CONNECT request

src/parser.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,17 @@ class parser::impl
13221322
body_avail_);
13231323
}
13241324

1325+
bool
1326+
has_buffered_data() const noexcept
1327+
{
1328+
if(state_ != state::complete)
1329+
return false;
1330+
1331+
if(is_plain())
1332+
return cb0_.size() > body_avail_;
1333+
return cb0_.size() > 0;
1334+
}
1335+
13251336
void
13261337
set_body_limit(std::uint64_t n)
13271338
{
@@ -1578,6 +1589,14 @@ release_buffered_data() noexcept
15781589
return {};
15791590
}
15801591

1592+
bool
1593+
parser::
1594+
has_buffered_data() const noexcept
1595+
{
1596+
BOOST_ASSERT(impl_);
1597+
return impl_->has_buffered_data();
1598+
}
1599+
15811600
void
15821601
parser::
15831602
set_body_limit(std::uint64_t n)

test/unit/parser.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,7 @@ struct parser_test
17761776
BOOST_TEST(! ec);
17771777
BOOST_TEST(pr.is_complete());
17781778
BOOST_TEST_EQ(pr.body(), body);
1779+
BOOST_TEST(pr.has_buffered_data());
17791780
};
17801781

17811782
check(
@@ -1792,6 +1793,99 @@ struct parser_test
17921793
"okX", "ok");
17931794
}
17941795

1796+
void
1797+
testHasBufferedData()
1798+
{
1799+
parser_config cfg{false};
1800+
cfg.headers.max_size = 100;
1801+
cfg.min_buffer = 100;
1802+
auto pcfg = make_parser_config(cfg);
1803+
1804+
auto const check = [&pcfg](
1805+
core::string_view octets,
1806+
core::string_view body,
1807+
bool buffered)
1808+
{
1809+
response_parser pr(pcfg);
1810+
pr.reset();
1811+
pr.start();
1812+
pr.commit(capy::buffer_copy(
1813+
pr.prepare(),
1814+
capy::const_buffer(
1815+
octets.data(), octets.size())));
1816+
1817+
system::error_code ec;
1818+
pr.parse(ec);
1819+
BOOST_TEST(! ec);
1820+
BOOST_TEST(pr.got_header());
1821+
pr.parse(ec);
1822+
BOOST_TEST(! ec);
1823+
BOOST_TEST(pr.is_complete());
1824+
1825+
// the body is not counted as buffered data
1826+
BOOST_TEST_EQ(pr.body(), body);
1827+
BOOST_TEST_EQ(pr.has_buffered_data(), buffered);
1828+
};
1829+
1830+
check(
1831+
"HTTP/1.1 200 OK\r\n"
1832+
"Content-Length: 2\r\n"
1833+
"\r\n"
1834+
"ok", "ok", false);
1835+
1836+
check(
1837+
"HTTP/1.1 200 OK\r\n"
1838+
"Content-Length: 2\r\n"
1839+
"\r\n"
1840+
"ok"
1841+
"HTTP/1.1 200 OK\r\n", "ok", true);
1842+
1843+
check(
1844+
"HTTP/1.1 200 OK\r\n"
1845+
"Content-Length: 2\r\n"
1846+
"\r\n"
1847+
"okX", "ok", true);
1848+
1849+
check(
1850+
"HTTP/1.1 200 OK\r\n"
1851+
"Transfer-Encoding: chunked\r\n"
1852+
"\r\n"
1853+
"2\r\nok\r\n0\r\n\r\n", "ok", false);
1854+
1855+
check(
1856+
"HTTP/1.1 200 OK\r\n"
1857+
"Transfer-Encoding: chunked\r\n"
1858+
"\r\n"
1859+
"2\r\nok\r\n0\r\n\r\n"
1860+
"GARBAGE", "ok", true);
1861+
1862+
check(
1863+
"HTTP/1.1 204 No Content\r\n"
1864+
"\r\n"
1865+
"GARBAGE", "", true);
1866+
1867+
{
1868+
response_parser pr(pcfg);
1869+
pr.reset();
1870+
pr.start();
1871+
core::string_view octets =
1872+
"HTTP/1.1 200 OK\r\n"
1873+
"Content-Length: 10\r\n"
1874+
"\r\n"
1875+
"123"; // body incomplete
1876+
pr.commit(capy::buffer_copy(
1877+
pr.prepare(),
1878+
capy::const_buffer(
1879+
octets.data(), octets.size())));
1880+
system::error_code ec;
1881+
pr.parse(ec);
1882+
BOOST_TEST(pr.got_header());
1883+
pr.parse(ec);
1884+
BOOST_TEST(! pr.is_complete());
1885+
BOOST_TEST(! pr.has_buffered_data());
1886+
}
1887+
}
1888+
17951889
void
17961890
run()
17971891
{
@@ -1809,6 +1903,7 @@ struct parser_test
18091903
testSetBodyLimit();
18101904
testAccessHeaderAfterBodyError();
18111905
testBodyWithTrailingData();
1906+
testHasBufferedData();
18121907
#else
18131908
// For profiling
18141909
for(int i = 0; i < 10000; ++i )

0 commit comments

Comments
 (0)