mirror of
https://github.com/boostorg/beast.git
synced 2025-08-02 14:24:31 +02:00
Use test::stream
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
Version 107:
|
Version 107:
|
||||||
|
|
||||||
|
* Use test::stream
|
||||||
|
|
||||||
WebSocket
|
WebSocket
|
||||||
|
|
||||||
* Fix done state for WebSocket reads
|
* Fix done state for WebSocket reads
|
||||||
|
@@ -11,8 +11,7 @@
|
|||||||
#include <boost/beast/core/buffered_read_stream.hpp>
|
#include <boost/beast/core/buffered_read_stream.hpp>
|
||||||
|
|
||||||
#include <boost/beast/core/multi_buffer.hpp>
|
#include <boost/beast/core/multi_buffer.hpp>
|
||||||
#include <boost/beast/test/fail_stream.hpp>
|
#include <boost/beast/test/stream.hpp>
|
||||||
#include <boost/beast/test/string_istream.hpp>
|
|
||||||
#include <boost/beast/test/yield_to.hpp>
|
#include <boost/beast/test/yield_to.hpp>
|
||||||
#include <boost/beast/unit_test/suite.hpp>
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
@@ -32,35 +31,32 @@ class buffered_read_stream_test
|
|||||||
public:
|
public:
|
||||||
void testSpecialMembers()
|
void testSpecialMembers()
|
||||||
{
|
{
|
||||||
using socket_type = boost::asio::ip::tcp::socket;
|
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
{
|
{
|
||||||
buffered_read_stream<socket_type, multi_buffer> srs(ios);
|
buffered_read_stream<test::stream, multi_buffer> srs(ios);
|
||||||
buffered_read_stream<socket_type, multi_buffer> srs2(std::move(srs));
|
buffered_read_stream<test::stream, multi_buffer> srs2(std::move(srs));
|
||||||
srs = std::move(srs2);
|
srs = std::move(srs2);
|
||||||
BEAST_EXPECT(&srs.get_io_service() == &ios);
|
BEAST_EXPECT(&srs.get_io_service() == &ios);
|
||||||
BEAST_EXPECT(&srs.get_io_service() == &srs2.get_io_service());
|
BEAST_EXPECT(&srs.get_io_service() == &srs2.get_io_service());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
socket_type sock(ios);
|
test::stream ts{ios};
|
||||||
buffered_read_stream<socket_type&, multi_buffer> srs(sock);
|
buffered_read_stream<test::stream&, multi_buffer> srs(ts);
|
||||||
buffered_read_stream<socket_type&, multi_buffer> srs2(std::move(srs));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct loop : std::enable_shared_from_this<loop>
|
struct loop : std::enable_shared_from_this<loop>
|
||||||
{
|
{
|
||||||
using stream_type = test::fail_stream<
|
|
||||||
test::string_istream>;
|
|
||||||
static std::size_t constexpr limit = 100;
|
static std::size_t constexpr limit = 100;
|
||||||
std::string s_;
|
std::string s_;
|
||||||
std::size_t n_ = 0;
|
std::size_t n_ = 0;
|
||||||
std::size_t cap_;
|
std::size_t cap_;
|
||||||
unit_test::suite& suite_;
|
unit_test::suite& suite_;
|
||||||
boost::asio::io_service& ios_;
|
boost::asio::io_service& ios_;
|
||||||
boost::optional<stream_type> fs_;
|
boost::optional<test::stream> ts_;
|
||||||
|
boost::optional<test::fail_counter> fc_;
|
||||||
boost::optional<buffered_read_stream<
|
boost::optional<buffered_read_stream<
|
||||||
stream_type&, multi_buffer>> brs_;
|
test::stream&, multi_buffer>> brs_;
|
||||||
|
|
||||||
loop(
|
loop(
|
||||||
unit_test::suite& suite,
|
unit_test::suite& suite,
|
||||||
@@ -101,8 +97,9 @@ public:
|
|||||||
using boost::asio::buffer;
|
using boost::asio::buffer;
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
s_.resize(13);
|
s_.resize(13);
|
||||||
fs_.emplace(n_, ios_, ", world!");
|
fc_.emplace(n_);
|
||||||
brs_.emplace(*fs_);
|
ts_.emplace(ios_, *fc_, ", world!");
|
||||||
|
brs_.emplace(*ts_);
|
||||||
brs_->buffer().commit(buffer_copy(
|
brs_->buffer().commit(buffer_copy(
|
||||||
brs_->buffer().prepare(5), buffer("Hello", 5)));
|
brs_->buffer().prepare(5), buffer("Hello", 5)));
|
||||||
boost::asio::async_read(*brs_,
|
boost::asio::async_read(*brs_,
|
||||||
@@ -133,10 +130,10 @@ public:
|
|||||||
|
|
||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
test::fail_stream<
|
test::fail_counter fc{n};
|
||||||
test::string_istream> fs(n, ios_, ", world!");
|
test::stream ts(ios_, fc, ", world!");
|
||||||
buffered_read_stream<
|
buffered_read_stream<
|
||||||
decltype(fs)&, multi_buffer> srs(fs);
|
test::stream&, multi_buffer> srs(ts);
|
||||||
srs.buffer().commit(buffer_copy(
|
srs.buffer().commit(buffer_copy(
|
||||||
srs.buffer().prepare(5), buffer("Hello", 5)));
|
srs.buffer().prepare(5), buffer("Hello", 5)));
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
@@ -151,10 +148,10 @@ public:
|
|||||||
|
|
||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
test::fail_stream<
|
test::fail_counter fc{n};
|
||||||
test::string_istream> fs(n, ios_, ", world!");
|
test::stream ts(ios_, fc, ", world!");
|
||||||
buffered_read_stream<
|
buffered_read_stream<
|
||||||
decltype(fs)&, multi_buffer> srs(fs);
|
test::stream&, multi_buffer> srs(ts);
|
||||||
srs.capacity(3);
|
srs.capacity(3);
|
||||||
srs.buffer().commit(buffer_copy(
|
srs.buffer().commit(buffer_copy(
|
||||||
srs.buffer().prepare(5), buffer("Hello", 5)));
|
srs.buffer().prepare(5), buffer("Hello", 5)));
|
||||||
@@ -170,10 +167,10 @@ public:
|
|||||||
|
|
||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
test::fail_stream<
|
test::fail_counter fc{n};
|
||||||
test::string_istream> fs(n, ios_, ", world!");
|
test::stream ts(ios_, fc, ", world!");
|
||||||
buffered_read_stream<
|
buffered_read_stream<
|
||||||
decltype(fs)&, multi_buffer> srs(fs);
|
test::stream&, multi_buffer> srs(ts);
|
||||||
srs.buffer().commit(buffer_copy(
|
srs.buffer().commit(buffer_copy(
|
||||||
srs.buffer().prepare(5), buffer("Hello", 5)));
|
srs.buffer().prepare(5), buffer("Hello", 5)));
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
@@ -189,10 +186,10 @@ public:
|
|||||||
|
|
||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
test::fail_stream<
|
test::fail_counter fc{n};
|
||||||
test::string_istream> fs(n, ios_, ", world!");
|
test::stream ts(ios_, fc, ", world!");
|
||||||
buffered_read_stream<
|
buffered_read_stream<
|
||||||
decltype(fs)&, multi_buffer> srs(fs);
|
test::stream&, multi_buffer> srs(ts);
|
||||||
srs.capacity(3);
|
srs.capacity(3);
|
||||||
srs.buffer().commit(buffer_copy(
|
srs.buffer().commit(buffer_copy(
|
||||||
srs.buffer().prepare(5), buffer("Hello", 5)));
|
srs.buffer().prepare(5), buffer("Hello", 5)));
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
#include <boost/beast/http/parser.hpp>
|
#include <boost/beast/http/parser.hpp>
|
||||||
#include <boost/beast/http/read.hpp>
|
#include <boost/beast/http/read.hpp>
|
||||||
#include <boost/beast/http/write.hpp>
|
#include <boost/beast/http/write.hpp>
|
||||||
#include <boost/beast/test/string_istream.hpp>
|
#include <boost/beast/test/stream.hpp>
|
||||||
#include <boost/beast/unit_test/suite.hpp>
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
@@ -61,10 +61,10 @@ public:
|
|||||||
"Content-Length: 3\r\n"
|
"Content-Length: 3\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"xyz";
|
"xyz";
|
||||||
test::string_istream ss(ios_, s);
|
test::stream ts(ios_, s);
|
||||||
response_parser<dynamic_body> p;
|
response_parser<dynamic_body> p;
|
||||||
multi_buffer b;
|
multi_buffer b;
|
||||||
read(ss, b, p);
|
read(ts, b, p);
|
||||||
auto const& m = p.get();
|
auto const& m = p.get();
|
||||||
BEAST_EXPECT(to_string(m.body.data()) == "xyz");
|
BEAST_EXPECT(to_string(m.body.data()) == "xyz");
|
||||||
BEAST_EXPECT(to_string(m) == s);
|
BEAST_EXPECT(to_string(m) == s);
|
||||||
|
@@ -13,8 +13,6 @@
|
|||||||
#include "test_parser.hpp"
|
#include "test_parser.hpp"
|
||||||
|
|
||||||
#include <boost/beast/unit_test/suite.hpp>
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
#include <boost/beast/test/string_istream.hpp>
|
|
||||||
#include <boost/beast/test/string_ostream.hpp>
|
|
||||||
#include <boost/beast/test/yield_to.hpp>
|
#include <boost/beast/test/yield_to.hpp>
|
||||||
#include <boost/beast/core/consuming_buffers.hpp>
|
#include <boost/beast/core/consuming_buffers.hpp>
|
||||||
#include <boost/beast/core/flat_buffer.hpp>
|
#include <boost/beast/core/flat_buffer.hpp>
|
||||||
|
@@ -18,10 +18,7 @@
|
|||||||
#include <boost/beast/http/dynamic_body.hpp>
|
#include <boost/beast/http/dynamic_body.hpp>
|
||||||
#include <boost/beast/http/parser.hpp>
|
#include <boost/beast/http/parser.hpp>
|
||||||
#include <boost/beast/http/string_body.hpp>
|
#include <boost/beast/http/string_body.hpp>
|
||||||
#include <boost/beast/test/fail_stream.hpp>
|
|
||||||
#include <boost/beast/test/pipe_stream.hpp>
|
|
||||||
#include <boost/beast/test/stream.hpp>
|
#include <boost/beast/test/stream.hpp>
|
||||||
#include <boost/beast/test/string_istream.hpp>
|
|
||||||
#include <boost/beast/test/yield_to.hpp>
|
#include <boost/beast/test/yield_to.hpp>
|
||||||
#include <boost/beast/unit_test/suite.hpp>
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
#include <boost/asio/spawn.hpp>
|
#include <boost/asio/spawn.hpp>
|
||||||
@@ -51,11 +48,11 @@ public:
|
|||||||
b.commit(buffer_copy(
|
b.commit(buffer_copy(
|
||||||
b.prepare(len), buffer(s, len)));
|
b.prepare(len), buffer(s, len)));
|
||||||
test::fail_counter fc(n);
|
test::fail_counter fc(n);
|
||||||
test::fail_stream<
|
test::stream ts{ios_, fc};
|
||||||
test::string_istream> fs{fc, ios_, ""};
|
|
||||||
test_parser<isRequest> p(fc);
|
test_parser<isRequest> p(fc);
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
read(fs, b, p, ec);
|
ts.remote().close();
|
||||||
|
read(ts, b, p, ec);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -67,11 +64,12 @@ public:
|
|||||||
b.commit(buffer_copy(
|
b.commit(buffer_copy(
|
||||||
b.prepare(pre), buffer(s, pre)));
|
b.prepare(pre), buffer(s, pre)));
|
||||||
test::fail_counter fc(n);
|
test::fail_counter fc(n);
|
||||||
test::fail_stream<test::string_istream> fs{
|
test::stream ts{ios_, fc,
|
||||||
fc, ios_, std::string{s + pre, len - pre}};
|
std::string(s + pre, len - pre)};
|
||||||
test_parser<isRequest> p(fc);
|
test_parser<isRequest> p(fc);
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
read(fs, b, p, ec);
|
ts.remote().close();
|
||||||
|
read(ts, b, p, ec);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -82,11 +80,11 @@ public:
|
|||||||
b.commit(buffer_copy(
|
b.commit(buffer_copy(
|
||||||
b.prepare(len), buffer(s, len)));
|
b.prepare(len), buffer(s, len)));
|
||||||
test::fail_counter fc(n);
|
test::fail_counter fc(n);
|
||||||
test::fail_stream<
|
test::stream ts{ios_, fc};
|
||||||
test::string_istream> fs{fc, ios_, ""};
|
|
||||||
test_parser<isRequest> p(fc);
|
test_parser<isRequest> p(fc);
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
async_read(fs, b, p, do_yield[ec]);
|
ts.remote().close();
|
||||||
|
async_read(ts, b, p, do_yield[ec]);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -98,11 +96,12 @@ public:
|
|||||||
b.commit(buffer_copy(
|
b.commit(buffer_copy(
|
||||||
b.prepare(pre), buffer(s, pre)));
|
b.prepare(pre), buffer(s, pre)));
|
||||||
test::fail_counter fc(n);
|
test::fail_counter fc(n);
|
||||||
test::fail_stream<test::string_istream> fs{
|
test::stream ts(ios_, fc,
|
||||||
fc, ios_, std::string{s + pre, len - pre}};
|
std::string{s + pre, len - pre});
|
||||||
test_parser<isRequest> p(fc);
|
test_parser<isRequest> p(fc);
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
async_read(fs, b, p, do_yield[ec]);
|
ts.remote().close();
|
||||||
|
async_read(ts, b, p, do_yield[ec]);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -226,10 +225,8 @@ public:
|
|||||||
,
|
,
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
for(std::size_t i = 0; req[i]; ++i)
|
for(std::size_t i = 0; req[i]; ++i)
|
||||||
failMatrix<true>(req[i], do_yield);
|
failMatrix<true>(req[i], do_yield);
|
||||||
|
|
||||||
for(std::size_t i = 0; res[i]; ++i)
|
for(std::size_t i = 0; res[i]; ++i)
|
||||||
failMatrix<false>(res[i], do_yield);
|
failMatrix<false>(res[i], do_yield);
|
||||||
}
|
}
|
||||||
@@ -264,17 +261,18 @@ public:
|
|||||||
|
|
||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
test::fail_stream<test::string_istream> fs(n, ios_,
|
test::fail_counter fc{n};
|
||||||
|
test::stream ts{ios_, fc,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: localhost\r\n"
|
"Host: localhost\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
"Content-Length: 0\r\n"
|
"Content-Length: 0\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
);
|
};
|
||||||
request<dynamic_body> m;
|
request<dynamic_body> m;
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
multi_buffer b;
|
multi_buffer b;
|
||||||
read(fs, b, m, ec);
|
read(ts, b, m, ec);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -305,18 +303,20 @@ public:
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
multi_buffer b;
|
multi_buffer b;
|
||||||
test::string_istream ss(ios_, "");
|
test::stream ts{ios_};
|
||||||
request_parser<dynamic_body> p;
|
request_parser<dynamic_body> p;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
read(ss, b, p, ec);
|
ts.remote().close();
|
||||||
|
read(ts, b, p, ec);
|
||||||
BEAST_EXPECT(ec == http::error::end_of_stream);
|
BEAST_EXPECT(ec == http::error::end_of_stream);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
multi_buffer b;
|
multi_buffer b;
|
||||||
test::string_istream ss(ios_, "");
|
test::stream ts{ios_};
|
||||||
request_parser<dynamic_body> p;
|
request_parser<dynamic_body> p;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
async_read(ss, b, p, do_yield[ec]);
|
ts.remote().close();
|
||||||
|
async_read(ts, b, p, do_yield[ec]);
|
||||||
BEAST_EXPECT(ec == http::error::end_of_stream);
|
BEAST_EXPECT(ec == http::error::end_of_stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,12 +339,12 @@ public:
|
|||||||
// Make sure handlers are not destroyed
|
// Make sure handlers are not destroyed
|
||||||
// after calling io_service::stop
|
// after calling io_service::stop
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
test::string_istream is{ios,
|
test::stream ts{ios,
|
||||||
"GET / HTTP/1.1\r\n\r\n"};
|
"GET / HTTP/1.1\r\n\r\n"};
|
||||||
BEAST_EXPECT(handler::count() == 0);
|
BEAST_EXPECT(handler::count() == 0);
|
||||||
multi_buffer b;
|
multi_buffer b;
|
||||||
request<dynamic_body> m;
|
request<dynamic_body> m;
|
||||||
async_read(is, b, m, handler{});
|
async_read(ts, b, m, handler{});
|
||||||
BEAST_EXPECT(handler::count() > 0);
|
BEAST_EXPECT(handler::count() > 0);
|
||||||
ios.stop();
|
ios.stop();
|
||||||
BEAST_EXPECT(handler::count() > 0);
|
BEAST_EXPECT(handler::count() > 0);
|
||||||
@@ -358,12 +358,12 @@ public:
|
|||||||
// destroyed when calling ~io_service
|
// destroyed when calling ~io_service
|
||||||
{
|
{
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
test::string_istream is{ios,
|
test::stream ts{ios,
|
||||||
"GET / HTTP/1.1\r\n\r\n"};
|
"GET / HTTP/1.1\r\n\r\n"};
|
||||||
BEAST_EXPECT(handler::count() == 0);
|
BEAST_EXPECT(handler::count() == 0);
|
||||||
multi_buffer b;
|
multi_buffer b;
|
||||||
request<dynamic_body> m;
|
request<dynamic_body> m;
|
||||||
async_read(is, b, m, handler{});
|
async_read(ts, b, m, handler{});
|
||||||
BEAST_EXPECT(handler::count() > 0);
|
BEAST_EXPECT(handler::count() > 0);
|
||||||
}
|
}
|
||||||
BEAST_EXPECT(handler::count() == 0);
|
BEAST_EXPECT(handler::count() == 0);
|
||||||
@@ -374,9 +374,9 @@ public:
|
|||||||
void
|
void
|
||||||
testRegression430()
|
testRegression430()
|
||||||
{
|
{
|
||||||
test::pipe c{ios_};
|
test::stream ts{ios_};
|
||||||
c.server.read_size(1);
|
ts.read_size(1);
|
||||||
ostream(c.server.buffer) <<
|
ostream(ts.buffer()) <<
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Transfer-Encoding: chunked\r\n"
|
"Transfer-Encoding: chunked\r\n"
|
||||||
"Content-Type: application/octet-stream\r\n"
|
"Content-Type: application/octet-stream\r\n"
|
||||||
@@ -386,7 +386,7 @@ public:
|
|||||||
error_code ec;
|
error_code ec;
|
||||||
flat_buffer fb;
|
flat_buffer fb;
|
||||||
response_parser<dynamic_body> p;
|
response_parser<dynamic_body> p;
|
||||||
read(c.server, fb, p, ec);
|
read(ts, fb, p, ec);
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,10 +402,10 @@ public:
|
|||||||
Parser p;
|
Parser p;
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
test::pipe c{ios_};
|
test::stream ts{ios_};
|
||||||
ostream(c.server.buffer) << s;
|
ostream(ts.buffer()) << s;
|
||||||
c.server.read_size(n);
|
ts.read_size(n);
|
||||||
read(c.server, b, p, ec);
|
read(ts, b, p, ec);
|
||||||
if(! BEAST_EXPECTS(! ec, ec.message()))
|
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||||
continue;
|
continue;
|
||||||
pred(p);
|
pred(p);
|
||||||
@@ -452,12 +452,18 @@ public:
|
|||||||
testThrow();
|
testThrow();
|
||||||
testBufferOverflow();
|
testBufferOverflow();
|
||||||
|
|
||||||
yield_to([&](yield_context yield){
|
yield_to([&](yield_context yield)
|
||||||
testFailures(yield); });
|
{
|
||||||
yield_to([&](yield_context yield){
|
testFailures(yield);
|
||||||
testRead(yield); });
|
});
|
||||||
yield_to([&](yield_context yield){
|
yield_to([&](yield_context yield)
|
||||||
testEof(yield); });
|
{
|
||||||
|
testRead(yield);
|
||||||
|
});
|
||||||
|
yield_to([&](yield_context yield)
|
||||||
|
{
|
||||||
|
testEof(yield);
|
||||||
|
});
|
||||||
|
|
||||||
testIoService();
|
testIoService();
|
||||||
testRegression430();
|
testRegression430();
|
||||||
|
@@ -18,10 +18,7 @@
|
|||||||
#include <boost/beast/http/string_body.hpp>
|
#include <boost/beast/http/string_body.hpp>
|
||||||
#include <boost/beast/core/error.hpp>
|
#include <boost/beast/core/error.hpp>
|
||||||
#include <boost/beast/core/multi_buffer.hpp>
|
#include <boost/beast/core/multi_buffer.hpp>
|
||||||
#include <boost/beast/test/fail_stream.hpp>
|
#include <boost/beast/test/stream.hpp>
|
||||||
#include <boost/beast/test/pipe_stream.hpp>
|
|
||||||
#include <boost/beast/test/string_istream.hpp>
|
|
||||||
#include <boost/beast/test/string_ostream.hpp>
|
|
||||||
#include <boost/beast/test/yield_to.hpp>
|
#include <boost/beast/test/yield_to.hpp>
|
||||||
#include <boost/beast/unit_test/suite.hpp>
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
#include <boost/asio/error.hpp>
|
#include <boost/asio/error.hpp>
|
||||||
@@ -287,13 +284,13 @@ public:
|
|||||||
bool
|
bool
|
||||||
equal_body(string_view sv, string_view body)
|
equal_body(string_view sv, string_view body)
|
||||||
{
|
{
|
||||||
test::string_istream si{
|
test::stream ts{ios_, sv};
|
||||||
get_io_service(), sv.to_string()};
|
|
||||||
message<isRequest, string_body, fields> m;
|
message<isRequest, string_body, fields> m;
|
||||||
multi_buffer b;
|
multi_buffer b;
|
||||||
|
ts.remote().close();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
read(si, b, m);
|
read(ts, b, m);
|
||||||
return m.body == body;
|
return m.body == body;
|
||||||
}
|
}
|
||||||
catch(std::exception const& e)
|
catch(std::exception const& e)
|
||||||
@@ -307,12 +304,12 @@ public:
|
|||||||
std::string
|
std::string
|
||||||
str(message<isRequest, Body, Fields> const& m)
|
str(message<isRequest, Body, Fields> const& m)
|
||||||
{
|
{
|
||||||
test::string_ostream ss(ios_);
|
test::stream ts(ios_);
|
||||||
error_code ec;
|
error_code ec;
|
||||||
write(ss, m, ec);
|
write(ts, m, ec);
|
||||||
if(ec && ec != error::end_of_stream)
|
if(ec && ec != error::end_of_stream)
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||||
return ss.str;
|
return ts.remote().str().to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -326,10 +323,10 @@ public:
|
|||||||
m.set(field::content_length, "5");
|
m.set(field::content_length, "5");
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
error_code ec;
|
error_code ec;
|
||||||
test::string_ostream ss{ios_};
|
test::stream ts{ios_};
|
||||||
async_write(ss, m, do_yield[ec]);
|
async_write(ts, m, do_yield[ec]);
|
||||||
if(BEAST_EXPECTS(ec == error::end_of_stream, ec.message()))
|
if(BEAST_EXPECTS(ec == error::end_of_stream, ec.message()))
|
||||||
BEAST_EXPECT(ss.str ==
|
BEAST_EXPECT(ts.remote().str() ==
|
||||||
"HTTP/1.0 200 OK\r\n"
|
"HTTP/1.0 200 OK\r\n"
|
||||||
"Server: test\r\n"
|
"Server: test\r\n"
|
||||||
"Content-Length: 5\r\n"
|
"Content-Length: 5\r\n"
|
||||||
@@ -344,10 +341,10 @@ public:
|
|||||||
m.set(field::transfer_encoding, "chunked");
|
m.set(field::transfer_encoding, "chunked");
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
error_code ec;
|
error_code ec;
|
||||||
test::string_ostream ss(ios_);
|
test::stream ts{ios_};
|
||||||
async_write(ss, m, do_yield[ec]);
|
async_write(ts, m, do_yield[ec]);
|
||||||
if(BEAST_EXPECTS(! ec, ec.message()))
|
if(BEAST_EXPECTS(! ec, ec.message()))
|
||||||
BEAST_EXPECT(ss.str ==
|
BEAST_EXPECT(ts.remote().str() ==
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Server: test\r\n"
|
"Server: test\r\n"
|
||||||
"Transfer-Encoding: chunked\r\n"
|
"Transfer-Encoding: chunked\r\n"
|
||||||
@@ -367,8 +364,7 @@ public:
|
|||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
test::fail_counter fc(n);
|
test::fail_counter fc(n);
|
||||||
test::fail_stream<
|
test::stream ts(ios_, fc);
|
||||||
test::string_ostream> fs(fc, ios_);
|
|
||||||
request<fail_body> m(verb::get, "/", 10, fc);
|
request<fail_body> m(verb::get, "/", 10, fc);
|
||||||
m.set(field::user_agent, "test");
|
m.set(field::user_agent, "test");
|
||||||
m.set(field::connection, "keep-alive");
|
m.set(field::connection, "keep-alive");
|
||||||
@@ -376,8 +372,8 @@ public:
|
|||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
write(fs, m);
|
write(ts, m);
|
||||||
BEAST_EXPECT(fs.next_layer().str ==
|
BEAST_EXPECT(ts.remote().str() ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
"Connection: keep-alive\r\n"
|
"Connection: keep-alive\r\n"
|
||||||
@@ -397,17 +393,16 @@ public:
|
|||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
test::fail_counter fc(n);
|
test::fail_counter fc(n);
|
||||||
test::fail_stream<
|
test::stream ts(ios_, fc);
|
||||||
test::string_ostream> fs(fc, ios_);
|
|
||||||
request<fail_body> m{verb::get, "/", 10, fc};
|
request<fail_body> m{verb::get, "/", 10, fc};
|
||||||
m.set(field::user_agent, "test");
|
m.set(field::user_agent, "test");
|
||||||
m.set(field::transfer_encoding, "chunked");
|
m.set(field::transfer_encoding, "chunked");
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
write(fs, m, ec);
|
write(ts, m, ec);
|
||||||
if(ec == error::end_of_stream)
|
if(ec == error::end_of_stream)
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(fs.next_layer().str ==
|
BEAST_EXPECT(ts.remote().str() ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
"Transfer-Encoding: chunked\r\n"
|
"Transfer-Encoding: chunked\r\n"
|
||||||
@@ -427,17 +422,16 @@ public:
|
|||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
test::fail_counter fc(n);
|
test::fail_counter fc(n);
|
||||||
test::fail_stream<
|
test::stream ts(ios_, fc);
|
||||||
test::string_ostream> fs(fc, ios_);
|
|
||||||
request<fail_body> m{verb::get, "/", 10, fc};
|
request<fail_body> m{verb::get, "/", 10, fc};
|
||||||
m.set(field::user_agent, "test");
|
m.set(field::user_agent, "test");
|
||||||
m.set(field::transfer_encoding, "chunked");
|
m.set(field::transfer_encoding, "chunked");
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
async_write(fs, m, do_yield[ec]);
|
async_write(ts, m, do_yield[ec]);
|
||||||
if(ec == error::end_of_stream)
|
if(ec == error::end_of_stream)
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(fs.next_layer().str ==
|
BEAST_EXPECT(ts.remote().str() ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
"Transfer-Encoding: chunked\r\n"
|
"Transfer-Encoding: chunked\r\n"
|
||||||
@@ -457,18 +451,17 @@ public:
|
|||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
test::fail_counter fc(n);
|
test::fail_counter fc(n);
|
||||||
test::fail_stream<
|
test::stream ts(ios_, fc);
|
||||||
test::string_ostream> fs(fc, ios_);
|
|
||||||
request<fail_body> m{verb::get, "/", 10, fc};
|
request<fail_body> m{verb::get, "/", 10, fc};
|
||||||
m.set(field::user_agent, "test");
|
m.set(field::user_agent, "test");
|
||||||
m.set(field::connection, "keep-alive");
|
m.set(field::connection, "keep-alive");
|
||||||
m.set(field::content_length, "5");
|
m.set(field::content_length, "5");
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
write(fs, m, ec);
|
write(ts, m, ec);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(fs.next_layer().str ==
|
BEAST_EXPECT(ts.remote().str() ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
"Connection: keep-alive\r\n"
|
"Connection: keep-alive\r\n"
|
||||||
@@ -484,18 +477,17 @@ public:
|
|||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
test::fail_counter fc(n);
|
test::fail_counter fc(n);
|
||||||
test::fail_stream<
|
test::stream ts(ios_, fc);
|
||||||
test::string_ostream> fs(fc, ios_);
|
|
||||||
request<fail_body> m{verb::get, "/", 10, fc};
|
request<fail_body> m{verb::get, "/", 10, fc};
|
||||||
m.set(field::user_agent, "test");
|
m.set(field::user_agent, "test");
|
||||||
m.set(field::connection, "keep-alive");
|
m.set(field::connection, "keep-alive");
|
||||||
m.set(field::content_length, "5");
|
m.set(field::content_length, "5");
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
async_write(fs, m, do_yield[ec]);
|
async_write(ts, m, do_yield[ec]);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(fs.next_layer().str ==
|
BEAST_EXPECT(ts.remote().str() ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
"Connection: keep-alive\r\n"
|
"Connection: keep-alive\r\n"
|
||||||
@@ -538,11 +530,11 @@ public:
|
|||||||
m.set(field::user_agent, "test");
|
m.set(field::user_agent, "test");
|
||||||
m.body = "*";
|
m.body = "*";
|
||||||
m.prepare_payload();
|
m.prepare_payload();
|
||||||
test::string_ostream ss(ios_);
|
test::stream ts(ios_);
|
||||||
error_code ec;
|
error_code ec;
|
||||||
write(ss, m, ec);
|
write(ts, m, ec);
|
||||||
BEAST_EXPECT(ec == error::end_of_stream);
|
BEAST_EXPECT(ec == error::end_of_stream);
|
||||||
BEAST_EXPECT(ss.str ==
|
BEAST_EXPECT(ts.remote().str() ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
@@ -575,10 +567,10 @@ public:
|
|||||||
m.set(field::user_agent, "test");
|
m.set(field::user_agent, "test");
|
||||||
m.body = "*";
|
m.body = "*";
|
||||||
m.prepare_payload();
|
m.prepare_payload();
|
||||||
test::string_ostream ss(ios_);
|
test::stream ts(ios_);
|
||||||
error_code ec;
|
error_code ec;
|
||||||
write(ss, m, ec);
|
write(ts, m, ec);
|
||||||
BEAST_EXPECT(ss.str ==
|
BEAST_EXPECT(ts.remote().str() ==
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
"Transfer-Encoding: chunked\r\n"
|
"Transfer-Encoding: chunked\r\n"
|
||||||
@@ -621,7 +613,7 @@ public:
|
|||||||
// Make sure handlers are not destroyed
|
// Make sure handlers are not destroyed
|
||||||
// after calling io_service::stop
|
// after calling io_service::stop
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
test::string_ostream os{ios};
|
test::stream ts{ios};
|
||||||
BEAST_EXPECT(handler::count() == 0);
|
BEAST_EXPECT(handler::count() == 0);
|
||||||
request<string_body> m;
|
request<string_body> m;
|
||||||
m.method(verb::get);
|
m.method(verb::get);
|
||||||
@@ -629,7 +621,7 @@ public:
|
|||||||
m.target("/");
|
m.target("/");
|
||||||
m.set("Content-Length", 5);
|
m.set("Content-Length", 5);
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
async_write(os, m, handler{});
|
async_write(ts, m, handler{});
|
||||||
BEAST_EXPECT(handler::count() > 0);
|
BEAST_EXPECT(handler::count() > 0);
|
||||||
ios.stop();
|
ios.stop();
|
||||||
BEAST_EXPECT(handler::count() > 0);
|
BEAST_EXPECT(handler::count() > 0);
|
||||||
@@ -643,7 +635,7 @@ public:
|
|||||||
// destroyed when calling ~io_service
|
// destroyed when calling ~io_service
|
||||||
{
|
{
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
test::string_ostream is{ios};
|
test::stream ts{ios};
|
||||||
BEAST_EXPECT(handler::count() == 0);
|
BEAST_EXPECT(handler::count() == 0);
|
||||||
request<string_body> m;
|
request<string_body> m;
|
||||||
m.method(verb::get);
|
m.method(verb::get);
|
||||||
@@ -651,7 +643,7 @@ public:
|
|||||||
m.target("/");
|
m.target("/");
|
||||||
m.set("Content-Length", 5);
|
m.set("Content-Length", 5);
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
async_write(is, m, handler{});
|
async_write(ts, m, handler{});
|
||||||
BEAST_EXPECT(handler::count() > 0);
|
BEAST_EXPECT(handler::count() > 0);
|
||||||
}
|
}
|
||||||
BEAST_EXPECT(handler::count() == 0);
|
BEAST_EXPECT(handler::count() == 0);
|
||||||
@@ -670,11 +662,9 @@ public:
|
|||||||
serializer<isRequest, Body, Fields> sr{m};
|
serializer<isRequest, Body, Fields> sr{m};
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
stream.nwrite = 0;
|
|
||||||
write_some(stream, sr, ec);
|
write_some(stream, sr, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
return;
|
return;
|
||||||
BEAST_EXPECT(stream.nwrite <= 1);
|
|
||||||
if(sr.is_done())
|
if(sr.is_done())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -693,11 +683,9 @@ public:
|
|||||||
serializer<isRequest, Body, Fields> sr{m};
|
serializer<isRequest, Body, Fields> sr{m};
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
stream.nwrite = 0;
|
|
||||||
async_write_some(stream, sr, yield[ec]);
|
async_write_some(stream, sr, yield[ec]);
|
||||||
if(ec)
|
if(ec)
|
||||||
return;
|
return;
|
||||||
BEAST_EXPECT(stream.nwrite <= 1);
|
|
||||||
if(sr.is_done())
|
if(sr.is_done())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -707,8 +695,9 @@ public:
|
|||||||
void
|
void
|
||||||
testWriteStream(boost::asio::yield_context yield)
|
testWriteStream(boost::asio::yield_context yield)
|
||||||
{
|
{
|
||||||
test::pipe p{ios_};
|
test::stream ts{ios_};
|
||||||
p.client.write_size(3);
|
auto tr = ts.remote();
|
||||||
|
ts.write_size(3);
|
||||||
|
|
||||||
response<Body> m0;
|
response<Body> m0;
|
||||||
m0.version = 11;
|
m0.version = 11;
|
||||||
@@ -726,20 +715,20 @@ public:
|
|||||||
{
|
{
|
||||||
auto m = m0;
|
auto m = m0;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
do_write(p.client, m, ec);
|
do_write(ts, m, ec);
|
||||||
BEAST_EXPECT(p.server.str() == result);
|
BEAST_EXPECT(tr.str() == result);
|
||||||
BEAST_EXPECT(equal_body<false>(
|
BEAST_EXPECT(equal_body<false>(
|
||||||
p.server.str(), m.body.s));
|
tr.str(), m.body.s));
|
||||||
p.server.clear();
|
tr.clear();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto m = m0;
|
auto m = m0;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
do_async_write(p.client, m, ec, yield);
|
do_async_write(ts, m, ec, yield);
|
||||||
BEAST_EXPECT(p.server.str() == result);
|
BEAST_EXPECT(tr.str() == result);
|
||||||
BEAST_EXPECT(equal_body<false>(
|
BEAST_EXPECT(equal_body<false>(
|
||||||
p.server.str(), m.body.s));
|
tr.str(), m.body.s));
|
||||||
p.server.clear();
|
tr.clear();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto m = m0;
|
auto m = m0;
|
||||||
@@ -748,12 +737,12 @@ public:
|
|||||||
sr.split(true);
|
sr.split(true);
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
write_some(p.client, sr);
|
write_some(ts, sr);
|
||||||
if(sr.is_header_done())
|
if(sr.is_header_done())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
BEAST_EXPECT(! m.body.read);
|
BEAST_EXPECT(! m.body.read);
|
||||||
p.server.clear();
|
tr.clear();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto m = m0;
|
auto m = m0;
|
||||||
@@ -762,12 +751,12 @@ public:
|
|||||||
sr.split(true);
|
sr.split(true);
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
async_write_some(p.client, sr, yield);
|
async_write_some(ts, sr, yield);
|
||||||
if(sr.is_header_done())
|
if(sr.is_header_done())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
BEAST_EXPECT(! m.body.read);
|
BEAST_EXPECT(! m.body.read);
|
||||||
p.server.clear();
|
tr.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -775,33 +764,18 @@ public:
|
|||||||
{
|
{
|
||||||
auto m = m0;
|
auto m = m0;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
do_write(p.client, m, ec);
|
do_write(ts, m, ec);
|
||||||
BEAST_EXPECT(equal_body<false>(
|
BEAST_EXPECT(equal_body<false>(
|
||||||
p.server.str(), m.body.s));
|
tr.str(), m.body.s));
|
||||||
p.server.clear();
|
tr.clear();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto m = m0;
|
auto m = m0;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
do_async_write(p.client, m, ec, yield);
|
do_async_write(ts, m, ec, yield);
|
||||||
BEAST_EXPECT(equal_body<false>(
|
BEAST_EXPECT(equal_body<false>(
|
||||||
p.server.str(), m.body.s));
|
tr.str(), m.body.s));
|
||||||
p.server.clear();
|
tr.clear();
|
||||||
}
|
|
||||||
{
|
|
||||||
auto m = m0;
|
|
||||||
error_code ec;
|
|
||||||
test::string_ostream so{get_io_service(), 3};
|
|
||||||
response_serializer<Body, fields> sr{m};
|
|
||||||
sr.split(true);
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
write_some(p.client, sr);
|
|
||||||
if(sr.is_header_done())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
BEAST_EXPECT(! m.body.read);
|
|
||||||
p.server.clear();
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto m = m0;
|
auto m = m0;
|
||||||
@@ -810,12 +784,26 @@ public:
|
|||||||
sr.split(true);
|
sr.split(true);
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
async_write_some(p.client, sr, yield);
|
write_some(ts, sr);
|
||||||
if(sr.is_header_done())
|
if(sr.is_header_done())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
BEAST_EXPECT(! m.body.read);
|
BEAST_EXPECT(! m.body.read);
|
||||||
p.server.clear();
|
tr.clear();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto m = m0;
|
||||||
|
error_code ec;
|
||||||
|
response_serializer<Body, fields> sr{m};
|
||||||
|
sr.split(true);
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
async_write_some(ts, sr, yield);
|
||||||
|
if(sr.is_header_done())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
BEAST_EXPECT(! m.body.read);
|
||||||
|
tr.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -824,12 +812,12 @@ public:
|
|||||||
testIssue655()
|
testIssue655()
|
||||||
{
|
{
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
test::pipe c{ios};
|
test::stream ts{ios};
|
||||||
|
|
||||||
response<empty_body> res;
|
response<empty_body> res;
|
||||||
res.chunked(true);
|
res.chunked(true);
|
||||||
response_serializer<empty_body> sr{res};
|
response_serializer<empty_body> sr{res};
|
||||||
async_write_header(c.client, sr,
|
async_write_header(ts, sr,
|
||||||
[&](const error_code&)
|
[&](const error_code&)
|
||||||
{
|
{
|
||||||
});
|
});
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
#include <boost/beast/websocket/stream.hpp>
|
#include <boost/beast/websocket/stream.hpp>
|
||||||
#include <boost/beast/websocket/detail/frame.hpp>
|
#include <boost/beast/websocket/detail/frame.hpp>
|
||||||
#include <boost/beast/unit_test/suite.hpp>
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
#include <boost/beast/test/pipe_stream.hpp>
|
|
||||||
#include <boost/beast/test/yield_to.hpp>
|
#include <boost/beast/test/yield_to.hpp>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#include <boost/beast/core/ostream.hpp>
|
#include <boost/beast/core/ostream.hpp>
|
||||||
#include <boost/beast/core/multi_buffer.hpp>
|
#include <boost/beast/core/multi_buffer.hpp>
|
||||||
#include <boost/beast/test/fail_stream.hpp>
|
|
||||||
#include <boost/beast/test/stream.hpp>
|
#include <boost/beast/test/stream.hpp>
|
||||||
#include <boost/beast/test/yield_to.hpp>
|
#include <boost/beast/test/yield_to.hpp>
|
||||||
#include <boost/beast/unit_test/suite.hpp>
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#include <boost/beast/core/flat_buffer.hpp>
|
#include <boost/beast/core/flat_buffer.hpp>
|
||||||
#include <boost/beast/core/ostream.hpp>
|
#include <boost/beast/core/ostream.hpp>
|
||||||
#include <boost/beast/test/pipe_stream.hpp>
|
#include <boost/beast/test/stream.hpp>
|
||||||
#include <boost/beast/test/yield_to.hpp>
|
#include <boost/beast/test/yield_to.hpp>
|
||||||
#include <boost/beast/unit_test/suite.hpp>
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
|
|
||||||
@@ -50,24 +50,23 @@ public:
|
|||||||
testRead()
|
testRead()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
test::pipe p{ios_};
|
test::stream ts(ios_,
|
||||||
ostream(p.server.buffer) <<
|
"\x16***");
|
||||||
"\x16***";
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
auto const result = detect_ssl(p.server, b, ec);
|
auto const result = detect_ssl(ts, b, ec);
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
BEAST_EXPECT(result);
|
BEAST_EXPECT(result);
|
||||||
}
|
}
|
||||||
yield_to(
|
yield_to(
|
||||||
[&](yield_context yield)
|
[&](yield_context yield)
|
||||||
{
|
{
|
||||||
test::pipe p{ios_};
|
test::stream ts(ios_,
|
||||||
ostream(p.server.buffer) <<
|
"\x16***");
|
||||||
"\x16***";
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
auto const result = async_detect_ssl(p.server, b, yield[ec]);
|
auto const result =
|
||||||
|
async_detect_ssl(ts, b, yield[ec]);
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
BEAST_EXPECT(result);
|
BEAST_EXPECT(result);
|
||||||
});
|
});
|
||||||
|
@@ -17,9 +17,7 @@
|
|||||||
#include <boost/beast/http/parser.hpp>
|
#include <boost/beast/http/parser.hpp>
|
||||||
#include <boost/beast/http/read.hpp>
|
#include <boost/beast/http/read.hpp>
|
||||||
#include <boost/beast/http/write.hpp>
|
#include <boost/beast/http/write.hpp>
|
||||||
#include <boost/beast/test/pipe_stream.hpp>
|
#include <boost/beast/test/stream.hpp>
|
||||||
#include <boost/beast/test/string_istream.hpp>
|
|
||||||
#include <boost/beast/test/string_ostream.hpp>
|
|
||||||
#include <boost/beast/test/yield_to.hpp>
|
#include <boost/beast/test/yield_to.hpp>
|
||||||
#include <boost/beast/unit_test/suite.hpp>
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -38,7 +36,7 @@ class examples_test
|
|||||||
, public beast::test::enable_yield_to
|
, public beast::test::enable_yield_to
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// two threads, for some examples using a pipe
|
// two threads, for some examples
|
||||||
examples_test()
|
examples_test()
|
||||||
: enable_yield_to(2)
|
: enable_yield_to(2)
|
||||||
{
|
{
|
||||||
@@ -73,13 +71,13 @@ public:
|
|||||||
bool
|
bool
|
||||||
equal_body(string_view sv, string_view body)
|
equal_body(string_view sv, string_view body)
|
||||||
{
|
{
|
||||||
test::string_istream si{
|
test::stream ts{ios_, sv};
|
||||||
get_io_service(), sv.to_string()};
|
|
||||||
message<isRequest, string_body, fields> m;
|
message<isRequest, string_body, fields> m;
|
||||||
multi_buffer b;
|
multi_buffer b;
|
||||||
|
ts.remote().close();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
read(si, b, m);
|
read(ts, b, m);
|
||||||
return m.body == body;
|
return m.body == body;
|
||||||
}
|
}
|
||||||
catch(std::exception const& e)
|
catch(std::exception const& e)
|
||||||
@@ -92,14 +90,15 @@ public:
|
|||||||
void
|
void
|
||||||
doExpect100Continue()
|
doExpect100Continue()
|
||||||
{
|
{
|
||||||
test::pipe p{ios_};
|
test::stream ts{ios_};
|
||||||
|
auto tr = ts.remote();
|
||||||
yield_to(
|
yield_to(
|
||||||
[&](yield_context)
|
[&](yield_context)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
flat_buffer buffer;
|
flat_buffer buffer;
|
||||||
receive_expect_100_continue(
|
receive_expect_100_continue(
|
||||||
p.server, buffer, ec);
|
tr, buffer, ec);
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
},
|
},
|
||||||
[&](yield_context)
|
[&](yield_context)
|
||||||
@@ -115,7 +114,7 @@ public:
|
|||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
send_expect_100_continue(
|
send_expect_100_continue(
|
||||||
p.client, buffer, req, ec);
|
ts, buffer, req, ec);
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -124,15 +123,14 @@ public:
|
|||||||
doCgiResponse()
|
doCgiResponse()
|
||||||
{
|
{
|
||||||
std::string const s = "Hello, world!";
|
std::string const s = "Hello, world!";
|
||||||
test::pipe child{ios_};
|
test::stream t0{ios_, s};
|
||||||
child.server.read_size(3);
|
t0.read_size(3);
|
||||||
ostream(child.server.buffer) << s;
|
t0.remote().close();
|
||||||
child.client.close();
|
test::stream t1{ios_};
|
||||||
test::pipe p{ios_};
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
send_cgi_response(child.server, p.client, ec);
|
send_cgi_response(t0, t1, ec);
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
BEAST_EXPECT(equal_body<false>(p.server.str(), s));
|
BEAST_EXPECT(equal_body<false>(t1.remote().str(), s));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -146,18 +144,19 @@ public:
|
|||||||
req.body = "Hello, world!";
|
req.body = "Hello, world!";
|
||||||
req.prepare_payload();
|
req.prepare_payload();
|
||||||
|
|
||||||
test::pipe downstream{ios_};
|
test::stream ds{ios_};
|
||||||
downstream.server.read_size(3);
|
auto dsr = ds.remote();
|
||||||
test::pipe upstream{ios_};
|
dsr.read_size(3);
|
||||||
upstream.client.write_size(3);
|
test::stream us{ios_};
|
||||||
|
us.write_size(3);
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
write(downstream.client, req);
|
write(ds, req);
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
downstream.client.close();
|
ds.close();
|
||||||
|
|
||||||
flat_buffer buffer;
|
flat_buffer buffer;
|
||||||
relay<true>(upstream.client, downstream.server, buffer, ec,
|
relay<true>(us, dsr, buffer, ec,
|
||||||
[&](header<true, fields>& h, error_code& ev)
|
[&](header<true, fields>& h, error_code& ev)
|
||||||
{
|
{
|
||||||
ev = {};
|
ev = {};
|
||||||
@@ -166,7 +165,7 @@ public:
|
|||||||
});
|
});
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
BEAST_EXPECT(equal_body<true>(
|
BEAST_EXPECT(equal_body<true>(
|
||||||
upstream.server.str(), req.body));
|
us.remote().str(), req.body));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -240,20 +239,21 @@ public:
|
|||||||
void
|
void
|
||||||
doHEAD()
|
doHEAD()
|
||||||
{
|
{
|
||||||
test::pipe p{ios_};
|
test::stream ts{ios_};
|
||||||
|
auto tr = ts.remote();
|
||||||
yield_to(
|
yield_to(
|
||||||
[&](yield_context)
|
[&](yield_context)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
flat_buffer buffer;
|
flat_buffer buffer;
|
||||||
do_server_head(p.server, buffer, ec);
|
do_server_head(tr, buffer, ec);
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
},
|
},
|
||||||
[&](yield_context)
|
[&](yield_context)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
flat_buffer buffer;
|
flat_buffer buffer;
|
||||||
auto res = do_head_request(p.client, buffer, "/", ec);
|
auto res = do_head_request(ts, buffer, "/", ec);
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -278,18 +278,17 @@ public:
|
|||||||
void
|
void
|
||||||
doDeferredBody()
|
doDeferredBody()
|
||||||
{
|
{
|
||||||
test::pipe p{ios_};
|
test::stream ts(ios_,
|
||||||
ostream(p.server.buffer) <<
|
|
||||||
"POST / HTTP/1.1\r\n"
|
"POST / HTTP/1.1\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
"Content-Type: multipart/form-data\r\n"
|
"Content-Type: multipart/form-data\r\n"
|
||||||
"Content-Length: 13\r\n"
|
"Content-Length: 13\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"Hello, world!";
|
"Hello, world!");
|
||||||
|
|
||||||
handler h;
|
handler h;
|
||||||
flat_buffer buffer;
|
flat_buffer buffer;
|
||||||
do_form_request(p.server, buffer, h);
|
do_form_request(ts, buffer, h);
|
||||||
BEAST_EXPECT(h.body == "Hello, world!");
|
BEAST_EXPECT(h.body == "Hello, world!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,9 +297,9 @@ public:
|
|||||||
void
|
void
|
||||||
doIncrementalRead()
|
doIncrementalRead()
|
||||||
{
|
{
|
||||||
test::pipe c{ios_};
|
test::stream ts{ios_};
|
||||||
std::string s(2048, '*');
|
std::string s(2048, '*');
|
||||||
ostream(c.server.buffer) <<
|
ostream(ts.buffer()) <<
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Length: 2048\r\n"
|
"Content-Length: 2048\r\n"
|
||||||
"Server: test\r\n"
|
"Server: test\r\n"
|
||||||
@@ -309,7 +308,7 @@ public:
|
|||||||
error_code ec;
|
error_code ec;
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
read_and_print_body<false>(ss, c.server, b, ec);
|
read_and_print_body<false>(ss, ts, b, ec);
|
||||||
if(BEAST_EXPECTS(! ec, ec.message()))
|
if(BEAST_EXPECTS(! ec, ec.message()))
|
||||||
BEAST_EXPECT(ss.str() == s);
|
BEAST_EXPECT(ss.str() == s);
|
||||||
}
|
}
|
||||||
@@ -325,7 +324,7 @@ public:
|
|||||||
return boost::asio::const_buffers_1{
|
return boost::asio::const_buffers_1{
|
||||||
s.data(), s.size()};
|
s.data(), s.size()};
|
||||||
};
|
};
|
||||||
test::pipe p{ios_};
|
test::stream ts{ios_};
|
||||||
|
|
||||||
response<empty_body> res{status::ok, 11};
|
response<empty_body> res{status::ok, 11};
|
||||||
res.set(field::server, "test");
|
res.set(field::server, "test");
|
||||||
@@ -334,26 +333,26 @@ public:
|
|||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
response_serializer<empty_body> sr{res};
|
response_serializer<empty_body> sr{res};
|
||||||
write_header(p.client, sr, ec);
|
write_header(ts, sr, ec);
|
||||||
|
|
||||||
chunk_extensions exts;
|
chunk_extensions exts;
|
||||||
|
|
||||||
boost::asio::write(p.client,
|
boost::asio::write(ts,
|
||||||
make_chunk(buf("First")), ec);
|
make_chunk(buf("First")), ec);
|
||||||
|
|
||||||
exts.insert("quality", "1.0");
|
exts.insert("quality", "1.0");
|
||||||
boost::asio::write(p.client,
|
boost::asio::write(ts,
|
||||||
make_chunk(buf("Hello, world!"), exts), ec);
|
make_chunk(buf("Hello, world!"), exts), ec);
|
||||||
|
|
||||||
exts.clear();
|
exts.clear();
|
||||||
exts.insert("file", "abc.txt");
|
exts.insert("file", "abc.txt");
|
||||||
exts.insert("quality", "0.7");
|
exts.insert("quality", "0.7");
|
||||||
boost::asio::write(p.client,
|
boost::asio::write(ts,
|
||||||
make_chunk(buf("The Next Chunk"), std::move(exts)), ec);
|
make_chunk(buf("The Next Chunk"), std::move(exts)), ec);
|
||||||
|
|
||||||
exts.clear();
|
exts.clear();
|
||||||
exts.insert("last");
|
exts.insert("last");
|
||||||
boost::asio::write(p.client,
|
boost::asio::write(ts,
|
||||||
make_chunk(buf("Last one"), std::move(exts),
|
make_chunk(buf("Last one"), std::move(exts),
|
||||||
std::allocator<double>{}), ec);
|
std::allocator<double>{}), ec);
|
||||||
|
|
||||||
@@ -361,13 +360,13 @@ public:
|
|||||||
trailers.set(field::expires, "never");
|
trailers.set(field::expires, "never");
|
||||||
trailers.set(field::content_md5, "f4a5c16584f03d90");
|
trailers.set(field::content_md5, "f4a5c16584f03d90");
|
||||||
|
|
||||||
boost::asio::write(p.client,
|
boost::asio::write(ts,
|
||||||
make_chunk_last(
|
make_chunk_last(
|
||||||
trailers,
|
trailers,
|
||||||
std::allocator<double>{}
|
std::allocator<double>{}
|
||||||
), ec);
|
), ec);
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
to_string(p.server.buffer.data()) ==
|
to_string(ts.remote().buffer().data()) ==
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Server: test\r\n"
|
"Server: test\r\n"
|
||||||
"Accept: Expires, Content-MD5\r\n"
|
"Accept: Expires, Content-MD5\r\n"
|
||||||
@@ -392,8 +391,7 @@ public:
|
|||||||
void
|
void
|
||||||
doExplicitChunkParse()
|
doExplicitChunkParse()
|
||||||
{
|
{
|
||||||
test::pipe c{ios_};
|
test::stream ts(ios_,
|
||||||
ostream(c.client.buffer) <<
|
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Server: test\r\n"
|
"Server: test\r\n"
|
||||||
"Trailer: Expires, Content-MD5\r\n"
|
"Trailer: Expires, Content-MD5\r\n"
|
||||||
@@ -410,13 +408,13 @@ public:
|
|||||||
"0\r\n"
|
"0\r\n"
|
||||||
"Expires: never\r\n"
|
"Expires: never\r\n"
|
||||||
"Content-MD5: f4a5c16584f03d90\r\n"
|
"Content-MD5: f4a5c16584f03d90\r\n"
|
||||||
"\r\n";
|
"\r\n");
|
||||||
|
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
flat_buffer b;
|
flat_buffer b;
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
print_chunked_body<false>(ss, c.client, b, ec);
|
print_chunked_body<false>(ss, ts, b, ec);
|
||||||
BEAST_EXPECTS(! ec, ec.message());
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
BEAST_EXPECT(ss.str() ==
|
BEAST_EXPECT(ss.str() ==
|
||||||
"Chunk Body: First\n"
|
"Chunk Body: First\n"
|
||||||
@@ -429,7 +427,6 @@ public:
|
|||||||
"Chunk Body: Last one\n"
|
"Chunk Body: Last one\n"
|
||||||
"Expires: never\n"
|
"Expires: never\n"
|
||||||
"Content-MD5: f4a5c16584f03d90\n");
|
"Content-MD5: f4a5c16584f03d90\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
@@ -1,200 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BOOST_BEAST_TEST_FAIL_STREAM_HPP
|
|
||||||
#define BOOST_BEAST_TEST_FAIL_STREAM_HPP
|
|
||||||
|
|
||||||
#include <boost/beast/core/async_result.hpp>
|
|
||||||
#include <boost/beast/core/bind_handler.hpp>
|
|
||||||
#include <boost/beast/core/error.hpp>
|
|
||||||
#include <boost/beast/core/detail/type_traits.hpp>
|
|
||||||
#include <boost/beast/websocket/teardown.hpp>
|
|
||||||
#include <boost/beast/test/fail_counter.hpp>
|
|
||||||
#include <boost/optional.hpp>
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace beast {
|
|
||||||
namespace test {
|
|
||||||
|
|
||||||
/** A stream wrapper that fails.
|
|
||||||
|
|
||||||
On the Nth operation, the stream will fail with the specified
|
|
||||||
error code, or the default error code of invalid_argument.
|
|
||||||
*/
|
|
||||||
template<class NextLayer>
|
|
||||||
class fail_stream
|
|
||||||
{
|
|
||||||
boost::optional<fail_counter> fc_;
|
|
||||||
fail_counter* pfc_;
|
|
||||||
NextLayer next_layer_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using next_layer_type =
|
|
||||||
typename std::remove_reference<NextLayer>::type;
|
|
||||||
|
|
||||||
using lowest_layer_type =
|
|
||||||
typename get_lowest_layer<next_layer_type>::type;
|
|
||||||
|
|
||||||
fail_stream(fail_stream&&) = delete;
|
|
||||||
fail_stream(fail_stream const&) = delete;
|
|
||||||
fail_stream& operator=(fail_stream&&) = delete;
|
|
||||||
fail_stream& operator=(fail_stream const&) = delete;
|
|
||||||
|
|
||||||
template<class... Args>
|
|
||||||
explicit
|
|
||||||
fail_stream(std::size_t n, Args&&... args)
|
|
||||||
: fc_(n)
|
|
||||||
, pfc_(&*fc_)
|
|
||||||
, next_layer_(std::forward<Args>(args)...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class... Args>
|
|
||||||
explicit
|
|
||||||
fail_stream(fail_counter& fc, Args&&... args)
|
|
||||||
: pfc_(&fc)
|
|
||||||
, next_layer_(std::forward<Args>(args)...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
next_layer_type&
|
|
||||||
next_layer()
|
|
||||||
{
|
|
||||||
return next_layer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
lowest_layer_type&
|
|
||||||
lowest_layer()
|
|
||||||
{
|
|
||||||
return next_layer_.lowest_layer();
|
|
||||||
}
|
|
||||||
|
|
||||||
lowest_layer_type const&
|
|
||||||
lowest_layer() const
|
|
||||||
{
|
|
||||||
return next_layer_.lowest_layer();
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::asio::io_service&
|
|
||||||
get_io_service()
|
|
||||||
{
|
|
||||||
return next_layer_.get_io_service();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
read_some(MutableBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
pfc_->fail();
|
|
||||||
return next_layer_.read_some(buffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
read_some(MutableBufferSequence const& buffers, error_code& ec)
|
|
||||||
{
|
|
||||||
if(pfc_->fail(ec))
|
|
||||||
return 0;
|
|
||||||
return next_layer_.read_some(buffers, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence, class ReadHandler>
|
|
||||||
async_return_type<
|
|
||||||
ReadHandler, void(error_code, std::size_t)>
|
|
||||||
async_read_some(MutableBufferSequence const& buffers,
|
|
||||||
ReadHandler&& handler)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
if(pfc_->fail(ec))
|
|
||||||
{
|
|
||||||
async_completion<ReadHandler,
|
|
||||||
void(error_code, std::size_t)> init{handler};
|
|
||||||
next_layer_.get_io_service().post(
|
|
||||||
bind_handler(init.completion_handler, ec, 0));
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
return next_layer_.async_read_some(buffers,
|
|
||||||
std::forward<ReadHandler>(handler));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(ConstBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
pfc_->fail();
|
|
||||||
return next_layer_.write_some(buffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(ConstBufferSequence const& buffers, error_code& ec)
|
|
||||||
{
|
|
||||||
if(pfc_->fail(ec))
|
|
||||||
return 0;
|
|
||||||
return next_layer_.write_some(buffers, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence, class WriteHandler>
|
|
||||||
async_return_type<
|
|
||||||
WriteHandler, void(error_code, std::size_t)>
|
|
||||||
async_write_some(ConstBufferSequence const& buffers,
|
|
||||||
WriteHandler&& handler)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
if(pfc_->fail(ec))
|
|
||||||
{
|
|
||||||
async_completion<WriteHandler,
|
|
||||||
void(error_code, std::size_t)> init{handler};
|
|
||||||
next_layer_.get_io_service().post(
|
|
||||||
bind_handler(init.completion_handler, ec, 0));
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
return next_layer_.async_write_some(buffers,
|
|
||||||
std::forward<WriteHandler>(handler));
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
teardown(
|
|
||||||
websocket::role_type role,
|
|
||||||
fail_stream<NextLayer>& stream,
|
|
||||||
boost::system::error_code& ec)
|
|
||||||
{
|
|
||||||
if(stream.pfc_->fail(ec))
|
|
||||||
return;
|
|
||||||
using beast::websocket::teardown;
|
|
||||||
teardown(role, stream.next_layer(), ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class TeardownHandler>
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
async_teardown(
|
|
||||||
websocket::role_type role,
|
|
||||||
fail_stream<NextLayer>& stream,
|
|
||||||
TeardownHandler&& handler)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
if(stream.pfc_->fail(ec))
|
|
||||||
{
|
|
||||||
stream.get_io_service().post(
|
|
||||||
bind_handler(std::move(handler), ec));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
using beast::websocket::async_teardown;
|
|
||||||
async_teardown(role, stream.next_layer(),
|
|
||||||
std::forward<TeardownHandler>(handler));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // test
|
|
||||||
} // beast
|
|
||||||
} // boost
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,553 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BOOST_BEAST_TEST_PIPE_STREAM_HPP
|
|
||||||
#define BOOST_BEAST_TEST_PIPE_STREAM_HPP
|
|
||||||
|
|
||||||
#include <boost/beast/core/async_result.hpp>
|
|
||||||
#include <boost/beast/core/bind_handler.hpp>
|
|
||||||
#include <boost/beast/core/flat_buffer.hpp>
|
|
||||||
#include <boost/beast/core/string.hpp>
|
|
||||||
#include <boost/beast/core/type_traits.hpp>
|
|
||||||
#include <boost/beast/websocket/teardown.hpp>
|
|
||||||
#include <boost/beast/test/fail_counter.hpp>
|
|
||||||
#include <boost/asio/buffer.hpp>
|
|
||||||
#include <boost/asio/io_service.hpp>
|
|
||||||
#include <boost/assert.hpp>
|
|
||||||
#include <boost/throw_exception.hpp>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <limits>
|
|
||||||
#include <mutex>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace beast {
|
|
||||||
namespace test {
|
|
||||||
|
|
||||||
/** A bidirectional in-memory communication channel
|
|
||||||
|
|
||||||
An instance of this class provides a client and server
|
|
||||||
endpoint that are automatically connected to each other
|
|
||||||
similarly to a connected socket.
|
|
||||||
|
|
||||||
Test pipes are used to facilitate writing unit tests
|
|
||||||
where the behavior of the transport is tightly controlled
|
|
||||||
to help illuminate all code paths (for code coverage)
|
|
||||||
*/
|
|
||||||
class pipe
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using buffer_type = flat_buffer;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct read_op
|
|
||||||
{
|
|
||||||
virtual ~read_op() = default;
|
|
||||||
virtual void operator()() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct state
|
|
||||||
{
|
|
||||||
std::mutex m;
|
|
||||||
buffer_type b;
|
|
||||||
std::condition_variable cv;
|
|
||||||
std::unique_ptr<read_op> op;
|
|
||||||
bool eof = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
state s_[2];
|
|
||||||
|
|
||||||
public:
|
|
||||||
/** Represents an endpoint.
|
|
||||||
|
|
||||||
Each pipe has a client stream and a server stream.
|
|
||||||
*/
|
|
||||||
class stream
|
|
||||||
{
|
|
||||||
friend class pipe;
|
|
||||||
|
|
||||||
template<class Handler, class Buffers>
|
|
||||||
class read_op_impl;
|
|
||||||
|
|
||||||
state& in_;
|
|
||||||
state& out_;
|
|
||||||
boost::asio::io_service& ios_;
|
|
||||||
fail_counter* fc_ = nullptr;
|
|
||||||
std::size_t read_max_ =
|
|
||||||
(std::numeric_limits<std::size_t>::max)();
|
|
||||||
std::size_t write_max_ =
|
|
||||||
(std::numeric_limits<std::size_t>::max)();
|
|
||||||
|
|
||||||
stream(state& in, state& out,
|
|
||||||
boost::asio::io_service& ios)
|
|
||||||
: in_(in)
|
|
||||||
, out_(out)
|
|
||||||
, ios_(ios)
|
|
||||||
, buffer(in_.b)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using buffer_type = pipe::buffer_type;
|
|
||||||
|
|
||||||
/// Direct access to the underlying buffer
|
|
||||||
buffer_type& buffer;
|
|
||||||
|
|
||||||
/// Counts the number of read calls
|
|
||||||
std::size_t nread = 0;
|
|
||||||
|
|
||||||
/// Counts the number of write calls
|
|
||||||
std::size_t nwrite = 0;
|
|
||||||
|
|
||||||
~stream() = default;
|
|
||||||
stream(stream&&) = default;
|
|
||||||
|
|
||||||
/// Set the fail counter on the object
|
|
||||||
#if 0
|
|
||||||
void
|
|
||||||
fail(fail_counter& fc)
|
|
||||||
{
|
|
||||||
fc_ = &fc;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/// Return the `io_service` associated with the object
|
|
||||||
boost::asio::io_service&
|
|
||||||
get_io_service()
|
|
||||||
{
|
|
||||||
return ios_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the maximum number of bytes returned by read_some
|
|
||||||
void
|
|
||||||
read_size(std::size_t n)
|
|
||||||
{
|
|
||||||
read_max_ = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the maximum number of bytes returned by write_some
|
|
||||||
void
|
|
||||||
write_size(std::size_t n)
|
|
||||||
{
|
|
||||||
write_max_ = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a string representing the pending input data
|
|
||||||
string_view
|
|
||||||
str() const
|
|
||||||
{
|
|
||||||
using boost::asio::buffer_cast;
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
return {
|
|
||||||
buffer_cast<char const*>(*in_.b.data().begin()),
|
|
||||||
buffer_size(*in_.b.data().begin())};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear the buffer holding the input data
|
|
||||||
void
|
|
||||||
clear()
|
|
||||||
{
|
|
||||||
in_.b.consume((std::numeric_limits<
|
|
||||||
std::size_t>::max)());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Close the stream.
|
|
||||||
|
|
||||||
The other end of the pipe will see
|
|
||||||
`boost::asio::error::eof` on read.
|
|
||||||
*/
|
|
||||||
template<class = void>
|
|
||||||
void
|
|
||||||
close();
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
read_some(MutableBufferSequence const& buffers);
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
read_some(MutableBufferSequence const& buffers,
|
|
||||||
error_code& ec);
|
|
||||||
|
|
||||||
template<class MutableBufferSequence, class ReadHandler>
|
|
||||||
async_return_type<
|
|
||||||
ReadHandler, void(error_code, std::size_t)>
|
|
||||||
async_read_some(MutableBufferSequence const& buffers,
|
|
||||||
ReadHandler&& handler);
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(ConstBufferSequence const& buffers);
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(
|
|
||||||
ConstBufferSequence const& buffers, error_code&);
|
|
||||||
|
|
||||||
template<class ConstBufferSequence, class WriteHandler>
|
|
||||||
async_return_type<
|
|
||||||
WriteHandler, void(error_code, std::size_t)>
|
|
||||||
async_write_some(ConstBufferSequence const& buffers,
|
|
||||||
WriteHandler&& handler);
|
|
||||||
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
teardown(
|
|
||||||
websocket::role_type role,
|
|
||||||
stream& s, boost::system::error_code& ec);
|
|
||||||
|
|
||||||
template<class TeardownHandler>
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
async_teardown(
|
|
||||||
websocket::role_type,
|
|
||||||
stream& s, TeardownHandler&& handler);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Constructor.
|
|
||||||
|
|
||||||
The client and server endpoints will use the same `io_service`.
|
|
||||||
*/
|
|
||||||
explicit
|
|
||||||
pipe(boost::asio::io_service& ios)
|
|
||||||
: client(s_[0], s_[1], ios)
|
|
||||||
, server(s_[1], s_[0], ios)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the client endpoint
|
|
||||||
stream client;
|
|
||||||
|
|
||||||
/// Represents the server endpoint
|
|
||||||
stream server;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
teardown(
|
|
||||||
websocket::role_type,
|
|
||||||
pipe::stream& s,
|
|
||||||
boost::system::error_code& ec)
|
|
||||||
{
|
|
||||||
if(s.fc_)
|
|
||||||
{
|
|
||||||
if(s.fc_->fail(ec))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s.close();
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class TeardownHandler>
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
async_teardown(websocket::role_type,
|
|
||||||
pipe::stream& s, TeardownHandler&& handler)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
if(s.fc_ && s.fc_->fail(ec))
|
|
||||||
return s.get_io_service().post(
|
|
||||||
bind_handler(std::move(handler), ec));
|
|
||||||
s.close();
|
|
||||||
s.get_io_service().post(
|
|
||||||
bind_handler(std::move(handler), ec));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Handler, class Buffers>
|
|
||||||
class pipe::stream::read_op_impl :
|
|
||||||
public pipe::read_op
|
|
||||||
{
|
|
||||||
stream& s_;
|
|
||||||
Buffers b_;
|
|
||||||
Handler h_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
read_op_impl(stream& s,
|
|
||||||
Buffers const& b, Handler&& h)
|
|
||||||
: s_(s)
|
|
||||||
, b_(b)
|
|
||||||
, h_(std::move(h))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
read_op_impl(stream& s,
|
|
||||||
Buffers const& b, Handler const& h)
|
|
||||||
: s_(s)
|
|
||||||
, b_(b)
|
|
||||||
, h_(h)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
operator()() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<class Handler, class Buffers>
|
|
||||||
void
|
|
||||||
pipe::stream::
|
|
||||||
read_op_impl<Handler, Buffers>::operator()()
|
|
||||||
{
|
|
||||||
using boost::asio::buffer_copy;
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
s_.ios_.post(
|
|
||||||
[&]()
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(s_.in_.op);
|
|
||||||
std::unique_lock<std::mutex> lock{s_.in_.m};
|
|
||||||
if(s_.in_.b.size() > 0)
|
|
||||||
{
|
|
||||||
auto const bytes_transferred = buffer_copy(
|
|
||||||
b_, s_.in_.b.data(), s_.read_max_);
|
|
||||||
s_.in_.b.consume(bytes_transferred);
|
|
||||||
auto& s = s_;
|
|
||||||
Handler h{std::move(h_)};
|
|
||||||
s.in_.op.reset(nullptr);
|
|
||||||
lock.unlock();
|
|
||||||
++s.nread;
|
|
||||||
s.ios_.post(bind_handler(std::move(h),
|
|
||||||
error_code{}, bytes_transferred));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(s_.in_.eof);
|
|
||||||
auto& s = s_;
|
|
||||||
Handler h{std::move(h_)};
|
|
||||||
s.in_.op.reset(nullptr);
|
|
||||||
lock.unlock();
|
|
||||||
++s.nread;
|
|
||||||
s.ios_.post(bind_handler(std::move(h),
|
|
||||||
boost::asio::error::eof, 0));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<class>
|
|
||||||
void
|
|
||||||
pipe::stream::
|
|
||||||
close()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock{out_.m};
|
|
||||||
if(! out_.eof)
|
|
||||||
{
|
|
||||||
out_.eof = true;
|
|
||||||
if(out_.op)
|
|
||||||
out_.op.get()->operator()();
|
|
||||||
else
|
|
||||||
out_.cv.notify_all();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
pipe::stream::
|
|
||||||
read_some(MutableBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
static_assert(is_mutable_buffer_sequence<
|
|
||||||
MutableBufferSequence>::value,
|
|
||||||
"MutableBufferSequence requirements not met");
|
|
||||||
error_code ec;
|
|
||||||
auto const n = read_some(buffers, ec);
|
|
||||||
if(ec)
|
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
pipe::stream::
|
|
||||||
read_some(MutableBufferSequence const& buffers,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
static_assert(is_mutable_buffer_sequence<
|
|
||||||
MutableBufferSequence>::value,
|
|
||||||
"MutableBufferSequence requirements not met");
|
|
||||||
using boost::asio::buffer_copy;
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
BOOST_ASSERT(! in_.op);
|
|
||||||
BOOST_ASSERT(buffer_size(buffers) > 0);
|
|
||||||
if(fc_ && fc_->fail(ec))
|
|
||||||
return 0;
|
|
||||||
std::unique_lock<std::mutex> lock{in_.m};
|
|
||||||
in_.cv.wait(lock,
|
|
||||||
[&]()
|
|
||||||
{
|
|
||||||
return in_.b.size() > 0 || in_.eof;
|
|
||||||
});
|
|
||||||
std::size_t bytes_transferred;
|
|
||||||
if(in_.b.size() > 0)
|
|
||||||
{
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
bytes_transferred = buffer_copy(
|
|
||||||
buffers, in_.b.data(), read_max_);
|
|
||||||
in_.b.consume(bytes_transferred);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(in_.eof);
|
|
||||||
bytes_transferred = 0;
|
|
||||||
ec = boost::asio::error::eof;
|
|
||||||
}
|
|
||||||
++nread;
|
|
||||||
return bytes_transferred;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence, class ReadHandler>
|
|
||||||
async_return_type<
|
|
||||||
ReadHandler, void(error_code, std::size_t)>
|
|
||||||
pipe::stream::
|
|
||||||
async_read_some(MutableBufferSequence const& buffers,
|
|
||||||
ReadHandler&& handler)
|
|
||||||
{
|
|
||||||
static_assert(is_mutable_buffer_sequence<
|
|
||||||
MutableBufferSequence>::value,
|
|
||||||
"MutableBufferSequence requirements not met");
|
|
||||||
using boost::asio::buffer_copy;
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
BOOST_ASSERT(! in_.op);
|
|
||||||
BOOST_ASSERT(buffer_size(buffers) > 0);
|
|
||||||
async_completion<ReadHandler,
|
|
||||||
void(error_code, std::size_t)> init{handler};
|
|
||||||
if(fc_)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
if(fc_->fail(ec))
|
|
||||||
return ios_.post(bind_handler(
|
|
||||||
init.completion_handler, ec, 0));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock{in_.m};
|
|
||||||
if(in_.eof)
|
|
||||||
{
|
|
||||||
lock.unlock();
|
|
||||||
++nread;
|
|
||||||
ios_.post(bind_handler(init.completion_handler,
|
|
||||||
boost::asio::error::eof, 0));
|
|
||||||
}
|
|
||||||
else if(buffer_size(buffers) == 0 ||
|
|
||||||
buffer_size(in_.b.data()) > 0)
|
|
||||||
{
|
|
||||||
auto const bytes_transferred = buffer_copy(
|
|
||||||
buffers, in_.b.data(), read_max_);
|
|
||||||
in_.b.consume(bytes_transferred);
|
|
||||||
lock.unlock();
|
|
||||||
++nread;
|
|
||||||
ios_.post(bind_handler(init.completion_handler,
|
|
||||||
error_code{}, bytes_transferred));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
in_.op.reset(new read_op_impl<handler_type<
|
|
||||||
ReadHandler, void(error_code, std::size_t)>,
|
|
||||||
MutableBufferSequence>{*this, buffers,
|
|
||||||
init.completion_handler});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
pipe::stream::
|
|
||||||
write_some(ConstBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
static_assert(is_const_buffer_sequence<
|
|
||||||
ConstBufferSequence>::value,
|
|
||||||
"ConstBufferSequence requirements not met");
|
|
||||||
BOOST_ASSERT(! out_.eof);
|
|
||||||
error_code ec;
|
|
||||||
auto const bytes_transferred =
|
|
||||||
write_some(buffers, ec);
|
|
||||||
if(ec)
|
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
||||||
return bytes_transferred;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
pipe::stream::
|
|
||||||
write_some(
|
|
||||||
ConstBufferSequence const& buffers, error_code& ec)
|
|
||||||
{
|
|
||||||
static_assert(is_const_buffer_sequence<
|
|
||||||
ConstBufferSequence>::value,
|
|
||||||
"ConstBufferSequence requirements not met");
|
|
||||||
using boost::asio::buffer_copy;
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
BOOST_ASSERT(! out_.eof);
|
|
||||||
if(fc_ && fc_->fail(ec))
|
|
||||||
return 0;
|
|
||||||
auto const n = (std::min)(
|
|
||||||
buffer_size(buffers), write_max_);
|
|
||||||
std::unique_lock<std::mutex> lock{out_.m};
|
|
||||||
auto const bytes_transferred =
|
|
||||||
buffer_copy(out_.b.prepare(n), buffers);
|
|
||||||
out_.b.commit(bytes_transferred);
|
|
||||||
if(out_.op)
|
|
||||||
out_.op.get()->operator()();
|
|
||||||
else
|
|
||||||
out_.cv.notify_all();
|
|
||||||
lock.unlock();
|
|
||||||
++nwrite;
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
return bytes_transferred;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence, class WriteHandler>
|
|
||||||
async_return_type<
|
|
||||||
WriteHandler, void(error_code, std::size_t)>
|
|
||||||
pipe::stream::
|
|
||||||
async_write_some(ConstBufferSequence const& buffers,
|
|
||||||
WriteHandler&& handler)
|
|
||||||
{
|
|
||||||
static_assert(is_const_buffer_sequence<
|
|
||||||
ConstBufferSequence>::value,
|
|
||||||
"ConstBufferSequence requirements not met");
|
|
||||||
using boost::asio::buffer_copy;
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
BOOST_ASSERT(! out_.eof);
|
|
||||||
async_completion<WriteHandler,
|
|
||||||
void(error_code, std::size_t)> init{handler};
|
|
||||||
if(fc_)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
if(fc_->fail(ec))
|
|
||||||
return ios_.post(bind_handler(
|
|
||||||
init.completion_handler, ec, 0));
|
|
||||||
}
|
|
||||||
auto const n =
|
|
||||||
(std::min)(buffer_size(buffers), write_max_);
|
|
||||||
std::unique_lock<std::mutex> lock{out_.m};
|
|
||||||
auto const bytes_transferred =
|
|
||||||
buffer_copy(out_.b.prepare(n), buffers);
|
|
||||||
out_.b.commit(bytes_transferred);
|
|
||||||
if(out_.op)
|
|
||||||
out_.op.get()->operator()();
|
|
||||||
else
|
|
||||||
out_.cv.notify_all();
|
|
||||||
lock.unlock();
|
|
||||||
++nwrite;
|
|
||||||
ios_.post(bind_handler(init.completion_handler,
|
|
||||||
error_code{}, bytes_transferred));
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // test
|
|
||||||
} // beast
|
|
||||||
} // boost
|
|
||||||
|
|
||||||
#endif
|
|
@@ -239,38 +239,40 @@ class stream
|
|||||||
using status = detail::stream_impl::status;
|
using status = detail::stream_impl::status;
|
||||||
|
|
||||||
std::shared_ptr<detail::stream_impl> impl_;
|
std::shared_ptr<detail::stream_impl> impl_;
|
||||||
detail::stream_impl::state& in_;
|
detail::stream_impl::state* in_;
|
||||||
detail::stream_impl::state& out_;
|
detail::stream_impl::state* out_;
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
stream(std::shared_ptr<
|
stream(std::shared_ptr<
|
||||||
detail::stream_impl> const& impl)
|
detail::stream_impl> const& impl)
|
||||||
: impl_(impl)
|
: impl_(impl)
|
||||||
, in_(impl_->s1_)
|
, in_(&impl_->s1_)
|
||||||
, out_(impl_->s0_)
|
, out_(&impl_->s0_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using buffer_type = flat_buffer;
|
using buffer_type = flat_buffer;
|
||||||
|
|
||||||
stream& operator=(stream const&) = delete;
|
/// Assignment
|
||||||
|
stream& operator=(stream&&) = default;
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~stream()
|
~stream()
|
||||||
{
|
{
|
||||||
if(! impl_)
|
if(! impl_)
|
||||||
return;
|
return;
|
||||||
BOOST_ASSERT(! in_.op);
|
BOOST_ASSERT(! in_->op);
|
||||||
std::unique_lock<std::mutex> lock{out_.m};
|
std::unique_lock<std::mutex> lock{out_->m};
|
||||||
if(out_.code == status::ok)
|
if(out_->code == status::ok)
|
||||||
{
|
{
|
||||||
out_.code = status::reset;
|
out_->code = status::reset;
|
||||||
out_.on_write();
|
out_->on_write();
|
||||||
}
|
}
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
stream(stream&& other)
|
stream(stream&& other)
|
||||||
: impl_(std::move(other.impl_))
|
: impl_(std::move(other.impl_))
|
||||||
, in_(other.in_)
|
, in_(other.in_)
|
||||||
@@ -284,8 +286,8 @@ public:
|
|||||||
boost::asio::io_service& ios)
|
boost::asio::io_service& ios)
|
||||||
: impl_(std::make_shared<
|
: impl_(std::make_shared<
|
||||||
detail::stream_impl>(ios, nullptr))
|
detail::stream_impl>(ios, nullptr))
|
||||||
, in_(impl_->s0_)
|
, in_(&impl_->s0_)
|
||||||
, out_(impl_->s1_)
|
, out_(&impl_->s1_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,8 +298,8 @@ public:
|
|||||||
boost::asio::io_service& ios1)
|
boost::asio::io_service& ios1)
|
||||||
: impl_(std::make_shared<
|
: impl_(std::make_shared<
|
||||||
detail::stream_impl>(ios0, ios1))
|
detail::stream_impl>(ios0, ios1))
|
||||||
, in_(impl_->s0_)
|
, in_(&impl_->s0_)
|
||||||
, out_(impl_->s1_)
|
, out_(&impl_->s1_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,8 +310,8 @@ public:
|
|||||||
fail_counter& fc)
|
fail_counter& fc)
|
||||||
: impl_(std::make_shared<
|
: impl_(std::make_shared<
|
||||||
detail::stream_impl>(ios, &fc))
|
detail::stream_impl>(ios, &fc))
|
||||||
, in_(impl_->s0_)
|
, in_(&impl_->s0_)
|
||||||
, out_(impl_->s1_)
|
, out_(&impl_->s1_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,13 +321,13 @@ public:
|
|||||||
string_view s)
|
string_view s)
|
||||||
: impl_(std::make_shared<
|
: impl_(std::make_shared<
|
||||||
detail::stream_impl>(ios, nullptr))
|
detail::stream_impl>(ios, nullptr))
|
||||||
, in_(impl_->s0_)
|
, in_(&impl_->s0_)
|
||||||
, out_(impl_->s1_)
|
, out_(&impl_->s1_)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer;
|
using boost::asio::buffer;
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
in_.b.commit(buffer_copy(
|
in_->b.commit(buffer_copy(
|
||||||
in_.b.prepare(s.size()),
|
in_->b.prepare(s.size()),
|
||||||
buffer(s.data(), s.size())));
|
buffer(s.data(), s.size())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,13 +338,13 @@ public:
|
|||||||
string_view s)
|
string_view s)
|
||||||
: impl_(std::make_shared<
|
: impl_(std::make_shared<
|
||||||
detail::stream_impl>(ios, &fc))
|
detail::stream_impl>(ios, &fc))
|
||||||
, in_(impl_->s0_)
|
, in_(&impl_->s0_)
|
||||||
, out_(impl_->s1_)
|
, out_(&impl_->s1_)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer;
|
using boost::asio::buffer;
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
in_.b.commit(buffer_copy(
|
in_->b.commit(buffer_copy(
|
||||||
in_.b.prepare(s.size()),
|
in_->b.prepare(s.size()),
|
||||||
buffer(s.data(), s.size())));
|
buffer(s.data(), s.size())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +352,7 @@ public:
|
|||||||
stream
|
stream
|
||||||
remote()
|
remote()
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(&in_ == &impl_->s0_);
|
BOOST_ASSERT(in_ == &impl_->s0_);
|
||||||
return stream{impl_};
|
return stream{impl_};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,28 +360,28 @@ public:
|
|||||||
boost::asio::io_service&
|
boost::asio::io_service&
|
||||||
get_io_service()
|
get_io_service()
|
||||||
{
|
{
|
||||||
return in_.ios;
|
return in_->ios;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum number of bytes returned by read_some
|
/// Set the maximum number of bytes returned by read_some
|
||||||
void
|
void
|
||||||
read_size(std::size_t n)
|
read_size(std::size_t n)
|
||||||
{
|
{
|
||||||
in_.read_max = n;
|
in_->read_max = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum number of bytes returned by write_some
|
/// Set the maximum number of bytes returned by write_some
|
||||||
void
|
void
|
||||||
write_size(std::size_t n)
|
write_size(std::size_t n)
|
||||||
{
|
{
|
||||||
out_.write_max = n;
|
out_->write_max = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Direct input buffer access
|
/// Direct input buffer access
|
||||||
buffer_type&
|
buffer_type&
|
||||||
buffer()
|
buffer()
|
||||||
{
|
{
|
||||||
return in_.b;
|
return in_->b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a string view representing the pending input data
|
/// Returns a string view representing the pending input data
|
||||||
@@ -389,8 +391,8 @@ public:
|
|||||||
using boost::asio::buffer_cast;
|
using boost::asio::buffer_cast;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
return {
|
return {
|
||||||
buffer_cast<char const*>(*in_.b.data().begin()),
|
buffer_cast<char const*>(*in_->b.data().begin()),
|
||||||
buffer_size(*in_.b.data().begin())};
|
buffer_size(*in_->b.data().begin())};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends a string to the pending input data
|
/// Appends a string to the pending input data
|
||||||
@@ -399,24 +401,32 @@ public:
|
|||||||
{
|
{
|
||||||
using boost::asio::buffer;
|
using boost::asio::buffer;
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
std::unique_lock<std::mutex> lock{in_.m};
|
std::lock_guard<std::mutex> lock{in_->m};
|
||||||
in_.b.commit(buffer_copy(
|
in_->b.commit(buffer_copy(
|
||||||
in_.b.prepare(s.size()),
|
in_->b.prepare(s.size()),
|
||||||
buffer(s.data(), s.size())));
|
buffer(s.data(), s.size())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear the pending input area
|
||||||
|
void
|
||||||
|
clear()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock{in_->m};
|
||||||
|
in_->b.consume(in_->b.size());
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the number of reads
|
/// Return the number of reads
|
||||||
std::size_t
|
std::size_t
|
||||||
nread() const
|
nread() const
|
||||||
{
|
{
|
||||||
return in_.nread;
|
return in_->nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the number of writes
|
/// Return the number of writes
|
||||||
std::size_t
|
std::size_t
|
||||||
nwrite() const
|
nwrite() const
|
||||||
{
|
{
|
||||||
return out_.nwrite;
|
return out_->nwrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Close the stream.
|
/** Close the stream.
|
||||||
@@ -499,35 +509,35 @@ read_some(MutableBufferSequence const& buffers,
|
|||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
BOOST_ASSERT(buffer_size(buffers) > 0);
|
BOOST_ASSERT(buffer_size(buffers) > 0);
|
||||||
if(in_.fc && in_.fc->fail(ec))
|
if(in_->fc && in_->fc->fail(ec))
|
||||||
return 0;
|
return 0;
|
||||||
std::unique_lock<std::mutex> lock{in_.m};
|
std::unique_lock<std::mutex> lock{in_->m};
|
||||||
BOOST_ASSERT(! in_.op);
|
BOOST_ASSERT(! in_->op);
|
||||||
in_.cv.wait(lock,
|
in_->cv.wait(lock,
|
||||||
[&]()
|
[&]()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
in_.b.size() > 0 ||
|
in_->b.size() > 0 ||
|
||||||
in_.code != status::ok;
|
in_->code != status::ok;
|
||||||
});
|
});
|
||||||
std::size_t bytes_transferred;
|
std::size_t bytes_transferred;
|
||||||
if(in_.b.size() > 0)
|
if(in_->b.size() > 0)
|
||||||
{
|
{
|
||||||
ec.assign(0, ec.category());
|
ec.assign(0, ec.category());
|
||||||
bytes_transferred = buffer_copy(
|
bytes_transferred = buffer_copy(
|
||||||
buffers, in_.b.data(), in_.read_max);
|
buffers, in_->b.data(), in_->read_max);
|
||||||
in_.b.consume(bytes_transferred);
|
in_->b.consume(bytes_transferred);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(in_.code != status::ok);
|
BOOST_ASSERT(in_->code != status::ok);
|
||||||
bytes_transferred = 0;
|
bytes_transferred = 0;
|
||||||
if(in_.code == status::eof)
|
if(in_->code == status::eof)
|
||||||
ec = boost::asio::error::eof;
|
ec = boost::asio::error::eof;
|
||||||
else if(in_.code == status::reset)
|
else if(in_->code == status::reset)
|
||||||
ec = boost::asio::error::connection_reset;
|
ec = boost::asio::error::connection_reset;
|
||||||
}
|
}
|
||||||
++in_.nread;
|
++in_->nread;
|
||||||
return bytes_transferred;
|
return bytes_transferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,45 +557,45 @@ async_read_some(
|
|||||||
BOOST_ASSERT(buffer_size(buffers) > 0);
|
BOOST_ASSERT(buffer_size(buffers) > 0);
|
||||||
async_completion<ReadHandler,
|
async_completion<ReadHandler,
|
||||||
void(error_code, std::size_t)> init{handler};
|
void(error_code, std::size_t)> init{handler};
|
||||||
if(in_.fc)
|
if(in_->fc)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
if(in_.fc->fail(ec))
|
if(in_->fc->fail(ec))
|
||||||
return in_.ios.post(bind_handler(
|
return in_->ios.post(bind_handler(
|
||||||
init.completion_handler, ec, 0));
|
init.completion_handler, ec, 0));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock{in_.m};
|
std::unique_lock<std::mutex> lock{in_->m};
|
||||||
BOOST_ASSERT(! in_.op);
|
BOOST_ASSERT(! in_->op);
|
||||||
if(buffer_size(buffers) == 0 ||
|
if(buffer_size(buffers) == 0 ||
|
||||||
buffer_size(in_.b.data()) > 0)
|
buffer_size(in_->b.data()) > 0)
|
||||||
{
|
{
|
||||||
auto const bytes_transferred = buffer_copy(
|
auto const bytes_transferred = buffer_copy(
|
||||||
buffers, in_.b.data(), in_.read_max);
|
buffers, in_->b.data(), in_->read_max);
|
||||||
in_.b.consume(bytes_transferred);
|
in_->b.consume(bytes_transferred);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
++in_.nread;
|
++in_->nread;
|
||||||
in_.ios.post(bind_handler(init.completion_handler,
|
in_->ios.post(bind_handler(init.completion_handler,
|
||||||
error_code{}, bytes_transferred));
|
error_code{}, bytes_transferred));
|
||||||
}
|
}
|
||||||
else if(in_.code != status::ok)
|
else if(in_->code != status::ok)
|
||||||
{
|
{
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
++in_.nread;
|
++in_->nread;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
if(in_.code == status::eof)
|
if(in_->code == status::eof)
|
||||||
ec = boost::asio::error::eof;
|
ec = boost::asio::error::eof;
|
||||||
else if(in_.code == status::reset)
|
else if(in_->code == status::reset)
|
||||||
ec = boost::asio::error::connection_reset;
|
ec = boost::asio::error::connection_reset;
|
||||||
in_.ios.post(bind_handler(
|
in_->ios.post(bind_handler(
|
||||||
init.completion_handler, ec, 0));
|
init.completion_handler, ec, 0));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
in_.op.reset(new
|
in_->op.reset(new
|
||||||
detail::stream_impl::read_op_impl<handler_type<
|
detail::stream_impl::read_op_impl<handler_type<
|
||||||
ReadHandler, void(error_code, std::size_t)>,
|
ReadHandler, void(error_code, std::size_t)>,
|
||||||
MutableBufferSequence>{in_, buffers,
|
MutableBufferSequence>{*in_, buffers,
|
||||||
init.completion_handler});
|
init.completion_handler});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -600,7 +610,7 @@ write_some(ConstBufferSequence const& buffers)
|
|||||||
static_assert(is_const_buffer_sequence<
|
static_assert(is_const_buffer_sequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
BOOST_ASSERT(out_.code == status::ok);
|
BOOST_ASSERT(out_->code == status::ok);
|
||||||
error_code ec;
|
error_code ec;
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
write_some(buffers, ec);
|
write_some(buffers, ec);
|
||||||
@@ -620,18 +630,18 @@ write_some(
|
|||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
BOOST_ASSERT(out_.code == status::ok);
|
BOOST_ASSERT(out_->code == status::ok);
|
||||||
if(in_.fc && in_.fc->fail(ec))
|
if(in_->fc && in_->fc->fail(ec))
|
||||||
return 0;
|
return 0;
|
||||||
auto const n = (std::min)(
|
auto const n = (std::min)(
|
||||||
buffer_size(buffers), out_.write_max);
|
buffer_size(buffers), out_->write_max);
|
||||||
std::unique_lock<std::mutex> lock{out_.m};
|
std::unique_lock<std::mutex> lock{out_->m};
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
buffer_copy(out_.b.prepare(n), buffers);
|
buffer_copy(out_->b.prepare(n), buffers);
|
||||||
out_.b.commit(bytes_transferred);
|
out_->b.commit(bytes_transferred);
|
||||||
out_.on_write();
|
out_->on_write();
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
++out_.nwrite;
|
++out_->nwrite;
|
||||||
ec.assign(0, ec.category());
|
ec.assign(0, ec.category());
|
||||||
return bytes_transferred;
|
return bytes_transferred;
|
||||||
}
|
}
|
||||||
@@ -648,26 +658,26 @@ async_write_some(ConstBufferSequence const& buffers,
|
|||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
BOOST_ASSERT(out_.code == status::ok);
|
BOOST_ASSERT(out_->code == status::ok);
|
||||||
async_completion<WriteHandler,
|
async_completion<WriteHandler,
|
||||||
void(error_code, std::size_t)> init{handler};
|
void(error_code, std::size_t)> init{handler};
|
||||||
if(in_.fc)
|
if(in_->fc)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
if(in_.fc->fail(ec))
|
if(in_->fc->fail(ec))
|
||||||
return in_.ios.post(bind_handler(
|
return in_->ios.post(bind_handler(
|
||||||
init.completion_handler, ec, 0));
|
init.completion_handler, ec, 0));
|
||||||
}
|
}
|
||||||
auto const n =
|
auto const n =
|
||||||
(std::min)(buffer_size(buffers), out_.write_max);
|
(std::min)(buffer_size(buffers), out_->write_max);
|
||||||
std::unique_lock<std::mutex> lock{out_.m};
|
std::unique_lock<std::mutex> lock{out_->m};
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
buffer_copy(out_.b.prepare(n), buffers);
|
buffer_copy(out_->b.prepare(n), buffers);
|
||||||
out_.b.commit(bytes_transferred);
|
out_->b.commit(bytes_transferred);
|
||||||
out_.on_write();
|
out_->on_write();
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
++out_.nwrite;
|
++out_->nwrite;
|
||||||
in_.ios.post(bind_handler(init.completion_handler,
|
in_->ios.post(bind_handler(init.completion_handler,
|
||||||
error_code{}, bytes_transferred));
|
error_code{}, bytes_transferred));
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
@@ -677,9 +687,9 @@ void
|
|||||||
teardown(websocket::role_type,
|
teardown(websocket::role_type,
|
||||||
stream& s, boost::system::error_code& ec)
|
stream& s, boost::system::error_code& ec)
|
||||||
{
|
{
|
||||||
if(s.in_.fc)
|
if(s.in_->fc)
|
||||||
{
|
{
|
||||||
if(s.in_.fc->fail(ec))
|
if(s.in_->fc->fail(ec))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -696,7 +706,7 @@ async_teardown(websocket::role_type,
|
|||||||
stream& s, TeardownHandler&& handler)
|
stream& s, TeardownHandler&& handler)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
if(s.in_.fc && s.in_.fc->fail(ec))
|
if(s.in_->fc && s.in_->fc->fail(ec))
|
||||||
return s.get_io_service().post(
|
return s.get_io_service().post(
|
||||||
bind_handler(std::move(handler), ec));
|
bind_handler(std::move(handler), ec));
|
||||||
s.close();
|
s.close();
|
||||||
@@ -709,12 +719,12 @@ void
|
|||||||
stream::
|
stream::
|
||||||
close()
|
close()
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(! in_.op);
|
BOOST_ASSERT(! in_->op);
|
||||||
std::lock_guard<std::mutex> lock{out_.m};
|
std::lock_guard<std::mutex> lock{out_->m};
|
||||||
if(out_.code == status::ok)
|
if(out_->code == status::ok)
|
||||||
{
|
{
|
||||||
out_.code = status::eof;
|
out_->code = status::eof;
|
||||||
out_.on_write();
|
out_->on_write();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,177 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BOOST_BEAST_TEST_STRING_IOSTREAM_HPP
|
|
||||||
#define BOOST_BEAST_TEST_STRING_IOSTREAM_HPP
|
|
||||||
|
|
||||||
#include <boost/beast/core/async_result.hpp>
|
|
||||||
#include <boost/beast/core/bind_handler.hpp>
|
|
||||||
#include <boost/beast/core/buffer_prefix.hpp>
|
|
||||||
#include <boost/beast/core/error.hpp>
|
|
||||||
#include <boost/beast/websocket/teardown.hpp>
|
|
||||||
#include <boost/asio/buffer.hpp>
|
|
||||||
#include <boost/asio/io_service.hpp>
|
|
||||||
#include <boost/throw_exception.hpp>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace beast {
|
|
||||||
namespace test {
|
|
||||||
|
|
||||||
/** A SyncStream and AsyncStream that reads from a string and writes to another string.
|
|
||||||
|
|
||||||
This class behaves like a socket, except that written data is
|
|
||||||
appended to a string exposed as a public data member, and when
|
|
||||||
data is read it comes from a string provided at construction.
|
|
||||||
*/
|
|
||||||
class string_iostream
|
|
||||||
{
|
|
||||||
std::string s_;
|
|
||||||
boost::asio::const_buffer cb_;
|
|
||||||
boost::asio::io_service& ios_;
|
|
||||||
std::size_t read_max_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
string_iostream(boost::asio::io_service& ios,
|
|
||||||
std::string s, std::size_t read_max =
|
|
||||||
(std::numeric_limits<std::size_t>::max)())
|
|
||||||
: s_(std::move(s))
|
|
||||||
, cb_(boost::asio::buffer(s_))
|
|
||||||
, ios_(ios)
|
|
||||||
, read_max_(read_max)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::asio::io_service&
|
|
||||||
get_io_service()
|
|
||||||
{
|
|
||||||
return ios_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
read_some(MutableBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
auto const n = read_some(buffers, ec);
|
|
||||||
if(ec)
|
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
read_some(MutableBufferSequence const& buffers,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
auto const n = boost::asio::buffer_copy(
|
|
||||||
buffers, buffer_prefix(read_max_, cb_));
|
|
||||||
if(n > 0)
|
|
||||||
{
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
cb_ = cb_ + n;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ec = boost::asio::error::eof;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence, class ReadHandler>
|
|
||||||
async_return_type<
|
|
||||||
ReadHandler, void(error_code, std::size_t)>
|
|
||||||
async_read_some(MutableBufferSequence const& buffers,
|
|
||||||
ReadHandler&& handler)
|
|
||||||
{
|
|
||||||
auto const n = boost::asio::buffer_copy(
|
|
||||||
buffers, boost::asio::buffer(s_));
|
|
||||||
error_code ec;
|
|
||||||
if(n > 0)
|
|
||||||
s_.erase(0, n);
|
|
||||||
else
|
|
||||||
ec = boost::asio::error::eof;
|
|
||||||
async_completion<ReadHandler,
|
|
||||||
void(error_code, std::size_t)> init{handler};
|
|
||||||
ios_.post(bind_handler(
|
|
||||||
init.completion_handler, ec, n));
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(ConstBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
auto const n = write_some(buffers, ec);
|
|
||||||
if(ec)
|
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(
|
|
||||||
ConstBufferSequence const& buffers, error_code& ec)
|
|
||||||
{
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
using boost::asio::buffer_cast;
|
|
||||||
auto const n = buffer_size(buffers);
|
|
||||||
str.reserve(str.size() + n);
|
|
||||||
for(boost::asio::const_buffer buffer : buffers)
|
|
||||||
str.append(buffer_cast<char const*>(buffer),
|
|
||||||
buffer_size(buffer));
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence, class WriteHandler>
|
|
||||||
async_return_type<
|
|
||||||
WriteHandler, void(error_code, std::size_t)>
|
|
||||||
async_write_some(ConstBufferSequence const& buffers,
|
|
||||||
WriteHandler&& handler)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
auto const bytes_transferred = write_some(buffers, ec);
|
|
||||||
async_completion<WriteHandler,
|
|
||||||
void(error_code, std::size_t)> init{handler};
|
|
||||||
get_io_service().post(
|
|
||||||
bind_handler(init.completion_handler, ec, bytes_transferred));
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
teardown(websocket::role_type,
|
|
||||||
string_iostream&,
|
|
||||||
boost::system::error_code& ec)
|
|
||||||
{
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class TeardownHandler>
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
async_teardown(websocket::role_type,
|
|
||||||
string_iostream& stream,
|
|
||||||
TeardownHandler&& handler)
|
|
||||||
{
|
|
||||||
stream.get_io_service().post(
|
|
||||||
bind_handler(std::move(handler),
|
|
||||||
error_code{}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // test
|
|
||||||
} // beast
|
|
||||||
} // boost
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,165 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BOOST_BEAST_TEST_STRING_ISTREAM_HPP
|
|
||||||
#define BOOST_BEAST_TEST_STRING_ISTREAM_HPP
|
|
||||||
|
|
||||||
#include <boost/beast/core/async_result.hpp>
|
|
||||||
#include <boost/beast/core/bind_handler.hpp>
|
|
||||||
#include <boost/beast/core/error.hpp>
|
|
||||||
#include <boost/beast/websocket/teardown.hpp>
|
|
||||||
#include <boost/asio/buffer.hpp>
|
|
||||||
#include <boost/asio/io_service.hpp>
|
|
||||||
#include <boost/throw_exception.hpp>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace beast {
|
|
||||||
namespace test {
|
|
||||||
|
|
||||||
/** A SyncStream and AsyncStream that reads from a string.
|
|
||||||
|
|
||||||
This class behaves like a socket, except that written data is simply
|
|
||||||
discarded, and when data is read it comes from a string provided
|
|
||||||
at construction.
|
|
||||||
*/
|
|
||||||
class string_istream
|
|
||||||
{
|
|
||||||
std::string s_;
|
|
||||||
boost::asio::const_buffer cb_;
|
|
||||||
boost::asio::io_service& ios_;
|
|
||||||
std::size_t read_max_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
string_istream(boost::asio::io_service& ios,
|
|
||||||
std::string s, std::size_t read_max =
|
|
||||||
(std::numeric_limits<std::size_t>::max)())
|
|
||||||
: s_(std::move(s))
|
|
||||||
, cb_(boost::asio::buffer(s_))
|
|
||||||
, ios_(ios)
|
|
||||||
, read_max_(read_max)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::asio::io_service&
|
|
||||||
get_io_service()
|
|
||||||
{
|
|
||||||
return ios_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
read_some(MutableBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
auto const n = read_some(buffers, ec);
|
|
||||||
if(ec)
|
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
read_some(MutableBufferSequence const& buffers,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
auto const n = boost::asio::buffer_copy(
|
|
||||||
buffers, cb_, read_max_);
|
|
||||||
if(n > 0)
|
|
||||||
{
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
cb_ = cb_ + n;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ec = boost::asio::error::eof;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence, class ReadHandler>
|
|
||||||
async_return_type<
|
|
||||||
ReadHandler, void(error_code, std::size_t)>
|
|
||||||
async_read_some(MutableBufferSequence const& buffers,
|
|
||||||
ReadHandler&& handler)
|
|
||||||
{
|
|
||||||
auto const n = boost::asio::buffer_copy(
|
|
||||||
buffers, boost::asio::buffer(s_));
|
|
||||||
error_code ec;
|
|
||||||
if(n > 0)
|
|
||||||
s_.erase(0, n);
|
|
||||||
else
|
|
||||||
ec = boost::asio::error::eof;
|
|
||||||
async_completion<ReadHandler,
|
|
||||||
void(error_code, std::size_t)> init{handler};
|
|
||||||
ios_.post(bind_handler(
|
|
||||||
init.completion_handler, ec, n));
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(ConstBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
auto const n = write_some(buffers, ec);
|
|
||||||
if(ec)
|
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(ConstBufferSequence const& buffers,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
return boost::asio::buffer_size(buffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBuffeSequence, class WriteHandler>
|
|
||||||
async_return_type<
|
|
||||||
WriteHandler, void(error_code, std::size_t)>
|
|
||||||
async_write_some(ConstBuffeSequence const& buffers,
|
|
||||||
WriteHandler&& handler)
|
|
||||||
{
|
|
||||||
async_completion<WriteHandler,
|
|
||||||
void(error_code, std::size_t)> init{handler};
|
|
||||||
ios_.post(bind_handler(init.completion_handler,
|
|
||||||
error_code{}, boost::asio::buffer_size(buffers)));
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
teardown(websocket::role_type,
|
|
||||||
string_istream&,
|
|
||||||
boost::system::error_code& ec)
|
|
||||||
{
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class TeardownHandler>
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
async_teardown(websocket::role_type,
|
|
||||||
string_istream& stream,
|
|
||||||
TeardownHandler&& handler)
|
|
||||||
{
|
|
||||||
stream.get_io_service().post(
|
|
||||||
bind_handler(std::move(handler),
|
|
||||||
error_code{}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // test
|
|
||||||
} // beast
|
|
||||||
} // boost
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,153 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BOOST_BEAST_TEST_STRING_OSTREAM_HPP
|
|
||||||
#define BOOST_BEAST_TEST_STRING_OSTREAM_HPP
|
|
||||||
|
|
||||||
#include <boost/beast/core/async_result.hpp>
|
|
||||||
#include <boost/beast/core/bind_handler.hpp>
|
|
||||||
#include <boost/beast/core/buffer_prefix.hpp>
|
|
||||||
#include <boost/beast/core/error.hpp>
|
|
||||||
#include <boost/beast/websocket/teardown.hpp>
|
|
||||||
#include <boost/asio/buffer.hpp>
|
|
||||||
#include <boost/asio/io_service.hpp>
|
|
||||||
#include <boost/throw_exception.hpp>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace beast {
|
|
||||||
namespace test {
|
|
||||||
|
|
||||||
class string_ostream
|
|
||||||
{
|
|
||||||
boost::asio::io_service& ios_;
|
|
||||||
std::size_t write_max_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
explicit
|
|
||||||
string_ostream(boost::asio::io_service& ios,
|
|
||||||
std::size_t write_max =
|
|
||||||
(std::numeric_limits<std::size_t>::max)())
|
|
||||||
: ios_(ios)
|
|
||||||
, write_max_(write_max)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::asio::io_service&
|
|
||||||
get_io_service()
|
|
||||||
{
|
|
||||||
return ios_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
read_some(MutableBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
auto const n = read_some(buffers, ec);
|
|
||||||
if(ec)
|
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
read_some(MutableBufferSequence const&,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
ec = boost::asio::error::eof;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence, class ReadHandler>
|
|
||||||
async_return_type<
|
|
||||||
ReadHandler, void(error_code, std::size_t)>
|
|
||||||
async_read_some(MutableBufferSequence const&,
|
|
||||||
ReadHandler&& handler)
|
|
||||||
{
|
|
||||||
async_completion<ReadHandler,
|
|
||||||
void(error_code, std::size_t)> init{handler};
|
|
||||||
ios_.post(bind_handler(init.completion_handler,
|
|
||||||
boost::asio::error::eof, 0));
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(ConstBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
auto const n = write_some(buffers, ec);
|
|
||||||
if(ec)
|
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(
|
|
||||||
ConstBufferSequence const& buffers, error_code& ec)
|
|
||||||
{
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
using boost::asio::buffer_cast;
|
|
||||||
auto const n =
|
|
||||||
(std::min)(buffer_size(buffers), write_max_);
|
|
||||||
str.reserve(str.size() + n);
|
|
||||||
for(boost::asio::const_buffer buffer :
|
|
||||||
buffer_prefix(n, buffers))
|
|
||||||
str.append(buffer_cast<char const*>(buffer),
|
|
||||||
buffer_size(buffer));
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence, class WriteHandler>
|
|
||||||
async_return_type<
|
|
||||||
WriteHandler, void(error_code, std::size_t)>
|
|
||||||
async_write_some(ConstBufferSequence const& buffers,
|
|
||||||
WriteHandler&& handler)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
auto const bytes_transferred = write_some(buffers, ec);
|
|
||||||
async_completion<WriteHandler,
|
|
||||||
void(error_code, std::size_t)> init{handler};
|
|
||||||
get_io_service().post(
|
|
||||||
bind_handler(init.completion_handler, ec, bytes_transferred));
|
|
||||||
return init.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
teardown(websocket::role_type,
|
|
||||||
string_ostream&,
|
|
||||||
boost::system::error_code& ec)
|
|
||||||
{
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class TeardownHandler>
|
|
||||||
friend
|
|
||||||
void
|
|
||||||
async_teardown(websocket::role_type,
|
|
||||||
string_ostream& stream,
|
|
||||||
TeardownHandler&& handler)
|
|
||||||
{
|
|
||||||
stream.get_io_service().post(
|
|
||||||
bind_handler(std::move(handler),
|
|
||||||
error_code{}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // test
|
|
||||||
} // beast
|
|
||||||
} // boost
|
|
||||||
|
|
||||||
#endif
|
|
Reference in New Issue
Block a user