Files

522 lines
15 KiB
C++
Raw Permalink Normal View History

//
2019-02-21 07:00:31 -08:00
// 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)
//
2017-07-20 13:40:34 -07:00
// Official repository: https://github.com/boostorg/beast
//
2017-07-20 08:01:46 -07:00
// Test that header file is self-contained.
2017-07-20 13:40:34 -07:00
#include <boost/beast/http/message.hpp>
2017-07-20 13:40:34 -07:00
#include <boost/beast/http/empty_body.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/beast/http/fields.hpp>
#include <boost/beast/http/string_body.hpp>
2018-11-11 14:07:55 -08:00
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <type_traits>
2017-07-20 13:40:34 -07:00
namespace boost {
namespace beast {
namespace http {
class message_test : public beast::unit_test::suite
{
public:
struct Arg1
{
bool moved = false;
2017-08-08 07:17:24 -07:00
Arg1(Arg1 const&) = default;
Arg1()
{
}
Arg1(Arg1&& other)
{
other.moved = true;
}
};
struct Arg2 { };
struct Arg3 { };
// default constructible Body
struct default_body
{
using value_type = std::string;
};
// 1-arg constructible Body
struct one_arg_body
{
struct value_type
{
explicit
value_type(Arg1 const&)
{
}
explicit
value_type(Arg1&& arg)
{
Arg1 arg_(std::move(arg));
}
};
};
// 2-arg constructible Body
struct two_arg_body
{
struct value_type
{
value_type(Arg1 const&, Arg2 const&)
{
}
};
};
// 0-arg
BOOST_STATIC_ASSERT(std::is_constructible<
request<default_body>>::value);
// 1-arg
BOOST_STATIC_ASSERT(! std::is_constructible<request<one_arg_body>
>::value);
2016-05-10 21:21:19 -04:00
//BOOST_STATIC_ASSERT(! std::is_constructible<request<one_arg_body>,
// verb, string_view, unsigned>::value);
2016-05-10 21:21:19 -04:00
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>,
verb, string_view, unsigned, Arg1>::value);
2016-05-10 21:21:19 -04:00
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>,
verb, string_view, unsigned, Arg1&&>::value);
2016-05-10 21:21:19 -04:00
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>,
verb, string_view, unsigned, Arg1 const>::value);
2016-05-10 21:21:19 -04:00
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>,
verb, string_view, unsigned, Arg1 const&>::value);
// 1-arg + fields
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>,
verb, string_view, unsigned, Arg1, fields::allocator_type>::value);
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1>>::value);
BOOST_STATIC_ASSERT(std::is_constructible<request<two_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>>::value);
BOOST_STATIC_ASSERT(std::is_constructible<request<two_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>, std::tuple<fields::allocator_type>>::value);
// special members
BOOST_STATIC_ASSERT(std::is_copy_constructible<header<true>>::value);
BOOST_STATIC_ASSERT(std::is_move_constructible<header<true>>::value);
BOOST_STATIC_ASSERT(std::is_copy_assignable<header<true>>::value);
BOOST_STATIC_ASSERT(std::is_move_assignable<header<true>>::value);
BOOST_STATIC_ASSERT(std::is_copy_constructible<header<false>>::value);
BOOST_STATIC_ASSERT(std::is_move_constructible<header<false>>::value);
BOOST_STATIC_ASSERT(std::is_copy_assignable<header<false>>::value);
BOOST_STATIC_ASSERT(std::is_move_assignable<header<false>>::value);
void
testMessage()
{
{
Arg1 arg1;
request<one_arg_body>{verb::get, "/", 11, std::move(arg1)};
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(arg1.moved);
}
{
2017-06-07 16:30:49 -07:00
header<true> h;
h.set(field::user_agent, "test");
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(h[field::user_agent] == "test");
request<default_body> m{std::move(h)};
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(m[field::user_agent] == "test");
BEAST_EXPECT(h.count(field::user_agent) == 0);
}
{
request<empty_body> h{verb::get, "/", 10};
h.set(field::user_agent, "test");
request<one_arg_body> m{std::move(h.base()), Arg1{}};
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(m["User-Agent"] == "test");
BEAST_EXPECT(h.count(http::field::user_agent) == 0);
BEAST_EXPECT(m.method() == verb::get);
BEAST_EXPECT(m.target() == "/");
BEAST_EXPECT(m.version() == 10);
}
// swap
2017-06-07 16:30:49 -07:00
request<string_body> m1;
request<string_body> m2;
m1.target("u");
m1.body() = "1";
2017-06-05 19:28:17 -07:00
m1.insert("h", "v");
2017-06-06 17:26:11 -07:00
m2.method_string("G");
m2.body() = "2";
swap(m1, m2);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(m1.method_string() == "G");
BEAST_EXPECT(m2.method_string().empty());
BEAST_EXPECT(m1.target().empty());
BEAST_EXPECT(m2.target() == "u");
BEAST_EXPECT(m1.body() == "2");
BEAST_EXPECT(m2.body() == "1");
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(! m1.count("h"));
BEAST_EXPECT(m2.count("h"));
}
struct MoveFields : fields
{
bool moved_to = false;
bool moved_from = false;
MoveFields() = default;
MoveFields(MoveFields&& other)
: moved_to(true)
{
other.moved_from = true;
}
2017-06-22 10:27:45 -07:00
MoveFields& operator=(MoveFields&&)
{
return *this;
}
};
struct token {};
struct test_fields
{
std::string target;
test_fields() = delete;
test_fields(token) {}
string_view get_method_impl() const { return {}; }
string_view get_target_impl() const { return target; }
string_view get_reason_impl() const { return {}; }
bool get_chunked_impl() const { return false; }
bool get_keep_alive_impl(unsigned) const { return true; }
bool has_content_length_impl() const { return false; }
void set_method_impl(string_view) {}
void set_target_impl(string_view s) { target = std::string(s); }
void set_reason_impl(string_view) {}
void set_chunked_impl(bool) {}
void set_content_length_impl(boost::optional<std::uint64_t>) {}
void set_keep_alive_impl(unsigned, bool) {}
};
void
testMessageCtors()
{
{
request<empty_body> req;
BEAST_EXPECT(req.version() == 11);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(req.method() == verb::unknown);
BEAST_EXPECT(req.target() == "");
}
{
request<empty_body> req{verb::get, "/", 11};
BEAST_EXPECT(req.version() == 11);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(req.method() == verb::get);
BEAST_EXPECT(req.target() == "/");
}
{
request<string_body> req{verb::get, "/", 11, "Hello"};
BEAST_EXPECT(req.version() == 11);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(req.method() == verb::get);
BEAST_EXPECT(req.target() == "/");
BEAST_EXPECT(req.body() == "Hello");
}
{
request<string_body, test_fields> req{
verb::get, "/", 11, "Hello", token{}};
BEAST_EXPECT(req.version() == 11);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(req.method() == verb::get);
BEAST_EXPECT(req.target() == "/");
BEAST_EXPECT(req.body() == "Hello");
BEAST_EXPECT(! req.has_content_length());
}
{
response<string_body> res;
BEAST_EXPECT(res.version() == 11);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(res.result() == status::ok);
BEAST_EXPECT(res.reason() == "OK");
}
{
response<string_body> res{status::bad_request, 10};
BEAST_EXPECT(res.version() == 10);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(res.result() == status::bad_request);
BEAST_EXPECT(res.reason() == "Bad Request");
}
{
response<string_body> res{status::bad_request, 10, "Hello"};
BEAST_EXPECT(res.version() == 10);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(res.result() == status::bad_request);
BEAST_EXPECT(res.reason() == "Bad Request");
BEAST_EXPECT(res.body() == "Hello");
}
{
response<string_body, test_fields> res{
status::bad_request, 10, "Hello", token{}};
BEAST_EXPECT(res.version() == 10);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(res.result() == status::bad_request);
BEAST_EXPECT(res.reason() == "Bad Request");
BEAST_EXPECT(res.body() == "Hello");
BEAST_EXPECT(! res.has_content_length());
}
}
void
testBody()
{
{
auto f = [](empty_body::value_type&){};
request<empty_body> m;
f(m.body());
}
{
auto f = [](empty_body::value_type const&){};
request<empty_body> const m{};
f(m.body());
f(std::move(m.body()));
}
{
auto f = [](empty_body::value_type&&){};
request<empty_body> m;
f(std::move(m).body());
f(std::move(m.body()));
}
{
auto f = [](empty_body::value_type const&&){};
request<empty_body> const m{};
f(std::move(m.body()));
}
}
void
testSwap()
{
2017-06-07 16:30:49 -07:00
response<string_body> m1;
response<string_body> m2;
m1.result(status::ok);
m1.version(10);
m1.body() = "1";
2017-06-05 19:28:17 -07:00
m1.insert("h", "v");
m2.result(status::not_found);
m2.body() = "2";
m2.version(11);
swap(m1, m2);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(m1.result() == status::not_found);
BEAST_EXPECT(m1.result_int() == 404);
BEAST_EXPECT(m2.result() == status::ok);
BEAST_EXPECT(m2.result_int() == 200);
BEAST_EXPECT(m1.reason() == "Not Found");
BEAST_EXPECT(m2.reason() == "OK");
BEAST_EXPECT(m1.version() == 11);
BEAST_EXPECT(m2.version() == 10);
BEAST_EXPECT(m1.body() == "2");
BEAST_EXPECT(m2.body() == "1");
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(! m1.count("h"));
BEAST_EXPECT(m2.count("h"));
}
void
testSpecialMembers()
{
response<string_body> r1;
response<string_body> r2{r1};
response<string_body> r3{std::move(r2)};
r2 = r3;
r1 = std::move(r2);
[r1]()
{
}();
}
void
testMethod()
{
header<true> h;
auto const vcheck =
[&](verb v)
{
h.method(v);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(h.method() == v);
BEAST_EXPECT(h.method_string() == to_string(v));
};
auto const scheck =
[&](string_view s)
{
2017-06-06 17:26:11 -07:00
h.method_string(s);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(h.method() == string_to_verb(s));
BEAST_EXPECT(h.method_string() == s);
};
vcheck(verb::get);
vcheck(verb::head);
scheck("GET");
scheck("HEAD");
scheck("XYZ");
}
void
testStatus()
{
header<false> h;
h.result(200);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(h.result_int() == 200);
BEAST_EXPECT(h.result() == status::ok);
h.result(status::switching_protocols);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(h.result_int() == 101);
BEAST_EXPECT(h.result() == status::switching_protocols);
h.result(1);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(h.result_int() == 1);
BEAST_EXPECT(h.result() == status::unknown);
}
void
testReason()
{
header<false> h;
h.result(status::ok);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(h.reason() == "OK");
h.reason("Pepe");
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(h.reason() == "Pepe");
h.result(status::not_found);
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(h.reason() == "Pepe");
h.reason({});
2017-07-25 12:35:54 -07:00
BEAST_EXPECT(h.reason() == "Not Found");
}
2017-10-25 18:41:04 -07:00
void
testNeedEof()
{
{
request<empty_body> m;
m.version(10);
m.keep_alive(false);
BEAST_EXPECT(m.need_eof());
m.keep_alive(true);
BEAST_EXPECT(! m.need_eof());
m.version(11);
m.keep_alive(false);
BEAST_EXPECT(m.need_eof());
m.keep_alive(true);
BEAST_EXPECT(! m.need_eof());
}
{
response<empty_body> m;
m.result(status::ok);
m.version(10);
m.keep_alive(false);
BEAST_EXPECT(! m.has_content_length());
BEAST_EXPECT(! m.chunked());
m.result(status::no_content);
BEAST_EXPECT(m.need_eof());
m.result(status::not_modified);
BEAST_EXPECT(m.need_eof());
m.result(status::continue_);
BEAST_EXPECT(m.need_eof());
m.result(status::switching_protocols);
BEAST_EXPECT(m.need_eof());
m.result(status::ok);
BEAST_EXPECT(m.need_eof());
m.version(10);
m.keep_alive(true);
BEAST_EXPECT(! m.has_content_length());
BEAST_EXPECT(! m.chunked());
m.result(status::no_content);
BEAST_EXPECT(! m.need_eof());
m.result(status::not_modified);
BEAST_EXPECT(! m.need_eof());
m.result(status::continue_);
BEAST_EXPECT(! m.need_eof());
m.result(status::switching_protocols);
BEAST_EXPECT(! m.need_eof());
m.result(status::ok);
BEAST_EXPECT(m.need_eof());
m.set(field::content_length, "1");
BEAST_EXPECT(! m.need_eof());
}
{
response<empty_body> m;
m.result(status::ok);
m.version(11);
m.keep_alive(false);
BEAST_EXPECT(! m.has_content_length());
BEAST_EXPECT(! m.chunked());
m.result(status::no_content);
BEAST_EXPECT(m.need_eof());
m.result(status::not_modified);
BEAST_EXPECT(m.need_eof());
m.result(status::continue_);
BEAST_EXPECT(m.need_eof());
m.result(status::switching_protocols);
BEAST_EXPECT(m.need_eof());
m.result(status::ok);
BEAST_EXPECT(m.need_eof());
m.chunked(true);
BEAST_EXPECT(m.need_eof());
m.content_length(1);
BEAST_EXPECT(m.need_eof());
}
{
response<empty_body> m;
m.result(status::ok);
m.version(11);
m.keep_alive(true);
BEAST_EXPECT(! m.has_content_length());
BEAST_EXPECT(! m.chunked());
m.result(status::no_content);
BEAST_EXPECT(! m.need_eof());
m.result(status::not_modified);
BEAST_EXPECT(! m.need_eof());
m.result(status::continue_);
BEAST_EXPECT(! m.need_eof());
m.result(status::switching_protocols);
BEAST_EXPECT(! m.need_eof());
m.result(status::ok);
BEAST_EXPECT(m.need_eof());
m.chunked(true);
BEAST_EXPECT(! m.need_eof());
m.content_length(1);
BEAST_EXPECT(! m.need_eof());
}
}
void
run() override
{
testMessage();
testMessageCtors();
testBody();
testSwap();
testSpecialMembers();
testMethod();
testStatus();
testReason();
2017-10-25 18:41:04 -07:00
testNeedEof();
}
};
2017-08-01 17:01:57 -07:00
BEAST_DEFINE_TESTSUITE(beast,http,message);
} // http
} // beast
2017-07-20 13:40:34 -07:00
} // boost