2017-07-20 08:01:46 -07:00
|
|
|
//
|
2017-02-06 20:07:03 -05:00
|
|
|
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
2017-07-20 08:01:46 -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)
|
|
|
|
//
|
|
|
|
|
|
|
|
// Test that header file is self-contained.
|
|
|
|
#include <beast/http/write.hpp>
|
2016-04-29 06:04:40 -04:00
|
|
|
|
2017-05-08 12:41:45 -07:00
|
|
|
#include <beast/http/buffer_body.hpp>
|
2016-11-10 05:34:49 -05:00
|
|
|
#include <beast/http/fields.hpp>
|
2016-04-29 06:04:40 -04:00
|
|
|
#include <beast/http/message.hpp>
|
2017-05-08 12:41:45 -07:00
|
|
|
#include <beast/http/read.hpp>
|
2016-04-29 06:04:40 -04:00
|
|
|
#include <beast/http/string_body.hpp>
|
2016-05-07 14:57:15 -04:00
|
|
|
#include <beast/core/error.hpp>
|
2017-05-04 15:40:07 -07:00
|
|
|
#include <beast/core/multi_buffer.hpp>
|
2016-05-07 17:06:46 -04:00
|
|
|
#include <beast/test/fail_stream.hpp>
|
2017-05-08 12:41:45 -07:00
|
|
|
#include <beast/test/pipe_stream.hpp>
|
|
|
|
#include <beast/test/string_istream.hpp>
|
2017-01-09 11:13:19 -05:00
|
|
|
#include <beast/test/string_ostream.hpp>
|
2016-05-07 17:06:46 -04:00
|
|
|
#include <beast/test/yield_to.hpp>
|
2016-05-06 19:14:17 -04:00
|
|
|
#include <beast/unit_test/suite.hpp>
|
2016-04-29 06:04:40 -04:00
|
|
|
#include <boost/asio/error.hpp>
|
2016-05-07 17:06:46 -04:00
|
|
|
#include <sstream>
|
2016-04-29 06:04:40 -04:00
|
|
|
#include <string>
|
|
|
|
|
|
|
|
namespace beast {
|
|
|
|
namespace http {
|
|
|
|
|
2016-05-07 17:06:46 -04:00
|
|
|
class write_test
|
|
|
|
: public beast::unit_test::suite
|
|
|
|
, public test::enable_yield_to
|
2016-04-29 06:04:40 -04:00
|
|
|
{
|
|
|
|
public:
|
2016-05-07 17:06:46 -04:00
|
|
|
struct unsized_body
|
2016-04-29 06:04:40 -04:00
|
|
|
{
|
|
|
|
using value_type = std::string;
|
|
|
|
|
2017-05-28 09:05:29 -07:00
|
|
|
class reader
|
2016-04-29 06:04:40 -04:00
|
|
|
{
|
|
|
|
value_type const& body_;
|
|
|
|
|
|
|
|
public:
|
2017-05-08 12:41:45 -07:00
|
|
|
using const_buffers_type =
|
|
|
|
boost::asio::const_buffers_1;
|
|
|
|
|
2016-04-29 06:04:40 -04:00
|
|
|
template<bool isRequest, class Allocator>
|
|
|
|
explicit
|
2017-06-25 08:28:41 -07:00
|
|
|
reader(message<isRequest, unsized_body,
|
|
|
|
Allocator> const& msg, error_code &ec)
|
2016-05-06 21:51:43 -04:00
|
|
|
: body_(msg.body)
|
|
|
|
{
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2016-05-06 21:51:43 -04:00
|
|
|
}
|
2017-05-08 12:41:45 -07:00
|
|
|
|
|
|
|
boost::optional<std::pair<const_buffers_type, bool>>
|
2017-06-13 07:08:52 -07:00
|
|
|
get(error_code& ec)
|
2017-05-08 12:41:45 -07:00
|
|
|
{
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2017-05-08 12:41:45 -07:00
|
|
|
return {{const_buffers_type{
|
|
|
|
body_.data(), body_.size()}, false}};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
template<
|
|
|
|
bool isSplit,
|
|
|
|
bool isFinalEmpty
|
|
|
|
>
|
|
|
|
struct test_body
|
|
|
|
{
|
|
|
|
struct value_type
|
|
|
|
{
|
|
|
|
std::string s;
|
|
|
|
bool mutable read = false;
|
|
|
|
};
|
|
|
|
|
2017-05-28 09:05:29 -07:00
|
|
|
class reader
|
2017-05-08 12:41:45 -07:00
|
|
|
{
|
|
|
|
int step_ = 0;
|
|
|
|
value_type const& body_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
using const_buffers_type =
|
|
|
|
boost::asio::const_buffers_1;
|
|
|
|
|
|
|
|
template<bool isRequest, class Fields>
|
|
|
|
explicit
|
2017-05-28 09:05:29 -07:00
|
|
|
reader(message<isRequest, test_body,
|
2017-06-25 08:28:41 -07:00
|
|
|
Fields> const& msg, error_code& ec)
|
2017-05-08 12:41:45 -07:00
|
|
|
: body_(msg.body)
|
|
|
|
{
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2017-05-08 12:41:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
boost::optional<std::pair<const_buffers_type, bool>>
|
2017-06-13 07:08:52 -07:00
|
|
|
get(error_code& ec)
|
2017-05-08 12:41:45 -07:00
|
|
|
{
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2017-05-08 12:41:45 -07:00
|
|
|
body_.read = true;
|
|
|
|
return get(
|
|
|
|
std::integral_constant<bool, isSplit>{},
|
|
|
|
std::integral_constant<bool, isFinalEmpty>{});
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
boost::optional<std::pair<const_buffers_type, bool>>
|
|
|
|
get(
|
|
|
|
std::false_type, // isSplit
|
|
|
|
std::false_type) // isFinalEmpty
|
|
|
|
{
|
|
|
|
using boost::asio::buffer;
|
|
|
|
if(body_.s.empty())
|
|
|
|
return boost::none;
|
|
|
|
return {{buffer(body_.s.data(), body_.s.size()), false}};
|
|
|
|
}
|
2016-05-06 21:51:43 -04:00
|
|
|
|
2017-05-08 12:41:45 -07:00
|
|
|
boost::optional<std::pair<const_buffers_type, bool>>
|
|
|
|
get(
|
|
|
|
std::false_type, // isSplit
|
|
|
|
std::true_type) // isFinalEmpty
|
2016-05-06 21:51:43 -04:00
|
|
|
{
|
2017-05-08 12:41:45 -07:00
|
|
|
using boost::asio::buffer;
|
|
|
|
if(body_.s.empty())
|
|
|
|
return boost::none;
|
|
|
|
switch(step_)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
step_ = 1;
|
|
|
|
return {{buffer(
|
|
|
|
body_.s.data(), body_.s.size()), true}};
|
|
|
|
default:
|
|
|
|
return boost::none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::optional<std::pair<const_buffers_type, bool>>
|
|
|
|
get(
|
|
|
|
std::true_type, // isSplit
|
|
|
|
std::false_type) // isFinalEmpty
|
|
|
|
{
|
|
|
|
using boost::asio::buffer;
|
|
|
|
auto const n = (body_.s.size() + 1) / 2;
|
|
|
|
switch(step_)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if(n == 0)
|
|
|
|
return boost::none;
|
|
|
|
step_ = 1;
|
|
|
|
return {{buffer(body_.s.data(), n),
|
|
|
|
body_.s.size() > 1}};
|
|
|
|
default:
|
|
|
|
return {{buffer(body_.s.data() + n,
|
|
|
|
body_.s.size() - n), false}};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::optional<std::pair<const_buffers_type, bool>>
|
|
|
|
get(
|
|
|
|
std::true_type, // isSplit
|
|
|
|
std::true_type) // isFinalEmpty
|
|
|
|
{
|
|
|
|
using boost::asio::buffer;
|
|
|
|
auto const n = (body_.s.size() + 1) / 2;
|
|
|
|
switch(step_)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if(n == 0)
|
|
|
|
return boost::none;
|
|
|
|
step_ = body_.s.size() > 1 ? 1 : 2;
|
|
|
|
return {{buffer(body_.s.data(), n), true}};
|
|
|
|
case 1:
|
|
|
|
BOOST_ASSERT(body_.s.size() > 1);
|
|
|
|
step_ = 2;
|
|
|
|
return {{buffer(body_.s.data() + n,
|
|
|
|
body_.s.size() - n), true}};
|
|
|
|
default:
|
|
|
|
return boost::none;
|
|
|
|
}
|
2016-05-06 21:51:43 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2016-05-07 17:06:46 -04:00
|
|
|
struct fail_body
|
2016-05-06 21:51:43 -04:00
|
|
|
{
|
2017-05-28 09:05:29 -07:00
|
|
|
class reader;
|
2016-05-07 17:06:46 -04:00
|
|
|
|
|
|
|
class value_type
|
|
|
|
{
|
2017-05-28 09:05:29 -07:00
|
|
|
friend class reader;
|
2016-05-07 17:06:46 -04:00
|
|
|
|
|
|
|
std::string s_;
|
|
|
|
test::fail_counter& fc_;
|
|
|
|
|
|
|
|
public:
|
2017-05-08 12:41:45 -07:00
|
|
|
explicit
|
|
|
|
value_type(test::fail_counter& fc)
|
2016-05-07 17:06:46 -04:00
|
|
|
: fc_(fc)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
value_type&
|
|
|
|
operator=(std::string s)
|
|
|
|
{
|
|
|
|
s_ = std::move(s);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
};
|
2016-05-06 21:51:43 -04:00
|
|
|
|
2017-05-28 09:05:29 -07:00
|
|
|
class reader
|
2016-05-06 21:51:43 -04:00
|
|
|
{
|
2016-05-07 17:06:46 -04:00
|
|
|
std::size_t n_ = 0;
|
2016-05-06 21:51:43 -04:00
|
|
|
value_type const& body_;
|
|
|
|
|
|
|
|
public:
|
2017-05-08 12:41:45 -07:00
|
|
|
using const_buffers_type =
|
|
|
|
boost::asio::const_buffers_1;
|
|
|
|
|
2016-05-06 21:51:43 -04:00
|
|
|
template<bool isRequest, class Allocator>
|
|
|
|
explicit
|
2017-06-25 08:28:41 -07:00
|
|
|
reader(message<isRequest, fail_body,
|
|
|
|
Allocator> const& msg, error_code& ec)
|
2016-04-29 06:04:40 -04:00
|
|
|
: body_(msg.body)
|
|
|
|
{
|
2016-05-07 17:06:46 -04:00
|
|
|
body_.fc_.fail(ec);
|
2016-04-29 06:04:40 -04:00
|
|
|
}
|
|
|
|
|
2017-05-08 12:41:45 -07:00
|
|
|
boost::optional<std::pair<const_buffers_type, bool>>
|
|
|
|
get(error_code& ec)
|
2016-04-29 06:04:40 -04:00
|
|
|
{
|
2016-05-07 17:06:46 -04:00
|
|
|
if(body_.fc_.fail(ec))
|
2017-05-08 12:41:45 -07:00
|
|
|
return boost::none;
|
2016-05-07 17:06:46 -04:00
|
|
|
if(n_ >= body_.s_.size())
|
2017-05-08 12:41:45 -07:00
|
|
|
return boost::none;
|
|
|
|
return {{const_buffers_type{
|
|
|
|
body_.s_.data() + n_++, 1}, true}};
|
2016-04-29 06:04:40 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2017-05-08 12:41:45 -07:00
|
|
|
template<bool isRequest>
|
|
|
|
bool
|
|
|
|
equal_body(string_view sv, string_view body)
|
|
|
|
{
|
|
|
|
test::string_istream si{
|
|
|
|
get_io_service(), sv.to_string()};
|
|
|
|
message<isRequest, string_body, fields> m;
|
|
|
|
multi_buffer b;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
read(si, b, m);
|
|
|
|
return m.body == body;
|
|
|
|
}
|
|
|
|
catch(std::exception const& e)
|
|
|
|
{
|
|
|
|
log << "equal_body: " << e.what() << std::endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-10 05:34:49 -05:00
|
|
|
template<bool isRequest, class Body, class Fields>
|
2016-04-29 06:04:40 -04:00
|
|
|
std::string
|
2016-11-10 05:34:49 -05:00
|
|
|
str(message<isRequest, Body, Fields> const& m)
|
2016-04-29 06:04:40 -04:00
|
|
|
{
|
2017-01-09 11:13:19 -05:00
|
|
|
test::string_ostream ss(ios_);
|
2017-06-19 14:35:32 -07:00
|
|
|
error_code ec;
|
|
|
|
write(ss, m, ec);
|
|
|
|
if(ec && ec != error::end_of_stream)
|
|
|
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
2016-04-29 06:04:40 -04:00
|
|
|
return ss.str;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-05-07 17:06:46 -04:00
|
|
|
testAsyncWrite(yield_context do_yield)
|
|
|
|
{
|
|
|
|
{
|
2017-06-07 16:30:49 -07:00
|
|
|
response<string_body> m;
|
2016-05-07 17:06:46 -04:00
|
|
|
m.version = 10;
|
2017-06-04 12:38:42 -07:00
|
|
|
m.result(status::ok);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.reason("OK");
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::server, "test");
|
2017-06-05 19:28:17 -07:00
|
|
|
m.insert("Content-Length", "5");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.body = "*****";
|
|
|
|
error_code ec;
|
2017-01-09 11:13:19 -05:00
|
|
|
test::string_ostream ss{ios_};
|
2016-05-07 17:06:46 -04:00
|
|
|
async_write(ss, m, do_yield[ec]);
|
2017-06-19 14:35:32 -07:00
|
|
|
if(BEAST_EXPECTS(ec == error::end_of_stream, ec.message()))
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(ss.str ==
|
2016-05-07 17:06:46 -04:00
|
|
|
"HTTP/1.0 200 OK\r\n"
|
|
|
|
"Server: test\r\n"
|
|
|
|
"Content-Length: 5\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"*****");
|
|
|
|
}
|
|
|
|
{
|
2017-06-07 16:30:49 -07:00
|
|
|
response<string_body> m;
|
2016-05-07 17:06:46 -04:00
|
|
|
m.version = 11;
|
2017-06-04 12:38:42 -07:00
|
|
|
m.result(status::ok);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.reason("OK");
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::server, "test");
|
2017-06-05 19:28:17 -07:00
|
|
|
m.insert("Transfer-Encoding", "chunked");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.body = "*****";
|
|
|
|
error_code ec;
|
2017-01-09 11:13:19 -05:00
|
|
|
test::string_ostream ss(ios_);
|
2016-05-07 17:06:46 -04:00
|
|
|
async_write(ss, m, do_yield[ec]);
|
2016-08-29 13:28:08 -04:00
|
|
|
if(BEAST_EXPECTS(! ec, ec.message()))
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(ss.str ==
|
2016-05-07 17:06:46 -04:00
|
|
|
"HTTP/1.1 200 OK\r\n"
|
|
|
|
"Server: test\r\n"
|
|
|
|
"Transfer-Encoding: chunked\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"5\r\n"
|
|
|
|
"*****\r\n"
|
|
|
|
"0\r\n\r\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
testFailures(yield_context do_yield)
|
|
|
|
{
|
|
|
|
static std::size_t constexpr limit = 100;
|
|
|
|
std::size_t n;
|
|
|
|
|
|
|
|
for(n = 0; n < limit; ++n)
|
|
|
|
{
|
|
|
|
test::fail_counter fc(n);
|
|
|
|
test::fail_stream<
|
2017-01-09 11:13:19 -05:00
|
|
|
test::string_ostream> fs(fc, ios_);
|
2017-06-07 16:30:49 -07:00
|
|
|
request<fail_body> m{fc};
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.version = 10;
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::user_agent, "test");
|
2017-06-19 14:35:32 -07:00
|
|
|
m.set(field::connection, "keep-alive");
|
|
|
|
m.set(field::content_length, "5");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.body = "*****";
|
|
|
|
try
|
|
|
|
{
|
|
|
|
write(fs, m);
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(fs.next_layer().str ==
|
2016-05-07 17:06:46 -04:00
|
|
|
"GET / HTTP/1.0\r\n"
|
|
|
|
"User-Agent: test\r\n"
|
2017-06-19 14:35:32 -07:00
|
|
|
"Connection: keep-alive\r\n"
|
2016-05-07 17:06:46 -04:00
|
|
|
"Content-Length: 5\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"*****"
|
|
|
|
);
|
|
|
|
pass();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
catch(std::exception const&)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(n < limit);
|
2016-05-07 17:06:46 -04:00
|
|
|
|
|
|
|
for(n = 0; n < limit; ++n)
|
|
|
|
{
|
|
|
|
test::fail_counter fc(n);
|
|
|
|
test::fail_stream<
|
2017-01-09 11:13:19 -05:00
|
|
|
test::string_ostream> fs(fc, ios_);
|
2017-06-07 16:30:49 -07:00
|
|
|
request<fail_body> m{fc};
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.version = 10;
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::user_agent, "test");
|
2017-06-05 19:28:17 -07:00
|
|
|
m.insert("Transfer-Encoding", "chunked");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.body = "*****";
|
2017-06-13 07:23:58 -07:00
|
|
|
error_code ec = test::error::fail_error;
|
2016-05-07 17:06:46 -04:00
|
|
|
write(fs, m, ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec == error::end_of_stream)
|
2016-05-07 17:06:46 -04:00
|
|
|
{
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(fs.next_layer().str ==
|
2016-05-07 17:06:46 -04:00
|
|
|
"GET / HTTP/1.0\r\n"
|
|
|
|
"User-Agent: test\r\n"
|
|
|
|
"Transfer-Encoding: chunked\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"1\r\n*\r\n"
|
|
|
|
"1\r\n*\r\n"
|
|
|
|
"1\r\n*\r\n"
|
|
|
|
"1\r\n*\r\n"
|
|
|
|
"1\r\n*\r\n"
|
|
|
|
"0\r\n\r\n"
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(n < limit);
|
2016-05-07 17:06:46 -04:00
|
|
|
|
|
|
|
for(n = 0; n < limit; ++n)
|
|
|
|
{
|
|
|
|
test::fail_counter fc(n);
|
|
|
|
test::fail_stream<
|
2017-01-09 11:13:19 -05:00
|
|
|
test::string_ostream> fs(fc, ios_);
|
2017-06-07 16:30:49 -07:00
|
|
|
request<fail_body> m{fc};
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.version = 10;
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::user_agent, "test");
|
2017-06-05 19:28:17 -07:00
|
|
|
m.insert("Transfer-Encoding", "chunked");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.body = "*****";
|
2017-06-13 07:23:58 -07:00
|
|
|
error_code ec = test::error::fail_error;
|
2016-05-07 17:06:46 -04:00
|
|
|
async_write(fs, m, do_yield[ec]);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec == error::end_of_stream)
|
2016-05-07 17:06:46 -04:00
|
|
|
{
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(fs.next_layer().str ==
|
2016-05-07 17:06:46 -04:00
|
|
|
"GET / HTTP/1.0\r\n"
|
|
|
|
"User-Agent: test\r\n"
|
|
|
|
"Transfer-Encoding: chunked\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"1\r\n*\r\n"
|
|
|
|
"1\r\n*\r\n"
|
|
|
|
"1\r\n*\r\n"
|
|
|
|
"1\r\n*\r\n"
|
|
|
|
"1\r\n*\r\n"
|
|
|
|
"0\r\n\r\n"
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(n < limit);
|
2016-05-07 17:06:46 -04:00
|
|
|
|
|
|
|
for(n = 0; n < limit; ++n)
|
|
|
|
{
|
|
|
|
test::fail_counter fc(n);
|
|
|
|
test::fail_stream<
|
2017-01-09 11:13:19 -05:00
|
|
|
test::string_ostream> fs(fc, ios_);
|
2017-06-07 16:30:49 -07:00
|
|
|
request<fail_body> m{fc};
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.version = 10;
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::user_agent, "test");
|
2017-06-19 14:35:32 -07:00
|
|
|
m.set(field::connection, "keep-alive");
|
|
|
|
m.set(field::content_length, "5");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.body = "*****";
|
2017-06-13 07:23:58 -07:00
|
|
|
error_code ec = test::error::fail_error;
|
2016-05-07 17:06:46 -04:00
|
|
|
write(fs, m, ec);
|
|
|
|
if(! ec)
|
|
|
|
{
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(fs.next_layer().str ==
|
2016-05-07 17:06:46 -04:00
|
|
|
"GET / HTTP/1.0\r\n"
|
|
|
|
"User-Agent: test\r\n"
|
2017-06-19 14:35:32 -07:00
|
|
|
"Connection: keep-alive\r\n"
|
2016-05-07 17:06:46 -04:00
|
|
|
"Content-Length: 5\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"*****"
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(n < limit);
|
2016-05-07 17:06:46 -04:00
|
|
|
|
|
|
|
for(n = 0; n < limit; ++n)
|
|
|
|
{
|
|
|
|
test::fail_counter fc(n);
|
|
|
|
test::fail_stream<
|
2017-01-09 11:13:19 -05:00
|
|
|
test::string_ostream> fs(fc, ios_);
|
2017-06-07 16:30:49 -07:00
|
|
|
request<fail_body> m{fc};
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.version = 10;
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::user_agent, "test");
|
2017-06-19 14:35:32 -07:00
|
|
|
m.set(field::connection, "keep-alive");
|
|
|
|
m.set(field::content_length, "5");
|
2016-05-07 17:06:46 -04:00
|
|
|
m.body = "*****";
|
2017-06-13 07:23:58 -07:00
|
|
|
error_code ec = test::error::fail_error;
|
2016-05-07 17:06:46 -04:00
|
|
|
async_write(fs, m, do_yield[ec]);
|
|
|
|
if(! ec)
|
|
|
|
{
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(fs.next_layer().str ==
|
2016-05-07 17:06:46 -04:00
|
|
|
"GET / HTTP/1.0\r\n"
|
|
|
|
"User-Agent: test\r\n"
|
2017-06-19 14:35:32 -07:00
|
|
|
"Connection: keep-alive\r\n"
|
2016-05-07 17:06:46 -04:00
|
|
|
"Content-Length: 5\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"*****"
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(n < limit);
|
2016-05-07 17:06:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
testOutput()
|
2016-04-29 06:04:40 -04:00
|
|
|
{
|
|
|
|
// auto content-length HTTP/1.0
|
|
|
|
{
|
2017-06-07 16:30:49 -07:00
|
|
|
request<string_body> m;
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2016-05-07 15:18:22 -04:00
|
|
|
m.version = 10;
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::user_agent, "test");
|
2016-04-29 06:04:40 -04:00
|
|
|
m.body = "*";
|
2017-06-19 15:37:39 -07:00
|
|
|
m.prepare_payload();
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(str(m) ==
|
2016-04-29 06:04:40 -04:00
|
|
|
"GET / HTTP/1.0\r\n"
|
|
|
|
"User-Agent: test\r\n"
|
|
|
|
"Content-Length: 1\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"*"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
// no content-length HTTP/1.0
|
|
|
|
{
|
2017-06-07 16:30:49 -07:00
|
|
|
request<unsized_body> m;
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2016-05-07 15:18:22 -04:00
|
|
|
m.version = 10;
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::user_agent, "test");
|
2016-04-29 06:04:40 -04:00
|
|
|
m.body = "*";
|
2017-06-19 15:37:39 -07:00
|
|
|
m.prepare_payload();
|
2017-01-09 11:13:19 -05:00
|
|
|
test::string_ostream ss(ios_);
|
2016-04-29 06:04:40 -04:00
|
|
|
error_code ec;
|
|
|
|
write(ss, m, ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
BEAST_EXPECT(ec == error::end_of_stream);
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(ss.str ==
|
2016-04-29 06:04:40 -04:00
|
|
|
"GET / HTTP/1.0\r\n"
|
|
|
|
"User-Agent: test\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"*"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
// auto content-length HTTP/1.1
|
|
|
|
{
|
2017-06-07 16:30:49 -07:00
|
|
|
request<string_body> m;
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2016-05-07 15:18:22 -04:00
|
|
|
m.version = 11;
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::user_agent, "test");
|
2016-04-29 06:04:40 -04:00
|
|
|
m.body = "*";
|
2017-06-19 15:37:39 -07:00
|
|
|
m.prepare_payload();
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(str(m) ==
|
2016-04-29 06:04:40 -04:00
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
"User-Agent: test\r\n"
|
|
|
|
"Content-Length: 1\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"*"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
// no content-length HTTP/1.1
|
|
|
|
{
|
2017-06-07 16:30:49 -07:00
|
|
|
request<unsized_body> m;
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2016-05-07 15:18:22 -04:00
|
|
|
m.version = 11;
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::user_agent, "test");
|
2016-04-29 06:04:40 -04:00
|
|
|
m.body = "*";
|
2017-06-19 15:37:39 -07:00
|
|
|
m.prepare_payload();
|
2017-01-09 11:13:19 -05:00
|
|
|
test::string_ostream ss(ios_);
|
2016-04-29 06:04:40 -04:00
|
|
|
error_code ec;
|
|
|
|
write(ss, m, ec);
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(ss.str ==
|
2016-04-29 06:04:40 -04:00
|
|
|
"GET / HTTP/1.1\r\n"
|
|
|
|
"User-Agent: test\r\n"
|
|
|
|
"Transfer-Encoding: chunked\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"1\r\n"
|
|
|
|
"*\r\n"
|
|
|
|
"0\r\n\r\n"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-07 13:51:10 -05:00
|
|
|
void test_std_ostream()
|
2016-04-29 06:04:40 -04:00
|
|
|
{
|
2016-11-07 13:51:10 -05:00
|
|
|
// Conversion to std::string via operator<<
|
2017-06-07 16:30:49 -07:00
|
|
|
request<string_body> m;
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2016-05-07 15:18:22 -04:00
|
|
|
m.version = 11;
|
2017-06-06 12:49:03 -07:00
|
|
|
m.insert(field::user_agent, "test");
|
2016-04-29 06:04:40 -04:00
|
|
|
m.body = "*";
|
2016-08-03 15:34:23 -04:00
|
|
|
BEAST_EXPECT(boost::lexical_cast<std::string>(m) ==
|
2016-11-07 13:51:10 -05:00
|
|
|
"GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n*");
|
2016-05-07 17:06:46 -04:00
|
|
|
}
|
|
|
|
|
2017-03-31 10:12:58 -04:00
|
|
|
// Ensure completion handlers are not leaked
|
|
|
|
struct handler
|
|
|
|
{
|
|
|
|
static std::atomic<std::size_t>&
|
|
|
|
count() { static std::atomic<std::size_t> n; return n; }
|
|
|
|
handler() { ++count(); }
|
|
|
|
~handler() { --count(); }
|
|
|
|
handler(handler const&) { ++count(); }
|
|
|
|
void operator()(error_code const&) const {}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
testIoService()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Make sure handlers are not destroyed
|
|
|
|
// after calling io_service::stop
|
|
|
|
boost::asio::io_service ios;
|
|
|
|
test::string_ostream os{ios};
|
|
|
|
BEAST_EXPECT(handler::count() == 0);
|
2017-06-07 16:30:49 -07:00
|
|
|
request<string_body> m;
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-03-31 10:12:58 -04:00
|
|
|
m.version = 11;
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2017-06-05 19:28:17 -07:00
|
|
|
m.insert("Content-Length", 5);
|
2017-03-31 10:12:58 -04:00
|
|
|
m.body = "*****";
|
|
|
|
async_write(os, m, handler{});
|
|
|
|
BEAST_EXPECT(handler::count() > 0);
|
|
|
|
ios.stop();
|
|
|
|
BEAST_EXPECT(handler::count() > 0);
|
|
|
|
ios.reset();
|
|
|
|
BEAST_EXPECT(handler::count() > 0);
|
|
|
|
ios.run_one();
|
|
|
|
BEAST_EXPECT(handler::count() == 0);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// Make sure uninvoked handlers are
|
|
|
|
// destroyed when calling ~io_service
|
|
|
|
{
|
|
|
|
boost::asio::io_service ios;
|
|
|
|
test::string_ostream is{ios};
|
|
|
|
BEAST_EXPECT(handler::count() == 0);
|
2017-06-07 16:30:49 -07:00
|
|
|
request<string_body> m;
|
2017-05-30 06:58:40 -07:00
|
|
|
m.method(verb::get);
|
2017-03-31 10:12:58 -04:00
|
|
|
m.version = 11;
|
2017-05-02 15:49:22 -07:00
|
|
|
m.target("/");
|
2017-06-05 19:28:17 -07:00
|
|
|
m.insert("Content-Length", 5);
|
2017-03-31 10:12:58 -04:00
|
|
|
m.body = "*****";
|
|
|
|
async_write(is, m, handler{});
|
|
|
|
BEAST_EXPECT(handler::count() > 0);
|
|
|
|
}
|
|
|
|
BEAST_EXPECT(handler::count() == 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-08 12:41:45 -07:00
|
|
|
template<class Stream,
|
|
|
|
bool isRequest, class Body, class Fields,
|
2017-06-03 06:49:11 -07:00
|
|
|
class Decorator = no_chunk_decorator>
|
2017-05-08 12:41:45 -07:00
|
|
|
void
|
|
|
|
do_write(Stream& stream, message<
|
|
|
|
isRequest, Body, Fields> const& m, error_code& ec,
|
|
|
|
Decorator const& decorator = Decorator{})
|
|
|
|
{
|
2017-06-22 10:27:45 -07:00
|
|
|
serializer<isRequest, Body, Fields, Decorator> sr{m, decorator};
|
2017-05-08 12:41:45 -07:00
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
stream.nwrite = 0;
|
2017-05-28 17:04:39 -07:00
|
|
|
write_some(stream, sr, ec);
|
2017-05-08 12:41:45 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
BEAST_EXPECT(stream.nwrite <= 1);
|
2017-05-28 17:04:39 -07:00
|
|
|
if(sr.is_done())
|
2017-05-08 12:41:45 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class Stream,
|
|
|
|
bool isRequest, class Body, class Fields,
|
2017-06-03 06:49:11 -07:00
|
|
|
class Decorator = no_chunk_decorator>
|
2017-05-08 12:41:45 -07:00
|
|
|
void
|
|
|
|
do_async_write(Stream& stream,
|
|
|
|
message<isRequest, Body, Fields> const& m,
|
|
|
|
error_code& ec, yield_context yield,
|
|
|
|
Decorator const& decorator = Decorator{})
|
|
|
|
{
|
2017-06-22 10:27:45 -07:00
|
|
|
serializer<isRequest, Body, Fields, Decorator> sr{m, decorator};
|
2017-05-08 12:41:45 -07:00
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
stream.nwrite = 0;
|
2017-05-28 17:04:39 -07:00
|
|
|
async_write_some(stream, sr, yield[ec]);
|
2017-05-08 12:41:45 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
BEAST_EXPECT(stream.nwrite <= 1);
|
2017-05-28 17:04:39 -07:00
|
|
|
if(sr.is_done())
|
2017-05-08 12:41:45 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct test_decorator
|
|
|
|
{
|
2017-06-03 06:49:11 -07:00
|
|
|
std::string s;
|
|
|
|
|
2017-05-08 12:41:45 -07:00
|
|
|
template<class ConstBufferSequence>
|
|
|
|
string_view
|
2017-06-03 06:49:11 -07:00
|
|
|
operator()(ConstBufferSequence const& buffers)
|
2017-05-08 12:41:45 -07:00
|
|
|
{
|
2017-06-03 06:49:11 -07:00
|
|
|
s = ";x=" + std::to_string(boost::asio::buffer_size(buffers));
|
|
|
|
return s;
|
2017-05-08 12:41:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
string_view
|
2017-06-03 06:49:11 -07:00
|
|
|
operator()(boost::asio::null_buffers)
|
2017-05-08 12:41:45 -07:00
|
|
|
{
|
2017-06-03 06:49:11 -07:00
|
|
|
return "Result: OK\r\n";
|
2017-05-08 12:41:45 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class Body>
|
|
|
|
void
|
|
|
|
testWriteStream(boost::asio::yield_context yield)
|
|
|
|
{
|
|
|
|
test::pipe p{ios_};
|
|
|
|
p.client.write_size(3);
|
|
|
|
|
2017-06-07 16:30:49 -07:00
|
|
|
response<Body> m0;
|
2017-05-08 12:41:45 -07:00
|
|
|
m0.version = 11;
|
2017-06-04 12:38:42 -07:00
|
|
|
m0.result(status::ok);
|
2017-05-08 12:41:45 -07:00
|
|
|
m0.reason("OK");
|
2017-06-06 12:49:03 -07:00
|
|
|
m0.insert(field::server, "test");
|
2017-05-08 12:41:45 -07:00
|
|
|
m0.body.s = "Hello, world!\n";
|
|
|
|
|
|
|
|
{
|
|
|
|
std::string const result =
|
|
|
|
"HTTP/1.1 200 OK\r\n"
|
|
|
|
"Server: test\r\n"
|
|
|
|
"\r\n"
|
|
|
|
"Hello, world!\n";
|
|
|
|
{
|
|
|
|
auto m = m0;
|
|
|
|
error_code ec;
|
|
|
|
do_write(p.client, m, ec);
|
|
|
|
BEAST_EXPECT(p.server.str() == result);
|
|
|
|
BEAST_EXPECT(equal_body<false>(
|
|
|
|
p.server.str(), m.body.s));
|
|
|
|
p.server.clear();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto m = m0;
|
|
|
|
error_code ec;
|
|
|
|
do_async_write(p.client, m, ec, yield);
|
|
|
|
BEAST_EXPECT(p.server.str() == result);
|
|
|
|
BEAST_EXPECT(equal_body<false>(
|
|
|
|
p.server.str(), m.body.s));
|
|
|
|
p.server.clear();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto m = m0;
|
|
|
|
error_code ec;
|
2017-06-22 22:17:45 -07:00
|
|
|
response_serializer<Body, fields> sr{m};
|
2017-05-28 17:04:39 -07:00
|
|
|
sr.split(true);
|
2017-05-08 12:41:45 -07:00
|
|
|
for(;;)
|
|
|
|
{
|
2017-05-28 17:04:39 -07:00
|
|
|
write_some(p.client, sr);
|
|
|
|
if(sr.is_header_done())
|
2017-05-08 12:41:45 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
BEAST_EXPECT(! m.body.read);
|
|
|
|
p.server.clear();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto m = m0;
|
|
|
|
error_code ec;
|
2017-06-22 22:17:45 -07:00
|
|
|
response_serializer<Body, fields> sr{m};
|
2017-05-28 17:04:39 -07:00
|
|
|
sr.split(true);
|
2017-05-08 12:41:45 -07:00
|
|
|
for(;;)
|
|
|
|
{
|
2017-05-28 17:04:39 -07:00
|
|
|
async_write_some(p.client, sr, yield);
|
|
|
|
if(sr.is_header_done())
|
2017-05-08 12:41:45 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
BEAST_EXPECT(! m.body.read);
|
|
|
|
p.server.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
2017-06-05 19:28:17 -07:00
|
|
|
m0.insert("Transfer-Encoding", "chunked");
|
2017-05-08 12:41:45 -07:00
|
|
|
{
|
|
|
|
auto m = m0;
|
|
|
|
error_code ec;
|
|
|
|
do_write(p.client, m, ec);
|
|
|
|
BEAST_EXPECT(equal_body<false>(
|
|
|
|
p.server.str(), m.body.s));
|
|
|
|
p.server.clear();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto m = m0;
|
|
|
|
error_code ec;
|
|
|
|
do_write(p.client, m, ec, test_decorator{});
|
|
|
|
BEAST_EXPECT(equal_body<false>(
|
|
|
|
p.server.str(), m.body.s));
|
|
|
|
p.server.clear();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto m = m0;
|
|
|
|
error_code ec;
|
|
|
|
do_async_write(p.client, m, ec, yield);
|
|
|
|
BEAST_EXPECT(equal_body<false>(
|
|
|
|
p.server.str(), m.body.s));
|
|
|
|
p.server.clear();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto m = m0;
|
|
|
|
error_code ec;
|
|
|
|
do_async_write(p.client, m, ec, yield, test_decorator{});
|
|
|
|
BEAST_EXPECT(equal_body<false>(
|
|
|
|
p.server.str(), m.body.s));
|
|
|
|
p.server.clear();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto m = m0;
|
|
|
|
error_code ec;
|
|
|
|
test::string_ostream so{get_io_service(), 3};
|
2017-06-22 22:17:45 -07:00
|
|
|
response_serializer<Body, fields> sr{m};
|
2017-05-28 17:04:39 -07:00
|
|
|
sr.split(true);
|
2017-05-08 12:41:45 -07:00
|
|
|
for(;;)
|
|
|
|
{
|
2017-05-28 17:04:39 -07:00
|
|
|
write_some(p.client, sr);
|
|
|
|
if(sr.is_header_done())
|
2017-05-08 12:41:45 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
BEAST_EXPECT(! m.body.read);
|
|
|
|
p.server.clear();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto m = m0;
|
|
|
|
error_code ec;
|
2017-06-22 22:17:45 -07:00
|
|
|
response_serializer<Body, fields> sr{m};
|
2017-05-28 17:04:39 -07:00
|
|
|
sr.split(true);
|
2017-05-08 12:41:45 -07:00
|
|
|
for(;;)
|
|
|
|
{
|
2017-05-28 17:04:39 -07:00
|
|
|
async_write_some(p.client, sr, yield);
|
|
|
|
if(sr.is_header_done())
|
2017-05-08 12:41:45 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
BEAST_EXPECT(! m.body.read);
|
|
|
|
p.server.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:04:40 -04:00
|
|
|
void run() override
|
|
|
|
{
|
2017-06-19 14:35:32 -07:00
|
|
|
yield_to([&](yield_context yield){ testAsyncWrite(yield); });
|
|
|
|
yield_to([&](yield_context yield){ testFailures(yield); });
|
2016-05-07 17:06:46 -04:00
|
|
|
testOutput();
|
2016-11-07 13:51:10 -05:00
|
|
|
test_std_ostream();
|
2017-03-31 10:12:58 -04:00
|
|
|
testIoService();
|
2017-05-08 12:41:45 -07:00
|
|
|
yield_to(
|
|
|
|
[&](yield_context yield)
|
|
|
|
{
|
2017-06-25 10:14:18 -07:00
|
|
|
testWriteStream<test_body<false, false>>(yield);
|
|
|
|
testWriteStream<test_body<false, true>>(yield);
|
|
|
|
testWriteStream<test_body< true, false>>(yield);
|
|
|
|
testWriteStream<test_body< true, true>>(yield);
|
2017-05-08 12:41:45 -07:00
|
|
|
});
|
2016-04-29 06:04:40 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
BEAST_DEFINE_TESTSUITE(write,http,beast);
|
|
|
|
|
|
|
|
} // http
|
|
|
|
} // beast
|