forked from boostorg/beast
Improvements to increase code coverage:
* Don't include the test code in coverage reports * Add test code for missing coverage Other: * Improve the README.md * Fix warning in sha1_context * Tidy up the examples use of namespaces * Various fixes to documentation and javadocs
This commit is contained in:
71
README.md
71
README.md
@@ -1,4 +1,8 @@
|
|||||||
# Beast [](https://travis-ci.org/vinniefalco/Beast) [](https://codecov.io/gh/sublimator/Beast)
|
# Beast
|
||||||
|
|
||||||
|
[](https://travis-ci.org/vinniefalco/Beast) [![codecov]
|
||||||
|
(https://codecov.io/gh/vinniefalco/Beast/branch/master/graph/badge.svg)](https://codecov.io/gh/vinniefalco/Beast) [![Documentation]
|
||||||
|
(https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/)
|
||||||
|
|
||||||
Beast provides implementations of the HTTP and WebSocket protocols
|
Beast provides implementations of the HTTP and WebSocket protocols
|
||||||
built on top of Boost.Asio and other parts of boost.
|
built on top of Boost.Asio and other parts of boost.
|
||||||
@@ -9,10 +13,69 @@ Requirements:
|
|||||||
* C++11 or greater
|
* C++11 or greater
|
||||||
* OpenSSL (optional)
|
* OpenSSL (optional)
|
||||||
|
|
||||||
Linking applications with beast:
|
Example WebSocket program:
|
||||||
|
```C++
|
||||||
|
#include <beast/to_string.hpp>
|
||||||
|
#include <beast/websocket.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
You need to include the .cpp file `src/beast_http_nodejs_parser.cpp`
|
int main()
|
||||||
in the build script or Makefile for your program in order to link.
|
{
|
||||||
|
// Normal boost::asio setup
|
||||||
|
std::string const host = "echo.websocket.org";
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::ip::tcp::resolver r(ios);
|
||||||
|
boost::asio::ip::tcp::socket sock(ios);
|
||||||
|
boost::asio::connect(sock,
|
||||||
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||||
|
|
||||||
|
// WebSocket connect and send message using beast
|
||||||
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
||||||
|
ws.handshake(host, "/");
|
||||||
|
ws.write(boost::asio::buffer("Hello, world!"));
|
||||||
|
|
||||||
|
// Receive WebSocket message, print and close using beast
|
||||||
|
beast::streambuf sb;
|
||||||
|
beast::websocket::opcode op;
|
||||||
|
ws.read(op, sb);
|
||||||
|
ws.close(beast::websocket::close_code::normal);
|
||||||
|
std::cout << to_string(sb.data()) << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example HTTP program:
|
||||||
|
```C++
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Normal boost::asio setup
|
||||||
|
std::string const host = "boost.org";
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::ip::tcp::resolver r(ios);
|
||||||
|
boost::asio::ip::tcp::socket sock(ios);
|
||||||
|
boost::asio::connect(sock,
|
||||||
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
|
// Send HTTP request using beast
|
||||||
|
beast::http::request_v1<beast::http::empty_body> req({"GET", "/", 11});
|
||||||
|
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
||||||
|
req.headers.replace("User-Agent", "Beast");
|
||||||
|
beast::http::prepare(req);
|
||||||
|
beast::http::write(sock, req);
|
||||||
|
|
||||||
|
// Receive and print HTTP response using beast
|
||||||
|
beast::streambuf sb;
|
||||||
|
beast::http::response_v1<beast::http::streambuf_body> resp;
|
||||||
|
beast::http::read(sock, sb, resp);
|
||||||
|
std::cout << resp;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Links:
|
Links:
|
||||||
|
|
||||||
|
17
TODO.txt
17
TODO.txt
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
General:
|
General:
|
||||||
* Use SFINAE on return values (search for "class =")
|
* Use SFINAE on return values (search for "class =")
|
||||||
|
* Remove http,websocket error_code types and use the one in <beast/error.hpp>
|
||||||
|
|
||||||
Boost.Http
|
Boost.Http
|
||||||
* Use enum instead of bool in isRequest
|
* Use enum instead of bool in isRequest
|
||||||
@@ -17,6 +18,8 @@ Docs:
|
|||||||
- See if we can include them now that xsl is fixed
|
- See if we can include them now that xsl is fixed
|
||||||
* Implement cleanup-param to remove spaces around template arguments
|
* Implement cleanup-param to remove spaces around template arguments
|
||||||
e.g. in basic_streambuf move constructor members
|
e.g. in basic_streambuf move constructor members
|
||||||
|
* Don't put using namespace at file scope in examples,
|
||||||
|
do something like "using ba = boost::asio" instead.
|
||||||
|
|
||||||
Core:
|
Core:
|
||||||
* Replace Jamroot with Jamfile
|
* Replace Jamroot with Jamfile
|
||||||
@@ -26,13 +29,13 @@ Core:
|
|||||||
WebSocket:
|
WebSocket:
|
||||||
* optimized versions of key/masking, choose prepared_key size
|
* optimized versions of key/masking, choose prepared_key size
|
||||||
* invokable unit test
|
* invokable unit test
|
||||||
* Finish up all of static_string including tests
|
* Don't try to read requests into empty_body
|
||||||
* Don't rely on default constructible mutable buffers
|
|
||||||
type in read_frame_op (smb_type). To see the error, use
|
|
||||||
boost::asio::streambuf in websocket_async_echo_peer
|
|
||||||
|
|
||||||
HTTP:
|
HTTP:
|
||||||
* Define Parser concept in HTTP
|
* Define Parser concept in HTTP
|
||||||
|
- Need parse version of read() so caller can set parser options
|
||||||
|
like maximum size of headers, maximum body size, etc
|
||||||
* trim public interface of rfc2616.h to essentials only
|
* trim public interface of rfc2616.h to essentials only
|
||||||
* add bool should_close(message_v1 const&) to replace the use
|
* add bool should_close(message_v1 const&) to replace the use
|
||||||
of eof return value from write and async_write
|
of eof return value from write and async_write
|
||||||
@@ -40,7 +43,7 @@ HTTP:
|
|||||||
* More fine grained parser errors
|
* More fine grained parser errors
|
||||||
* HTTP parser size limit with test (configurable?)
|
* HTTP parser size limit with test (configurable?)
|
||||||
* HTTP parser trailers with test
|
* HTTP parser trailers with test
|
||||||
* URL parser, strong URL checking in HTTP parser
|
* URL parser, strong URL character checking in HTTP parser
|
||||||
* Update for rfc7230
|
* Update for rfc7230
|
||||||
* Consider rename to MessageBody concept
|
* Consider rename to MessageBody concept
|
||||||
* Fix prepare() calling content_length() without init()
|
* Fix prepare() calling content_length() without init()
|
||||||
@@ -48,3 +51,7 @@ HTTP:
|
|||||||
* Complete allocator testing in basic_streambuf, basic_headers
|
* Complete allocator testing in basic_streambuf, basic_headers
|
||||||
* Fix http::async_write op, case 3 should break at the end.
|
* Fix http::async_write op, case 3 should break at the end.
|
||||||
* Add tests for writer using the resume function / coros
|
* Add tests for writer using the resume function / coros
|
||||||
|
* Custom HTTP error codes for various situations
|
||||||
|
* Make empty_body write-only, remove reader nested type
|
||||||
|
* Add concepts WritableBody ReadableBody with type checks,
|
||||||
|
check them in read and write functions
|
||||||
|
@@ -112,19 +112,17 @@ int main()
|
|||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
using namespace beast::http;
|
|
||||||
|
|
||||||
// Send HTTP request using beast
|
// Send HTTP request using beast
|
||||||
request<empty_body> req({"GET", "/", 11});
|
beast::http::request_v1<beast::http::empty_body> req({"GET", "/", 11});
|
||||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
||||||
req.headers.replace("User-Agent", "Beast");
|
req.headers.replace("User-Agent", "Beast");
|
||||||
prepare(req);
|
beast::http::prepare(req);
|
||||||
write(sock, req);
|
beast::http::write(sock, req);
|
||||||
|
|
||||||
// Receive and print HTTP response using beast
|
// Receive and print HTTP response using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
response<streambuf_body> resp;
|
beast::http::response_v1<beast::http::streambuf_body> resp;
|
||||||
read(sock, sb, resp);
|
beast::http::read(sock, sb, resp);
|
||||||
std::cout << resp;
|
std::cout << resp;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -147,18 +145,16 @@ int main()
|
|||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||||
|
|
||||||
using namespace beast::websocket;
|
|
||||||
|
|
||||||
// WebSocket connect and send message using beast
|
// WebSocket connect and send message using beast
|
||||||
stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
||||||
ws.handshake(host, "/");
|
ws.handshake(host, "/");
|
||||||
ws.write(boost::asio::buffer("Hello, world!"));
|
ws.write(boost::asio::buffer("Hello, world!"));
|
||||||
|
|
||||||
// Receive WebSocket message, print and close using beast
|
// Receive WebSocket message, print and close using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
opcode op;
|
beast::websocket::opcode op;
|
||||||
ws.read(op, sb);
|
ws.read(op, sb);
|
||||||
ws.close(close_code::normal);
|
ws.close(beast::websocket::close_code::normal);
|
||||||
std::cout << to_string(sb.data()) << "\n";
|
std::cout << to_string(sb.data()) << "\n";
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@@ -44,7 +44,7 @@ libraries. It is not designed to be end-user facing. There is no convenient
|
|||||||
class that implements the core of a web server, nor is there a convenient
|
class that implements the core of a web server, nor is there a convenient
|
||||||
class to quickly perform common operations such as fetching a file or
|
class to quickly perform common operations such as fetching a file or
|
||||||
connecting and retrieving a document from a secure connection. These
|
connecting and retrieving a document from a secure connection. These
|
||||||
use-cases are important. But this library does not try to do that. Instead,
|
use-cases are important, but this library does not try to do that. Instead,
|
||||||
it offers primitives that can be used to build those user-facing algorithms.
|
it offers primitives that can be used to build those user-facing algorithms.
|
||||||
|
|
||||||
A HTTP message (referred to hereafter as "message") contains request or
|
A HTTP message (referred to hereafter as "message") contains request or
|
||||||
|
@@ -28,7 +28,7 @@ using namespace boost::asio;
|
|||||||
|
|
||||||
template<class String>
|
template<class String>
|
||||||
void
|
void
|
||||||
err(error_code const& ec, String const& what)
|
err(beast::error_code const& ec, String const& what)
|
||||||
{
|
{
|
||||||
std::cerr << what << ": " << ec.message() << std::endl;
|
std::cerr << what << ": " << ec.message() << std::endl;
|
||||||
}
|
}
|
||||||
|
@@ -20,18 +20,16 @@ int main()
|
|||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
using namespace beast::http;
|
|
||||||
|
|
||||||
// Send HTTP request using beast
|
// Send HTTP request using beast
|
||||||
request_v1<empty_body> req({"GET", "/", 11});
|
beast::http::request_v1<beast::http::empty_body> req({"GET", "/", 11});
|
||||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
||||||
req.headers.replace("User-Agent", "Beast");
|
req.headers.replace("User-Agent", "Beast");
|
||||||
prepare(req);
|
beast::http::prepare(req);
|
||||||
write(sock, req);
|
beast::http::write(sock, req);
|
||||||
|
|
||||||
// Receive and print HTTP response using beast
|
// Receive and print HTTP response using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
response_v1<streambuf_body> resp;
|
beast::http::response_v1<beast::http::streambuf_body> resp;
|
||||||
read(sock, sb, resp);
|
beast::http::read(sock, sb, resp);
|
||||||
std::cout << resp;
|
std::cout << resp;
|
||||||
}
|
}
|
||||||
|
@@ -21,17 +21,15 @@ int main()
|
|||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||||
|
|
||||||
using namespace beast::websocket;
|
|
||||||
|
|
||||||
// WebSocket connect and send message using beast
|
// WebSocket connect and send message using beast
|
||||||
stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
||||||
ws.handshake(host, "/");
|
ws.handshake(host, "/");
|
||||||
ws.write(boost::asio::buffer("Hello, world!"));
|
ws.write(boost::asio::buffer("Hello, world!"));
|
||||||
|
|
||||||
// Receive WebSocket message, print and close using beast
|
// Receive WebSocket message, print and close using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
opcode op;
|
beast::websocket::opcode op;
|
||||||
ws.read(op, sb);
|
ws.read(op, sb);
|
||||||
ws.close(close_code::normal);
|
ws.close(beast::websocket::close_code::normal);
|
||||||
std::cout << to_string(sb.data()) << "\n";
|
std::cout << to_string(sb.data()) << "\n";
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,6 @@ namespace beast {
|
|||||||
template<class MutableBufferSequence>
|
template<class MutableBufferSequence>
|
||||||
class buffers_adapter
|
class buffers_adapter
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
static_assert(is_MutableBufferSequence<MutableBufferSequence>::value,
|
static_assert(is_MutableBufferSequence<MutableBufferSequence>::value,
|
||||||
"MutableBufferSequence requirements not met");
|
"MutableBufferSequence requirements not met");
|
||||||
|
|
||||||
|
@@ -5,18 +5,20 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef BEAST_HTTP_ERROR_HPP
|
#ifndef BEAST_ERROR_HPP
|
||||||
#define BEAST_HTTP_ERROR_HPP
|
#define BEAST_ERROR_HPP
|
||||||
|
|
||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
#include <boost/system/system_error.hpp>
|
#include <boost/system/system_error.hpp>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
|
||||||
|
|
||||||
|
/// The type of error code used by the library
|
||||||
using error_code = boost::system::error_code;
|
using error_code = boost::system::error_code;
|
||||||
|
|
||||||
} // http
|
/// The type of system error thrown by the library
|
||||||
|
using system_error = boost::system::system_error;
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
@@ -12,7 +12,6 @@
|
|||||||
#include <beast/http/basic_parser_v1.hpp>
|
#include <beast/http/basic_parser_v1.hpp>
|
||||||
#include <beast/http/body_type.hpp>
|
#include <beast/http/body_type.hpp>
|
||||||
#include <beast/http/empty_body.hpp>
|
#include <beast/http/empty_body.hpp>
|
||||||
#include <beast/http/error.hpp>
|
|
||||||
#include <beast/http/headers.hpp>
|
#include <beast/http/headers.hpp>
|
||||||
#include <beast/http/message.hpp>
|
#include <beast/http/message.hpp>
|
||||||
#include <beast/http/message_v1.hpp>
|
#include <beast/http/message_v1.hpp>
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
// Convenience header to include everything
|
// Convenience header to include everything
|
||||||
// needed when declarating a user defined Body type.
|
// needed when declarating a user defined Body type.
|
||||||
|
|
||||||
#include <beast/http/error.hpp>
|
#include <beast/error.hpp>
|
||||||
#include <beast/http/message.hpp>
|
#include <beast/http/message.hpp>
|
||||||
#include <beast/http/resume_context.hpp>
|
#include <beast/http/resume_context.hpp>
|
||||||
#include <boost/logic/tribool.hpp>
|
#include <boost/logic/tribool.hpp>
|
||||||
|
@@ -149,7 +149,9 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
case s_req_url_start:
|
case s_req_url_start:
|
||||||
if(ch == ' ')
|
if(ch == ' ')
|
||||||
return err(parse_error::bad_uri);
|
return err(parse_error::bad_uri);
|
||||||
// VFALCO TODO Require valid URL character
|
// VFALCO TODO Better checking for valid URL characters
|
||||||
|
if(! is_text(ch))
|
||||||
|
return err(parse_error::bad_uri);
|
||||||
if(cb(&self::call_on_uri))
|
if(cb(&self::call_on_uri))
|
||||||
return used();
|
return used();
|
||||||
s_ = s_req_url;
|
s_ = s_req_url;
|
||||||
@@ -163,7 +165,9 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
s_ = s_req_http_start;
|
s_ = s_req_http_start;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// VFALCO TODO Require valid URL character
|
// VFALCO TODO Better checking for valid URL characters
|
||||||
|
if(! is_text(ch))
|
||||||
|
return err(parse_error::bad_uri);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case s_req_http_start:
|
case s_req_http_start:
|
||||||
|
@@ -212,6 +212,18 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class SyncReadStream, class Streambuf,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
void
|
||||||
|
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||||
|
message_v1<isRequest, Body, Headers>& msg)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
read(stream, streambuf, msg, ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
}
|
||||||
|
|
||||||
template<class SyncReadStream, class Streambuf,
|
template<class SyncReadStream, class Streambuf,
|
||||||
bool isRequest, class Body, class Headers>
|
bool isRequest, class Body, class Headers>
|
||||||
void
|
void
|
||||||
|
@@ -8,8 +8,7 @@
|
|||||||
#ifndef BEAST_HTTP_PARSE_ERROR_HPP
|
#ifndef BEAST_HTTP_PARSE_ERROR_HPP
|
||||||
#define BEAST_HTTP_PARSE_ERROR_HPP
|
#define BEAST_HTTP_PARSE_ERROR_HPP
|
||||||
|
|
||||||
#include <beast/http/error.hpp>
|
#include <beast/error.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
|
@@ -8,8 +8,8 @@
|
|||||||
#ifndef BEAST_HTTP_PARSER_V1_HPP
|
#ifndef BEAST_HTTP_PARSER_V1_HPP
|
||||||
#define BEAST_HTTP_PARSER_V1_HPP
|
#define BEAST_HTTP_PARSER_V1_HPP
|
||||||
|
|
||||||
|
#include <beast/error.hpp>
|
||||||
#include <beast/http/basic_parser_v1.hpp>
|
#include <beast/http/basic_parser_v1.hpp>
|
||||||
#include <beast/http/error.hpp>
|
|
||||||
#include <beast/http/message_v1.hpp>
|
#include <beast/http/message_v1.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
#ifndef BEAST_HTTP_READ_HPP
|
#ifndef BEAST_HTTP_READ_HPP
|
||||||
#define BEAST_HTTP_READ_HPP
|
#define BEAST_HTTP_READ_HPP
|
||||||
|
|
||||||
#include <beast/http/error.hpp>
|
#include <beast/error.hpp>
|
||||||
#include <beast/http/parser_v1.hpp>
|
#include <beast/http/parser_v1.hpp>
|
||||||
#include <beast/async_completion.hpp>
|
#include <beast/async_completion.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
@@ -47,13 +47,7 @@ template<class SyncReadStream, class Streambuf,
|
|||||||
bool isRequest, class Body, class Headers>
|
bool isRequest, class Body, class Headers>
|
||||||
void
|
void
|
||||||
read(SyncReadStream& stream, Streambuf& streambuf,
|
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||||
message_v1<isRequest, Body, Headers>& msg)
|
message_v1<isRequest, Body, Headers>& msg);
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
read(stream, streambuf, msg, ec);
|
|
||||||
if(ec)
|
|
||||||
throw boost::system::system_error{ec};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read a HTTP/1 message from a stream.
|
/** Read a HTTP/1 message from a stream.
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
#ifndef BEAST_HTTP_TYPE_CHECK_HPP
|
#ifndef BEAST_HTTP_TYPE_CHECK_HPP
|
||||||
#define BEAST_HTTP_TYPE_CHECK_HPP
|
#define BEAST_HTTP_TYPE_CHECK_HPP
|
||||||
|
|
||||||
#include <beast/http/error.hpp>
|
#include <beast/error.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
#ifndef BEAST_HTTP_WRITE_HPP
|
#ifndef BEAST_HTTP_WRITE_HPP
|
||||||
#define BEAST_HTTP_WRITE_HPP
|
#define BEAST_HTTP_WRITE_HPP
|
||||||
|
|
||||||
#include <beast/http/error.hpp>
|
#include <beast/error.hpp>
|
||||||
#include <beast/http/message_v1.hpp>
|
#include <beast/http/message_v1.hpp>
|
||||||
#include <beast/async_completion.hpp>
|
#include <beast/async_completion.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
@@ -33,7 +33,7 @@ namespace http {
|
|||||||
The implementation will automatically perform chunk encoding if
|
The implementation will automatically perform chunk encoding if
|
||||||
the contents of the message indicate that chunk encoding is required.
|
the contents of the message indicate that chunk encoding is required.
|
||||||
If the semantics of the message indicate that the connection should
|
If the semantics of the message indicate that the connection should
|
||||||
be closed after the message is sent, the error returns from this
|
be closed after the message is sent, the error thrown from this
|
||||||
function will be `boost::asio::error::eof`.
|
function will be `boost::asio::error::eof`.
|
||||||
|
|
||||||
@param stream The stream to which the data is to be written.
|
@param stream The stream to which the data is to be written.
|
||||||
@@ -64,7 +64,7 @@ write(SyncWriteStream& stream,
|
|||||||
The implementation will automatically perform chunk encoding if
|
The implementation will automatically perform chunk encoding if
|
||||||
the contents of the message indicate that chunk encoding is required.
|
the contents of the message indicate that chunk encoding is required.
|
||||||
If the semantics of the message indicate that the connection should
|
If the semantics of the message indicate that the connection should
|
||||||
be closed after the message is sent, the error returns from this
|
be closed after the message is sent, the error returned from this
|
||||||
function will be `boost::asio::error::eof`.
|
function will be `boost::asio::error::eof`.
|
||||||
|
|
||||||
@param stream The stream to which the data is to be written.
|
@param stream The stream to which the data is to be written.
|
||||||
|
@@ -582,7 +582,7 @@ basic_streambuf<Allocator>::prepare(size_type n) ->
|
|||||||
list_.push_back(e);
|
list_.push_back(e);
|
||||||
if(out_ == list_.end())
|
if(out_ == list_.end())
|
||||||
out_ = list_.iterator_to(e);
|
out_ = list_.iterator_to(e);
|
||||||
if(n > e.size())
|
if(n >= e.size())
|
||||||
{
|
{
|
||||||
out_end_ = e.size();
|
out_end_ = e.size();
|
||||||
n -= e.size();
|
n -= e.size();
|
||||||
|
@@ -469,9 +469,8 @@ template<class MutableBufferSequence>
|
|||||||
void
|
void
|
||||||
buffers_adapter<MutableBufferSequence>::consume(std::size_t n)
|
buffers_adapter<MutableBufferSequence>::consume(std::size_t n)
|
||||||
{
|
{
|
||||||
for(;;)
|
using boost::asio::buffer_size;
|
||||||
{
|
while(begin_ != out_)
|
||||||
if(begin_ != out_)
|
|
||||||
{
|
{
|
||||||
auto const avail =
|
auto const avail =
|
||||||
buffer_size(*begin_) - in_pos_;
|
buffer_size(*begin_) - in_pos_;
|
||||||
@@ -479,15 +478,13 @@ buffers_adapter<MutableBufferSequence>::consume(std::size_t n)
|
|||||||
{
|
{
|
||||||
in_size_ -= n;
|
in_size_ -= n;
|
||||||
in_pos_ += n;
|
in_pos_ += n;
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
n -= avail;
|
n -= avail;
|
||||||
in_size_ -= avail;
|
in_size_ -= avail;
|
||||||
in_pos_ = 0;
|
in_pos_ = 0;
|
||||||
++begin_;
|
++begin_;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
auto const avail = out_pos_ - in_pos_;
|
auto const avail = out_pos_ - in_pos_;
|
||||||
if(n < avail)
|
if(n < avail)
|
||||||
{
|
{
|
||||||
@@ -497,22 +494,8 @@ buffers_adapter<MutableBufferSequence>::consume(std::size_t n)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
in_size_ -= avail;
|
in_size_ -= avail;
|
||||||
if(out_pos_ != out_end_||
|
|
||||||
out_ != std::prev(bs_.end()))
|
|
||||||
{
|
|
||||||
in_pos_ = out_pos_;
|
in_pos_ = out_pos_;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Use the whole buffer now.
|
|
||||||
in_pos_ = 0;
|
|
||||||
out_pos_ = 0;
|
|
||||||
out_end_ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
@@ -279,13 +279,6 @@ public:
|
|||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reduces memory usage by freeing unused memory.
|
|
||||||
void
|
|
||||||
shrink_to_fit()
|
|
||||||
{
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clears the contents.
|
/// Clears the contents.
|
||||||
void
|
void
|
||||||
clear()
|
clear()
|
||||||
@@ -310,7 +303,8 @@ public:
|
|||||||
|
|
||||||
/// Compare two character sequences.
|
/// Compare two character sequences.
|
||||||
template<std::size_t M>
|
template<std::size_t M>
|
||||||
int compare(static_string<M, CharT, Traits> const& rhs) const;
|
int
|
||||||
|
compare(static_string<M, CharT, Traits> const& rhs) const;
|
||||||
|
|
||||||
/// Return the characters as a `basic_string`.
|
/// Return the characters as a `basic_string`.
|
||||||
std::basic_string<CharT, Traits>
|
std::basic_string<CharT, Traits>
|
||||||
@@ -488,7 +482,8 @@ assign(CharT const* s)
|
|||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
int compare(
|
int
|
||||||
|
compare(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
const CharT (&s)[M])
|
const CharT (&s)[M])
|
||||||
{
|
{
|
||||||
@@ -512,27 +507,13 @@ int compare(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
int compare(
|
inline
|
||||||
|
int
|
||||||
|
compare(
|
||||||
const CharT (&s)[M],
|
const CharT (&s)[M],
|
||||||
static_string<N, CharT, Traits> const& rhs)
|
static_string<N, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
if(M-1 < rhs.size())
|
return -compare(rhs, s);
|
||||||
{
|
|
||||||
auto const v = Traits::compare(
|
|
||||||
&s[0], rhs.data(), M-1);
|
|
||||||
if(v == 0)
|
|
||||||
return -1;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
else if(M-1 > rhs.size())
|
|
||||||
{
|
|
||||||
auto const v = Traits::compare(
|
|
||||||
&s[0], rhs.data(), rhs.size());
|
|
||||||
if(v == 0)
|
|
||||||
return 1;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
return Traits::compare(&s[0], rhs.data(), M-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
@@ -540,7 +521,8 @@ int compare(
|
|||||||
#if ! GENERATING_DOCS
|
#if ! GENERATING_DOCS
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator==(
|
bool
|
||||||
|
operator==(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -548,7 +530,8 @@ bool operator==(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator!=(
|
bool
|
||||||
|
operator!=(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -556,7 +539,8 @@ bool operator!=(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator<(
|
bool
|
||||||
|
operator<(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -564,7 +548,8 @@ bool operator<(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator<=(
|
bool
|
||||||
|
operator<=(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -572,7 +557,8 @@ bool operator<=(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator>(
|
bool
|
||||||
|
operator>(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -580,7 +566,8 @@ bool operator>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator>=(
|
bool
|
||||||
|
operator>=(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -590,7 +577,8 @@ bool operator>=(
|
|||||||
//---
|
//---
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator==(
|
bool
|
||||||
|
operator==(
|
||||||
const CharT (&s)[N],
|
const CharT (&s)[N],
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -598,7 +586,8 @@ bool operator==(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
bool operator==(
|
bool
|
||||||
|
operator==(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
const CharT (&s)[M])
|
const CharT (&s)[M])
|
||||||
{
|
{
|
||||||
@@ -606,7 +595,8 @@ bool operator==(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator!=(
|
bool
|
||||||
|
operator!=(
|
||||||
const CharT (&s)[N],
|
const CharT (&s)[N],
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -614,7 +604,8 @@ bool operator!=(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
bool operator!=(
|
bool
|
||||||
|
operator!=(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
const CharT (&s)[M])
|
const CharT (&s)[M])
|
||||||
{
|
{
|
||||||
@@ -622,7 +613,8 @@ bool operator!=(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator<(
|
bool
|
||||||
|
operator<(
|
||||||
const CharT (&s)[N],
|
const CharT (&s)[N],
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -630,7 +622,8 @@ bool operator<(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
bool operator<(
|
bool
|
||||||
|
operator<(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
const CharT (&s)[M])
|
const CharT (&s)[M])
|
||||||
{
|
{
|
||||||
@@ -638,7 +631,8 @@ bool operator<(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator<=(
|
bool
|
||||||
|
operator<=(
|
||||||
const CharT (&s)[N],
|
const CharT (&s)[N],
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -646,7 +640,8 @@ bool operator<=(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
bool operator<=(
|
bool
|
||||||
|
operator<=(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
const CharT (&s)[M])
|
const CharT (&s)[M])
|
||||||
{
|
{
|
||||||
@@ -654,7 +649,8 @@ bool operator<=(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator>(
|
bool
|
||||||
|
operator>(
|
||||||
const CharT (&s)[N],
|
const CharT (&s)[N],
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -662,7 +658,8 @@ bool operator>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
bool operator>(
|
bool
|
||||||
|
operator>(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
const CharT (&s)[M])
|
const CharT (&s)[M])
|
||||||
{
|
{
|
||||||
@@ -670,7 +667,8 @@ bool operator>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
bool operator>=(
|
bool
|
||||||
|
operator>=(
|
||||||
const CharT (&s)[N],
|
const CharT (&s)[N],
|
||||||
static_string<M, CharT, Traits> const& rhs)
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
{
|
{
|
||||||
@@ -678,7 +676,8 @@ bool operator>=(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
bool operator>=(
|
bool
|
||||||
|
operator>=(
|
||||||
static_string<N, CharT, Traits> const& lhs,
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
const CharT (&s)[M])
|
const CharT (&s)[M])
|
||||||
{
|
{
|
||||||
|
@@ -127,7 +127,7 @@ ror(T t, unsigned n = 1)
|
|||||||
static_cast<typename std::make_unsigned<T>::type>(t) >> n));
|
static_cast<typename std::make_unsigned<T>::type>(t) >> n));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 32-bit Uuoptimized
|
// 32-bit Unoptimized
|
||||||
//
|
//
|
||||||
template<class = void>
|
template<class = void>
|
||||||
void
|
void
|
||||||
|
@@ -8,15 +8,11 @@
|
|||||||
#ifndef BEAST_WEBSOCKET_ERROR_HPP
|
#ifndef BEAST_WEBSOCKET_ERROR_HPP
|
||||||
#define BEAST_WEBSOCKET_ERROR_HPP
|
#define BEAST_WEBSOCKET_ERROR_HPP
|
||||||
|
|
||||||
#include <boost/system/error_code.hpp>
|
#include <beast/error.hpp>
|
||||||
#include <boost/system/system_error.hpp>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace websocket {
|
namespace websocket {
|
||||||
|
|
||||||
/// The type of error used by functions and completion handlers.
|
|
||||||
using error_code = boost::system::error_code;
|
|
||||||
|
|
||||||
/// Error codes returned from @ref stream operations.
|
/// Error codes returned from @ref stream operations.
|
||||||
enum class error
|
enum class error
|
||||||
{
|
{
|
||||||
|
@@ -617,7 +617,7 @@ public:
|
|||||||
|
|
||||||
If the passed HTTP request is a valid HTTP WebSocket Upgrade
|
If the passed HTTP request is a valid HTTP WebSocket Upgrade
|
||||||
request, a HTTP response is sent back indicating a successful
|
request, a HTTP response is sent back indicating a successful
|
||||||
upgrade. When this asynchronous operaiton completes, the stream is
|
upgrade. When this asynchronous operation completes, the stream is
|
||||||
then ready to send and receive WebSocket protocol frames and messages.
|
then ready to send and receive WebSocket protocol frames and messages.
|
||||||
|
|
||||||
If the HTTP request is invalid or cannot be satisfied, a HTTP
|
If the HTTP request is invalid or cannot be satisfied, a HTTP
|
||||||
|
@@ -136,7 +136,7 @@ namespace websocket_helpers {
|
|||||||
template<class Socket>
|
template<class Socket>
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
call_teardown(Socket& socket, websocket::error_code& ec)
|
call_teardown(Socket& socket, error_code& ec)
|
||||||
{
|
{
|
||||||
using websocket::teardown;
|
using websocket::teardown;
|
||||||
teardown(socket, ec);
|
teardown(socket, ec);
|
||||||
|
@@ -13,6 +13,7 @@ add_executable (core-tests
|
|||||||
buffer_concepts.cpp
|
buffer_concepts.cpp
|
||||||
buffers_adapter.cpp
|
buffers_adapter.cpp
|
||||||
consuming_buffers.cpp
|
consuming_buffers.cpp
|
||||||
|
error.cpp
|
||||||
handler_alloc.cpp
|
handler_alloc.cpp
|
||||||
handler_concepts.cpp
|
handler_concepts.cpp
|
||||||
http.cpp
|
http.cpp
|
||||||
@@ -38,12 +39,14 @@ endif()
|
|||||||
|
|
||||||
add_executable (http-tests
|
add_executable (http-tests
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
fail_stream.hpp
|
||||||
|
string_stream.hpp
|
||||||
|
yield_to.hpp
|
||||||
main.cpp
|
main.cpp
|
||||||
http/basic_headers.cpp
|
http/basic_headers.cpp
|
||||||
http/basic_parser_v1.cpp
|
http/basic_parser_v1.cpp
|
||||||
http/body_type.cpp
|
http/body_type.cpp
|
||||||
http/empty_body.cpp
|
http/empty_body.cpp
|
||||||
http/error.cpp
|
|
||||||
http/headers.cpp
|
http/headers.cpp
|
||||||
http/message.cpp
|
http/message.cpp
|
||||||
http/message_v1.cpp
|
http/message_v1.cpp
|
||||||
@@ -79,6 +82,8 @@ endif()
|
|||||||
add_executable (websocket-tests
|
add_executable (websocket-tests
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
fail_stream.hpp
|
fail_stream.hpp
|
||||||
|
string_stream.hpp
|
||||||
|
yield_to.hpp
|
||||||
websocket/websocket_async_echo_peer.hpp
|
websocket/websocket_async_echo_peer.hpp
|
||||||
websocket/websocket_sync_echo_peer.hpp
|
websocket/websocket_sync_echo_peer.hpp
|
||||||
main.cpp
|
main.cpp
|
||||||
|
@@ -16,6 +16,7 @@ unit-test core-tests :
|
|||||||
buffer_concepts.cpp
|
buffer_concepts.cpp
|
||||||
buffers_adapter.cpp
|
buffers_adapter.cpp
|
||||||
consuming_buffers.cpp
|
consuming_buffers.cpp
|
||||||
|
error.cpp
|
||||||
handler_alloc.cpp
|
handler_alloc.cpp
|
||||||
handler_concepts.cpp
|
handler_concepts.cpp
|
||||||
http.cpp
|
http.cpp
|
||||||
@@ -41,7 +42,6 @@ unit-test http-tests :
|
|||||||
http/basic_parser_v1.cpp
|
http/basic_parser_v1.cpp
|
||||||
http/body_type.cpp
|
http/body_type.cpp
|
||||||
http/empty_body.cpp
|
http/empty_body.cpp
|
||||||
http/error.cpp
|
|
||||||
http/headers.cpp
|
http/headers.cpp
|
||||||
http/message.cpp
|
http/message.cpp
|
||||||
http/message_v1.cpp
|
http/message_v1.cpp
|
||||||
|
@@ -9,8 +9,10 @@
|
|||||||
#include <beast/basic_streambuf.hpp>
|
#include <beast/basic_streambuf.hpp>
|
||||||
|
|
||||||
#include <beast/streambuf.hpp>
|
#include <beast/streambuf.hpp>
|
||||||
|
#include <beast/to_string.hpp>
|
||||||
#include <beast/detail/unit_test/suite.hpp>
|
#include <beast/detail/unit_test/suite.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -137,30 +139,117 @@ public:
|
|||||||
class basic_streambuf_test : public beast::detail::unit_test::suite
|
class basic_streambuf_test : public beast::detail::unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template<class ConstBufferSequence>
|
template<class Alloc1, class Alloc2>
|
||||||
static
|
static
|
||||||
std::string
|
bool
|
||||||
to_string(ConstBufferSequence const& bs)
|
eq(basic_streambuf<Alloc1> const& sb1,
|
||||||
|
basic_streambuf<Alloc2> const& sb2)
|
||||||
{
|
{
|
||||||
|
return to_string(sb1.data()) == to_string(sb2.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testSpecialMembers()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
using boost::asio::buffer_cast;
|
using boost::asio::buffer_cast;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
std::string s;
|
std::string const s = "Hello, world";
|
||||||
s.reserve(buffer_size(bs));
|
expect(s.size() == 12);
|
||||||
for(auto const& b : bs)
|
for(std::size_t i = 1; i < 12; ++i) {
|
||||||
s.append(buffer_cast<char const*>(b),
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
buffer_size(b));
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
return s;
|
std::size_t z = s.size() - (x + y);
|
||||||
|
{
|
||||||
|
streambuf sb(i);
|
||||||
|
sb.commit(buffer_copy(sb.prepare(x), buffer(s.data(), x)));
|
||||||
|
sb.commit(buffer_copy(sb.prepare(y), buffer(s.data()+x, y)));
|
||||||
|
sb.commit(buffer_copy(sb.prepare(z), buffer(s.data()+x+y, z)));
|
||||||
|
expect(to_string(sb.data()) == s);
|
||||||
|
{
|
||||||
|
streambuf sb2(sb);
|
||||||
|
expect(eq(sb, sb2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
streambuf sb2;
|
||||||
|
sb2 = sb;
|
||||||
|
expect(eq(sb, sb2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
streambuf sb2(std::move(sb));
|
||||||
|
expect(to_string(sb2.data()) == s);
|
||||||
|
expect(buffer_size(sb.data()) == 0);
|
||||||
|
sb = std::move(sb2);
|
||||||
|
expect(to_string(sb.data()) == s);
|
||||||
|
expect(buffer_size(sb2.data()) == 0);
|
||||||
|
}
|
||||||
|
sb = sb;
|
||||||
|
sb = std::move(sb);
|
||||||
|
}
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAllocator()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
test_allocator<char, false, false, false, false>;
|
||||||
|
using sb_type = basic_streambuf<alloc_type>;
|
||||||
|
sb_type sb;
|
||||||
|
expect(sb.get_allocator().id() == 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
test_allocator<char, false, false, false, false>;
|
||||||
|
using sb_type = basic_streambuf<alloc_type>;
|
||||||
|
sb_type sb;
|
||||||
|
expect(sb.get_allocator().id() == 2);
|
||||||
|
sb_type sb2(sb);
|
||||||
|
expect(sb2.get_allocator().id() == 2);
|
||||||
|
sb_type sb3(sb, alloc_type{});
|
||||||
|
//expect(sb3.get_allocator().id() == 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testPrepare()
|
testPrepare()
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
|
{
|
||||||
streambuf sb(2);
|
streambuf sb(2);
|
||||||
expect(buffer_size(sb.prepare(5)) == 5);
|
expect(buffer_size(sb.prepare(5)) == 5);
|
||||||
expect(buffer_size(sb.prepare(8)) == 8);
|
expect(buffer_size(sb.prepare(8)) == 8);
|
||||||
expect(buffer_size(sb.prepare(7)) == 7);
|
expect(buffer_size(sb.prepare(7)) == 7);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
streambuf sb(2);
|
||||||
|
sb.prepare(2);
|
||||||
|
{
|
||||||
|
auto const bs = sb.prepare(5);
|
||||||
|
expect(std::distance(
|
||||||
|
bs.begin(), bs.end()) == 2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const bs = sb.prepare(8);
|
||||||
|
expect(std::distance(
|
||||||
|
bs.begin(), bs.end()) == 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto const bs = sb.prepare(4);
|
||||||
|
expect(std::distance(
|
||||||
|
bs.begin(), bs.end()) == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testCommit()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
streambuf sb(2);
|
||||||
|
sb.prepare(2);
|
||||||
|
sb.prepare(5);
|
||||||
|
sb.commit(1);
|
||||||
|
expect(buffer_size(sb.data()) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
void testStreambuf()
|
void testStreambuf()
|
||||||
{
|
{
|
||||||
@@ -257,88 +346,67 @@ public:
|
|||||||
}}}}}
|
}}}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Alloc1, class Alloc2>
|
void testIterators()
|
||||||
static
|
|
||||||
bool
|
|
||||||
eq(basic_streambuf<Alloc1> const& sb1,
|
|
||||||
basic_streambuf<Alloc2> const& sb2)
|
|
||||||
{
|
{
|
||||||
return to_string(sb1.data()) == to_string(sb2.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void testSpecial()
|
|
||||||
{
|
|
||||||
using boost::asio::buffer;
|
|
||||||
using boost::asio::buffer_cast;
|
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
std::string const s = "Hello, world";
|
streambuf sb(1);
|
||||||
expect(s.size() == 12);
|
sb.prepare(1);
|
||||||
for(std::size_t i = 1; i < 12; ++i) {
|
sb.commit(1);
|
||||||
for(std::size_t x = 1; x < 4; ++x) {
|
sb.prepare(2);
|
||||||
for(std::size_t y = 1; y < 4; ++y) {
|
sb.commit(2);
|
||||||
std::size_t z = s.size() - (x + y);
|
expect(buffer_size(sb.data()) == 3);
|
||||||
|
sb.prepare(1);
|
||||||
|
expect(buffer_size(sb.prepare(3)) == 3);
|
||||||
|
expect(read_size_helper(sb, 3) == 3);
|
||||||
|
sb.commit(2);
|
||||||
|
try
|
||||||
{
|
{
|
||||||
streambuf sb(i);
|
streambuf sb0(0);
|
||||||
sb.commit(buffer_copy(sb.prepare(x), buffer(s.data(), x)));
|
fail();
|
||||||
sb.commit(buffer_copy(sb.prepare(y), buffer(s.data()+x, y)));
|
}
|
||||||
sb.commit(buffer_copy(sb.prepare(z), buffer(s.data()+x+y, z)));
|
catch(std::exception const&)
|
||||||
expect(to_string(sb.data()) == s);
|
|
||||||
{
|
{
|
||||||
streambuf sb2(sb);
|
pass();
|
||||||
expect(eq(sb, sb2));
|
|
||||||
}
|
}
|
||||||
{
|
std::size_t n;
|
||||||
streambuf sb2;
|
n = 0;
|
||||||
sb2 = sb;
|
for(auto it = sb.data().begin();
|
||||||
expect(eq(sb, sb2));
|
it != sb.data().end(); it++)
|
||||||
}
|
++n;
|
||||||
{
|
expect(n == 4);
|
||||||
streambuf sb2(std::move(sb));
|
n = 0;
|
||||||
expect(to_string(sb2.data()) == s);
|
for(auto it = sb.data().begin();
|
||||||
expect(buffer_size(sb.data()) == 0);
|
it != sb.data().end(); ++it)
|
||||||
sb = std::move(sb2);
|
++n;
|
||||||
expect(to_string(sb.data()) == s);
|
expect(n == 4);
|
||||||
expect(buffer_size(sb2.data()) == 0);
|
n = 0;
|
||||||
}
|
for(auto it = sb.data().end();
|
||||||
}
|
it != sb.data().begin(); it--)
|
||||||
}}}
|
++n;
|
||||||
|
expect(n == 4);
|
||||||
|
n = 0;
|
||||||
|
for(auto it = sb.data().end();
|
||||||
|
it != sb.data().begin(); --it)
|
||||||
|
++n;
|
||||||
|
expect(n == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testAllocator()
|
void testOutputStream()
|
||||||
{
|
|
||||||
{
|
|
||||||
using alloc_type =
|
|
||||||
test_allocator<char, false, false, false, false>;
|
|
||||||
using sb_type = basic_streambuf<alloc_type>;
|
|
||||||
sb_type sb;
|
|
||||||
expect(sb.get_allocator().id() == 1);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
using alloc_type =
|
|
||||||
test_allocator<char, false, false, false, false>;
|
|
||||||
using sb_type = basic_streambuf<alloc_type>;
|
|
||||||
sb_type sb;
|
|
||||||
expect(sb.get_allocator().id() == 2);
|
|
||||||
sb_type sb2(sb);
|
|
||||||
expect(sb2.get_allocator().id() == 2);
|
|
||||||
sb_type sb3(sb, alloc_type{});
|
|
||||||
//expect(sb3.get_allocator().id() == 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testStream()
|
|
||||||
{
|
{
|
||||||
streambuf sb;
|
streambuf sb;
|
||||||
sb << "x";
|
sb << "x";
|
||||||
|
expect(to_string(sb.data()) == "x");
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
testPrepare();
|
testSpecialMembers();
|
||||||
testStreambuf();
|
|
||||||
testSpecial();
|
|
||||||
testAllocator();
|
testAllocator();
|
||||||
testStream();
|
testPrepare();
|
||||||
|
testCommit();
|
||||||
|
testStreambuf();
|
||||||
|
testIterators();
|
||||||
|
testOutputStream();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -68,9 +68,64 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testIterators()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
char buf[9];
|
||||||
|
std::vector<const_buffer> b1{
|
||||||
|
const_buffer{buf+0, 1},
|
||||||
|
const_buffer{buf+1, 2}};
|
||||||
|
std::array<const_buffer, 3> b2{{
|
||||||
|
const_buffer{buf+3, 1},
|
||||||
|
const_buffer{buf+4, 2},
|
||||||
|
const_buffer{buf+6, 3}}};
|
||||||
|
auto bs = buffer_cat(b1, b2);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::size_t n = 0;
|
||||||
|
for(auto it = bs.begin(); n < 100; ++it)
|
||||||
|
++n;
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::size_t n = 0;
|
||||||
|
for(auto it = bs.end(); n < 100; --it)
|
||||||
|
++n;
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
expect((buffer_size(*bs.end()) == 0, false));
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
auto bs2 = bs;
|
||||||
|
expect(bs.begin() != bs2.begin());
|
||||||
|
expect(bs.end() != bs2.end());
|
||||||
|
decltype(bs)::const_iterator it;
|
||||||
|
decltype(bs2)::const_iterator it2;
|
||||||
|
expect(it == it2);
|
||||||
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
testBufferCat();
|
testBufferCat();
|
||||||
|
testIterators();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <beast/buffers_adapter.hpp>
|
#include <beast/buffers_adapter.hpp>
|
||||||
|
|
||||||
|
#include <beast/streambuf.hpp>
|
||||||
#include <beast/detail/unit_test/suite.hpp>
|
#include <beast/detail/unit_test/suite.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/asio/streambuf.hpp>
|
#include <boost/asio/streambuf.hpp>
|
||||||
@@ -149,9 +150,38 @@ public:
|
|||||||
}
|
}
|
||||||
}}}}}}
|
}}}}}}
|
||||||
}
|
}
|
||||||
|
void testCommit()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
{
|
||||||
|
using sb_type = boost::asio::streambuf;
|
||||||
|
sb_type sb;
|
||||||
|
buffers_adapter<
|
||||||
|
sb_type::mutable_buffers_type> ba(sb.prepare(3));
|
||||||
|
expect(buffer_size(ba.prepare(3)) == 3);
|
||||||
|
ba.commit(2);
|
||||||
|
expect(buffer_size(ba.data()) == 2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
using sb_type = beast::streambuf;
|
||||||
|
sb_type sb(2);
|
||||||
|
sb.prepare(3);
|
||||||
|
buffers_adapter<
|
||||||
|
sb_type::mutable_buffers_type> ba(sb.prepare(8));
|
||||||
|
expect(buffer_size(ba.prepare(8)) == 8);
|
||||||
|
ba.commit(2);
|
||||||
|
expect(buffer_size(ba.data()) == 2);
|
||||||
|
ba.consume(1);
|
||||||
|
ba.commit(6);
|
||||||
|
ba.consume(2);
|
||||||
|
expect(buffer_size(ba.data()) == 5);
|
||||||
|
ba.consume(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
testBuffersAdapter();
|
testBuffersAdapter();
|
||||||
|
testCommit();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -81,10 +81,22 @@ public:
|
|||||||
expect(buffer_copy(cb2, cb) == 0);
|
expect(buffer_copy(cb2, cb) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testIterator()
|
||||||
|
{
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
std::array<const_buffer, 3> ba;
|
||||||
|
consuming_buffers<decltype(ba)> cb(ba);
|
||||||
|
std::size_t n = 0;
|
||||||
|
for(auto it = cb.end(); it != cb.begin(); --it)
|
||||||
|
++n;
|
||||||
|
expect(n == 3);
|
||||||
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
testBuffers();
|
testBuffers();
|
||||||
testNullBuffers();
|
testNullBuffers();
|
||||||
|
testIterator();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include <beast/detail/sha1.hpp>
|
#include <beast/detail/sha1.hpp>
|
||||||
#include <beast/detail/unit_test/suite.hpp>
|
#include <beast/detail/unit_test/suite.hpp>
|
||||||
#include <boost/algorithm/hex.hpp>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
@@ -16,20 +15,45 @@ namespace detail {
|
|||||||
class sha1_test : public beast::detail::unit_test::suite
|
class sha1_test : public beast::detail::unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
std::uint8_t
|
||||||
|
unhex(char c)
|
||||||
|
{
|
||||||
|
if(c >= '0' && c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
if(c >= 'a' && c <= 'f')
|
||||||
|
return c - 'a' + 10;
|
||||||
|
if(c >= 'A' && c <= 'F')
|
||||||
|
return c - 'A' + 10;
|
||||||
|
throw std::invalid_argument("not a hex digit");
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
unhex(std::string const& in)
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
out.reserve(in.size() / 2);
|
||||||
|
if(in.size() % 2)
|
||||||
|
throw std::domain_error("invalid hex string");
|
||||||
|
for(std::size_t i = 0; i < in.size(); i += 2)
|
||||||
|
out.push_back(
|
||||||
|
(unhex(in[i])<<4) + unhex(in[i+1]));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
check(std::string const& message, std::string const& answer)
|
check(std::string const& message, std::string const& answer)
|
||||||
{
|
{
|
||||||
using digest_type =
|
std::string digest;
|
||||||
std::array<std::uint8_t, sha1_context::digest_size>;
|
digest = unhex(answer);
|
||||||
digest_type digest;
|
|
||||||
if(! expect(boost::algorithm::unhex(
|
|
||||||
answer, digest.begin()) == digest.end()))
|
|
||||||
return;
|
|
||||||
sha1_context ctx;
|
sha1_context ctx;
|
||||||
digest_type result;
|
std::string result;
|
||||||
|
result.resize(sha1_context::digest_size);
|
||||||
init(ctx);
|
init(ctx);
|
||||||
update(ctx, message.data(), message.size());
|
update(ctx, message.data(), message.size());
|
||||||
finish(ctx, result.data());
|
finish(ctx, &result[0]);
|
||||||
expect(result == digest);
|
expect(result == digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,4 +6,4 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <beast/http/error.hpp>
|
#include <beast/error.hpp>
|
@@ -22,10 +22,12 @@
|
|||||||
|
|
||||||
#include <beast/async_completion.hpp>
|
#include <beast/async_completion.hpp>
|
||||||
#include <beast/bind_handler.hpp>
|
#include <beast/bind_handler.hpp>
|
||||||
|
#include <beast/error.hpp>
|
||||||
|
#include <beast/websocket/teardown.hpp>
|
||||||
#include <beast/detail/get_lowest_layer.hpp>
|
#include <beast/detail/get_lowest_layer.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
/* A stream wrapper that fails.
|
/* A stream wrapper that fails.
|
||||||
|
|
||||||
@@ -35,12 +37,6 @@ namespace beast {
|
|||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
class fail_stream
|
class fail_stream
|
||||||
{
|
{
|
||||||
using error_code =
|
|
||||||
boost::system::error_code;
|
|
||||||
|
|
||||||
using system_error =
|
|
||||||
boost::system::system_error;
|
|
||||||
|
|
||||||
error_code ec_;
|
error_code ec_;
|
||||||
std::size_t n_ = 0;
|
std::size_t n_ = 0;
|
||||||
NextLayer next_layer_;
|
NextLayer next_layer_;
|
||||||
@@ -204,6 +200,7 @@ async_teardown(fail_stream<NextLayer>& stream,
|
|||||||
stream.next_layer(), std::forward<TeardownHandler>(handler));
|
stream.next_layer(), std::forward<TeardownHandler>(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // test
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
namespace test {
|
|
||||||
|
|
||||||
class basic_headers_test : public beast::detail::unit_test::suite
|
class basic_headers_test : public beast::detail::unit_test::suite
|
||||||
{
|
{
|
||||||
@@ -48,6 +47,7 @@ public:
|
|||||||
bh h3(std::move(h1));
|
bh h3(std::move(h1));
|
||||||
expect(h3.size() == 2);
|
expect(h3.size() == 2);
|
||||||
expect(h1.size() == 0);
|
expect(h1.size() == 0);
|
||||||
|
h2 = std::move(h2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
@@ -58,6 +58,5 @@ public:
|
|||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(basic_headers,http,beast);
|
BEAST_DEFINE_TESTSUITE(basic_headers,http,beast);
|
||||||
|
|
||||||
} // test
|
|
||||||
} // asio
|
} // asio
|
||||||
} // beast
|
} // beast
|
||||||
|
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
#include "message_fuzz.hpp"
|
#include "message_fuzz.hpp"
|
||||||
|
|
||||||
|
#include <beast/error.hpp>
|
||||||
#include <beast/streambuf.hpp>
|
#include <beast/streambuf.hpp>
|
||||||
#include <beast/write_streambuf.hpp>
|
#include <beast/write_streambuf.hpp>
|
||||||
#include <beast/http/error.hpp>
|
|
||||||
#include <beast/http/rfc2616.hpp>
|
#include <beast/http/rfc2616.hpp>
|
||||||
#include <beast/detail/ci_char_traits.hpp>
|
#include <beast/detail/ci_char_traits.hpp>
|
||||||
#include <beast/detail/unit_test/suite.hpp>
|
#include <beast/detail/unit_test/suite.hpp>
|
||||||
@@ -29,8 +29,6 @@ namespace http {
|
|||||||
|
|
||||||
class basic_parser_v1_test : public beast::detail::unit_test::suite
|
class basic_parser_v1_test : public beast::detail::unit_test::suite
|
||||||
{
|
{
|
||||||
std::mt19937 rng_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct cb_req_checker
|
struct cb_req_checker
|
||||||
{
|
{
|
||||||
@@ -302,17 +300,6 @@ public:
|
|||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class UInt = std::size_t>
|
|
||||||
UInt
|
|
||||||
rand(std::size_t n)
|
|
||||||
{
|
|
||||||
return static_cast<UInt>(
|
|
||||||
std::uniform_int_distribution<
|
|
||||||
std::size_t>{0, n-1}(rng_));
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Parse a valid message with expected version
|
// Parse a valid message with expected version
|
||||||
//
|
//
|
||||||
template<bool isRequest>
|
template<bool isRequest>
|
||||||
@@ -481,6 +468,42 @@ public:
|
|||||||
parse_ev<true>("GET / HTTP/1.1\r\nf :", parse_error::bad_field);
|
parse_ev<true>("GET / HTTP/1.1\r\nf :", parse_error::bad_field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testCorrupt()
|
||||||
|
{
|
||||||
|
using boost::asio::buffer;
|
||||||
|
std::string s;
|
||||||
|
for(std::size_t n = 0;;++n)
|
||||||
|
{
|
||||||
|
// Create a request and set one octet to an invalid char
|
||||||
|
s =
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"Host: localhost\r\n"
|
||||||
|
"User-Agent: test\r\n"
|
||||||
|
"Content-Length: 00\r\n"
|
||||||
|
"\r\n";
|
||||||
|
auto const len = s.size();
|
||||||
|
if(n >= s.size())
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s[n] = 0;
|
||||||
|
for(std::size_t m = 1; m < len - 1; ++m)
|
||||||
|
{
|
||||||
|
null_parser<true> p;
|
||||||
|
error_code ec;
|
||||||
|
p.write(buffer(s.data(), m), ec);
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
p.write(buffer(s.data() + m, len - m), ec);
|
||||||
|
expect(ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testRandomReq(std::size_t N)
|
testRandomReq(std::size_t N)
|
||||||
{
|
{
|
||||||
@@ -629,6 +652,7 @@ public:
|
|||||||
testFlags();
|
testFlags();
|
||||||
testUpgrade();
|
testUpgrade();
|
||||||
testBad();
|
testBad();
|
||||||
|
testCorrupt();
|
||||||
testRandomReq(100);
|
testRandomReq(100);
|
||||||
testRandomResp(100);
|
testRandomResp(100);
|
||||||
testBody();
|
testBody();
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2013-2016 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)
|
|
||||||
//
|
|
||||||
|
|
||||||
// Test that header file is self-contained.
|
|
||||||
#include <beast/http/body_type.hpp>
|
|
@@ -34,7 +34,6 @@ namespace test {
|
|||||||
class sync_echo_http_server
|
class sync_echo_http_server
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using error_code = boost::system::error_code;
|
|
||||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
using address_type = boost::asio::ip::address;
|
using address_type = boost::asio::ip::address;
|
||||||
using socket_type = boost::asio::ip::tcp::socket;
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
@@ -136,11 +135,46 @@ private:
|
|||||||
class message_test : public beast::detail::unit_test::suite
|
class message_test : public beast::detail::unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using error_code = boost::system::error_code;
|
|
||||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
using address_type = boost::asio::ip::address;
|
using address_type = boost::asio::ip::address;
|
||||||
using socket_type = boost::asio::ip::tcp::socket;
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
|
void testFunctions()
|
||||||
|
{
|
||||||
|
request_v1<empty_body> m;
|
||||||
|
m.version = 10;
|
||||||
|
expect(! is_upgrade(m));
|
||||||
|
m.headers.insert("Transfer-Encoding", "chunked");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
prepare(m);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
m.headers.erase("Transfer-Encoding");
|
||||||
|
m.headers.insert("Content-Length", "0");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
prepare(m);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
m.headers.erase("Content-Length");
|
||||||
|
m.headers.insert("Connection", "keep-alive");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
prepare(m);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
syncEcho(endpoint_type ep)
|
syncEcho(endpoint_type ep)
|
||||||
{
|
{
|
||||||
@@ -174,6 +208,7 @@ public:
|
|||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
|
testFunctions();
|
||||||
testAsio();
|
testAsio();
|
||||||
pass();
|
pass();
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include "nodejs-parser/http_parser.h"
|
#include "nodejs-parser/http_parser.h"
|
||||||
|
|
||||||
#include <beast/http/error.hpp>
|
#include <beast/error.hpp>
|
||||||
#include <beast/http/message_v1.hpp>
|
#include <beast/http/message_v1.hpp>
|
||||||
#include <beast/http/rfc2616.hpp>
|
#include <beast/http/rfc2616.hpp>
|
||||||
#include <beast/buffer_concepts.hpp>
|
#include <beast/buffer_concepts.hpp>
|
||||||
|
@@ -7,3 +7,97 @@
|
|||||||
|
|
||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <beast/http/read.hpp>
|
#include <beast/http/read.hpp>
|
||||||
|
|
||||||
|
#include "../fail_stream.hpp"
|
||||||
|
#include "../string_stream.hpp"
|
||||||
|
#include "../yield_to.hpp"
|
||||||
|
|
||||||
|
#include <beast/http/streambuf_body.hpp>
|
||||||
|
#include <beast/detail/unit_test/suite.hpp>
|
||||||
|
#include <boost/asio/spawn.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
class read_test
|
||||||
|
: public beast::detail::unit_test::suite
|
||||||
|
, public test::enable_yield_to
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void testRead(yield_context do_yield)
|
||||||
|
{
|
||||||
|
static std::size_t constexpr limit = 100;
|
||||||
|
std::size_t n;
|
||||||
|
for(n = 1; n < limit; ++n)
|
||||||
|
{
|
||||||
|
streambuf sb;
|
||||||
|
test::fail_stream<test::string_stream> fs(n, ios_,
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"Host: localhost\r\n"
|
||||||
|
"User-Agent: test\r\n"
|
||||||
|
"Content-Length: 0\r\n"
|
||||||
|
"\r\n"
|
||||||
|
);
|
||||||
|
request_v1<streambuf_body> m;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
read(fs, sb, m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(n < limit);
|
||||||
|
for(n = 1; n < limit; ++n)
|
||||||
|
{
|
||||||
|
streambuf sb;
|
||||||
|
test::fail_stream<test::string_stream> fs(n, ios_,
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"Host: localhost\r\n"
|
||||||
|
"User-Agent: test\r\n"
|
||||||
|
"Content-Length: 0\r\n"
|
||||||
|
"\r\n"
|
||||||
|
);
|
||||||
|
request_v1<streambuf_body> m;
|
||||||
|
error_code ec;
|
||||||
|
read(fs, sb, m, ec);
|
||||||
|
if(! ec)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
expect(n < limit);
|
||||||
|
ios_.post(
|
||||||
|
[&]{
|
||||||
|
n = 1;
|
||||||
|
});
|
||||||
|
for(n = 1; n < limit; ++n)
|
||||||
|
{
|
||||||
|
streambuf sb;
|
||||||
|
test::fail_stream<test::string_stream> fs(n, ios_,
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"Host: localhost\r\n"
|
||||||
|
"User-Agent: test\r\n"
|
||||||
|
"Content-Length: 0\r\n"
|
||||||
|
"\r\n"
|
||||||
|
);
|
||||||
|
request_v1<streambuf_body> m;
|
||||||
|
error_code ec;
|
||||||
|
async_read(fs, sb, m, do_yield[ec]);
|
||||||
|
if(! ec)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
expect(n < limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
yield_to(std::bind(&read_test::testRead,
|
||||||
|
this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(read,http,beast);
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <beast/http/write.hpp>
|
#include <beast/http/write.hpp>
|
||||||
|
|
||||||
#include <beast/http/error.hpp>
|
#include <beast/error.hpp>
|
||||||
#include <beast/http/headers.hpp>
|
#include <beast/http/headers.hpp>
|
||||||
#include <beast/http/message.hpp>
|
#include <beast/http/message.hpp>
|
||||||
#include <beast/http/empty_body.hpp>
|
#include <beast/http/empty_body.hpp>
|
||||||
|
@@ -87,10 +87,26 @@ public:
|
|||||||
expect(buffer_copy(pbc, cb) == 0);
|
expect(buffer_copy(pbc, cb) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testIterator()
|
||||||
|
{
|
||||||
|
using boost::asio::const_buffer;
|
||||||
|
char b[3];
|
||||||
|
std::array<const_buffer, 3> bs{{
|
||||||
|
const_buffer{&b[0], 1},
|
||||||
|
const_buffer{&b[1], 1},
|
||||||
|
const_buffer{&b[2], 1}}};
|
||||||
|
auto pb = prepare_buffers(2, bs);
|
||||||
|
std::size_t n = 0;
|
||||||
|
for(auto it = pb.end(); it != pb.begin(); --it)
|
||||||
|
++n;
|
||||||
|
expect(n == 2);
|
||||||
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
testBuffers();
|
testBuffers();
|
||||||
testNullBuffers();
|
testNullBuffers();
|
||||||
|
testIterator();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -93,6 +93,7 @@ public:
|
|||||||
expect(s3.back() == 'x');
|
expect(s3.back() == 'x');
|
||||||
s2 = "y";
|
s2 = "y";
|
||||||
expect(s2 == "y");
|
expect(s2 == "y");
|
||||||
|
expect(s3 == "x");
|
||||||
s1 = s2;
|
s1 = s2;
|
||||||
expect(s1 == "y");
|
expect(s1 == "y");
|
||||||
s1.clear();
|
s1.clear();
|
||||||
@@ -140,6 +141,35 @@ public:
|
|||||||
pass();
|
pass();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
str1 s1("x");
|
||||||
|
str2 s2;
|
||||||
|
s2 = s1;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
s1.resize(2);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::length_error const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
s1 = "1";
|
||||||
|
s2 = "2";
|
||||||
|
expect(s1.compare(s2) < 0);
|
||||||
|
expect(s2.compare(s1) > 0);
|
||||||
|
expect(s1 < "10");
|
||||||
|
expect(s2 > "1");
|
||||||
|
expect("10" > s1);
|
||||||
|
expect("1" < s2);
|
||||||
|
}
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void testCompare()
|
||||||
|
{
|
||||||
|
using str1 = static_string<1>;
|
||||||
|
using str2 = static_string<2>;
|
||||||
{
|
{
|
||||||
str2 s1("x");
|
str2 s1("x");
|
||||||
str2 s2("x");
|
str2 s2("x");
|
||||||
@@ -175,12 +205,49 @@ public:
|
|||||||
expect(! ("x" > s));
|
expect(! ("x" > s));
|
||||||
expect(! ("x" != s));
|
expect(! ("x" != s));
|
||||||
}
|
}
|
||||||
pass();
|
{
|
||||||
|
str2 s("x");
|
||||||
|
expect(s <= "y");
|
||||||
|
expect(s < "y");
|
||||||
|
expect(s != "y");
|
||||||
|
expect(! (s == "y"));
|
||||||
|
expect(! (s >= "y"));
|
||||||
|
expect(! (s > "x"));
|
||||||
|
expect("y" >= s);
|
||||||
|
expect("y" > s);
|
||||||
|
expect("y" != s);
|
||||||
|
expect(! ("y" == s));
|
||||||
|
expect(! ("y" <= s));
|
||||||
|
expect(! ("y" < s));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
str1 s1("x");
|
||||||
|
str2 s2("y");
|
||||||
|
expect(s1 <= s2);
|
||||||
|
expect(s1 < s2);
|
||||||
|
expect(s1 != s2);
|
||||||
|
expect(! (s1 == s2));
|
||||||
|
expect(! (s1 >= s2));
|
||||||
|
expect(! (s1 > s2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
str1 s1("x");
|
||||||
|
str2 s2("xx");
|
||||||
|
expect(s1 < s2);
|
||||||
|
expect(s2 > s1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
str1 s1("x");
|
||||||
|
str2 s2("yy");
|
||||||
|
expect(s1 < s2);
|
||||||
|
expect(s2 > s1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
testMembers();
|
testMembers();
|
||||||
|
testCompare();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -25,6 +25,8 @@ public:
|
|||||||
streambuf_readstream<socket_type, streambuf> srs(ios);
|
streambuf_readstream<socket_type, streambuf> srs(ios);
|
||||||
streambuf_readstream<socket_type, streambuf> srs2(std::move(srs));
|
streambuf_readstream<socket_type, streambuf> srs2(std::move(srs));
|
||||||
srs = std::move(srs2);
|
srs = std::move(srs2);
|
||||||
|
expect(&srs.get_io_service() == &ios);
|
||||||
|
expect(&srs.get_io_service() == &srs2.get_io_service());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
socket_type sock(ios);
|
socket_type sock(ios);
|
||||||
|
114
test/string_stream.hpp
Normal file
114
test/string_stream.hpp
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2016 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)
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BEAST_TEST_STRING_STREAM_HPP
|
||||||
|
#define BEAST_TEST_STRING_STREAM_HPP
|
||||||
|
|
||||||
|
#include <beast/bind_handler.hpp>
|
||||||
|
#include <beast/error.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/asio/io_service.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
// meets the requirements of AsyncStream, SyncStream
|
||||||
|
class string_stream
|
||||||
|
{
|
||||||
|
std::string s_;
|
||||||
|
boost::asio::io_service& ios_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
string_stream(boost::asio::io_service& ios,
|
||||||
|
std::string s)
|
||||||
|
: s_(std::move(s))
|
||||||
|
, ios_(ios)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
throw boost::system::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, boost::asio::buffer(s_));
|
||||||
|
s_.erase(0, n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class MutableBufferSequence, class ReadHandler>
|
||||||
|
typename async_completion<ReadHandler,
|
||||||
|
void(error_code, std::size_t)>::result_type
|
||||||
|
async_read_some(MutableBufferSequence const& buffers,
|
||||||
|
ReadHandler&& handler)
|
||||||
|
{
|
||||||
|
auto const n = boost::asio::buffer_copy(
|
||||||
|
buffers, boost::asio::buffer(s_));
|
||||||
|
s_.erase(0, n);
|
||||||
|
async_completion<ReadHandler,
|
||||||
|
void(error_code, std::size_t)> completion(handler);
|
||||||
|
ios_.post(bind_handler(
|
||||||
|
completion.handler, error_code{}, n));
|
||||||
|
return completion.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)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_some(ConstBufferSequence const& buffers,
|
||||||
|
error_code&)
|
||||||
|
{
|
||||||
|
return boost::asio::buffer_size(buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ConstBuffeSequence, class WriteHandler>
|
||||||
|
typename async_completion<WriteHandler,
|
||||||
|
void(error_code, std::size_t)>::result_type
|
||||||
|
async_write_some(ConstBuffeSequence const& buffers,
|
||||||
|
WriteHandler&& handler)
|
||||||
|
{
|
||||||
|
async_completion<WriteHandler,
|
||||||
|
void(error_code, std::size_t)> completion(handler);
|
||||||
|
ios_.post(bind_handler(completion.handler,
|
||||||
|
error_code{}, boost::asio::buffer_size(buffers)));
|
||||||
|
return completion.result.get();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // test
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
@@ -9,164 +9,31 @@
|
|||||||
#include <beast/websocket/stream.hpp>
|
#include <beast/websocket/stream.hpp>
|
||||||
|
|
||||||
#include "../fail_stream.hpp"
|
#include "../fail_stream.hpp"
|
||||||
|
#include "../string_stream.hpp"
|
||||||
|
#include "../yield_to.hpp"
|
||||||
|
|
||||||
#include "websocket_async_echo_peer.hpp"
|
#include "websocket_async_echo_peer.hpp"
|
||||||
#include "websocket_sync_echo_peer.hpp"
|
#include "websocket_sync_echo_peer.hpp"
|
||||||
|
|
||||||
#include <beast/bind_handler.hpp>
|
|
||||||
#include <beast/streambuf.hpp>
|
#include <beast/streambuf.hpp>
|
||||||
#include <beast/to_string.hpp>
|
#include <beast/to_string.hpp>
|
||||||
#include <beast/detail/unit_test/suite.hpp>
|
#include <beast/detail/unit_test/suite.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/asio/spawn.hpp>
|
#include <boost/asio/spawn.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <condition_variable>
|
|
||||||
#include <functional>
|
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include <beast/http/parser_v1.hpp>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace websocket {
|
namespace websocket {
|
||||||
|
|
||||||
class stream_test : public beast::detail::unit_test::suite
|
class stream_test
|
||||||
|
: public beast::detail::unit_test::suite
|
||||||
|
, public test::enable_yield_to
|
||||||
{
|
{
|
||||||
boost::asio::io_service ios_;
|
|
||||||
boost::optional<boost::asio::io_service::work> work_;
|
|
||||||
std::thread thread_;
|
|
||||||
std::mutex m_;
|
|
||||||
std::condition_variable cv_;
|
|
||||||
bool running_ = false;;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
using address_type = boost::asio::ip::address;
|
using address_type = boost::asio::ip::address;
|
||||||
using socket_type = boost::asio::ip::tcp::socket;
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
// meets the requirements of AsyncStream, SyncStream
|
|
||||||
class string_Stream
|
|
||||||
{
|
|
||||||
std::string s_;
|
|
||||||
boost::asio::io_service& ios_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
string_Stream(boost::asio::io_service& ios,
|
|
||||||
std::string s)
|
|
||||||
: s_(s)
|
|
||||||
, ios_(ios)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
throw boost::system::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, boost::asio::buffer(s_));
|
|
||||||
s_.erase(0, n);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class MutableBufferSequence, class ReadHandler>
|
|
||||||
typename async_completion<ReadHandler,
|
|
||||||
void(error_code, std::size_t)>::result_type
|
|
||||||
async_read_some(MutableBufferSequence const& buffers,
|
|
||||||
ReadHandler&& handler)
|
|
||||||
{
|
|
||||||
auto const n = boost::asio::buffer_copy(
|
|
||||||
buffers, boost::asio::buffer(s_));
|
|
||||||
s_.erase(0, n);
|
|
||||||
async_completion<ReadHandler,
|
|
||||||
void(error_code, std::size_t)> completion(handler);
|
|
||||||
ios_.post(bind_handler(
|
|
||||||
completion.handler, error_code{}, n));
|
|
||||||
return completion.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)
|
|
||||||
throw boost::system::system_error{ec};
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
std::size_t
|
|
||||||
write_some(ConstBufferSequence const& buffers,
|
|
||||||
error_code&)
|
|
||||||
{
|
|
||||||
return boost::asio::buffer_size(buffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ConstBuffeSequence, class WriteHandler>
|
|
||||||
typename async_completion<WriteHandler,
|
|
||||||
void(error_code, std::size_t)>::result_type
|
|
||||||
async_write_some(ConstBuffeSequence const& buffers,
|
|
||||||
WriteHandler&& handler)
|
|
||||||
{
|
|
||||||
async_completion<WriteHandler,
|
|
||||||
void(error_code, std::size_t)> completion(handler);
|
|
||||||
ios_.post(bind_handler(completion.handler,
|
|
||||||
error_code{}, boost::asio::buffer_size(buffers)));
|
|
||||||
return completion.result.get();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
stream_test()
|
|
||||||
: work_(ios_)
|
|
||||||
, thread_([&]{ ios_.run(); })
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~stream_test()
|
|
||||||
{
|
|
||||||
work_ = boost::none;
|
|
||||||
thread_.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Function>
|
|
||||||
void exec(Function&& f)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(m_);
|
|
||||||
running_ = true;
|
|
||||||
}
|
|
||||||
boost::asio::spawn(ios_,
|
|
||||||
[&](boost::asio::yield_context do_yield)
|
|
||||||
{
|
|
||||||
f(do_yield);
|
|
||||||
std::lock_guard<std::mutex> lock(m_);
|
|
||||||
running_ = false;
|
|
||||||
cv_.notify_all();
|
|
||||||
}
|
|
||||||
, boost::coroutines::attributes(2 * 1024 * 1024));
|
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(m_);
|
|
||||||
cv_.wait(lock, [&]{ return ! running_; });
|
|
||||||
}
|
|
||||||
|
|
||||||
void testSpecialMembers()
|
void testSpecialMembers()
|
||||||
{
|
{
|
||||||
stream<socket_type> ws(ios_);
|
stream<socket_type> ws(ios_);
|
||||||
@@ -177,6 +44,7 @@ public:
|
|||||||
stream<socket_type> ws2(ios_);
|
stream<socket_type> ws2(ios_);
|
||||||
ws = std::move(ws2);
|
ws = std::move(ws2);
|
||||||
}
|
}
|
||||||
|
expect(&ws.get_io_service() == &ios_);
|
||||||
pass();
|
pass();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,8 +55,16 @@ public:
|
|||||||
ws.set_option(read_buffer_size(8192));
|
ws.set_option(read_buffer_size(8192));
|
||||||
ws.set_option(read_message_max(1 * 1024 * 1024));
|
ws.set_option(read_message_max(1 * 1024 * 1024));
|
||||||
ws.set_option(write_buffer_size(2048));
|
ws.set_option(write_buffer_size(2048));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ws.set_option(message_type(opcode::close));
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
pass();
|
pass();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<std::size_t N>
|
template<std::size_t N>
|
||||||
static
|
static
|
||||||
@@ -198,10 +74,10 @@ public:
|
|||||||
return boost::asio::const_buffers_1(&s[0], N-1);
|
return boost::asio::const_buffers_1(&s[0], N-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testAccept(boost::asio::yield_context do_yield)
|
void testAccept(yield_context do_yield)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: localhost:80\r\n"
|
"Host: localhost:80\r\n"
|
||||||
"Upgrade: WebSocket\r\n"
|
"Upgrade: WebSocket\r\n"
|
||||||
@@ -220,7 +96,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"\r\n");
|
"\r\n");
|
||||||
try
|
try
|
||||||
@@ -234,7 +110,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: localhost:80\r\n"
|
"Host: localhost:80\r\n"
|
||||||
"Upgrade: WebSocket\r\n"
|
"Upgrade: WebSocket\r\n"
|
||||||
@@ -247,7 +123,7 @@ public:
|
|||||||
expect(! ec, ec.message());
|
expect(! ec, ec.message());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"\r\n");
|
"\r\n");
|
||||||
error_code ec;
|
error_code ec;
|
||||||
@@ -255,7 +131,7 @@ public:
|
|||||||
expect(ec);
|
expect(ec);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"Host: localhost:80\r\n"
|
"Host: localhost:80\r\n"
|
||||||
"Upgrade: WebSocket\r\n"
|
"Upgrade: WebSocket\r\n"
|
||||||
@@ -268,7 +144,7 @@ public:
|
|||||||
expect(! ec, ec.message());
|
expect(! ec, ec.message());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"\r\n");
|
"\r\n");
|
||||||
error_code ec;
|
error_code ec;
|
||||||
@@ -276,7 +152,7 @@ public:
|
|||||||
expect(ec);
|
expect(ec);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"Host: localhost:80\r\n"
|
"Host: localhost:80\r\n"
|
||||||
"Upgrade: WebSocket\r\n"
|
"Upgrade: WebSocket\r\n"
|
||||||
"Connection: upgrade\r\n"
|
"Connection: upgrade\r\n"
|
||||||
@@ -295,7 +171,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"\r\n");
|
"\r\n");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -309,7 +185,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"Host: localhost:80\r\n"
|
"Host: localhost:80\r\n"
|
||||||
"Upgrade: WebSocket\r\n"
|
"Upgrade: WebSocket\r\n"
|
||||||
"Connection: upgrade\r\n"
|
"Connection: upgrade\r\n"
|
||||||
@@ -322,7 +198,7 @@ public:
|
|||||||
expect(! ec, ec.message());
|
expect(! ec, ec.message());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"\r\n");
|
"\r\n");
|
||||||
error_code ec;
|
error_code ec;
|
||||||
@@ -330,7 +206,7 @@ public:
|
|||||||
expect(ec);
|
expect(ec);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"Host: localhost:80\r\n"
|
"Host: localhost:80\r\n"
|
||||||
"Upgrade: WebSocket\r\n"
|
"Upgrade: WebSocket\r\n"
|
||||||
"Connection: upgrade\r\n"
|
"Connection: upgrade\r\n"
|
||||||
@@ -343,7 +219,7 @@ public:
|
|||||||
expect(! ec, ec.message());
|
expect(! ec, ec.message());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
stream<string_Stream> ws(ios_,
|
stream<test::string_stream> ws(ios_,
|
||||||
"\r\n");
|
"\r\n");
|
||||||
error_code ec;
|
error_code ec;
|
||||||
ws.async_accept(strbuf(
|
ws.async_accept(strbuf(
|
||||||
@@ -353,7 +229,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void testHandshake(endpoint_type const& ep,
|
void testHandshake(endpoint_type const& ep,
|
||||||
boost::asio::yield_context do_yield)
|
yield_context do_yield)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
// disconnected socket
|
// disconnected socket
|
||||||
@@ -423,7 +299,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void testErrorHandling(endpoint_type const& ep,
|
void testErrorHandling(endpoint_type const& ep,
|
||||||
boost::asio::yield_context do_yield)
|
yield_context do_yield)
|
||||||
{
|
{
|
||||||
static std::size_t constexpr limit = 100;
|
static std::size_t constexpr limit = 100;
|
||||||
std::size_t n;
|
std::size_t n;
|
||||||
@@ -436,7 +312,7 @@ public:
|
|||||||
sock.connect(ep, ec);
|
sock.connect(ep, ec);
|
||||||
if(! expect(! ec, ec.message()))
|
if(! expect(! ec, ec.message()))
|
||||||
break;
|
break;
|
||||||
stream<fail_stream<socket_type&>> ws(n, sock);
|
stream<test::fail_stream<socket_type&>> ws(n, sock);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ws.handshake("localhost", "/");
|
ws.handshake("localhost", "/");
|
||||||
@@ -475,7 +351,7 @@ public:
|
|||||||
sock.connect(ep, ec);
|
sock.connect(ep, ec);
|
||||||
if(! expect(! ec, ec.message()))
|
if(! expect(! ec, ec.message()))
|
||||||
break;
|
break;
|
||||||
stream<fail_stream<socket_type&>> ws(n, sock);
|
stream<test::fail_stream<socket_type&>> ws(n, sock);
|
||||||
ws.handshake("localhost", "/", ec);
|
ws.handshake("localhost", "/", ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
continue;
|
continue;
|
||||||
@@ -510,7 +386,7 @@ public:
|
|||||||
sock.connect(ep, ec);
|
sock.connect(ep, ec);
|
||||||
if(! expect(! ec, ec.message()))
|
if(! expect(! ec, ec.message()))
|
||||||
break;
|
break;
|
||||||
stream<fail_stream<socket_type&>> ws(n, sock);
|
stream<test::fail_stream<socket_type&>> ws(n, sock);
|
||||||
ws.async_handshake("localhost", "/", do_yield[ec]);
|
ws.async_handshake("localhost", "/", do_yield[ec]);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
@@ -538,13 +414,70 @@ public:
|
|||||||
expect(n < limit);
|
expect(n < limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testMask(endpoint_type const& ep,
|
||||||
|
yield_context do_yield)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::vector<char> v;
|
||||||
|
for(char n = 0; n < 20; ++n)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
socket_type sock(ios_);
|
||||||
|
sock.connect(ep, ec);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
break;
|
||||||
|
stream<socket_type&> ws(sock);
|
||||||
|
ws.handshake("localhost", "/", ec);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
break;
|
||||||
|
ws.write(boost::asio::buffer(v), ec);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
break;
|
||||||
|
opcode op;
|
||||||
|
streambuf sb;
|
||||||
|
ws.read(op, sb, ec);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
break;
|
||||||
|
expect(to_string(sb.data()) ==
|
||||||
|
std::string{v.data(), v.size()});
|
||||||
|
v.push_back(n+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::vector<char> v;
|
||||||
|
for(char n = 0; n < 20; ++n)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
socket_type sock(ios_);
|
||||||
|
sock.connect(ep, ec);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
break;
|
||||||
|
stream<socket_type&> ws(sock);
|
||||||
|
ws.handshake("localhost", "/", ec);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
break;
|
||||||
|
ws.async_write(boost::asio::buffer(v), do_yield[ec]);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
break;
|
||||||
|
opcode op;
|
||||||
|
streambuf sb;
|
||||||
|
ws.async_read(op, sb, do_yield[ec]);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
break;
|
||||||
|
expect(to_string(sb.data()) ==
|
||||||
|
std::string{v.data(), v.size()});
|
||||||
|
v.push_back(n+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
testSpecialMembers();
|
testSpecialMembers();
|
||||||
|
|
||||||
testOptions();
|
testOptions();
|
||||||
|
|
||||||
exec(std::bind(&stream_test::testAccept,
|
yield_to(std::bind(&stream_test::testAccept,
|
||||||
this, std::placeholders::_1));
|
this, std::placeholders::_1));
|
||||||
|
|
||||||
auto const any = endpoint_type{
|
auto const any = endpoint_type{
|
||||||
@@ -552,22 +485,30 @@ public:
|
|||||||
{
|
{
|
||||||
sync_echo_peer server(true, any);
|
sync_echo_peer server(true, any);
|
||||||
|
|
||||||
exec(std::bind(&stream_test::testHandshake,
|
yield_to(std::bind(&stream_test::testHandshake,
|
||||||
this, server.local_endpoint(),
|
this, server.local_endpoint(),
|
||||||
std::placeholders::_1));
|
std::placeholders::_1));
|
||||||
|
|
||||||
exec(std::bind(&stream_test::testErrorHandling,
|
yield_to(std::bind(&stream_test::testErrorHandling,
|
||||||
|
this, server.local_endpoint(),
|
||||||
|
std::placeholders::_1));
|
||||||
|
|
||||||
|
yield_to(std::bind(&stream_test::testMask,
|
||||||
this, server.local_endpoint(),
|
this, server.local_endpoint(),
|
||||||
std::placeholders::_1));
|
std::placeholders::_1));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
async_echo_peer server(true, any, 1);
|
async_echo_peer server(true, any, 1);
|
||||||
|
|
||||||
exec(std::bind(&stream_test::testHandshake,
|
yield_to(std::bind(&stream_test::testHandshake,
|
||||||
this, server.local_endpoint(),
|
this, server.local_endpoint(),
|
||||||
std::placeholders::_1));
|
std::placeholders::_1));
|
||||||
|
|
||||||
exec(std::bind(&stream_test::testErrorHandling,
|
yield_to(std::bind(&stream_test::testErrorHandling,
|
||||||
|
this, server.local_endpoint(),
|
||||||
|
std::placeholders::_1));
|
||||||
|
|
||||||
|
yield_to(std::bind(&stream_test::testMask,
|
||||||
this, server.local_endpoint(),
|
this, server.local_endpoint(),
|
||||||
std::placeholders::_1));
|
std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,6 @@ namespace websocket {
|
|||||||
class async_echo_peer
|
class async_echo_peer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using error_code = boost::system::error_code;
|
|
||||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
using address_type = boost::asio::ip::address;
|
using address_type = boost::asio::ip::address;
|
||||||
using socket_type = boost::asio::ip::tcp::socket;
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
@@ -36,7 +36,6 @@ namespace websocket {
|
|||||||
class sync_echo_peer
|
class sync_echo_peer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using error_code = boost::system::error_code;
|
|
||||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
using address_type = boost::asio::ip::address;
|
using address_type = boost::asio::ip::address;
|
||||||
using socket_type = boost::asio::ip::tcp::socket;
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
86
test/yield_to.hpp
Normal file
86
test/yield_to.hpp
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2016 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)
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BEAST_TEST_ENABLE_YIELD_TO_HPP
|
||||||
|
#define BEAST_TEST_ENABLE_YIELD_TO_HPP
|
||||||
|
|
||||||
|
#include <boost/asio/io_service.hpp>
|
||||||
|
#include <boost/asio/spawn.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
// Mix-in to support tests using coroutines
|
||||||
|
class enable_yield_to
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
boost::asio::io_service ios_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::optional<boost::asio::io_service::work> work_;
|
||||||
|
std::thread thread_;
|
||||||
|
std::mutex m_;
|
||||||
|
std::condition_variable cv_;
|
||||||
|
bool running_ = false;;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
using yield_context =
|
||||||
|
boost::asio::yield_context;
|
||||||
|
|
||||||
|
enable_yield_to()
|
||||||
|
: work_(ios_)
|
||||||
|
, thread_([&]
|
||||||
|
{
|
||||||
|
ios_.run();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~enable_yield_to()
|
||||||
|
{
|
||||||
|
work_ = boost::none;
|
||||||
|
thread_.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run a function in a coroutine
|
||||||
|
template<class Function>
|
||||||
|
void
|
||||||
|
yield_to(Function&& f);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Function>
|
||||||
|
void
|
||||||
|
enable_yield_to::yield_to(Function&& f)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_);
|
||||||
|
running_ = true;
|
||||||
|
}
|
||||||
|
boost::asio::spawn(ios_,
|
||||||
|
[&](boost::asio::yield_context do_yield)
|
||||||
|
{
|
||||||
|
f(do_yield);
|
||||||
|
std::lock_guard<std::mutex> lock(m_);
|
||||||
|
running_ = false;
|
||||||
|
cv_.notify_all();
|
||||||
|
}
|
||||||
|
, boost::coroutines::attributes(2 * 1024 * 1024));
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(m_);
|
||||||
|
cv_.wait(lock, [&]{ return ! running_; });
|
||||||
|
}
|
||||||
|
|
||||||
|
} // test
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user