mirror of
https://github.com/boostorg/beast.git
synced 2025-08-03 14:54:32 +02:00
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
|
||||
built on top of Boost.Asio and other parts of boost.
|
||||
@@ -9,10 +13,69 @@ Requirements:
|
||||
* C++11 or greater
|
||||
* 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`
|
||||
in the build script or Makefile for your program in order to link.
|
||||
int main()
|
||||
{
|
||||
// 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:
|
||||
|
||||
|
17
TODO.txt
17
TODO.txt
@@ -2,6 +2,7 @@
|
||||
|
||||
General:
|
||||
* Use SFINAE on return values (search for "class =")
|
||||
* Remove http,websocket error_code types and use the one in <beast/error.hpp>
|
||||
|
||||
Boost.Http
|
||||
* Use enum instead of bool in isRequest
|
||||
@@ -17,6 +18,8 @@ Docs:
|
||||
- See if we can include them now that xsl is fixed
|
||||
* Implement cleanup-param to remove spaces around template arguments
|
||||
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:
|
||||
* Replace Jamroot with Jamfile
|
||||
@@ -26,13 +29,13 @@ Core:
|
||||
WebSocket:
|
||||
* optimized versions of key/masking, choose prepared_key size
|
||||
* invokable unit test
|
||||
* Finish up all of static_string including tests
|
||||
* 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
|
||||
* Don't try to read requests into empty_body
|
||||
|
||||
|
||||
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
|
||||
* add bool should_close(message_v1 const&) to replace the use
|
||||
of eof return value from write and async_write
|
||||
@@ -40,7 +43,7 @@ HTTP:
|
||||
* More fine grained parser errors
|
||||
* HTTP parser size limit with test (configurable?)
|
||||
* 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
|
||||
* Consider rename to MessageBody concept
|
||||
* Fix prepare() calling content_length() without init()
|
||||
@@ -48,3 +51,7 @@ HTTP:
|
||||
* Complete allocator testing in basic_streambuf, basic_headers
|
||||
* Fix http::async_write op, case 3 should break at the end.
|
||||
* 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,
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||
|
||||
using namespace beast::http;
|
||||
|
||||
// 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("User-Agent", "Beast");
|
||||
prepare(req);
|
||||
write(sock, req);
|
||||
beast::http::prepare(req);
|
||||
beast::http::write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
beast::streambuf sb;
|
||||
response<streambuf_body> resp;
|
||||
read(sock, sb, resp);
|
||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
||||
beast::http::read(sock, sb, resp);
|
||||
std::cout << resp;
|
||||
}
|
||||
```
|
||||
@@ -147,18 +145,16 @@ int main()
|
||||
boost::asio::connect(sock,
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||
|
||||
using namespace beast::websocket;
|
||||
|
||||
// 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.write(boost::asio::buffer("Hello, world!"));
|
||||
|
||||
// Receive WebSocket message, print and close using beast
|
||||
beast::streambuf sb;
|
||||
opcode op;
|
||||
beast::websocket::opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(close_code::normal);
|
||||
ws.close(beast::websocket::close_code::normal);
|
||||
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 to quickly perform common operations such as fetching a file or
|
||||
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.
|
||||
|
||||
A HTTP message (referred to hereafter as "message") contains request or
|
||||
|
@@ -28,7 +28,7 @@ using namespace boost::asio;
|
||||
|
||||
template<class String>
|
||||
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;
|
||||
}
|
||||
|
@@ -20,18 +20,16 @@ int main()
|
||||
boost::asio::connect(sock,
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||
|
||||
using namespace beast::http;
|
||||
|
||||
// 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("User-Agent", "Beast");
|
||||
prepare(req);
|
||||
write(sock, req);
|
||||
beast::http::prepare(req);
|
||||
beast::http::write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
beast::streambuf sb;
|
||||
response_v1<streambuf_body> resp;
|
||||
read(sock, sb, resp);
|
||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
||||
beast::http::read(sock, sb, resp);
|
||||
std::cout << resp;
|
||||
}
|
||||
|
@@ -21,17 +21,15 @@ int main()
|
||||
boost::asio::connect(sock,
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||
|
||||
using namespace beast::websocket;
|
||||
|
||||
// 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.write(boost::asio::buffer("Hello, world!"));
|
||||
|
||||
// Receive WebSocket message, print and close using beast
|
||||
beast::streambuf sb;
|
||||
opcode op;
|
||||
beast::websocket::opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(close_code::normal);
|
||||
ws.close(beast::websocket::close_code::normal);
|
||||
std::cout << to_string(sb.data()) << "\n";
|
||||
}
|
||||
|
@@ -31,7 +31,6 @@ namespace beast {
|
||||
template<class MutableBufferSequence>
|
||||
class buffers_adapter
|
||||
{
|
||||
private:
|
||||
static_assert(is_MutableBufferSequence<MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
|
||||
|
@@ -5,18 +5,20 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_HTTP_ERROR_HPP
|
||||
#define BEAST_HTTP_ERROR_HPP
|
||||
#ifndef BEAST_ERROR_HPP
|
||||
#define BEAST_ERROR_HPP
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/// The type of error code used by the library
|
||||
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
|
||||
|
||||
#endif
|
@@ -12,7 +12,6 @@
|
||||
#include <beast/http/basic_parser_v1.hpp>
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/headers.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
|
@@ -11,7 +11,7 @@
|
||||
// Convenience header to include everything
|
||||
// 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/resume_context.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:
|
||||
if(ch == ' ')
|
||||
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))
|
||||
return used();
|
||||
s_ = s_req_url;
|
||||
@@ -163,7 +165,9 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
||||
s_ = s_req_http_start;
|
||||
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;
|
||||
|
||||
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,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
|
@@ -8,8 +8,7 @@
|
||||
#ifndef BEAST_HTTP_PARSE_ERROR_HPP
|
||||
#define BEAST_HTTP_PARSE_ERROR_HPP
|
||||
|
||||
#include <beast/http/error.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <beast/error.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
@@ -8,8 +8,8 @@
|
||||
#ifndef 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/error.hpp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <functional>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#ifndef 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/async_completion.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
@@ -47,13 +47,7 @@ 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};
|
||||
}
|
||||
message_v1<isRequest, Body, Headers>& msg);
|
||||
|
||||
/** Read a HTTP/1 message from a stream.
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#ifndef 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 <type_traits>
|
||||
#include <utility>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#ifndef 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/async_completion.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
@@ -33,7 +33,7 @@ namespace http {
|
||||
The implementation will automatically perform chunk encoding if
|
||||
the contents of the message indicate that chunk encoding is required.
|
||||
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`.
|
||||
|
||||
@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 contents of the message indicate that chunk encoding is required.
|
||||
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`.
|
||||
|
||||
@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);
|
||||
if(out_ == list_.end())
|
||||
out_ = list_.iterator_to(e);
|
||||
if(n > e.size())
|
||||
if(n >= e.size())
|
||||
{
|
||||
out_end_ = e.size();
|
||||
n -= e.size();
|
||||
|
@@ -469,49 +469,32 @@ template<class MutableBufferSequence>
|
||||
void
|
||||
buffers_adapter<MutableBufferSequence>::consume(std::size_t n)
|
||||
{
|
||||
for(;;)
|
||||
using boost::asio::buffer_size;
|
||||
while(begin_ != out_)
|
||||
{
|
||||
if(begin_ != out_)
|
||||
auto const avail =
|
||||
buffer_size(*begin_) - in_pos_;
|
||||
if(n < avail)
|
||||
{
|
||||
auto const avail =
|
||||
buffer_size(*begin_) - in_pos_;
|
||||
if(n < avail)
|
||||
{
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
break;
|
||||
}
|
||||
n -= avail;
|
||||
in_size_ -= avail;
|
||||
in_pos_ = 0;
|
||||
++begin_;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const avail = out_pos_ - in_pos_;
|
||||
if(n < avail)
|
||||
{
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_size_ -= avail;
|
||||
if(out_pos_ != out_end_||
|
||||
out_ != std::prev(bs_.end()))
|
||||
{
|
||||
in_pos_ = out_pos_;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the whole buffer now.
|
||||
in_pos_ = 0;
|
||||
out_pos_ = 0;
|
||||
out_end_ = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
return;
|
||||
}
|
||||
n -= avail;
|
||||
in_size_ -= avail;
|
||||
in_pos_ = 0;
|
||||
++begin_;
|
||||
}
|
||||
auto const avail = out_pos_ - in_pos_;
|
||||
if(n < avail)
|
||||
{
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_size_ -= avail;
|
||||
in_pos_ = out_pos_;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -279,13 +279,6 @@ public:
|
||||
return N;
|
||||
}
|
||||
|
||||
/// Reduces memory usage by freeing unused memory.
|
||||
void
|
||||
shrink_to_fit()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
/// Clears the contents.
|
||||
void
|
||||
clear()
|
||||
@@ -310,7 +303,8 @@ public:
|
||||
|
||||
/// Compare two character sequences.
|
||||
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`.
|
||||
std::basic_string<CharT, Traits>
|
||||
@@ -488,7 +482,8 @@ assign(CharT const* s)
|
||||
namespace detail {
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
int compare(
|
||||
int
|
||||
compare(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
@@ -512,27 +507,13 @@ int compare(
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
int compare(
|
||||
inline
|
||||
int
|
||||
compare(
|
||||
const CharT (&s)[M],
|
||||
static_string<N, CharT, Traits> const& rhs)
|
||||
{
|
||||
if(M-1 < rhs.size())
|
||||
{
|
||||
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);
|
||||
return -compare(rhs, s);
|
||||
}
|
||||
|
||||
} // detail
|
||||
@@ -540,7 +521,8 @@ int compare(
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
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<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
@@ -548,7 +530,8 @@ bool operator==(
|
||||
}
|
||||
|
||||
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<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
@@ -556,7 +539,8 @@ bool operator!=(
|
||||
}
|
||||
|
||||
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<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
@@ -564,7 +548,8 @@ bool operator<(
|
||||
}
|
||||
|
||||
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<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
@@ -572,7 +557,8 @@ bool operator<=(
|
||||
}
|
||||
|
||||
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<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
@@ -580,7 +566,8 @@ bool operator>(
|
||||
}
|
||||
|
||||
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<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
@@ -590,7 +577,8 @@ bool operator>=(
|
||||
//---
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator==(
|
||||
bool
|
||||
operator==(
|
||||
const CharT (&s)[N],
|
||||
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>
|
||||
bool operator==(
|
||||
bool
|
||||
operator==(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
@@ -606,7 +595,8 @@ bool operator==(
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator!=(
|
||||
bool
|
||||
operator!=(
|
||||
const CharT (&s)[N],
|
||||
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>
|
||||
bool operator!=(
|
||||
bool
|
||||
operator!=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
@@ -622,7 +613,8 @@ bool operator!=(
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator<(
|
||||
bool
|
||||
operator<(
|
||||
const CharT (&s)[N],
|
||||
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>
|
||||
bool operator<(
|
||||
bool
|
||||
operator<(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
@@ -638,7 +631,8 @@ bool operator<(
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator<=(
|
||||
bool
|
||||
operator<=(
|
||||
const CharT (&s)[N],
|
||||
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>
|
||||
bool operator<=(
|
||||
bool
|
||||
operator<=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
@@ -654,7 +649,8 @@ bool operator<=(
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator>(
|
||||
bool
|
||||
operator>(
|
||||
const CharT (&s)[N],
|
||||
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>
|
||||
bool operator>(
|
||||
bool
|
||||
operator>(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
@@ -670,7 +667,8 @@ bool operator>(
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator>=(
|
||||
bool
|
||||
operator>=(
|
||||
const CharT (&s)[N],
|
||||
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>
|
||||
bool operator>=(
|
||||
bool
|
||||
operator>=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
|
@@ -127,7 +127,7 @@ ror(T t, unsigned n = 1)
|
||||
static_cast<typename std::make_unsigned<T>::type>(t) >> n));
|
||||
}
|
||||
|
||||
// 32-bit Uuoptimized
|
||||
// 32-bit Unoptimized
|
||||
//
|
||||
template<class = void>
|
||||
void
|
||||
|
@@ -8,15 +8,11 @@
|
||||
#ifndef BEAST_WEBSOCKET_ERROR_HPP
|
||||
#define BEAST_WEBSOCKET_ERROR_HPP
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <beast/error.hpp>
|
||||
|
||||
namespace beast {
|
||||
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.
|
||||
enum class error
|
||||
{
|
||||
|
@@ -617,7 +617,7 @@ public:
|
||||
|
||||
If the passed HTTP request is a valid HTTP WebSocket Upgrade
|
||||
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.
|
||||
|
||||
If the HTTP request is invalid or cannot be satisfied, a HTTP
|
||||
|
@@ -136,7 +136,7 @@ namespace websocket_helpers {
|
||||
template<class Socket>
|
||||
inline
|
||||
void
|
||||
call_teardown(Socket& socket, websocket::error_code& ec)
|
||||
call_teardown(Socket& socket, error_code& ec)
|
||||
{
|
||||
using websocket::teardown;
|
||||
teardown(socket, ec);
|
||||
|
@@ -13,6 +13,7 @@ add_executable (core-tests
|
||||
buffer_concepts.cpp
|
||||
buffers_adapter.cpp
|
||||
consuming_buffers.cpp
|
||||
error.cpp
|
||||
handler_alloc.cpp
|
||||
handler_concepts.cpp
|
||||
http.cpp
|
||||
@@ -38,12 +39,14 @@ endif()
|
||||
|
||||
add_executable (http-tests
|
||||
${BEAST_INCLUDES}
|
||||
fail_stream.hpp
|
||||
string_stream.hpp
|
||||
yield_to.hpp
|
||||
main.cpp
|
||||
http/basic_headers.cpp
|
||||
http/basic_parser_v1.cpp
|
||||
http/body_type.cpp
|
||||
http/empty_body.cpp
|
||||
http/error.cpp
|
||||
http/headers.cpp
|
||||
http/message.cpp
|
||||
http/message_v1.cpp
|
||||
@@ -79,6 +82,8 @@ endif()
|
||||
add_executable (websocket-tests
|
||||
${BEAST_INCLUDES}
|
||||
fail_stream.hpp
|
||||
string_stream.hpp
|
||||
yield_to.hpp
|
||||
websocket/websocket_async_echo_peer.hpp
|
||||
websocket/websocket_sync_echo_peer.hpp
|
||||
main.cpp
|
||||
|
@@ -16,6 +16,7 @@ unit-test core-tests :
|
||||
buffer_concepts.cpp
|
||||
buffers_adapter.cpp
|
||||
consuming_buffers.cpp
|
||||
error.cpp
|
||||
handler_alloc.cpp
|
||||
handler_concepts.cpp
|
||||
http.cpp
|
||||
@@ -41,7 +42,6 @@ unit-test http-tests :
|
||||
http/basic_parser_v1.cpp
|
||||
http/body_type.cpp
|
||||
http/empty_body.cpp
|
||||
http/error.cpp
|
||||
http/headers.cpp
|
||||
http/message.cpp
|
||||
http/message_v1.cpp
|
||||
|
@@ -9,8 +9,10 @@
|
||||
#include <beast/basic_streambuf.hpp>
|
||||
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <beast/to_string.hpp>
|
||||
#include <beast/detail/unit_test/suite.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -137,29 +139,116 @@ public:
|
||||
class basic_streambuf_test : public beast::detail::unit_test::suite
|
||||
{
|
||||
public:
|
||||
template<class ConstBufferSequence>
|
||||
template<class Alloc1, class Alloc2>
|
||||
static
|
||||
std::string
|
||||
to_string(ConstBufferSequence const& bs)
|
||||
bool
|
||||
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_size;
|
||||
std::string s;
|
||||
s.reserve(buffer_size(bs));
|
||||
for(auto const& b : bs)
|
||||
s.append(buffer_cast<char const*>(b),
|
||||
buffer_size(b));
|
||||
return s;
|
||||
std::string const s = "Hello, world";
|
||||
expect(s.size() == 12);
|
||||
for(std::size_t i = 1; i < 12; ++i) {
|
||||
for(std::size_t x = 1; x < 4; ++x) {
|
||||
for(std::size_t y = 1; y < 4; ++y) {
|
||||
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
|
||||
testPrepare()
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
{
|
||||
streambuf sb(2);
|
||||
expect(buffer_size(sb.prepare(5)) == 5);
|
||||
expect(buffer_size(sb.prepare(8)) == 8);
|
||||
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);
|
||||
expect(buffer_size(sb.prepare(5)) == 5);
|
||||
expect(buffer_size(sb.prepare(8)) == 8);
|
||||
expect(buffer_size(sb.prepare(7)) == 7);
|
||||
sb.prepare(2);
|
||||
sb.prepare(5);
|
||||
sb.commit(1);
|
||||
expect(buffer_size(sb.data()) == 1);
|
||||
}
|
||||
|
||||
void testStreambuf()
|
||||
@@ -257,88 +346,67 @@ public:
|
||||
}}}}}
|
||||
}
|
||||
|
||||
template<class Alloc1, class Alloc2>
|
||||
static
|
||||
bool
|
||||
eq(basic_streambuf<Alloc1> const& sb1,
|
||||
basic_streambuf<Alloc2> const& sb2)
|
||||
void testIterators()
|
||||
{
|
||||
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;
|
||||
std::string const s = "Hello, world";
|
||||
expect(s.size() == 12);
|
||||
for(std::size_t i = 1; i < 12; ++i) {
|
||||
for(std::size_t x = 1; x < 4; ++x) {
|
||||
for(std::size_t y = 1; y < 4; ++y) {
|
||||
std::size_t z = s.size() - (x + y);
|
||||
streambuf sb(1);
|
||||
sb.prepare(1);
|
||||
sb.commit(1);
|
||||
sb.prepare(2);
|
||||
sb.commit(2);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
streambuf sb0(0);
|
||||
fail();
|
||||
}
|
||||
}}}
|
||||
catch(std::exception const&)
|
||||
{
|
||||
pass();
|
||||
}
|
||||
std::size_t n;
|
||||
n = 0;
|
||||
for(auto it = sb.data().begin();
|
||||
it != sb.data().end(); it++)
|
||||
++n;
|
||||
expect(n == 4);
|
||||
n = 0;
|
||||
for(auto it = sb.data().begin();
|
||||
it != sb.data().end(); ++it)
|
||||
++n;
|
||||
expect(n == 4);
|
||||
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()
|
||||
{
|
||||
{
|
||||
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()
|
||||
void testOutputStream()
|
||||
{
|
||||
streambuf sb;
|
||||
sb << "x";
|
||||
expect(to_string(sb.data()) == "x");
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
testPrepare();
|
||||
testStreambuf();
|
||||
testSpecial();
|
||||
testSpecialMembers();
|
||||
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
|
||||
{
|
||||
testBufferCat();
|
||||
testIterators();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/buffers_adapter.hpp>
|
||||
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <beast/detail/unit_test/suite.hpp>
|
||||
#include <boost/asio/buffer.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
|
||||
{
|
||||
testBuffersAdapter();
|
||||
testCommit();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -81,10 +81,22 @@ public:
|
||||
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
|
||||
{
|
||||
testBuffers();
|
||||
testNullBuffers();
|
||||
testIterator();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <beast/detail/sha1.hpp>
|
||||
#include <beast/detail/unit_test/suite.hpp>
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace beast {
|
||||
@@ -16,20 +15,45 @@ namespace detail {
|
||||
class sha1_test : public beast::detail::unit_test::suite
|
||||
{
|
||||
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
|
||||
check(std::string const& message, std::string const& answer)
|
||||
{
|
||||
using digest_type =
|
||||
std::array<std::uint8_t, sha1_context::digest_size>;
|
||||
digest_type digest;
|
||||
if(! expect(boost::algorithm::unhex(
|
||||
answer, digest.begin()) == digest.end()))
|
||||
return;
|
||||
std::string digest;
|
||||
digest = unhex(answer);
|
||||
sha1_context ctx;
|
||||
digest_type result;
|
||||
std::string result;
|
||||
result.resize(sha1_context::digest_size);
|
||||
init(ctx);
|
||||
update(ctx, message.data(), message.size());
|
||||
finish(ctx, result.data());
|
||||
finish(ctx, &result[0]);
|
||||
expect(result == digest);
|
||||
}
|
||||
|
||||
|
@@ -6,4 +6,4 @@
|
||||
//
|
||||
|
||||
// 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/bind_handler.hpp>
|
||||
#include <beast/error.hpp>
|
||||
#include <beast/websocket/teardown.hpp>
|
||||
#include <beast/detail/get_lowest_layer.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace test {
|
||||
|
||||
/* A stream wrapper that fails.
|
||||
|
||||
@@ -35,12 +37,6 @@ namespace beast {
|
||||
template<class NextLayer>
|
||||
class fail_stream
|
||||
{
|
||||
using error_code =
|
||||
boost::system::error_code;
|
||||
|
||||
using system_error =
|
||||
boost::system::system_error;
|
||||
|
||||
error_code ec_;
|
||||
std::size_t n_ = 0;
|
||||
NextLayer next_layer_;
|
||||
@@ -204,6 +200,7 @@ async_teardown(fail_stream<NextLayer>& stream,
|
||||
stream.next_layer(), std::forward<TeardownHandler>(handler));
|
||||
}
|
||||
|
||||
} // test
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
@@ -12,7 +12,6 @@
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace test {
|
||||
|
||||
class basic_headers_test : public beast::detail::unit_test::suite
|
||||
{
|
||||
@@ -48,6 +47,7 @@ public:
|
||||
bh h3(std::move(h1));
|
||||
expect(h3.size() == 2);
|
||||
expect(h1.size() == 0);
|
||||
h2 = std::move(h2);
|
||||
}
|
||||
|
||||
void run() override
|
||||
@@ -58,6 +58,5 @@ public:
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(basic_headers,http,beast);
|
||||
|
||||
} // test
|
||||
} // asio
|
||||
} // beast
|
||||
|
@@ -10,9 +10,9 @@
|
||||
|
||||
#include "message_fuzz.hpp"
|
||||
|
||||
#include <beast/error.hpp>
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <beast/write_streambuf.hpp>
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/rfc2616.hpp>
|
||||
#include <beast/detail/ci_char_traits.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
|
||||
{
|
||||
std::mt19937 rng_;
|
||||
|
||||
public:
|
||||
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
|
||||
//
|
||||
template<bool isRequest>
|
||||
@@ -481,6 +468,42 @@ public:
|
||||
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
|
||||
testRandomReq(std::size_t N)
|
||||
{
|
||||
@@ -629,6 +652,7 @@ public:
|
||||
testFlags();
|
||||
testUpgrade();
|
||||
testBad();
|
||||
testCorrupt();
|
||||
testRandomReq(100);
|
||||
testRandomResp(100);
|
||||
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
|
||||
{
|
||||
public:
|
||||
using error_code = boost::system::error_code;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
@@ -136,11 +135,46 @@ private:
|
||||
class message_test : public beast::detail::unit_test::suite
|
||||
{
|
||||
public:
|
||||
using error_code = boost::system::error_code;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
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
|
||||
syncEcho(endpoint_type ep)
|
||||
{
|
||||
@@ -174,6 +208,7 @@ public:
|
||||
|
||||
void run() override
|
||||
{
|
||||
testFunctions();
|
||||
testAsio();
|
||||
pass();
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "nodejs-parser/http_parser.h"
|
||||
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/error.hpp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <beast/http/rfc2616.hpp>
|
||||
#include <beast/buffer_concepts.hpp>
|
||||
|
@@ -7,3 +7,97 @@
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#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.
|
||||
#include <beast/http/write.hpp>
|
||||
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/error.hpp>
|
||||
#include <beast/http/headers.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/empty_body.hpp>
|
||||
|
@@ -87,10 +87,26 @@ public:
|
||||
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
|
||||
{
|
||||
testBuffers();
|
||||
testNullBuffers();
|
||||
testIterator();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -93,6 +93,7 @@ public:
|
||||
expect(s3.back() == 'x');
|
||||
s2 = "y";
|
||||
expect(s2 == "y");
|
||||
expect(s3 == "x");
|
||||
s1 = s2;
|
||||
expect(s1 == "y");
|
||||
s1.clear();
|
||||
@@ -140,6 +141,35 @@ public:
|
||||
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 s2("x");
|
||||
@@ -175,12 +205,49 @@ public:
|
||||
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
|
||||
{
|
||||
testMembers();
|
||||
testCompare();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -25,6 +25,8 @@ public:
|
||||
streambuf_readstream<socket_type, streambuf> srs(ios);
|
||||
streambuf_readstream<socket_type, streambuf> srs2(std::move(srs));
|
||||
srs = std::move(srs2);
|
||||
expect(&srs.get_io_service() == &ios);
|
||||
expect(&srs.get_io_service() == &srs2.get_io_service());
|
||||
}
|
||||
{
|
||||
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 "../fail_stream.hpp"
|
||||
#include "../string_stream.hpp"
|
||||
#include "../yield_to.hpp"
|
||||
|
||||
#include "websocket_async_echo_peer.hpp"
|
||||
#include "websocket_sync_echo_peer.hpp"
|
||||
|
||||
#include <beast/bind_handler.hpp>
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <beast/to_string.hpp>
|
||||
#include <beast/detail/unit_test/suite.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <beast/http/parser_v1.hpp>
|
||||
|
||||
namespace beast {
|
||||
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:
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
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()
|
||||
{
|
||||
stream<socket_type> ws(ios_);
|
||||
@@ -177,6 +44,7 @@ public:
|
||||
stream<socket_type> ws2(ios_);
|
||||
ws = std::move(ws2);
|
||||
}
|
||||
expect(&ws.get_io_service() == &ios_);
|
||||
pass();
|
||||
}
|
||||
|
||||
@@ -187,7 +55,15 @@ public:
|
||||
ws.set_option(read_buffer_size(8192));
|
||||
ws.set_option(read_message_max(1 * 1024 * 1024));
|
||||
ws.set_option(write_buffer_size(2048));
|
||||
pass();
|
||||
try
|
||||
{
|
||||
ws.set_option(message_type(opcode::close));
|
||||
fail();
|
||||
}
|
||||
catch(std::exception const&)
|
||||
{
|
||||
pass();
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
@@ -198,10 +74,10 @@ public:
|
||||
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"
|
||||
"Host: localhost:80\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"
|
||||
"\r\n");
|
||||
try
|
||||
@@ -234,7 +110,7 @@ public:
|
||||
}
|
||||
}
|
||||
{
|
||||
stream<string_Stream> ws(ios_,
|
||||
stream<test::string_stream> ws(ios_,
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"Host: localhost:80\r\n"
|
||||
"Upgrade: WebSocket\r\n"
|
||||
@@ -247,7 +123,7 @@ public:
|
||||
expect(! ec, ec.message());
|
||||
}
|
||||
{
|
||||
stream<string_Stream> ws(ios_,
|
||||
stream<test::string_stream> ws(ios_,
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"\r\n");
|
||||
error_code ec;
|
||||
@@ -255,7 +131,7 @@ public:
|
||||
expect(ec);
|
||||
}
|
||||
{
|
||||
stream<string_Stream> ws(ios_,
|
||||
stream<test::string_stream> ws(ios_,
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"Host: localhost:80\r\n"
|
||||
"Upgrade: WebSocket\r\n"
|
||||
@@ -268,7 +144,7 @@ public:
|
||||
expect(! ec, ec.message());
|
||||
}
|
||||
{
|
||||
stream<string_Stream> ws(ios_,
|
||||
stream<test::string_stream> ws(ios_,
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"\r\n");
|
||||
error_code ec;
|
||||
@@ -276,7 +152,7 @@ public:
|
||||
expect(ec);
|
||||
}
|
||||
{
|
||||
stream<string_Stream> ws(ios_,
|
||||
stream<test::string_stream> ws(ios_,
|
||||
"Host: localhost:80\r\n"
|
||||
"Upgrade: WebSocket\r\n"
|
||||
"Connection: upgrade\r\n"
|
||||
@@ -295,7 +171,7 @@ public:
|
||||
}
|
||||
}
|
||||
{
|
||||
stream<string_Stream> ws(ios_,
|
||||
stream<test::string_stream> ws(ios_,
|
||||
"\r\n");
|
||||
try
|
||||
{
|
||||
@@ -309,7 +185,7 @@ public:
|
||||
}
|
||||
}
|
||||
{
|
||||
stream<string_Stream> ws(ios_,
|
||||
stream<test::string_stream> ws(ios_,
|
||||
"Host: localhost:80\r\n"
|
||||
"Upgrade: WebSocket\r\n"
|
||||
"Connection: upgrade\r\n"
|
||||
@@ -322,7 +198,7 @@ public:
|
||||
expect(! ec, ec.message());
|
||||
}
|
||||
{
|
||||
stream<string_Stream> ws(ios_,
|
||||
stream<test::string_stream> ws(ios_,
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"\r\n");
|
||||
error_code ec;
|
||||
@@ -330,7 +206,7 @@ public:
|
||||
expect(ec);
|
||||
}
|
||||
{
|
||||
stream<string_Stream> ws(ios_,
|
||||
stream<test::string_stream> ws(ios_,
|
||||
"Host: localhost:80\r\n"
|
||||
"Upgrade: WebSocket\r\n"
|
||||
"Connection: upgrade\r\n"
|
||||
@@ -343,7 +219,7 @@ public:
|
||||
expect(! ec, ec.message());
|
||||
}
|
||||
{
|
||||
stream<string_Stream> ws(ios_,
|
||||
stream<test::string_stream> ws(ios_,
|
||||
"\r\n");
|
||||
error_code ec;
|
||||
ws.async_accept(strbuf(
|
||||
@@ -353,7 +229,7 @@ public:
|
||||
}
|
||||
|
||||
void testHandshake(endpoint_type const& ep,
|
||||
boost::asio::yield_context do_yield)
|
||||
yield_context do_yield)
|
||||
{
|
||||
{
|
||||
// disconnected socket
|
||||
@@ -423,7 +299,7 @@ public:
|
||||
}
|
||||
|
||||
void testErrorHandling(endpoint_type const& ep,
|
||||
boost::asio::yield_context do_yield)
|
||||
yield_context do_yield)
|
||||
{
|
||||
static std::size_t constexpr limit = 100;
|
||||
std::size_t n;
|
||||
@@ -436,7 +312,7 @@ public:
|
||||
sock.connect(ep, ec);
|
||||
if(! expect(! ec, ec.message()))
|
||||
break;
|
||||
stream<fail_stream<socket_type&>> ws(n, sock);
|
||||
stream<test::fail_stream<socket_type&>> ws(n, sock);
|
||||
try
|
||||
{
|
||||
ws.handshake("localhost", "/");
|
||||
@@ -475,7 +351,7 @@ public:
|
||||
sock.connect(ep, ec);
|
||||
if(! expect(! ec, ec.message()))
|
||||
break;
|
||||
stream<fail_stream<socket_type&>> ws(n, sock);
|
||||
stream<test::fail_stream<socket_type&>> ws(n, sock);
|
||||
ws.handshake("localhost", "/", ec);
|
||||
if(ec)
|
||||
continue;
|
||||
@@ -510,7 +386,7 @@ public:
|
||||
sock.connect(ep, ec);
|
||||
if(! expect(! ec, ec.message()))
|
||||
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]);
|
||||
if(ec)
|
||||
break;
|
||||
@@ -538,13 +414,70 @@ public:
|
||||
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
|
||||
{
|
||||
testSpecialMembers();
|
||||
|
||||
testOptions();
|
||||
|
||||
exec(std::bind(&stream_test::testAccept,
|
||||
yield_to(std::bind(&stream_test::testAccept,
|
||||
this, std::placeholders::_1));
|
||||
|
||||
auto const any = endpoint_type{
|
||||
@@ -552,22 +485,30 @@ public:
|
||||
{
|
||||
sync_echo_peer server(true, any);
|
||||
|
||||
exec(std::bind(&stream_test::testHandshake,
|
||||
yield_to(std::bind(&stream_test::testHandshake,
|
||||
this, server.local_endpoint(),
|
||||
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(),
|
||||
std::placeholders::_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(),
|
||||
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(),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
@@ -37,7 +37,6 @@ namespace websocket {
|
||||
class async_echo_peer
|
||||
{
|
||||
public:
|
||||
using error_code = boost::system::error_code;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
@@ -36,7 +36,6 @@ namespace websocket {
|
||||
class sync_echo_peer
|
||||
{
|
||||
public:
|
||||
using error_code = boost::system::error_code;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
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