//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "message_fuzz.hpp"
#include "test_parser.hpp"
+#include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/buffers_cat.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/buffers_suffix.hpp>
#include <boost/beast/http/parser.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/beast/test/fuzz.hpp>
-#include <boost/beast/unit_test/suite.hpp>
+#include <boost/beast/_experimental/unit_test/suite.hpp>
namespace boost {
namespace beast {
template<class Parser, class ConstBufferSequence, class Test>
typename std::enable_if<
- boost::asio::is_const_buffer_sequence<ConstBufferSequence>::value>::type
+ net::is_const_buffer_sequence<ConstBufferSequence>::value>::type
parsegrind(ConstBufferSequence const& buffers,
Test const& test, bool skip = false)
{
- auto const size = boost::asio::buffer_size(buffers);
+ auto const size = buffer_bytes(buffers);
for(std::size_t i = 1; i < size - 1; ++i)
{
Parser p;
n = p.put(cb, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
continue;
- if(! BEAST_EXPECT(n == boost::asio::buffer_size(cb)))
+ if(! BEAST_EXPECT(n == buffer_bytes(cb)))
continue;
if(p.need_eof())
{
void
parsegrind(string_view msg, Test const& test, bool skip = false)
{
- parsegrind<Parser>(boost::asio::const_buffer{
+ parsegrind<Parser>(net::const_buffer{
msg.data(), msg.size()}, test, skip);
}
template<class Parser, class ConstBufferSequence>
typename std::enable_if<
- boost::asio::is_const_buffer_sequence<ConstBufferSequence>::value>::type
+ net::is_const_buffer_sequence<ConstBufferSequence>::value>::type
parsegrind(ConstBufferSequence const& buffers)
{
parsegrind<Parser>(buffers, [](Parser const&){});
Parser p;
p.eager(true);
error_code ec;
- buffers_suffix<boost::asio::const_buffer> cb{
+ buffers_suffix<net::const_buffer> cb{
boost::in_place_init, msg.data(), msg.size()};
auto n = p.put(buffers_prefix(i, cb), ec);
if(ec == result)
p.eager(true);
error_code ec;
p.put(buffers_cat(
- boost::asio::const_buffer{msg.data(), i},
- boost::asio::const_buffer{
+ net::const_buffer{msg.data(), i},
+ net::const_buffer{
msg.data() + i, msg.size() - i}), ec);
if(! ec)
p.put_eof(ec);
{
{
multi_buffer b;
- ostream(b) <<
+ ostream(b) <<
"POST / HTTP/1.1\r\n"
"Content-Length: 2\r\n"
"\r\n"
}
{
multi_buffer b;
- ostream(b) <<
+ ostream(b) <<
"POST / HTTP/1.1\r\n"
"Content-Length: 2\r\n"
"\r\n"
}
{
multi_buffer b;
- ostream(b) <<
+ ostream(b) <<
"HTTP/1.1 200 OK\r\n"
"\r\n"
"**";
}
{
multi_buffer b;
- ostream(b) <<
+ ostream(b) <<
"POST / HTTP/1.1\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
//--------------------------------------------------------------------------
static
- boost::asio::const_buffer
+ net::const_buffer
buf(string_view s)
{
return {s.data(), s.size()};
}
- template<class ConstBufferSequence, bool isRequest, class Derived>
+ template<class ConstBufferSequence, bool isRequest>
std::size_t
feed(ConstBufferSequence const& buffers,
- basic_parser<isRequest, Derived>& p, error_code& ec)
+ basic_parser<isRequest>& p, error_code& ec)
{
p.eager(true);
return p.put(buffers, ec);
"GET / HTTP/1.1\r\n"
"\r\n"
"die!";
- p.put(boost::asio::buffer(
+ p.put(net::buffer(
s.data(), s.size()), ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
"HTTP/1.1 101 Switching Protocols\r\n"
"Content-Length: 2147483648\r\n"
"\r\n";
- p.put(boost::asio::buffer(
+ p.put(net::buffer(
s.data(), s.size()), ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
error_code ec;
test_parser<false> p;
p.eager(true);
- p.put(boost::asio::const_buffer{
+ p.put(net::const_buffer{
s.data(), s.size()}, ec);
});
};
"HTTP/1.1 200 OK\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
- "0" + s.to_string() + "\r\n"
+ "0" + std::string(s) + "\r\n"
"\r\n";
error_code ec;
test_parser<false> p;
p.eager(true);
- p.put(boost::asio::const_buffer{
+ p.put(net::const_buffer{
msg.data(), msg.size()}, ec);
BEAST_EXPECTS(! ec, ec.message());
grind(msg);
"HTTP/1.1 200 OK\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
- "0" + s.to_string() + "\r\n"
+ "0" + std::string(s) + "\r\n"
"\r\n";
error_code ec;
test_parser<false> p;
p.eager(true);
- p.put(boost::asio::const_buffer{
+ p.put(net::const_buffer{
msg.data(), msg.size()}, ec);
BEAST_EXPECT(ec);
grind(msg);
error_code ec;
test_parser<true> p;
- feed(boost::asio::buffer(buf, sizeof(buf)), p, ec);
+ feed(net::buffer(buf, sizeof(buf)), p, ec);
BEAST_EXPECT(ec);
}
+ void
+ testIssue1211()
+ {
+ using base = detail::basic_parser_base;
+ auto const good =
+ [&](string_view s, std::uint32_t v0)
+ {
+ std::uint64_t v;
+ auto const result =
+ base::parse_dec(s, v);
+ if(BEAST_EXPECTS(result, s))
+ BEAST_EXPECTS(v == v0, s);
+ };
+ auto const bad =
+ [&](string_view s)
+ {
+ std::uint64_t v;
+ auto const result =
+ base::parse_dec(s, v);
+ BEAST_EXPECTS(! result, s);
+ };
+ good("0", 0);
+ good("00", 0);
+ good("001", 1);
+ good("255", 255);
+ good("65535", 65535);
+ good("65536", 65536);
+ good("4294967295", 4294967295);
+ bad ("");
+ bad (" ");
+ bad (" 0");
+ bad ("0 ");
+ bad ("-1");
+ bad ("18446744073709551616"); // max(uint64) + 1
+ }
+
+ void
+ testIssue1267()
+ {
+ using base = detail::basic_parser_base;
+ auto const good =
+ [&](string_view s, std::uint64_t v0)
+ {
+ std::uint64_t v;
+ auto it = s.data();
+ auto const result =
+ base::parse_hex(it, v);
+ if(BEAST_EXPECTS(result, s))
+ BEAST_EXPECTS(v == v0, s);
+ };
+ auto const bad =
+ [&](string_view s)
+ {
+ std::uint64_t v;
+ auto it = s.data();
+ auto const result =
+ base::parse_hex(it, v);
+ BEAST_EXPECTS(! result, s);
+ };
+ good("f\r\n", 15);
+ good("ff\r\n", 255);
+ good("ffff\r\n", 65535);
+ good("ffffffffr\n", 4294967295);
+ good("ffffffffffffffff\r\n", 18446744073709551615ULL);
+ bad ("\r\n");
+ bad ("g\r\n");
+ bad ("10000000000000000\r\n");
+ bad ("ffffffffffffffffffffff\r\n");
+ }
+
+ //--------------------------------------------------------------------------
+
+ // https://github.com/boostorg/beast/issues/1734
+
+ void
+ testIssue1734()
+ {
+ // Ensure more than one buffer, this is to avoid an optimized path in
+ // basic_parser::put(ConstBufferSequence const&,...) which avoids
+ // buffer flattening.
+ auto multibufs = [](multi_buffer::const_buffers_type buffers) {
+ std::vector<net::const_buffer> bs;
+ for (auto b : buffers_range(buffers))
+ bs.push_back(b);
+ while (std::distance(bs.begin(), bs.end()) < 2) {
+ bs.push_back({});
+ }
+ return bs;
+ };
+
+ // Buffers must be bigger than max_stack_buffer to force flattening
+ // in basic_parser::put(ConstBufferSequence const&,...)
+ std::string first_chunk_data(
+ 2 * basic_parser<false>::max_stack_buffer + 1, 'x');
+
+ std::string second_chunk_data_part1(
+ basic_parser<false>::max_stack_buffer + 2, 'x');
+ std::string second_chunk_data_part2(
+ basic_parser<false>::max_stack_buffer + 1, 'x');
+
+ multi_buffer b;
+ parser<false, string_body> p;
+ p.eager(true);
+ error_code ec;
+ std::size_t used;
+
+ ostream(b) <<
+ "HTTP/1.1 200 OK\r\n"
+ "Server: test\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n";
+
+ used = p.put(b.data(), ec);
+ b.consume(used);
+
+ BEAST_EXPECT(net::buffer_size(b.data()) == 0);
+ BEAST_EXPECTS(!ec, ec.message());
+ BEAST_EXPECT(!p.is_done());
+ BEAST_EXPECT(p.is_header_done());
+
+ ostream(b) <<
+ std::hex <<
+ first_chunk_data.size() << "\r\n" <<
+ first_chunk_data << "\r\n";
+
+ // First chunk
+ used = p.put(multibufs(b.data()), ec);
+ b.consume(used);
+
+ BEAST_EXPECTS(ec == error::need_more, ec.message());
+ BEAST_EXPECT(!p.is_done());
+
+ ostream(b) <<
+ std::hex <<
+ (second_chunk_data_part1.size() +
+ second_chunk_data_part2.size() ) << "\r\n" <<
+ second_chunk_data_part1;
+
+ // Second chunk, part 1
+ used = p.put(multibufs(b.data()), ec);
+ b.consume(used);
+
+ BEAST_EXPECTS(!ec, ec.message());
+ BEAST_EXPECT(!p.is_done());
+
+ ostream(b) <<
+ second_chunk_data_part2 << "\r\n"
+ << "0\r\n\r\n";
+
+ // Second chunk, part 2
+ used = p.put(multibufs(b.data()), ec);
+ b.consume(used);
+
+ BEAST_EXPECTS(!ec, ec.message()); // <-- Error: bad chunk
+ if(p.need_eof())
+ {
+ p.put_eof(ec);
+ BEAST_EXPECTS(! ec, ec.message());
+ }
+ BEAST_EXPECT(p.is_done());
+ }
+
//--------------------------------------------------------------------------
void
testIssue692();
testFuzz();
testRegression1();
+ testIssue1211();
+ testIssue1267();
}
};