2017-07-09 20:09:30 -07:00
|
|
|
//
|
2019-02-21 07:00:31 -08:00
|
|
|
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
|
2017-07-09 20:09:30 -07:00
|
|
|
//
|
|
|
|
|
// 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)
|
|
|
|
|
//
|
2017-07-20 13:40:34 -07:00
|
|
|
// Official repository: https://github.com/boostorg/beast
|
|
|
|
|
//
|
2017-07-09 20:09:30 -07:00
|
|
|
|
|
|
|
|
// Test that header file is self-contained.
|
2017-07-20 13:40:34 -07:00
|
|
|
#include <boost/beast/http/chunk_encode.hpp>
|
2017-07-09 20:09:30 -07:00
|
|
|
|
2017-07-12 18:06:36 -07:00
|
|
|
#include "message_fuzz.hpp"
|
|
|
|
|
|
2018-04-24 10:55:39 -07:00
|
|
|
#include <boost/beast/core/buffers_to_string.hpp>
|
2017-07-20 13:40:34 -07:00
|
|
|
#include <boost/beast/core/static_string.hpp>
|
|
|
|
|
#include <boost/beast/http/fields.hpp>
|
|
|
|
|
#include <boost/beast/test/fuzz.hpp>
|
2018-11-11 14:07:55 -08:00
|
|
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
2017-07-09 20:09:30 -07:00
|
|
|
#include <boost/optional.hpp>
|
2017-07-12 18:06:36 -07:00
|
|
|
#include <random>
|
2017-07-09 20:09:30 -07:00
|
|
|
|
2017-07-20 13:40:34 -07:00
|
|
|
namespace boost {
|
2017-07-09 20:09:30 -07:00
|
|
|
namespace beast {
|
|
|
|
|
namespace http {
|
|
|
|
|
|
|
|
|
|
class chunk_encode_test
|
|
|
|
|
: public beast::unit_test::suite
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
struct not_chunk_extensions {};
|
|
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
|
detail::is_chunk_extensions<chunk_extensions>::value);
|
|
|
|
|
|
|
|
|
|
BOOST_STATIC_ASSERT(
|
|
|
|
|
! detail::is_chunk_extensions<not_chunk_extensions>::value);
|
|
|
|
|
|
|
|
|
|
template<class T, class... Args>
|
|
|
|
|
void
|
|
|
|
|
check(string_view match, Args&&... args)
|
|
|
|
|
{
|
2017-08-08 07:17:24 -07:00
|
|
|
T t(std::forward<Args>(args)...);
|
2018-04-24 10:55:39 -07:00
|
|
|
BEAST_EXPECT(buffers_to_string(t) == match);
|
2017-08-08 07:17:24 -07:00
|
|
|
T t2(t);
|
2018-04-24 10:55:39 -07:00
|
|
|
BEAST_EXPECT(buffers_to_string(t2) == match);
|
2017-08-08 07:17:24 -07:00
|
|
|
T t3(std::move(t2));
|
2018-04-24 10:55:39 -07:00
|
|
|
BEAST_EXPECT(buffers_to_string(t3) == match);
|
2017-07-09 20:09:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class T, class... Args>
|
|
|
|
|
void
|
|
|
|
|
check_fwd(string_view match, Args&&... args)
|
|
|
|
|
{
|
2017-08-10 17:44:21 -07:00
|
|
|
T t(std::forward<Args>(args)...);
|
2018-04-24 10:55:39 -07:00
|
|
|
BEAST_EXPECT(buffers_to_string(t) == match);
|
2017-08-10 17:44:21 -07:00
|
|
|
T t2(t);
|
2018-04-24 10:55:39 -07:00
|
|
|
BEAST_EXPECT(buffers_to_string(t2) == match);
|
2017-08-10 17:44:21 -07:00
|
|
|
T t3(std::move(t2));
|
2018-04-24 10:55:39 -07:00
|
|
|
BEAST_EXPECT(buffers_to_string(t3) == match);
|
2017-07-09 20:09:30 -07:00
|
|
|
}
|
|
|
|
|
|
2018-11-30 14:58:38 -08:00
|
|
|
using cb_t = net::const_buffer;
|
2017-07-09 20:09:30 -07:00
|
|
|
|
|
|
|
|
static
|
|
|
|
|
cb_t
|
|
|
|
|
cb(string_view s)
|
|
|
|
|
{
|
|
|
|
|
return {s.data(), s.size()};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testChunkCRLF()
|
|
|
|
|
{
|
|
|
|
|
#if ! defined(BOOST_GCC) || BOOST_GCC >= 50000
|
|
|
|
|
check<chunk_crlf>("\r\n");
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testChunkHeader()
|
|
|
|
|
{
|
|
|
|
|
check<chunk_header>("10\r\n", 16u);
|
|
|
|
|
|
|
|
|
|
check<chunk_header>("20;x\r\n", 32u, ";x");
|
|
|
|
|
|
|
|
|
|
chunk_extensions exts;
|
|
|
|
|
exts.insert("y");
|
|
|
|
|
exts.insert("z");
|
|
|
|
|
|
|
|
|
|
check<chunk_header>("30;y;z\r\n", 48u, exts);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto exts2 = exts;
|
|
|
|
|
|
|
|
|
|
check_fwd<chunk_header>(
|
|
|
|
|
"30;y;z\r\n", 48u, std::move(exts2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check<chunk_header>("30;y;z\r\n", 48u, exts,
|
|
|
|
|
std::allocator<double>{});
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto exts2 = exts;
|
|
|
|
|
|
|
|
|
|
check<chunk_header>(
|
|
|
|
|
"30;y;z\r\n", 48u, std::move(exts2),
|
|
|
|
|
std::allocator<double>{});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testChunkBody()
|
|
|
|
|
{
|
|
|
|
|
check<chunk_body<cb_t>>(
|
|
|
|
|
"3\r\n***\r\n", cb("***"));
|
|
|
|
|
|
|
|
|
|
check<chunk_body<cb_t>>(
|
|
|
|
|
"3;x\r\n***\r\n", cb("***"), ";x");
|
|
|
|
|
|
|
|
|
|
chunk_extensions exts;
|
|
|
|
|
exts.insert("y");
|
|
|
|
|
exts.insert("z");
|
|
|
|
|
|
|
|
|
|
check<chunk_body<cb_t>>(
|
|
|
|
|
"3;y;z\r\n***\r\n",
|
|
|
|
|
cb("***"), exts);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto exts2 = exts;
|
|
|
|
|
|
|
|
|
|
check_fwd<chunk_body<cb_t>>(
|
|
|
|
|
"3;y;z\r\n***\r\n",
|
|
|
|
|
cb("***"), std::move(exts2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check<chunk_body<cb_t>>(
|
|
|
|
|
"3;y;z\r\n***\r\n",
|
|
|
|
|
cb("***"), exts, std::allocator<double>{});
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto exts2 = exts;
|
|
|
|
|
|
|
|
|
|
check_fwd<chunk_body<cb_t>>(
|
|
|
|
|
"3;y;z\r\n***\r\n",
|
|
|
|
|
cb("***"), std::move(exts2),
|
|
|
|
|
std::allocator<double>{});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testChunkFinal()
|
|
|
|
|
{
|
|
|
|
|
check<chunk_last<>>(
|
|
|
|
|
"0\r\n\r\n");
|
|
|
|
|
|
|
|
|
|
check<chunk_last<cb_t>>(
|
|
|
|
|
"0\r\nMD5:ou812\r\n\r\n",
|
|
|
|
|
cb("MD5:ou812\r\n\r\n"));
|
|
|
|
|
|
|
|
|
|
fields trailers;
|
|
|
|
|
trailers.set(field::content_md5, "ou812");
|
|
|
|
|
|
|
|
|
|
check<chunk_last<fields>>(
|
|
|
|
|
"0\r\nContent-MD5: ou812\r\n\r\n",
|
|
|
|
|
trailers);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto trailers2 = trailers;
|
|
|
|
|
|
|
|
|
|
check_fwd<chunk_last<fields>>(
|
|
|
|
|
"0\r\nContent-MD5: ou812\r\n\r\n",
|
|
|
|
|
std::move(trailers2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check<chunk_last<fields>>(
|
|
|
|
|
"0\r\nContent-MD5: ou812\r\n\r\n",
|
|
|
|
|
trailers, std::allocator<double>{});
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
auto trailers2 = trailers;
|
|
|
|
|
|
|
|
|
|
check<chunk_last<fields>>(
|
|
|
|
|
"0\r\nContent-MD5: ou812\r\n\r\n",
|
|
|
|
|
std::move(trailers2), std::allocator<double>{});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testChunkExtensions()
|
|
|
|
|
{
|
2017-07-12 18:06:36 -07:00
|
|
|
auto const str =
|
|
|
|
|
[](chunk_extensions const& ce)
|
|
|
|
|
{
|
|
|
|
|
std::string s;
|
|
|
|
|
for(auto const& v : ce)
|
|
|
|
|
{
|
2019-02-07 23:47:05 +01:00
|
|
|
s.append(std::string(v.first));
|
2017-07-12 18:06:36 -07:00
|
|
|
s.push_back(',');
|
|
|
|
|
if(! v.second.empty())
|
|
|
|
|
{
|
2019-02-07 23:47:05 +01:00
|
|
|
s.append(std::string(v.second));
|
2017-07-12 18:06:36 -07:00
|
|
|
s.push_back(',');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
};
|
2017-07-09 20:09:30 -07:00
|
|
|
chunk_extensions ce;
|
|
|
|
|
ce.insert("x");
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECT(ce.str() == ";x");
|
|
|
|
|
BEAST_EXPECT(str(ce) == "x,");
|
2017-07-09 20:09:30 -07:00
|
|
|
ce.insert("y", "z");
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECT(ce.str() == ";x;y=z");
|
|
|
|
|
BEAST_EXPECT(str(ce) == "x,y,z,");
|
2017-07-09 20:09:30 -07:00
|
|
|
ce.insert("z", R"(")");
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECT(ce.str() == R"(;x;y=z;z="\"")");
|
|
|
|
|
BEAST_EXPECT(str(ce) == R"(x,y,z,z,",)");
|
2017-07-09 20:09:30 -07:00
|
|
|
ce.insert("p", R"(\)");
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECT(ce.str() == R"(;x;y=z;z="\"";p="\\")");
|
|
|
|
|
BEAST_EXPECT(str(ce) == R"(x,y,z,z,",p,\,)");
|
2017-07-09 20:09:30 -07:00
|
|
|
ce.insert("q", R"(1"2\)");
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECT(ce.str() == R"(;x;y=z;z="\"";p="\\";q="1\"2\\")");
|
|
|
|
|
BEAST_EXPECT(str(ce) == R"(x,y,z,z,",p,\,q,1"2\,)");
|
2017-07-12 18:06:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
testParseChunkExtensions()
|
|
|
|
|
{
|
|
|
|
|
auto const grind =
|
|
|
|
|
[&](string_view s)
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
2022-04-16 10:11:24 -04:00
|
|
|
static_string<200> ss(s.data(), s.size());
|
2017-07-12 18:06:36 -07:00
|
|
|
test::fuzz_rand r;
|
|
|
|
|
for(auto i = 3; i--;)
|
|
|
|
|
{
|
|
|
|
|
test::fuzz(ss, 5, 5, r,
|
|
|
|
|
[&](string_view s)
|
|
|
|
|
{
|
|
|
|
|
chunk_extensions c1;
|
|
|
|
|
c1.parse(s, ec);
|
|
|
|
|
if(ec)
|
|
|
|
|
{
|
|
|
|
|
pass();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
chunk_extensions c2;
|
|
|
|
|
c2.parse(c1.str(), ec);
|
2017-07-25 12:35:54 -07:00
|
|
|
if(! BEAST_EXPECTS(! ec, ec.message()))
|
2017-07-12 18:06:36 -07:00
|
|
|
return;
|
|
|
|
|
chunk_extensions c3;
|
|
|
|
|
for(auto const& v : c2)
|
|
|
|
|
if(v.second.empty())
|
|
|
|
|
c3.insert(v.first);
|
|
|
|
|
else
|
|
|
|
|
c3.insert(v.first, v.second);
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECTS(c2.str() == c3.str(), c3.str());
|
2017-07-12 18:06:36 -07:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
auto const good =
|
|
|
|
|
[&](string_view s)
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
chunk_extensions ce;
|
|
|
|
|
ce.parse(s, ec);
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECTS(! ec, ec.message());
|
2017-07-12 18:06:36 -07:00
|
|
|
grind(s);
|
|
|
|
|
};
|
|
|
|
|
auto const bad =
|
|
|
|
|
[&](string_view s)
|
|
|
|
|
{
|
|
|
|
|
error_code ec;
|
|
|
|
|
chunk_extensions ce;
|
|
|
|
|
ce.parse(s, ec);
|
2017-07-25 12:35:54 -07:00
|
|
|
BEAST_EXPECT(ec);
|
2017-07-12 18:06:36 -07:00
|
|
|
grind(s);
|
|
|
|
|
};
|
|
|
|
|
chunkExtensionsTest(good, bad);
|
2017-07-09 20:09:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
run() override
|
|
|
|
|
{
|
|
|
|
|
testChunkCRLF();
|
|
|
|
|
testChunkHeader();
|
|
|
|
|
testChunkBody();
|
|
|
|
|
testChunkFinal();
|
|
|
|
|
testChunkExtensions();
|
2017-07-12 18:06:36 -07:00
|
|
|
testParseChunkExtensions();
|
2017-07-09 20:09:30 -07:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-01 17:01:57 -07:00
|
|
|
BEAST_DEFINE_TESTSUITE(beast,http,chunk_encode);
|
2017-07-09 20:09:30 -07:00
|
|
|
|
|
|
|
|
} // http
|
|
|
|
|
} // beast
|
2017-07-20 13:40:34 -07:00
|
|
|
} // boost
|