// // Copyright (c) 2016-2017 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) // // Official repository: https://github.com/boostorg/beast // // Test that header file is self-contained. #include #include "message_fuzz.hpp" #include #include #include #include #include #include namespace boost { 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::value); BOOST_STATIC_ASSERT( ! detail::is_chunk_extensions::value); template static std::string to_string(ConstBufferSequence const& buffers) { std::string s; s.reserve(boost::asio::buffer_size(buffers)); for(boost::asio::const_buffer buffer : buffers) s.append( boost::asio::buffer_cast(buffer), boost::asio::buffer_size(buffer)); return s; } template void check(string_view match, Args&&... args) { T t{std::forward(args)...}; BOOST_BEAST_EXPECT(to_string(t) == match); T t2{t}; BOOST_BEAST_EXPECT(to_string(t2) == match); T t3{std::move(t2)}; BOOST_BEAST_EXPECT(to_string(t3) == match); } template void check_fwd(string_view match, Args&&... args) { T t{std::forward(args)...}; BOOST_BEAST_EXPECT(to_string(t) == match); T t2{t}; BOOST_BEAST_EXPECT(to_string(t2) == match); T t3{std::move(t2)}; BOOST_BEAST_EXPECT(to_string(t3) == match); } using cb_t = boost::asio::const_buffers_1; static cb_t cb(string_view s) { return {s.data(), s.size()}; } void testChunkCRLF() { #if ! defined(BOOST_GCC) || BOOST_GCC >= 50000 check("\r\n"); #endif } void testChunkHeader() { check("10\r\n", 16u); check("20;x\r\n", 32u, ";x"); chunk_extensions exts; exts.insert("y"); exts.insert("z"); check("30;y;z\r\n", 48u, exts); { auto exts2 = exts; check_fwd( "30;y;z\r\n", 48u, std::move(exts2)); } check("30;y;z\r\n", 48u, exts, std::allocator{}); { auto exts2 = exts; check( "30;y;z\r\n", 48u, std::move(exts2), std::allocator{}); } } void testChunkBody() { check>( "3\r\n***\r\n", cb("***")); check>( "3;x\r\n***\r\n", cb("***"), ";x"); chunk_extensions exts; exts.insert("y"); exts.insert("z"); check>( "3;y;z\r\n***\r\n", cb("***"), exts); { auto exts2 = exts; check_fwd>( "3;y;z\r\n***\r\n", cb("***"), std::move(exts2)); } check>( "3;y;z\r\n***\r\n", cb("***"), exts, std::allocator{}); { auto exts2 = exts; check_fwd>( "3;y;z\r\n***\r\n", cb("***"), std::move(exts2), std::allocator{}); } } void testChunkFinal() { check>( "0\r\n\r\n"); check>( "0\r\nMD5:ou812\r\n\r\n", cb("MD5:ou812\r\n\r\n")); fields trailers; trailers.set(field::content_md5, "ou812"); check>( "0\r\nContent-MD5: ou812\r\n\r\n", trailers); { auto trailers2 = trailers; check_fwd>( "0\r\nContent-MD5: ou812\r\n\r\n", std::move(trailers2)); } check>( "0\r\nContent-MD5: ou812\r\n\r\n", trailers, std::allocator{}); { auto trailers2 = trailers; check>( "0\r\nContent-MD5: ou812\r\n\r\n", std::move(trailers2), std::allocator{}); } } void testChunkExtensions() { auto const str = [](chunk_extensions const& ce) { std::string s; for(auto const& v : ce) { s.append(v.first.to_string()); s.push_back(','); if(! v.second.empty()) { s.append(v.second.to_string()); s.push_back(','); } } return s; }; chunk_extensions ce; ce.insert("x"); BOOST_BEAST_EXPECT(ce.str() == ";x"); BOOST_BEAST_EXPECT(str(ce) == "x,"); ce.insert("y", "z"); BOOST_BEAST_EXPECT(ce.str() == ";x;y=z"); BOOST_BEAST_EXPECT(str(ce) == "x,y,z,"); ce.insert("z", R"(")"); BOOST_BEAST_EXPECT(ce.str() == R"(;x;y=z;z="\"")"); BOOST_BEAST_EXPECT(str(ce) == R"(x,y,z,z,",)"); ce.insert("p", R"(\)"); BOOST_BEAST_EXPECT(ce.str() == R"(;x;y=z;z="\"";p="\\")"); BOOST_BEAST_EXPECT(str(ce) == R"(x,y,z,z,",p,\,)"); ce.insert("q", R"(1"2\)"); BOOST_BEAST_EXPECT(ce.str() == R"(;x;y=z;z="\"";p="\\";q="1\"2\\")"); BOOST_BEAST_EXPECT(str(ce) == R"(x,y,z,z,",p,\,q,1"2\,)"); } void testParseChunkExtensions() { auto const grind = [&](string_view s) { error_code ec; static_string<200> ss{s}; 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); if(! BOOST_BEAST_EXPECTS(! ec, ec.message())) return; chunk_extensions c3; for(auto const& v : c2) if(v.second.empty()) c3.insert(v.first); else c3.insert(v.first, v.second); BOOST_BEAST_EXPECTS(c2.str() == c3.str(), c3.str()); }); } }; auto const good = [&](string_view s) { error_code ec; chunk_extensions ce; ce.parse(s, ec); BOOST_BEAST_EXPECTS(! ec, ec.message()); grind(s); }; auto const bad = [&](string_view s) { error_code ec; chunk_extensions ce; ce.parse(s, ec); BOOST_BEAST_EXPECT(ec); grind(s); }; chunkExtensionsTest(good, bad); } void run() override { testChunkCRLF(); testChunkHeader(); testChunkBody(); testChunkFinal(); testChunkExtensions(); testParseChunkExtensions(); } }; BOOST_BEAST_DEFINE_TESTSUITE(chunk_encode,http,beast); } // http } // beast } // boost