Concept revision and documentation (API Change):

The concept type traits are renamed for consistency,
and consolidated into a single header file <beast/core/type_traits.hpp>

A new section, Core Concepts, is added to the documentation describing all
of the core utility classes and functions. This also includes a complete
explanation and sample program describing how to write asynchronous initiation
functions and their associated composed operations.
This commit is contained in:
Vinnie Falco
2017-05-10 12:03:00 -07:00
parent aa8a0a2a4b
commit 51f11f0902
66 changed files with 1822 additions and 944 deletions

View File

@@ -1,6 +1,7 @@
Version 41
* Trim Appveyor matrix rows
* Concept revision and documentation
API Changes

611
doc/core.qbk Normal file
View File

@@ -0,0 +1,611 @@
[/
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
]
[section:core Core Concepts]
[block '''
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
<member><link linkend="beast.core.concepts">Concepts</link></member>
<member><link linkend="beast.core.dynamic_buffer">DynamicBuffer</link></member>
<member><link linkend="beast.core.algorithms">Buffer Algorithms</link></member>
<member><link linkend="beast.core.async">Asynchronous Model</link></member>
<member><link linkend="beast.core.tutorial">Tutorial</link></member>
</simplelist></entry></row></tbody></tgroup></informaltable>
''']
In addition to network protocols, Beast provides users with robust concepts,
implementations, and algorithms which can be used to design higher level
abstractions that interoperate with Boost.Asio. In the sections that follow
are descriptions of these concepts, followed by algorithms using the concepts,
and then concluding with a tutorial on developing composed asynchronous
operations which are compatible with the Extensible Asynchronous Model provided
in Boost.Asio, __N3747__, and __N4588__.
[section:concepts Concepts]
Beast provides template metaprogramming functions to allow users to perform
concept checks on parameters, preventing undefined or illegal use. These trait
traits are used in the implementation of the library and part of its public
interface so users may build on the library using the same features. Use of
concept checks benefit users by providing accurate, concise compilation error
diagnostics.
[table Type Traits
[[Name][Description]]
[[
[link beast.ref.has_get_io_service `has_get_io_service`]
][
Determine if the `get_io_service` member function is present with the
correct signature.
]]
[[
[link beast.ref.is_async_read_stream `is_async_read_stream`]
][
Determine if a type meets the requirements of __AsyncReadStream__.
]]
[[
[link beast.ref.is_async_stream `is_async_stream`]
][
Determine if a type meets the requirements of both __AsyncReadStream__
and __AsyncWriteStream__.
]]
[[
[link beast.ref.is_async_write_stream `is_async_write_stream`]
][
Determine if a type meets the requirements of __AsyncWriteStream__.
]]
[[
[link beast.ref.is_completion_handler `is_completion_handler`]
][
Determine if a type meets the requirements of __CompletionHandler__,
and is callable with a specified signature.
]]
[[
[link beast.ref.is_const_buffer_sequence `is_const_buffer_sequence`]
][
Determine if a type meets the requirements of __ConstBufferSequence__.
]]
[[
[link beast.ref.is_dynamic_buffer `is_dynamic_buffer`]
][
Determine if a type meets the requirements of __DynamicBuffer__.
]]
[[
[link beast.ref.is_mutable_buffer_sequence `is_mutable_buffer_sequence`]
][
Determine if a type meets the requirements of __MutableBufferSequence__.
]]
[[
[link beast.ref.is_sync_read_stream `is_sync_read_stream`]
][
Determine if a type meets the requirements of __SyncReadStream__.
]]
[[
[link beast.ref.is_sync_stream `is_sync_stream`]
][
Determine if a type meets the requirements of both __SyncReadStream__
and __SyncWriteStream__.
]]
[[
[link beast.ref.is_sync_write_stream `is_sync_write_stream`]
][
Determine if a type meets the requirements of __SyncWriteStream__.
]]
]
[endsect]
[section:dynamic_buffer DynamicBuffer]
The networking technical specification described in __N4588__ provides a
concept called a __DynamicBuffer__. Instances of this concept define
an output area expressed as a __MutableBufferSequence__ and an input area
expressed as a __ConstBufferSequence__. Octets may be moved from the output
area to the input area through a structured interface, and later consumed
from the input area when the data is no longer needed. Beast adopts this
concept by providing a concise definition taken directly from the technical
specification and using it as the interface for operations which require
dynamically sized buffers. Several classes are provided which implement the
dynamic buffer concept using various strategies:
[table Dynamic buffer implementations
[[Name][Description]]
[[
[link beast.ref.multi_buffer `multi_buffer`]
[link beast.ref.basic_multi_buffer `basic_multi_buffer`]
][
Uses a sequence of one or more character arrays of varying sizes.
Additional character array objects are appended to the sequence to
accommodate changes in the size of the character sequence. The basic
container supports the standard allocator model.
]]
[[
[link beast.ref.flat_buffer `flat_buffer`]
[link beast.ref.basic_flat_buffer `basic_flat_buffer`]
][
Guarantees that input and output areas are buffer sequences with
length one. Upon construction an optional upper limit to the total
size of the input and output areas may be set. The basic container
supports the standard allocator model.
]]
[[
[link beast.ref.static_buffer `static_buffer`]
[link beast.ref.static_buffer `static_buffer_n`]
][
Provides the facilities of a dynamic buffer, subject to an upper
limit placed on the total size of the input and output areas defined
by a constexpr template parameter. The storage for the sequences are
kept in the class; the implementation does not perform heap allocations.
]]
[[
[link beast.ref.buffers_adapter `buffers_adapter`]
][
This wrapper adapts any __MutableBufferSequence__ into a
__DynamicBuffer__ with an upper limit on the total size of the input and
output areas equal to the size of the underlying mutable buffer sequence.
The implementation does not perform heap allocations.
]]
]
[endsect]
[section:algorithms Buffer Algorithms]
Beast provides a collection of algorithms to work on __ConstBufferSequence__
or __MutableBufferSequence__ objects. These algorithms allow composition of
new algorithms which work on any objects meeting the buffer sequence
requirements, in an efficient way: no memory allocations are performed;
instead, the algorithms implement lightweight iterators over the existing
underlying memory, whose lifetime is retained by the caller.
[table Buffer algorithms
[[Name][Description]]
[[
[link beast.ref.buffer_cat `buffer_cat`]
][
The functions returns a new buffer sequence which, when iterated,
traverses the sequence which would be formed if all of the input buffer
sequences were concatenated. This powerful function allows multiple calls
to a stream's `write_some` function to be combined into one, eliminating
expensive system calls.
]]
[[
[link beast.ref.consuming_buffers `consuming_buffers`]
][
This class wraps the underlying memory of an existing buffer sequence
and presents a suffix of the original sequence. The length of the suffix
may be progressively shortened. This lets callers work with sequential
increments of a buffer sequence.
]]
[[
[link beast.ref.prepare_buffer `prepare_buffer`]
[link beast.ref.prepare_buffers `prepare_buffers`]
][
These functions return a new buffer sequence which wraps the underlying
memory of an existing buffer sequence, but with a smaller size. This
lets callers work with a prefix of a buffer sequence.
]]
]
[endsect]
[section:async Asynchronous Model]
Asynchronous operations are started by calling a free function or member
function known as an ['asynchronous initiation function]. The initiation
function accepts parameters specific to the operation as well as a "completion
token." This token is either a completion handler, or another type allowing for
customization of how the result of the asynchronous operation is conveyed to
callers. Boost.Asio allows the special completion tokens __use_future__ and
objects of type __yield_context__ to allow callers to specify the use of futures
and coroutines respectively. This system, where the return value and method of
indicating completion may be customize at the call site of the asynchronous
initiation function, is known as the ['Extensible Asynchronous Model] described
in __N3747__, and built-in to __N4588__.
[note
A full explanation of completion handlers, the Extensible Asynchronous
Model and how Boost.Asio's asynchronous interfaces are used is beyond the
scope of this document. Readers should consult the Boost.Asio documentation
for a comprehensive treatment.
]
Since Beast is low level, authors of libraries may wish to create higher level
interfaces using the primitives found in this library. Non-trivial applications
will want to provide their own asychronous initiation functions which perform
a series of other, intermediate asynchronous operations before invoking the
final completion handler. The set of intermediate actions produced by calling
an initiation function is known as a ['composed operation]. To ensure full
interoperability and well-defined behavior, Boost.Asio imposes requirements on
the implementation of composed operations. Beast provides a number of useful
classes and macros to facilitate the development of composed operations and
the associated asynchronous initiation functions used to launch them.
[table Asynchronous Helpers
[[Name][Description]]
[[
[link beast.ref.handler_type `handler_type`]
][
This template alias converts a completion token and signature to the
correct completion handler type. It is used in the implementation of
asynchronous initiation functions to meet the requirements of the
Extensible Asynchronous Model.
]]
[[
[link beast.ref.async_return_type `async_return_type`]
][
This template alias determines the return value of an asynchronous
initiation function given the completion token and signature. It is used
by asynchronous initiation functions to meet the requirements of the
Extensible Asynchronous Model.
]]
[[
[link beast.ref.async_completion `async_completion`]
][
This class aggregates the completion handler customization point and
the asynchronous initiation function return value customization point
into a single object which exposes the appropriate output types for the
given input types, and also contains boilerplate that is necessary to
implement an initiation function using the Extensible Model.
]]
[[
[link beast.ref.handler_alloc `handler_alloc`]
][
This class meets the requirements of [*Allocator], and uses any custom
memory allocation and deallocation hooks associated with a given handler.
It is useful for when a composed operation requires temporary dynamic
allocations to achieve its result. Memory allocated using this allocator
must be freed before the final completion handler is invoked.
]]
[[
[link beast.ref.handler_ptr `handler_ptr`]
][
This is a smart pointer container used to manage the internal state of a
composed operation. It is useful when the state is non trivial. For example
when the state has non-copyable or expensive to copy types. The container
takes ownership of the final completion handler, and provides boilerplate
to invoke the final handler in a way that also deletes the internal state.
The internal state is allocated using the final completion handler's
associated allocator, benefiting from all handler memory management
optimizations transparently.
]]
[[
[link beast.ref.bind_handler `bind_handler`]
][
This function returns a new, nullary completion handler which when
invoked with no arguments invokes the original completion handler with a
list of bound arguments. The invocation is made from the same implicit
or explicit strand as that which would be used to invoke the original
handler. This is accomplished by using the correct overload of
`asio_handler_invoke` associated with the original completion handler.
]]
]
When implementing composed operations it is necessary to provide hooks for
the composed operation which forward the hook calls to the hooks associated
with the final completion handler. These calls must be made from a namespace
that does not include overloads of the hook functions, since they depend on
argument dependent lookup to resolve. Beast provides a set of public helper
functions to invoke these hooks. These hooks are all located in the
`beast_asio_helpers` namespace rather than the `beast` namespace:
[table Handler Hooks
[[Name][Description]]
[[
[link beast.ref.beast_asio_helpers__allocate `allocate`]
][
Allocation function for a handler. Asynchronous operations may need to
allocate temporary objects. Since asynchronous operations have a handler
function object, these temporary objects can be said to be associated with
the handler.
]]
[[
[link beast.ref.beast_asio_helpers__deallocate `deallocate`]
][
Deallocation function for a handler. The implementation guarantees that
the deallocation will occur before the associated handler is invoked, which
means the memory is ready to be reused for any new asynchronous operations
started by the handler.
]]
[[
[link beast.ref.beast_asio_helpers__invoke `invoke`]
][
Invocation function for a handler. When asynchronous operations are
composed from other asynchronous operations, all intermediate handlers
should be invoked using the same method as the final handler. This is
required to ensure that user-defined objects are not accessed in a way
that may violate the guarantees. This hooking function ensures that the
invoked method used for the final handler is accessible at each
intermediate step.
]]
[[
[link beast.ref.beast_asio_helpers__is_continuation `is_continuation`]
][
Continuation function for a handler. Asynchronous operations may represent
a continuation of the asynchronous control flow associated with the current
handler. The implementation can use this knowledge to optimise scheduling
of the handler.
]]
]
[endsect]
[section:tutorial Tutorial]
To illustrate the usage of the asynchronous helpers in the core section of
this library, we will develop a simple asynchronous composed operation called
[*echo]. This operation will read up to the first newline on a stream, and
then write the same line including the newline back on the stream.
First we define the input parameters and results, then declare our initiation
function. For our echo operation the only inputs are the stream and the
completion token. The output is the error code which is usually included in
all completion handler signatures.
```
#include <beast/core.hpp>
#include <boost/asio.hpp>
#include <cstddef>
#include <memory>
#include <utility>
// Read a line and echo it back
//
template<class AsyncStream, class CompletionToken>
beast::async_return_type<CompletionToken, void(beast::error_code)>
async_echo(AsyncStream& stream, CompletionToken&& token)
```
Now that we have a declaration, we will define the body of the function. We
want to achieve the following goals: perform static type checking on the input
parameters, set up the return value as per __N3747__, and launch the composed
operation by constructing the object and invoking it.
```
template<class AsyncStream, class Handler>
class echo_op; // This is our composed operation implementation
// Read a line and echo it back
//
template<class AsyncStream, class CompletionToken>
beast::async_return_type<CompletionToken, void(beast::error_code)>
async_echo(AsyncStream& stream, CompletionToken&& token)
{
// Make sure stream meets the requirements. We use static_assert
// instead of letting the compiler generate several pages of hard
// to read error messages.
//
static_assert(beast::is_async_stream<AsyncStream>::value,
"AsyncStream requirements not met");
// This helper manages some of the handler's lifetime and
// uses the result and handler specializations associated with
// the completion token to help customize the return value.
//
beast::async_completion<CompletionToken, void(beast::error_code)> init{token};
// Create the composed operation and launch it. This is a constructor
// call followed by invocation of operator(). We use BEAST_HANDLER_TYPE
// to convert the completion token into the correct handler type,
// allowing user defined specializations of the async result template
// to take effect.
//
echo_op<AsyncStream, beast::handler_type<CompletionToken, void(beast::error_code)>>{
stream, init.completion_handler}(beast::error_code{}, 0);
// This hook lets the caller see a return value when appropriate.
// For example this might return std::future<error_code> if
// CompletionToken is boost::asio::use_future, or this might
// return an error code if CompletionToken specifies a coroutine.
//
return init.result.get();
}
```
The initiation function contains a few relatively simple parts. There is the
customization of the return value type, static type checking, building the
return value type using the helper, and creating and launching the composed
operation object. The [*`echo_op`] object does most of the work here, and has
a somewhat non-trivial structure. This structure is necessary to meet the
stringent requirements of composed operations (described in more detail in
the Boost.Asio documentation). We will touch on these requirements without
explaining them in depth.
First we will create boilerplate which is present in all composed operations
written in this style:
```
// This composed operation reads a line of input and echoes it back.
//
template<class AsyncStream, class Handler>
class echo_op
{
// This holds all of the state information required by the operation.
struct state
{
// The stream to read and write to
AsyncStream& stream;
// Indicates what step in the operation's state machine
// to perform next, starting from zero.
int step = 0;
// The buffer used to hold the input and output data.
// Note that we use a custom allocator for performance,
// this allows the implementation of the io_service to
// make efficient re-use of memory allocated by composed
// operations during continuations.
//
boost::asio::basic_streambuf<beast::handler_alloc<char, Handler>> buffer;
// handler_ptr requires that the first parameter to the
// contained object constructor is a reference to the
// managed final completion handler.
//
explicit state(Handler& handler, AsyncStream& stream_)
: stream(stream_)
, buffer((std::numeric_limits<std::size_t>::max)(),
beast::handler_alloc<char, Handler>{handler})
{
}
};
// This smart pointer container allocates our state using the
// memory allocation hooks associated with the final completion
// handler, manages the lifetime of that handler for us, and
// enforces the destroy-before-invocation requirement on memory
// allocated using the hooks.
//
beast::handler_ptr<state, Handler> p_;
public:
// Boost.Asio requires that handlers are CopyConstructible.
// In some cases, it takes advantage of handlers that are
// MoveConstructible. This operation supports both.
//
echo_op(echo_op&&) = default;
echo_op(echo_op const&) = default;
// The constructor simply creates our state variables in
// the smart pointer container.
//
template<class DeducedHandler, class... Args>
echo_op(AsyncStream& stream, DeducedHandler&& handler)
: p_(std::forward<DeducedHandler>(handler), stream)
{
}
// Determines if the next asynchronous operation represents a
// continuation of the asynchronous flow of control associated
// with the final handler. If we are past step one, it means
// we have performed an asynchronous operation therefore any
// subsequent operation would represent a continuation.
// Otherwise, we propagate the handler's associated value of
// is_continuation. Getting this right means the implementation
// may schedule the invokation of the invoked functions more
// efficiently.
//
friend bool asio_handler_is_continuation(echo_op* op)
{
// This next call is structured to permit argument
// dependent lookup to take effect.
using boost::asio::asio_handler_is_continuation;
// Always use std::addressof to pass the pointer to the handler,
// otherwise an unwanted overload of operator& may be called instead.
return op->p_->step > 1 ||
asio_handler_is_continuation(std::addressof(op->p_.handler()));
}
// Handler hook forwarding. These free functions invoke the hooks
// associated with the final completion handler. In effect, they
// make the Asio implementation treat our composed operation the
// same way it would treat the final completion handler for the
// purpose of memory allocation and invocation.
//
// Our implementation just passes through the call to the hook
// associated with the final handler.
friend void* asio_handler_allocate(std::size_t size, echo_op* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(size, std::addressof(op->p_.handler()));
}
friend void asio_handler_deallocate(void* p, std::size_t size, echo_op* op)
{
using boost::asio::asio_handler_deallocate;
return asio_handler_deallocate(p, size, std::addressof(op->p_.handler()));
}
template<class Function>
friend void asio_handler_invoke(Function&& f, echo_op* op)
{
using boost::asio::asio_handler_invoke;
return asio_handler_invoke(f, std::addressof(op->p_.handler()));
}
// Our main entry point. This will get called as our
// intermediate operations complete. Definition below.
//
void operator()(beast::error_code ec, std::size_t bytes_transferred);
};
```
We have the common boilerplate for a composed operation and now we just need
to implement the function call operator. Our strategy is to make our composed
object meet the requirements of a completion handler by being copyable (also
movable), and by providing the function call operator with the correct
signature. Rather than using `std::bind` or `boost::bind`, which destroys
the type information and therefore breaks the allocation and invocation
hooks, we will simply pass `std::move(*this)` as the completion handler
parameter for any operations that we initiate. For the move to work correctly,
care must be taken to ensure that no access to data members are made after the
move takes place. Here is the implementation of the function call operator for
this echo operation:
```
// We are callable with the signature void(error_code, bytes_transferred),
// allowing `*this` to be used as both a ReadHandler and a WriteHandler.
//
template<class AsyncStream, class Handler>
void echo_op<AsyncStream, Handler>::
operator()(beast::error_code ec, std::size_t bytes_transferred)
{
// Store a reference to our state. The address of the state won't
// change, and this solves the problem where dereferencing the
// data member is undefined after a move.
auto& p = *p_;
// Now perform the next step in the state machine
switch(ec ? 2 : p.step)
{
// initial entry
case 0:
// read up to the first newline
p.step = 1;
return boost::asio::async_read_until(p.stream, p.buffer, "\n", std::move(*this));
case 1:
// write everything back
p.step = 2;
return boost::asio::async_write(p.stream, p.buffer.data(), std::move(*this));
case 2:
break;
}
// Invoke the final handler. If we wanted to pass any arguments
// which come from our state, they would have to be moved to the
// stack first, since the `handler_ptr` guarantees that the state
// is destroyed before
// the handler is invoked.
//
p_.invoke(ec);
return;
}
```
A complete, runnable version of this example may be found in the examples
directory.
[endsect]
[endsect]

View File

@@ -486,7 +486,7 @@ start. Other design goals:
Beast doesn't allocate or make copies of buffers when sending data. The
caller's buffers are sent in-place. You can use any object meeting the
requirements of
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html ConstBufferSequence],
[@http://www.boost.org/doc/html/boost_asio/reference/ConstBufferSequence.html ConstBufferSequence],
permitting efficient scatter-gather I/O.
The [*ConstBufferSequence] interface allows callers to send data from
@@ -588,8 +588,8 @@ start. Other design goals:
[table
[
[[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/async_connect.html Beast],
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html also]]
[[@http://www.boost.org/doc/html/boost_asio/reference/async_connect.html Beast],
[@http://www.boost.org/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html also]]
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/endpoint.hpp#L52 websocketpp]]
][
[```

View File

@@ -127,6 +127,15 @@ type, in `file_body`.
* [@examples/http_sync_server.hpp]
* [@examples/http_server.cpp]
[heading Composed Operations]
This program shows how to use Beast's core foundations to build a
composable asynchronous initiation function with associated composed
operation implementation. This is a complete, runnable version of
the example described in the Core Foundations document section.
* [@examples/echo_op.cpp]
[heading Listings]
These are stand-alone listings of the HTTP and WebSocket examples.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -23,22 +23,25 @@
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
[def __N3747__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3747.pdf [*N3747]]]
[def __N4588__ [@http://cplusplus.github.io/networking-ts/draft.pdf [*N4588]]]
[def __rfc6455__ [@https://tools.ietf.org/html/rfc6455 rfc6455]]
[def __rfc7230__ [@https://tools.ietf.org/html/rfc7230 rfc7230]]
[def __asio_handler_invoke__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]]
[def __asio_handler_allocate__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]]
[def __void_or_deduced__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]]
[def __asio_handler_invoke__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]]
[def __asio_handler_allocate__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]]
[def __void_or_deduced__ [@http://www.boost.org/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]]
[def __use_future__ [@http://www.boost.org/doc/html/boost_asio/reference/use_future_t.html `boost::asio::use_future`]]
[def __yield_context__ [@http://www.boost.org/doc/html/boost_asio/reference/yield_context.html `boost::asio::yield_context`]]
[def __AsyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]]
[def __AsyncWriteStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]]
[def __CompletionHandler__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]]
[def __ConstBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]]
[def __Handler__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/Handler.html [*Handler]]]
[def __MutableBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]]
[def __SyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]]
[def __SyncWriteStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]]
[def __AsyncReadStream__ [@http://www.boost.org/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]]
[def __AsyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]]
[def __CompletionHandler__ [@http://www.boost.org/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]]
[def __ConstBufferSequence__ [@http://www.boost.org/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]]
[def __Handler__ [@http://www.boost.org/doc/html/boost_asio/reference/Handler.html [*Handler]]]
[def __MutableBufferSequence__ [@http://www.boost.org/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]]
[def __SyncReadStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]]
[def __SyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]]
[def __Body__ [link beast.ref.Body [*`Body`]]]
[def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]]
@@ -62,6 +65,11 @@ provides implementations of the HTTP and WebSocket protocols.
][
An introduction with features, requirements, and credits.
]]
[[
[link beast.core Core Concepts]
][
Library-wide concepts, classes, functions, and traits.
]]
[[
[link beast.http Using HTTP]
][
@@ -96,6 +104,7 @@ provides implementations of the HTTP and WebSocket protocols.
]
[include overview.qbk]
[include core.qbk]
[include http.qbk]
[include websocket.qbk]
[include examples.qbk]

View File

@@ -43,7 +43,7 @@ Beast requires:
* [*Boost.] Beast is built on Boost, especially Boost.Asio.
* [*OpenSSL.] If using TLS/Secure sockets (optional).
[note Tested compilers: msvc-14+, gcc 5+, clang 3.6+]
[note Tested compilers: msvc-14+, gcc 4.8+, clang 3.6+]
The library is [*header-only]. It is not necessary to add any .cpp files,
or to add commands to your build script for building Beast. To link your

View File

@@ -29,7 +29,7 @@
<entry valign="top">
<bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__basic_dynamic_body">http__basic_dynamic_body</link></member>
<member><link linkend="beast.ref.http__basic_dynamic_body">basic_dynamic_body</link></member>
<member><link linkend="beast.ref.http__basic_fields">basic_fields</link></member>
<member><link linkend="beast.ref.http__basic_parser">basic_parser</link></member>
<member><link linkend="beast.ref.http__dynamic_body">dynamic_body</link></member>
@@ -159,7 +159,6 @@
<member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member>
<member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member>
<member><link linkend="beast.ref.buffered_read_stream">buffered_read_stream</link></member>
<member><link linkend="beast.ref.errc">errc</link></member>
<member><link linkend="beast.ref.error_category">error_category</link></member>
<member><link linkend="beast.ref.error_code">error_code</link></member>
<member><link linkend="beast.ref.error_condition">error_condition</link></member>
@@ -187,23 +186,35 @@
<member><link linkend="beast.ref.system_category">system_category</link></member>
<member><link linkend="beast.ref.to_static_string">to_static_string</link></member>
</simplelist>
<bridgehead renderas="sect3">Constants</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.errc">errc</link></member>
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
<member><link linkend="beast.ref.is_AsyncStream">is_AsyncStream</link></member>
<member><link linkend="beast.ref.is_CompletionHandler">is_CompletionHandler</link></member>
<member><link linkend="beast.ref.has_get_io_service">has_get_io_service</link></member>
<member><link linkend="beast.ref.is_async_read_stream">is_async_read_stream</link></member>
<member><link linkend="beast.ref.is_async_write_stream">is_async_write_stream</link></member>
<member><link linkend="beast.ref.is_async_stream">is_async_stream</link></member>
<member><link linkend="beast.ref.is_completion_handler">is_completion_handler</link></member>
<member><link linkend="beast.ref.is_const_buffer_sequence">is_const_buffer_sequence</link></member>
<member><link linkend="beast.ref.is_dynamic_buffer">is_dynamic_buffer</link></member>
<member><link linkend="beast.ref.is_mutable_buffer_sequence">is_mutable_buffer_sequence</link></member>
<member><link linkend="beast.ref.is_SyncReadStream">is_SyncReadStream</link></member>
<member><link linkend="beast.ref.is_SyncStream">is_SyncStream</link></member>
<member><link linkend="beast.ref.is_SyncWriteStream">is_SyncWriteStream</link></member>
<member><link linkend="beast.ref.is_sync_read_stream">is_sync_read_stream</link></member>
<member><link linkend="beast.ref.is_sync_stream">is_sync_stream</link></member>
<member><link linkend="beast.ref.is_sync_write_stream">is_sync_write_stream</link></member>
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Helpers</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.beast_asio_helpers__allocate">allocate</link></member>
<member><link linkend="beast.ref.beast_asio_helpers__deallocate">deallocate</link></member>
<member><link linkend="beast.ref.beast_asio_helpers__invoke">invoke</link></member>
<member><link linkend="beast.ref.beast_asio_helpers__is_continuation">is_continuation</link></member>
</simplelist>
<bridgehead renderas="sect3">Concepts</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.streams.AsyncStream">AsyncStream</link></member>

View File

@@ -9,7 +9,7 @@
A `BufferSequence` is a type meeting either of the following requirements:
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*`ConstBufferSequence`]]
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*`MutableBufferSequence`]]
* __ConstBufferSequence__
* __MutableBufferSequence__
[endsect]

View File

@@ -37,8 +37,8 @@ In the table below:
* `a` denotes a value of type `X`.
* `c` denotes a (possibly const) value of type `X`.
* `n` denotes a value of type `std::size_t`.
* `T` denotes a type meeting the requirements for [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html `ConstBufferSequence`].
* `U` denotes a type meeting the requirements for [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html `MutableBufferSequence`].
* `T` denotes a type meeting the requirements for __ConstBufferSequence__.
* `U` denotes a type meeting the requirements for __MutableBufferSequence__.
[table DynamicBuffer requirements
[[operation] [type] [semantics, pre/post-conditions]]

View File

@@ -21,14 +21,14 @@ A type modeling [*`Stream`] meets either or both of the following requirements:
A type modeling [*`AsyncStream`] meets the following requirements:
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncReadStream.html [*`AsyncReadStream`]]
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*`AsyncWriteStream`]]
* __AsyncReadStream__
* __AsyncWriteStream__
[heading:SyncStream SyncStream]
A type modeling [*`SyncStream`] meets the following requirements:
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncReadStream.html [*`SyncReadStream`]]
* [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncWriteStream.html [*`SyncWriteStream`]]
* __SyncReadStream__
* __SyncWriteStream__
[endsect]

View File

@@ -12,13 +12,10 @@
<member><link linkend="beast.websocket.creation">Creation</link></member>
<member><link linkend="beast.websocket.connections">Making connections</link></member>
<member><link linkend="beast.websocket.handshaking">Handshaking</link></member>
<member><link linkend="beast.websocket.accepting">Accepting</link></member>
<member><link linkend="beast.websocket.messages">Messages</link></member>
<member><link linkend="beast.websocket.frames">Frames</link></member>
<member><link linkend="beast.websocket.control">Control Frames</link></member>
<member><link linkend="beast.websocket.buffers">Buffers</link></member>
<member><link linkend="beast.websocket.async">Asynchronous interface</link></member>
<member><link linkend="beast.websocket.io_service">The io_service</link></member>
<member><link linkend="beast.websocket.threads">Thread Safety</link></member>
<member><link linkend="beast.websocket.notes">Notes</link></member>
</simplelist></entry></row></tbody></tgroup></informaltable>
''']
@@ -30,9 +27,8 @@ this technology is to provide a mechanism for browser-based applications that
need two-way communication with servers that does not rely on opening multiple
HTTP connections.
Beast.WebSocket provides developers with a robust WebSocket implementation
built on Boost.Asio with a consistent asynchronous model using a modern
C++ approach.
Beast provides developers with a robust WebSocket implementation built on
Boost.Asio with a consistent asynchronous model using a modern C++ approach.
The WebSocket protocol is described fully in
[@https://tools.ietf.org/html/rfc6455 rfc6455]
@@ -48,11 +44,11 @@ The WebSocket protocol is described fully in
[section:creation Creation]
The interface to Beast's WebSocket implementation is a single template
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
class [link beast.ref.websocket__stream `websocket::stream`] which
wraps a "next layer" object. The next layer object must meet the requirements
of [link beast.ref.streams.SyncStream [*`SyncStream`]] if synchronous
of [link beast.ref.streams.SyncStream [*SyncStream]] if synchronous
operations are performed, or
[link beast.ref.streams.AsyncStream [*`AsyncStream`]] if asynchronous
[link beast.ref.streams.AsyncStream [*AsyncStream]] if asynchronous
operations are performed, or both. Arguments supplied during construction are
passed to next layer's constructor. Here we declare a websocket stream over
a TCP/IP socket with ownership of the socket:
@@ -85,7 +81,7 @@ beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>
For servers that can handshake in multiple protocols, it may be desired
to wrap an object that already exists. This socket can be moved in:
```
boost::asio::ip::tcp::socket&& sock;
boost::asio::ip::tcp::socket sock;
...
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{std::move(sock)};
```
@@ -140,6 +136,22 @@ void do_accept(boost::asio::ip::tcp::acceptor& acceptor)
}
```
When using SSL, which itself wraps a next layer object that is usualy a
TCP/IP socket, multiple calls to retrieve the next layer may be required:
```
beast::websocket::stream<boost::asio::ssl::stream<
boost::asio::ip::tcp::socket>> ws{ios, ctx};
// connect the underlying TCP/IP socket
ws.next_layer().next_layer().connect(ep);
// perform SSL handshake
ws.next_layer().handshake(boost::asio::ssl::stream_base::client);
// perform WebSocket handshake
ws.handshake("localhost", "/");
```
[note
Examples use synchronous interfaces for clarity of exposition.
]
@@ -154,17 +166,103 @@ A WebSocket session begins when one side sends the HTTP Upgrade request
for websocket, and the other side sends an appropriate HTTP response
indicating that the request was accepted and that the connection has
been upgraded. The HTTP Upgrade request must include the Host HTTP field,
and the URI of the resource to request.
[link beast.ref.websocket__stream.handshake `handshake`] is used to send the
request with the required host and resource strings.
and the target of the resource to request. The stream member functions
[link beast.ref.websocket__stream.handshake `handshake`] and
[link beast.ref.websocket__stream.async_handshake `async_handshake`]
are used to send the request with the required host and target strings.
```
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
...
ws.set_option(beast::websocket::keep_alive(true));
ws.handshake("ws.example.com:80", "/cgi-bin/bitcoin-prices");
ws.handshake("localhost", "/");
```
The [link beast.ref.websocket__stream `stream`] automatically
The implementation will create and send an HTTP request that typically
looks like this:
[table WebSocket Upgrade HTTP Request
[[Serialized Octets][Description]]
[[
```
GET / HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Key: 2pGeTR0DsE4dfZs2pH+8MA==
Sec-WebSocket-Version: 13
User-Agent: Beast
```
][
The host and target parameters become part of the Host field
and request-target in the resulting HTTP request. The key is
generated by the implementation. Callers may add fields or
modify fields by providing a ['decorator], described below.
]]]
[heading Decorators]
If the caller wishes to add or modify fields, the member functions
[link beast.ref.websocket__stream.handshake_ex `handshake_ex`] and
[link beast.ref.websocket__stream.async_handshake_ex `async_handshake_ex`]
are provided which allow an additional function object, called a
['decorator], to be passed. The decorator is invoked to modify
the HTTP Upgrade request as needed. This example sets a subprotocol
on the request:
```
void decorate(beast::websocket::request_type& req)
{
req.fields.insert("Sec-WebSocket-Protocol", "xmpp;ws-chat");
}
...
ws.handshake_ex("localhost", "/", &decorate);
```
The HTTP Upgrade request produced by the previous call will look thusly:
[table Decorated WebSocket Upgrade HTTP Request
[[Serialized Octets][Description]]
[[
```
GET / HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Key: 2pGeTR0DsE4dfZs2pH+8MA==
Sec-WebSocket-Version: 13
Sec-WebSocket-Protocol: xmpp;ws-chat
User-Agent: Beast
```
][
Undefined behavior results if the decorator modifies the fields
specific to perform the WebSocket Upgrade , such as the Upgrade
and Connection fields.
]]]
[heading Filtering]
When a client receives an HTTP Upgrade response from the server indicating
a successful upgrade, the caller may wish to perform additional validation
on the received HTTP response message. For example, to check that the
response to a basic authentication challenge is valid. To achieve this,
overloads of the handshake member function allow the caller to store the
received HTTP message in an output reference argument as
[link beast.ref.websocket__response_type `response_type`]
as follows:
```
beast::websocket::response_type res;
ws.handshake(res, "localhost", "/");
if(! res.fields.exists("Sec-WebSocket-Protocol"))
throw std::invalid_argument("missing subprotocols");
```
[endsect]
[section:accepting Accepting]
A [link beast.ref.websocket__stream `stream`] automatically
handles receiving and processing the HTTP response to the handshake request.
The call to handshake is successful if a HTTP response is received with the
101 "Switching Protocols" status code. On failure, an error is returned or an
@@ -179,10 +277,113 @@ similarly. If the handshake fails, an error is returned or exception thrown:
ws.accept();
```
Servers that can handshake in multiple protocols may have already read data
on the connection, or might have already received an entire HTTP request
containing the upgrade request. Overloads of `accept` allow callers to
pass in this additional buffered handshake data.
Successful WebSocket Upgrade responses generated by the implementation will
typically look like this:
[table Decorated WebSocket Upgrade HTTP Request
[[Serialized Octets][Description]]
[[
```
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Server: Beast/40
```
][
The Sec-WebSocket-Accept field value is generated from the
request in a fashion specified by the WebSocket protocol.
]]]
[heading Decorators]
If the caller wishes to add or modify fields, the member functions
[link beast.ref.websocket__stream.accept_ex `accept_ex`] and
[link beast.ref.websocket__stream.async_accept_ex `async_accept_ex`]
are provided which allow an additional function object, called a
['decorator], to be passed. The decorator is invoked to modify
the HTTP Upgrade request as needed. This example sets the Server
field on the response:
```
ws.accept_ex(
[](beast::websocket::response_type& res)
{
res.fields.insert("Server", "AcmeServer");
});
```
The HTTP Upgrade response produced by the previous call will look thusly:
[table Decorated WebSocket Upgrade HTTP Request
[[Serialized Octets][Description]]
[[
```
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Server: AcmeServer
```
][
When the Upgrade request fails, the implementation will still invoke
the decorator to modify the response. In this case, the response
object will have a status code other than 101.
Undefined behavior results when the upgrade request is successful
and the decorator modifies the fields specific to perform the
WebSocket Upgrade , such as the Upgrade and Connection fields.
]]]
[heading Passing HTTP Requests]
When implementing an HTTP server that also supports WebSocket, the
server usually reads the HTTP request from the client. To detect when
the incoming HTTP request is a WebSocket Upgrade request, the function
[link beast.ref.websocket__is_upgrade `is_upgrade`] may be used.
Once the caller determines that the HTTP request is a WebSocket Upgrade,
additional overloads of
[link beast.ref.websocket__stream.accept `accept`],
[link beast.ref.websocket__stream.accept_ex `accept_ex`],
[link beast.ref.websocket__stream.async_accept `async_accept`], and
[link beast.ref.websocket__stream.async_accept_ex `async_accept_ex`]
are provided which receive the entire HTTP request header as an object
to perform the handshake. In this example, the request is first read
in using the HTTP algorithms, and then passed to a newly constructed
stream:
```
void handle_connection(boost::asio::ip::tcp::socket& sock)
{
beast::flat_buffer buffer;
beast::http::request<beast::http::string_body> req;
beast::http::read(sock, buffer, req);
if(beast::websocket::is_upgrade(req))
{
beast::websocket::stream<decltype(sock)> ws{std::move(sock)};
ws.accept(req);
}
}
```
[heading Buffered Handshakes]
Sometimes a server implementation wishes to read octets on the stream
in order to route the incoming request. For example, a server may read
the first 6 octets after accepting an incoming connection to determine
if a TLS protocol is being negotiated, and choose a suitable implementation
at run-time. In the case where the server wishes to accept the incoming
request as an HTTP WebSocket Upgrade request, additional overloads of
[link beast.ref.websocket__stream.accept `accept`],
[link beast.ref.websocket__stream.accept_ex `accept_ex`],
[link beast.ref.websocket__stream.async_accept `async_accept`], and
[link beast.ref.websocket__stream.async_accept_ex `async_accept_ex`]
are provided which receive the additional buffered octects and consume
them as part of the handshake.
In this example, the server reads the initial HTTP message into the
specified dynamic buffer as an octet sequence in the buffer's output
area, and later uses those octets to attempt an HTTP WebSocket Upgrade:
```
void do_accept(boost::asio::ip::tcp::socket& sock)
{
@@ -195,93 +396,6 @@ void do_accept(boost::asio::ip::tcp::socket& sock)
}
```
Alternatively, the caller can pass an entire HTTP request if it was
obtained elsewhere:
```
void do_accept(boost::asio::ip::tcp::socket& sock)
{
boost::asio::streambuf sb;
beast::http::request<http::empty_body> request;
beast::http::read(sock, sb, request);
if(beast::http::is_upgrade(request))
{
websocket::stream<ip::tcp::socket&> ws{sock};
ws.accept(request);
...
}
}
```
[heading Decorators]
Often, callers may need the handshake HTTP request and response objects
generated by the implementation to contain additional HTTP fields. Some
examples include:
* Setting the "User-Agent" or "Server" fields to a custom value
* Announcing a subprotocol by setting the "Sec-WebSocket-Protocol" field
* Adding fields used for HTTP's Basic Authentication
To achieve this, the websocket interface provides the functions
[link beast.ref.websocket__stream.handshake_ex `handshake_ex`],
[link beast.ref.websocket__stream.async_handshake_ex `async_handshake_ex`],
[link beast.ref.websocket__stream.accept_ex `accept_ex`], and
[link beast.ref.websocket__stream.async_accept_ex `async_accept_ex`]
which allow passing of an additional decorator parameter. This parameter is
a function object to invoke which takes a writable reference to the handshake
message. The function is called after the implementation creates the message,
providing an opportunity for further modification. For client handshakes
using
[link beast.ref.websocket__stream.handshake_ex `handshake_ex`] or
[link beast.ref.websocket__stream.async_handshake_ex `async_handshake_ex`],
the message is passed as a reference to
[link beast.ref.websocket__request_type `request_type`]. Here is an example
that sets the user agent for a client request:
```
ws.handshake_ex("ws.example.com:80", "/",
[](request_type& req)
{
req.fields.insert("User-Agent", "Beast Example");
});
```
For server handshakes using
[link beast.ref.websocket__stream.accept_ex `accept_ex`], and
[link beast.ref.websocket__stream.async_accept_ex `async_accept_ex`] the function
object receives the message as a reference to
[link beast.ref.websocket__response_type `response_type`].
Here is an example that sets the server field:
```
ws.accept_ex(
[](response_type& res)
{
res.fields.insert("Server", "Beast Example");
});
```
[heading Response Filtering]
When a client receives an HTTP Upgrade response from the server indicating
a successful upgrade, the caller may wish to perform additional validation
on the received HTTP response message. For example, to check that the
response to a basic authentication challenge is valid. To achieve this,
the functions
[link beast.ref.websocket__stream.handshake `handshake`],
[link beast.ref.websocket__stream.handshake_ex `handshake_ex`] or
[link beast.ref.websocket__stream.async_handshake `async_handshake`],
[link beast.ref.websocket__stream.async_handshake_ex `async_handshake_ex`],
have an additional set of overloads which store the received HTTP message
in the callers parameter, which must be a reference to type
[link beast.ref.websocket__response_type `response_type`], like this:
```
response_type res;
ws.handshake(res, "ws.example.com:80", "/");
// res now contains the complete HTTP response.
```
[endsect]
@@ -310,11 +424,7 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
to perform other operations.
]
[endsect]
[section:frames Frames]
[heading Frames]
Some use-cases make it impractical or impossible to buffer the entire
message ahead of time:
@@ -470,12 +580,12 @@ the fragments:
[section:buffers Buffers]
[section:notes Notes]
Because calls to read data may return a variable amount of bytes, the
interface to calls that read data require an object that meets the requirements
of [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on
[@http://www.boost.org/doc/libs/1_64_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
[@http://www.boost.org/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
The implementation does not perform queueing or buffering of messages. If
desired, these features should be provided by callers. The impact of this
@@ -483,11 +593,7 @@ design is that library users are in full control of the allocation strategy
used to store data and the back-pressure applied on the read and write side
of the underlying TCP/IP connection.
[endsect]
[section:async Asynchronous interface]
[heading Asynchronous Operations]
Asynchronous versions are available for all functions:
```
@@ -513,24 +619,16 @@ void echo(websocket::stream<ip::tcp::socket>& ws,
}
```
[endsect]
[section:io_service The io_service]
[heading The io_service]
The creation and operation of the
[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/io_service.html `boost::asio::io_service`]
[@http://www.boost.org/doc/html/boost_asio/reference/io_service.html `boost::asio::io_service`]
associated with the underlying stream is left to the callers, permitting any
implementation strategy including one that does not require threads for
environments where threads are unavailable. Beast.WebSocket itself does not
environments where threads are unavailable. Beast WebSocket itself does not
use or require threads.
[endsect]
[section:threads Thread Safety]
[heading Thread Safety]
Like a regular asio socket, a [link beast.ref.websocket__stream `stream`] is
not thread safe. Callers are responsible for synchronizing operations on the

View File

@@ -5,6 +5,17 @@ GroupSources(include/beast beast)
GroupSources(examples "/")
add_executable (echo-op
${BEAST_INCLUDES}
echo_op.cpp
)
if (NOT WIN32)
target_link_libraries(echo-op ${Boost_LIBRARIES} Threads::Threads)
else()
target_link_libraries(echo-op ${Boost_LIBRARIES})
endif()
add_executable (http-crawl
${BEAST_INCLUDES}
${EXTRAS_INCLUDES}

View File

@@ -5,6 +5,10 @@
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
exe echo-op :
echo_op.cpp
;
exe http-crawl :
http_crawl.cpp
urls_large_data.cpp

230
examples/echo_op.cpp Normal file
View File

@@ -0,0 +1,230 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <beast/core.hpp>
#include <boost/asio.hpp>
#include <cstddef>
#include <memory>
#include <utility>
// This composed operation reads a line of input and echoes it back.
//
template<class AsyncStream, class Handler>
class echo_op
{
// This holds all of the state information required by the operation.
struct state
{
// The stream to read and write to
AsyncStream& stream;
// Indicates what step in the operation's state machine
// to perform next, starting from zero.
int step = 0;
// The buffer used to hold the input and output data.
// Note that we use a custom allocator for performance,
// this allows the implementation of the io_service to
// make efficient re-use of memory allocated by composed
// operations during continuations.
//
boost::asio::basic_streambuf<beast::handler_alloc<char, Handler>> buffer;
// handler_ptr requires that the first parameter to the
// contained object constructor is a reference to the
// managed final completion handler.
//
explicit state(Handler& handler, AsyncStream& stream_)
: stream(stream_)
, buffer((std::numeric_limits<std::size_t>::max)(),
beast::handler_alloc<char, Handler>{handler})
{
}
};
// This smart pointer container allocates our state using the
// memory allocation hooks associated with the final completion
// handler, manages the lifetime of that handler for us, and
// enforces the destroy-before-invocation requirement on memory
// allocated using the hooks.
//
beast::handler_ptr<state, Handler> p_;
public:
// Boost.Asio requires that handlers are CopyConstructible.
// In some cases, it takes advantage of handlers that are
// MoveConstructible. This operation supports both.
//
echo_op(echo_op&&) = default;
echo_op(echo_op const&) = default;
// The constructor simply creates our state variables in
// the smart pointer container.
//
template<class DeducedHandler, class... Args>
echo_op(AsyncStream& stream, DeducedHandler&& handler)
: p_(std::forward<DeducedHandler>(handler), stream)
{
}
// Determines if the next asynchronous operation represents a
// continuation of the asynchronous flow of control associated
// with the final handler. If we are past step one, it means
// we have performed an asynchronous operation therefore any
// subsequent operation would represent a continuation.
// Otherwise, we propagate the handler's associated value of
// is_continuation. Getting this right means the implementation
// may schedule the invokation of the invoked functions more
// efficiently.
//
friend bool asio_handler_is_continuation(echo_op* op)
{
// This next call is structured to permit argument
// dependent lookup to take effect.
using boost::asio::asio_handler_is_continuation;
// Always use std::addressof to pass the pointer to the handler,
// otherwise an unwanted overload of operator& may be called instead.
return op->p_->step > 1 ||
asio_handler_is_continuation(std::addressof(op->p_.handler()));
}
// Handler hook forwarding. These free functions invoke the hooks
// associated with the final completion handler. In effect, they
// make the Asio implementation treat our composed operation the
// same way it would treat the final completion handler for the
// purpose of memory allocation and invocation.
//
// Our implementation just passes through the call to the hook
// associated with the final handler.
friend void* asio_handler_allocate(std::size_t size, echo_op* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(size, std::addressof(op->p_.handler()));
}
friend void asio_handler_deallocate(void* p, std::size_t size, echo_op* op)
{
using boost::asio::asio_handler_deallocate;
return asio_handler_deallocate(p, size, std::addressof(op->p_.handler()));
}
template<class Function>
friend void asio_handler_invoke(Function&& f, echo_op* op)
{
using boost::asio::asio_handler_invoke;
return asio_handler_invoke(f, std::addressof(op->p_.handler()));
}
// Our main entry point. This will get called as our
// intermediate operations complete. Definition below.
//
void operator()(beast::error_code ec, std::size_t bytes_transferred);
};
// We are callable with the signature void(error_code, bytes_transferred),
// allowing `*this` to be used as both a ReadHandler and a WriteHandler.
//
template<class AsyncStream, class Handler>
void echo_op<AsyncStream, Handler>::
operator()(beast::error_code ec, std::size_t bytes_transferred)
{
// Store a reference to our state. The address of the state won't
// change, and this solves the problem where dereferencing the
// data member is undefined after a move.
auto& p = *p_;
// Now perform the next step in the state machine
switch(ec ? 2 : p.step)
{
// initial entry
case 0:
// read up to the first newline
p.step = 1;
return boost::asio::async_read_until(p.stream, p.buffer, "\n", std::move(*this));
case 1:
// write everything back
p.step = 2;
return boost::asio::async_write(p.stream, p.buffer.data(), std::move(*this));
case 2:
break;
}
// Invoke the final handler. If we wanted to pass any arguments
// which come from our state, they would have to be moved to the
// stack first, since the `handler_ptr` guarantees that the state
// is destroyed before
// the handler is invoked.
//
p_.invoke(ec);
return;
}
// Read a line and echo it back
//
template<class AsyncStream, class CompletionToken>
beast::async_return_type<CompletionToken, void(beast::error_code)>
async_echo(AsyncStream& stream, CompletionToken&& token)
{
// Make sure stream meets the requirements. We use static_assert
// instead of letting the compiler generate several pages of hard
// to read error messages.
//
static_assert(beast::is_async_stream<AsyncStream>::value,
"AsyncStream requirements not met");
// This helper manages some of the handler's lifetime and
// uses the result and handler specializations associated with
// the completion token to help customize the return value.
//
beast::async_completion<CompletionToken, void(beast::error_code)> init{token};
// Create the composed operation and launch it. This is a constructor
// call followed by invocation of operator(). We use BEAST_HANDLER_TYPE
// to convert the completion token into the correct handler type,
// allowing user defined specializations of the async result template
// to take effect.
//
echo_op<AsyncStream, beast::handler_type<CompletionToken, void(beast::error_code)>>{
stream, init.completion_handler}(beast::error_code{}, 0);
// This hook lets the caller see a return value when appropriate.
// For example this might return std::future<error_code> if
// CompletionToken is boost::asio::use_future, or this might
// return an error code if CompletionToken specifies a coroutine.
//
return init.result.get();
}
int main()
{
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
using endpoint_type = boost::asio::ip::tcp::endpoint;
// Create a listening socket, accept a connection, perform
// the echo, and then shut everything down and exit.
boost::asio::io_service ios;
socket_type sock{ios};
{
boost::asio::ip::tcp::acceptor acceptor{ios};
endpoint_type ep{address_type::from_string("0.0.0.0"), 0};
acceptor.open(ep.protocol());
acceptor.bind(ep);
acceptor.listen();
acceptor.accept(sock);
}
async_echo(sock,
[&](beast::error_code ec)
{
});
ios.run();
return 0;
}

View File

@@ -13,14 +13,12 @@
#include <beast/core/async_result.hpp>
#include <beast/core/bind_handler.hpp>
#include <beast/core/buffer_cat.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/buffers_adapter.hpp>
#include <beast/core/consuming_buffers.hpp>
#include <beast/core/buffered_read_stream.hpp>
#include <beast/core/error.hpp>
#include <beast/core/flat_buffer.hpp>
#include <beast/core/handler_alloc.hpp>
#include <beast/core/handler_concepts.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/multi_buffer.hpp>
@@ -28,6 +26,6 @@
#include <beast/core/prepare_buffer.hpp>
#include <beast/core/static_buffer.hpp>
#include <beast/core/static_string.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/type_traits.hpp>
#endif

View File

@@ -9,8 +9,7 @@
#define BEAST_ASYNC_COMPLETION_HPP
#include <beast/config.hpp>
#include <beast/core/handler_concepts.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/handler_type.hpp>
#include <type_traits>
@@ -18,11 +17,11 @@
namespace beast {
/** An interface for customising the behaviour of an initiating function.
/** An interface for customising the behaviour of an asynchronous initiation function.
The async_result class is used for determining:
This class is used for determining:
@li the concrete completion handler type to be called at the end of the
@li The concrete completion handler type to be called at the end of the
asynchronous operation;
@li the initiating function return type; and
@@ -91,12 +90,6 @@ public:
allows customization of the return type of the initiating function, and the
function signature of the final handler.
@tparam CompletionToken A completion handler, or a user defined type
with specializations for customizing the return type (for example,
`boost::asio::use_future` or `boost::asio::yield_context`).
@tparam Signature The callable signature of the final completion handler.
Example:
@code
...
@@ -150,7 +143,7 @@ struct async_completion
, result(completion_handler)
{
// CompletionToken is not invokable with the given signature
static_assert(is_CompletionHandler<
static_assert(is_completion_handler<
completion_handler_type, Signature>::value,
"CompletionToken requirements not met: signature mismatch");
}
@@ -167,37 +160,11 @@ struct async_completion
CompletionToken>::type, Signature> result;
};
/** Convert a completion token to the correct completion handler type.
This helps asynchronous initiation functions to meet the
requirements of the Extensible Asynchronous Model.
@tparam CompletionToken Specifies the model used to obtain the result of
the asynchronous operation.
@tparam Signature The call signature for the completion handler type invoked
on completion of the asynchronous operation.
@see @ref async_completion, @ref async_return_type
*/
template<class CompletionToken, typename Signature>
using handler_type = typename beast::async_result<
typename std::decay<CompletionToken>::type,
Signature>::completion_handler_type;
/** Determine the return value of an asynchronous initiation function
This helps asynchronous initiation functions to meet the
requirements of the Extensible Asynchronous Model.
@tparam CompletionToken Specifies the model used to obtain the result of
the asynchronous operation.
@tparam Signature The call signature for the completion handler type invoked
on completion of the asynchronous operation.
@see @ref async_completion, @ref handler_type
*/
template<class CompletionToken, typename Signature>
using async_return_type = typename beast::async_result<
typename std::decay<CompletionToken>::type,

View File

@@ -9,7 +9,7 @@
#define BEAST_BIND_HANDLER_HPP
#include <beast/config.hpp>
#include <beast/core/handler_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <beast/core/detail/bind_handler.hpp>
#include <type_traits>
#include <utility>
@@ -24,24 +24,23 @@ namespace beast {
the returned handler, which provides the same `io_service`
execution guarantees as the original handler.
Unlike `io_service::wrap`, the returned handler can be used in
a subsequent call to `io_service::post` instead of
`io_service::dispatch`, to ensure that the handler will not be
invoked immediately by the calling function.
Unlike `boost::asio::io_service::wrap`, the returned handler can
be used in a subsequent call to `boost::asio::io_service::post`
instead of `boost::asio::io_service::dispatch`, to ensure that
the handler will not be invoked immediately by the calling
function.
Example:
@code
template<class AsyncReadStream, class ReadHandler>
void
do_cancel(AsyncReadStream& stream, ReadHandler&& handler)
signal_aborted(AsyncReadStream& stream, ReadHandler&& handler)
{
stream.get_io_service().post(
bind_handler(std::forward<ReadHandler>(handler),
boost::asio::error::operation_aborted, 0));
}
@endcode
@param handler The handler to wrap.
@@ -58,7 +57,7 @@ detail::bound_handler<
#endif
bind_handler(Handler&& handler, Args&&... args)
{
static_assert(is_CompletionHandler<
static_assert(is_completion_handler<
Handler, void(Args...)>::value,
"Handler requirements not met");
return detail::bound_handler<typename std::decay<

View File

@@ -34,8 +34,8 @@ namespace beast {
@return A new buffer sequence that represents the concatenation of
the input buffer sequences. This buffer sequence will be a
@b MutableBufferSequence if each of the passed buffer sequences is
also a @b MutableBufferSequence, else the returned buffer sequence
will be a @b ConstBufferSequence.
also a @b MutableBufferSequence; otherwise the returned buffer
sequence will be a @b ConstBufferSequence.
*/
#if BEAST_DOXYGEN
template<class... BufferSequence>

View File

@@ -1,55 +0,0 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_BUFFER_CONCEPTS_HPP
#define BEAST_BUFFER_CONCEPTS_HPP
#include <beast/config.hpp>
#include <beast/core/detail/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
#include <type_traits>
namespace beast {
/// Determine if `T` meets the requirements of @b ConstBufferSequence.
template<class T>
#if BEAST_DOXYGEN
struct is_const_buffer_sequence : std::integral_constant<bool, ...>
#else
struct is_const_buffer_sequence :
detail::is_buffer_sequence<T,
boost::asio::const_buffer>::type
#endif
{
};
/// Determine if `T` meets the requirements of @b DynamicBuffer.
template<class T>
#if BEAST_DOXYGEN
struct is_dynamic_buffer : std::integral_constant<bool, ...>
#else
struct is_dynamic_buffer :
detail::is_dynamic_buffer<T>::type
#endif
{
};
/// Determine if `T` meets the requirements of @b MutableBufferSequence.
template<class T>
#if BEAST_DOXYGEN
struct is_mutable_buffer_sequence : std::integral_constant<bool, ...>
#else
struct is_mutable_buffer_sequence :
detail::is_buffer_sequence<T,
boost::asio::mutable_buffer>::type
#endif
{
};
} // beast
#endif

View File

@@ -10,11 +10,9 @@
#include <beast/config.hpp>
#include <beast/core/async_result.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/error.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/multi_buffer.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_service.hpp>
#include <cstdint>
@@ -26,7 +24,7 @@ namespace beast {
This wraps a @b Stream implementation so that calls to write are
passed through to the underlying stream, while calls to read will
first consume the input sequence stored in a @b `DynamicBuffer` which
first consume the input sequence stored in a @b DynamicBuffer which
is part of the object.
The use-case for this class is different than that of the
@@ -292,7 +290,7 @@ public:
std::size_t
write_some(ConstBufferSequence const& buffers)
{
static_assert(is_SyncWriteStream<next_layer_type>::value,
static_assert(is_sync_write_stream<next_layer_type>::value,
"SyncWriteStream requirements not met");
return next_layer_.write_some(buffers);
}
@@ -314,7 +312,7 @@ public:
write_some(ConstBufferSequence const& buffers,
error_code& ec)
{
static_assert(is_SyncWriteStream<next_layer_type>::value,
static_assert(is_sync_write_stream<next_layer_type>::value,
"SyncWriteStream requirements not met");
return next_layer_.write_some(buffers, ec);
}

View File

@@ -9,16 +9,16 @@
#define BEAST_BUFFERS_ADAPTER_HPP
#include <beast/config.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <type_traits>
namespace beast {
/** Adapts a @b `MutableBufferSequence` into a @b `DynamicBuffer`.
/** Adapts a @b MutableBufferSequence into a @b DynamicBuffer.
This class wraps a @b `MutableBufferSequence` to meet the requirements
of @b `DynamicBuffer`. Upon construction the input and output sequences are
This class wraps a @b MutableBufferSequence to meet the requirements
of @b DynamicBuffer. Upon construction the input and output sequences are
empty. A copy of the mutable buffer sequence object is stored; however,
ownership of the underlying memory is not transferred. The caller is
responsible for making sure that referenced memory remains valid

View File

@@ -8,8 +8,7 @@
#ifndef BEAST_DETAIL_BUFFER_CAT_HPP
#define BEAST_DETAIL_BUFFER_CAT_HPP
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <cstdint>
#include <iterator>

View File

@@ -1,180 +0,0 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_DETAIL_BUFFER_CONCEPTS_HPP
#define BEAST_DETAIL_BUFFER_CONCEPTS_HPP
#include <boost/asio/buffer.hpp>
#include <iterator>
#include <type_traits>
namespace beast {
namespace detail {
// Types that meet the requirements,
// for use with std::declval only.
template<class BufferType>
struct BufferSequence
{
using value_type = BufferType;
using const_iterator = BufferType const*;
~BufferSequence();
BufferSequence(BufferSequence const&) = default;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
};
using ConstBufferSequence =
BufferSequence<boost::asio::const_buffer>;
using MutableBufferSequence =
BufferSequence<boost::asio::mutable_buffer>;
template<class T, class BufferType>
class is_buffer_sequence
{
template<class U, class R = std::is_convertible<
typename U::value_type, BufferType> >
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_base_of<
#if 0
std::bidirectional_iterator_tag,
typename std::iterator_traits<
typename U::const_iterator>::iterator_category>>
#else
// workaround:
// boost::asio::detail::consuming_buffers::const_iterator
// is not bidirectional
std::forward_iterator_tag,
typename std::iterator_traits<
typename U::const_iterator>::iterator_category>>
#endif
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
template<class U, class R = typename
std::is_convertible<decltype(
std::declval<U>().begin()),
typename U::const_iterator>::type>
static R check3(int);
template<class>
static std::false_type check3(...);
using type3 = decltype(check3<T>(0));
template<class U, class R = typename std::is_convertible<decltype(
std::declval<U>().end()),
typename U::const_iterator>::type>
static R check4(int);
template<class>
static std::false_type check4(...);
using type4 = decltype(check4<T>(0));
public:
using type = std::integral_constant<bool,
std::is_copy_constructible<T>::value &&
std::is_destructible<T>::value &&
type1::value && type2::value &&
type3::value && type4::value>;
};
template<class B1, class... Bn>
struct is_all_ConstBufferSequence
: std::integral_constant<bool,
is_buffer_sequence<B1, boost::asio::const_buffer>::type::value &&
is_all_ConstBufferSequence<Bn...>::value>
{
};
template<class B1>
struct is_all_ConstBufferSequence<B1>
: is_buffer_sequence<B1, boost::asio::const_buffer>::type
{
};
template<class T>
class is_dynamic_buffer
{
// size()
template<class U, class R = std::is_convertible<decltype(
std::declval<U const>().size()), std::size_t>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
// max_size()
template<class U, class R = std::is_convertible<decltype(
std::declval<U const>().max_size()), std::size_t>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
// capacity()
template<class U, class R = std::is_convertible<decltype(
std::declval<U const>().capacity()), std::size_t>>
static R check3(int);
template<class>
static std::false_type check3(...);
using type3 = decltype(check3<T>(0));
// data()
template<class U, class R = std::integral_constant<
bool, is_buffer_sequence<decltype(
std::declval<U const>().data()),
boost::asio::const_buffer>::type::value>>
static R check4(int);
template<class>
static std::false_type check4(...);
using type4 = decltype(check4<T>(0));
// prepare()
template<class U, class R = std::integral_constant<
bool, is_buffer_sequence<decltype(
std::declval<U>().prepare(1)),
boost::asio::mutable_buffer>::type::value>>
static R check5(int);
template<class>
static std::false_type check5(...);
using type5 = decltype(check5<T>(0));
// commit()
template<class U, class R = decltype(
std::declval<U>().commit(1), std::true_type{})>
static R check6(int);
template<class>
static std::false_type check6(...);
using type6 = decltype(check6<T>(0));
// consume
template<class U, class R = decltype(
std::declval<U>().consume(1), std::true_type{})>
static R check7(int);
template<class>
static std::false_type check7(...);
using type7 = decltype(check7<T>(0));
public:
using type = std::integral_constant<bool,
type1::value
&& type2::value
//&& type3::value // Networking TS
&& type4::value
&& type5::value
&& type6::value
&& type7::value
>;
};
} // detail
} // beast
#endif

View File

@@ -1,134 +0,0 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_DETAIL_STREAM_CONCEPTS_HPP
#define BEAST_DETAIL_STREAM_CONCEPTS_HPP
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/error.hpp>
#include <boost/asio/io_service.hpp>
#include <type_traits>
#include <utility>
namespace beast {
namespace detail {
// Types that meet the requirements,
// for use with std::declval only.
struct StreamHandler
{
StreamHandler(StreamHandler const&) = default;
void operator()(error_code ec, std::size_t);
};
using ReadHandler = StreamHandler;
using WriteHandler = StreamHandler;
template<class T>
class has_get_io_service
{
template<class U, class R = typename std::is_same<
decltype(std::declval<U>().get_io_service()),
boost::asio::io_service&>>
static R check(int);
template<class>
static std::false_type check(...);
public:
using type = decltype(check<T>(0));
};
template<class T>
class is_AsyncReadStream
{
template<class U, class R = decltype(
std::declval<U>().async_read_some(
std::declval<MutableBufferSequence>(),
std::declval<ReadHandler>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type1 = decltype(check<T>(0));
public:
using type = std::integral_constant<bool,
type1::value &&
has_get_io_service<T>::type::value>;
};
template<class T>
class is_AsyncWriteStream
{
template<class U, class R = decltype(
std::declval<U>().async_write_some(
std::declval<ConstBufferSequence>(),
std::declval<WriteHandler>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type1 = decltype(check<T>(0));
public:
using type = std::integral_constant<bool,
type1::value &&
has_get_io_service<T>::type::value>;
};
template<class T>
class is_SyncReadStream
{
template<class U, class R = std::is_same<decltype(
std::declval<U>().read_some(
std::declval<MutableBufferSequence>())),
std::size_t>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_same<decltype(
std::declval<U>().read_some(
std::declval<MutableBufferSequence>(),
std::declval<error_code&>())), std::size_t>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
public:
using type = std::integral_constant<bool,
type1::value && type2::value>;
};
template<class T>
class is_SyncWriteStream
{
template<class U, class R = std::is_same<decltype(
std::declval<U>().write_some(
std::declval<ConstBufferSequence>())),
std::size_t>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_same<decltype(
std::declval<U>().write_some(
std::declval<ConstBufferSequence>(),
std::declval<error_code&>())), std::size_t>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
public:
using type = std::integral_constant<bool,
type1::value && type2::value>;
};
} // detail
} // beast
#endif

View File

@@ -8,8 +8,8 @@
#ifndef BEAST_DETAIL_SYNC_OSTREAM_HPP
#define BEAST_DETAIL_SYNC_OSTREAM_HPP
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/error.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <ostream>

View File

@@ -8,6 +8,10 @@
#ifndef BEAST_DETAIL_TYPE_TRAITS_HPP
#define BEAST_DETAIL_TYPE_TRAITS_HPP
#include <beast/core/error.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_service.hpp>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <stdexcept>
@@ -16,6 +20,10 @@
namespace beast {
namespace detail {
//
// utilities
//
template<class... Ts>
struct make_void
{
@@ -160,6 +168,288 @@ struct get_lowest_layer
has_lowest_layer<T>::value>::type;
};
//------------------------------------------------------------------------------
//
// buffer concepts
//
// Types that meet the requirements,
// for use with std::declval only.
template<class BufferType>
struct BufferSequence
{
using value_type = BufferType;
using const_iterator = BufferType const*;
~BufferSequence();
BufferSequence(BufferSequence const&) = default;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
};
using ConstBufferSequence =
BufferSequence<boost::asio::const_buffer>;
using MutableBufferSequence =
BufferSequence<boost::asio::mutable_buffer>;
template<class T, class BufferType>
class is_buffer_sequence
{
template<class U, class R = std::is_convertible<
typename U::value_type, BufferType> >
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_base_of<
#if 0
std::bidirectional_iterator_tag,
typename std::iterator_traits<
typename U::const_iterator>::iterator_category>>
#else
// workaround:
// boost::asio::detail::consuming_buffers::const_iterator
// is not bidirectional
std::forward_iterator_tag,
typename std::iterator_traits<
typename U::const_iterator>::iterator_category>>
#endif
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
template<class U, class R = typename
std::is_convertible<decltype(
std::declval<U>().begin()),
typename U::const_iterator>::type>
static R check3(int);
template<class>
static std::false_type check3(...);
using type3 = decltype(check3<T>(0));
template<class U, class R = typename std::is_convertible<decltype(
std::declval<U>().end()),
typename U::const_iterator>::type>
static R check4(int);
template<class>
static std::false_type check4(...);
using type4 = decltype(check4<T>(0));
public:
using type = std::integral_constant<bool,
std::is_copy_constructible<T>::value &&
std::is_destructible<T>::value &&
type1::value && type2::value &&
type3::value && type4::value>;
};
template<class B1, class... Bn>
struct is_all_ConstBufferSequence
: std::integral_constant<bool,
is_buffer_sequence<B1, boost::asio::const_buffer>::type::value &&
is_all_ConstBufferSequence<Bn...>::value>
{
};
template<class B1>
struct is_all_ConstBufferSequence<B1>
: is_buffer_sequence<B1, boost::asio::const_buffer>::type
{
};
template<class T>
class is_dynamic_buffer
{
// size()
template<class U, class R = std::is_convertible<decltype(
std::declval<U const>().size()), std::size_t>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
// max_size()
template<class U, class R = std::is_convertible<decltype(
std::declval<U const>().max_size()), std::size_t>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
// capacity()
template<class U, class R = std::is_convertible<decltype(
std::declval<U const>().capacity()), std::size_t>>
static R check3(int);
template<class>
static std::false_type check3(...);
using type3 = decltype(check3<T>(0));
// data()
template<class U, class R = std::integral_constant<
bool, is_buffer_sequence<decltype(
std::declval<U const>().data()),
boost::asio::const_buffer>::type::value>>
static R check4(int);
template<class>
static std::false_type check4(...);
using type4 = decltype(check4<T>(0));
// prepare()
template<class U, class R = std::integral_constant<
bool, is_buffer_sequence<decltype(
std::declval<U>().prepare(1)),
boost::asio::mutable_buffer>::type::value>>
static R check5(int);
template<class>
static std::false_type check5(...);
using type5 = decltype(check5<T>(0));
// commit()
template<class U, class R = decltype(
std::declval<U>().commit(1), std::true_type{})>
static R check6(int);
template<class>
static std::false_type check6(...);
using type6 = decltype(check6<T>(0));
// consume
template<class U, class R = decltype(
std::declval<U>().consume(1), std::true_type{})>
static R check7(int);
template<class>
static std::false_type check7(...);
using type7 = decltype(check7<T>(0));
public:
using type = std::integral_constant<bool,
type1::value
&& type2::value
//&& type3::value // Networking TS
&& type4::value
&& type5::value
&& type6::value
&& type7::value
>;
};
//------------------------------------------------------------------------------
//
// stream concepts
//
// Types that meet the requirements,
// for use with std::declval only.
struct StreamHandler
{
StreamHandler(StreamHandler const&) = default;
void operator()(error_code ec, std::size_t);
};
using ReadHandler = StreamHandler;
using WriteHandler = StreamHandler;
template<class T>
class has_get_io_service
{
template<class U, class R = typename std::is_same<
decltype(std::declval<U>().get_io_service()),
boost::asio::io_service&>>
static R check(int);
template<class>
static std::false_type check(...);
public:
using type = decltype(check<T>(0));
};
template<class T>
class is_async_read_stream
{
template<class U, class R = decltype(
std::declval<U>().async_read_some(
std::declval<MutableBufferSequence>(),
std::declval<ReadHandler>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type1 = decltype(check<T>(0));
public:
using type = std::integral_constant<bool,
type1::value &&
has_get_io_service<T>::type::value>;
};
template<class T>
class is_async_write_stream
{
template<class U, class R = decltype(
std::declval<U>().async_write_some(
std::declval<ConstBufferSequence>(),
std::declval<WriteHandler>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type1 = decltype(check<T>(0));
public:
using type = std::integral_constant<bool,
type1::value &&
has_get_io_service<T>::type::value>;
};
template<class T>
class is_sync_read_stream
{
template<class U, class R = std::is_same<decltype(
std::declval<U>().read_some(
std::declval<MutableBufferSequence>())),
std::size_t>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_same<decltype(
std::declval<U>().read_some(
std::declval<MutableBufferSequence>(),
std::declval<error_code&>())), std::size_t>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
public:
using type = std::integral_constant<bool,
type1::value && type2::value>;
};
template<class T>
class is_sync_write_stream
{
template<class U, class R = std::is_same<decltype(
std::declval<U>().write_some(
std::declval<ConstBufferSequence>())),
std::size_t>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_same<decltype(
std::declval<U>().write_some(
std::declval<ConstBufferSequence>(),
std::declval<error_code&>())), std::size_t>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
public:
using type = std::integral_constant<bool,
type1::value && type2::value>;
};
} // detail
} // beast

View File

@@ -1,28 +0,0 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HANDLER_CONCEPTS_HPP
#define BEAST_HANDLER_CONCEPTS_HPP
#include <beast/config.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <type_traits>
namespace beast {
/// Determine if `T` meets the requirements of @b `CompletionHandler`.
template<class T, class Signature>
#if BEAST_DOXYGEN
using is_CompletionHandler = std::integral_constant<bool, ...>;
#else
using is_CompletionHandler = std::integral_constant<bool,
std::is_copy_constructible<typename std::decay<T>::type>::value &&
detail::is_invocable<T, Signature>::value>;
#endif
} // beast
#endif

View File

@@ -191,6 +191,11 @@ public:
deallocation-before-invocation Asio guarantee. All
instances of @ref handler_ptr which refer to the
same owned object will be reset, including this instance.
@note Care must be taken when the arguments are themselves
stored in the owned object. Such arguments must first be
moved to the stack or elsewhere, and then passed, or else
undefined behavior will result.
*/
template<class... Args>
void

View File

@@ -10,9 +10,9 @@
#include <beast/core/bind_handler.hpp>
#include <beast/core/error.hpp>
#include <beast/core/handler_concepts.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/type_traits.hpp>
namespace beast {
@@ -164,12 +164,12 @@ async_write_some(ConstBufferSequence const& buffers,
WriteHandler&& handler) ->
async_return_type<WriteHandler, void(error_code)>
{
static_assert(is_AsyncWriteStream<next_layer_type>::value,
static_assert(is_async_write_stream<next_layer_type>::value,
"AsyncWriteStream requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
static_assert(is_CompletionHandler<WriteHandler,
static_assert(is_completion_handler<WriteHandler,
void(error_code, std::size_t)>::value,
"WriteHandler requirements not met");
return next_layer_.async_write_some(buffers,
@@ -183,7 +183,7 @@ buffered_read_stream<Stream, DynamicBuffer>::
read_some(
MutableBufferSequence const& buffers)
{
static_assert(is_SyncReadStream<next_layer_type>::value,
static_assert(is_sync_read_stream<next_layer_type>::value,
"SyncReadStream requirements not met");
static_assert(is_mutable_buffer_sequence<
MutableBufferSequence>::value,
@@ -202,7 +202,7 @@ buffered_read_stream<Stream, DynamicBuffer>::
read_some(MutableBufferSequence const& buffers,
error_code& ec)
{
static_assert(is_SyncReadStream<next_layer_type>::value,
static_assert(is_sync_read_stream<next_layer_type>::value,
"SyncReadStream requirements not met");
static_assert(is_mutable_buffer_sequence<
MutableBufferSequence>::value,
@@ -232,7 +232,7 @@ async_read_some(MutableBufferSequence const& buffers,
ReadHandler&& handler) ->
async_return_type<ReadHandler, void(error_code)>
{
static_assert(is_AsyncReadStream<next_layer_type>::value,
static_assert(is_async_read_stream<next_layer_type>::value,
"Stream requirements not met");
static_assert(is_mutable_buffer_sequence<
MutableBufferSequence>::value,

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_IMPL_CONSUMING_BUFFERS_IPP
#define BEAST_IMPL_CONSUMING_BUFFERS_IPP
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <algorithm>
#include <cstdint>
#include <iterator>

View File

@@ -19,7 +19,7 @@
namespace beast {
/** A @b `DynamicBuffer` that uses multiple buffers internally.
/** A @b DynamicBuffer that uses multiple buffers internally.
The implementation uses a sequence of one or more character arrays
of varying sizes. Additional character array objects are appended to
@@ -315,15 +315,7 @@ private:
debug_check() const;
};
/** A @b `DynamicBuffer` that uses multiple buffers internally.
The implementation uses a sequence of one or more character arrays
of varying sizes. Additional character array objects are appended to
the sequence to accommodate changes in the size of the character
sequence.
@note Meets the requirements of @b `DynamicBuffer`.
*/
/// A typical multi buffer
using multi_buffer = basic_multi_buffer<std::allocator<char>>;
} // beast

View File

@@ -9,7 +9,7 @@
#define BEAST_WRITE_OSTREAM_HPP
#include <beast/config.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <beast/core/detail/ostream.hpp>
#include <type_traits>
#include <streambuf>
@@ -35,6 +35,8 @@ namespace beast {
@param b An object meeting the requirements of @b ConstBufferSequence
to be streamed. The implementation will make a copy of this object.
Ownership of the underlying memory is not transferred, the application
is still responsible for managing its lifetime.
*/
template<class ConstBufferSequence>
#if BEAST_DOXYGEN
@@ -68,11 +70,12 @@ buffers(ConstBufferSequence const& b)
@param buffer An object meeting the requirements of @b DynamicBuffer
into which the formatted output will be placed.
@return An object derived from `std::ostream` which directs output
into the specified dynamic buffer. Ownership of the dynamic buffer
is not transferred. The caller is responsible for ensuring the
dynamic buffer is not destroyed for the lifetime of the output
stream.
@return An object derived from `std::ostream` which redirects output
The wrapped dynamic buffer is not modified, a copy is made instead.
Ownership of the underlying memory is not transferred, the application
is still responsible for managing its lifetime. The caller is
responsible for ensuring the dynamic buffer is not destroyed for the
lifetime of the output stream.
*/
template<class DynamicBuffer>
#if BEAST_DOXYGEN

View File

@@ -25,6 +25,11 @@ namespace beast {
of template functions receiving static stream buffer arguments in a
deduced context, the signature of the receiving function should use
@ref static_buffer.
When used with @ref static_buffer_n this implements a dynamic
buffer using no memory allocations.
@see @ref static_buffer_n
*/
class static_buffer
{
@@ -141,11 +146,15 @@ protected:
/** A @b DynamicBuffer with a fixed size internal buffer.
This implements a dynamic buffer using no memory allocations.
@tparam N The number of bytes in the internal buffer.
@note To reduce the number of template instantiations when passing
objects of this type in a deduced context, the signature of the
receiving function should use `static_buffer` instead.
receiving function should use @ref static_buffer instead.
@see @ref static_buffer
*/
template<std::size_t N>
class static_buffer_n
@@ -179,9 +188,10 @@ public:
/** Reset the static buffer.
Postconditions:
The input sequence and output sequence are empty,
`max_size()` returns `N`.
@par Effects
The input sequence and output sequence are empty,
@ref max_size returns `N`.
*/
void
reset()

View File

@@ -1,77 +0,0 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_STREAM_CONCEPTS_HPP
#define BEAST_STREAM_CONCEPTS_HPP
#include <beast/config.hpp>
#include <beast/core/detail/stream_concepts.hpp>
#include <type_traits>
namespace beast {
/// Determine if `T` has the `get_io_service` member.
template<class T>
#if BEAST_DOXYGEN
struct has_get_io_service : std::integral_constant<bool, ...>{};
#else
using has_get_io_service = typename detail::has_get_io_service<T>::type;
#endif
/// Determine if `T` meets the requirements of @b `AsyncReadStream`.
template<class T>
#if BEAST_DOXYGEN
struct is_AsyncReadStream : std::integral_constant<bool, ...>{};
#else
using is_AsyncReadStream = typename detail::is_AsyncReadStream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b `AsyncWriteStream`.
template<class T>
#if BEAST_DOXYGEN
struct is_AsyncWriteStream : std::integral_constant<bool, ...>{};
#else
using is_AsyncWriteStream = typename detail::is_AsyncWriteStream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b `SyncReadStream`.
template<class T>
#if BEAST_DOXYGEN
struct is_SyncReadStream : std::integral_constant<bool, ...>{};
#else
using is_SyncReadStream = typename detail::is_SyncReadStream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b `SyncWriterStream`.
template<class T>
#if BEAST_DOXYGEN
struct is_SyncWriteStream : std::integral_constant<bool, ...>{};
#else
using is_SyncWriteStream = typename detail::is_SyncWriteStream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b `AsyncStream`.
template<class T>
#if BEAST_DOXYGEN
struct is_AsyncStream : std::integral_constant<bool, ...>{};
#else
using is_AsyncStream = std::integral_constant<bool,
is_AsyncReadStream<T>::value && is_AsyncWriteStream<T>::value>;
#endif
/// Determine if `T` meets the requirements of @b `SyncStream`.
template<class T>
#if BEAST_DOXYGEN
struct is_SyncStream : std::integral_constant<bool, ...>{};
#else
using is_SyncStream = std::integral_constant<bool,
is_SyncReadStream<T>::value && is_SyncWriteStream<T>::value>;
#endif
} // beast
#endif

View File

@@ -0,0 +1,123 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_TYPE_TRAITS_HPP
#define BEAST_TYPE_TRAITS_HPP
#include <beast/config.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <type_traits>
namespace beast {
/// Determine if `T` meets the requirements of @b ConstBufferSequence.
template<class T>
#if BEAST_DOXYGEN
struct is_const_buffer_sequence : std::integral_constant<bool, ...>
#else
struct is_const_buffer_sequence :
detail::is_buffer_sequence<T,
boost::asio::const_buffer>::type
#endif
{
};
/// Determine if `T` meets the requirements of @b DynamicBuffer.
template<class T>
#if BEAST_DOXYGEN
struct is_dynamic_buffer : std::integral_constant<bool, ...>
#else
struct is_dynamic_buffer :
detail::is_dynamic_buffer<T>::type
#endif
{
};
/// Determine if `T` meets the requirements of @b MutableBufferSequence.
template<class T>
#if BEAST_DOXYGEN
struct is_mutable_buffer_sequence : std::integral_constant<bool, ...>
#else
struct is_mutable_buffer_sequence :
detail::is_buffer_sequence<T,
boost::asio::mutable_buffer>::type
#endif
{
};
/// Determine if `T` has the `get_io_service` member.
template<class T>
#if BEAST_DOXYGEN
struct has_get_io_service : std::integral_constant<bool, ...>{};
#else
using has_get_io_service = typename detail::has_get_io_service<T>::type;
#endif
/// Determine if `T` meets the requirements of @b AsyncReadStream.
template<class T>
#if BEAST_DOXYGEN
struct is_async_read_stream : std::integral_constant<bool, ...>{};
#else
using is_async_read_stream = typename detail::is_async_read_stream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b AsyncWriteStream.
template<class T>
#if BEAST_DOXYGEN
struct is_async_write_stream : std::integral_constant<bool, ...>{};
#else
using is_async_write_stream = typename detail::is_async_write_stream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b SyncReadStream.
template<class T>
#if BEAST_DOXYGEN
struct is_sync_read_stream : std::integral_constant<bool, ...>{};
#else
using is_sync_read_stream = typename detail::is_sync_read_stream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b SyncWriterStream.
template<class T>
#if BEAST_DOXYGEN
struct is_sync_write_stream : std::integral_constant<bool, ...>{};
#else
using is_sync_write_stream = typename detail::is_sync_write_stream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b AsyncStream.
template<class T>
#if BEAST_DOXYGEN
struct is_async_stream : std::integral_constant<bool, ...>{};
#else
using is_async_stream = std::integral_constant<bool,
is_async_read_stream<T>::value && is_async_write_stream<T>::value>;
#endif
/// Determine if `T` meets the requirements of @b SyncStream.
template<class T>
#if BEAST_DOXYGEN
struct is_sync_stream : std::integral_constant<bool, ...>{};
#else
using is_sync_stream = std::integral_constant<bool,
is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
#endif
/// Determine if `T` meets the requirements of @b CompletionHandler.
template<class T, class Signature>
#if BEAST_DOXYGEN
using is_completion_handler = std::integral_constant<bool, ...>;
#else
using is_completion_handler = std::integral_constant<bool,
std::is_copy_constructible<typename std::decay<T>::type>::value &&
detail::is_invocable<T, Signature>::value>;
#endif
} // beast
#endif

View File

@@ -10,8 +10,7 @@
#include <beast/config.hpp>
#include <beast/core/error.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/optional.hpp>
#include <type_traits>

View File

@@ -16,9 +16,9 @@
namespace beast {
namespace http {
/** A message body represented by a @b `DynamicBuffer`
/** A message body represented by a @b DynamicBuffer
Meets the requirements of @b `Body`.
Meets the requirements of @b Body.
*/
template<class DynamicBuffer>
struct basic_dynamic_body
@@ -113,7 +113,7 @@ private:
/** A dynamic message body represented by a @ref multi_buffer
Meets the requirements of @b `Body`.
Meets the requirements of @b Body.
*/
using dynamic_body = basic_dynamic_body<multi_buffer>;

View File

@@ -15,7 +15,7 @@
#include <beast/core/bind_handler.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/assert.hpp>
#include <boost/optional.hpp>
@@ -645,7 +645,7 @@ async_read_some(
basic_parser<isRequest, isDirect, Derived>& parser,
ReadHandler&& handler)
{
static_assert(is_AsyncReadStream<AsyncReadStream>::value,
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -667,7 +667,7 @@ async_read(
basic_parser<isRequest, isDirect, Derived>& parser,
ReadHandler&& handler)
{
static_assert(is_AsyncReadStream<AsyncReadStream>::value,
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -694,7 +694,7 @@ async_read(
message<isRequest, Body, Fields>& msg,
ReadHandler&& handler)
{
static_assert(is_AsyncReadStream<AsyncReadStream>::value,
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");

View File

@@ -8,10 +8,9 @@
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_IPP
#define BEAST_HTTP_IMPL_BASIC_PARSER_IPP
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <beast/core/detail/ci_char_traits.hpp>
#include <beast/core/detail/clamp.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <beast/http/error.hpp>
#include <beast/http/rfc7230.hpp>
#include <boost/asio/buffer.hpp>

View File

@@ -15,7 +15,7 @@
#include <beast/core/bind_handler.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/assert.hpp>
#include <boost/optional.hpp>
@@ -192,7 +192,7 @@ read_some(
DynamicBuffer& dynabuf,
basic_parser<isRequest, isDirect, Derived>& parser)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -216,7 +216,7 @@ read_some(
basic_parser<isRequest, isDirect, Derived>& parser,
error_code& ec)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -234,7 +234,7 @@ read(
DynamicBuffer& dynabuf,
basic_parser<isRequest, isDirect, Derived>& parser)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -256,7 +256,7 @@ read(
basic_parser<isRequest, isDirect, Derived>& parser,
error_code& ec)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -282,7 +282,7 @@ read(
DynamicBuffer& dynabuf,
message<isRequest, Body, Fields>& msg)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -310,7 +310,7 @@ read(
message<isRequest, Body, Fields>& msg,
error_code& ec)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");

View File

@@ -12,12 +12,11 @@
#include <beast/http/chunk_encode.hpp>
#include <beast/core/buffer_cat.hpp>
#include <beast/core/bind_handler.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/ostream.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/multi_buffer.hpp>
#include <beast/core/type_traits.hpp>
#include <beast/core/detail/sync_ostream.hpp>
#include <boost/asio/write.hpp>
#include <condition_variable>
@@ -183,7 +182,7 @@ void
write(SyncWriteStream& stream,
header<isRequest, Fields> const& msg)
{
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
static_assert(is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
error_code ec;
write(stream, msg, ec);
@@ -198,7 +197,7 @@ write(SyncWriteStream& stream,
header<isRequest, Fields> const& msg,
error_code& ec)
{
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
static_assert(is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
multi_buffer b;
{
@@ -219,7 +218,7 @@ async_write(AsyncWriteStream& stream,
header<isRequest, Fields> const& msg,
WriteHandler&& handler)
{
static_assert(is_AsyncWriteStream<AsyncWriteStream>::value,
static_assert(is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met");
async_completion<WriteHandler,
void(error_code)> init{handler};
@@ -565,7 +564,7 @@ void
write(SyncWriteStream& stream,
message<isRequest, Body, Fields> const& msg)
{
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
static_assert(is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
static_assert(is_Body<Body>::value,
"Body requirements not met");
@@ -587,7 +586,7 @@ write(SyncWriteStream& stream,
message<isRequest, Body, Fields> const& msg,
error_code& ec)
{
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
static_assert(is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
static_assert(is_Body<Body>::value,
"Body requirements not met");
@@ -647,7 +646,7 @@ async_write(AsyncWriteStream& stream,
message<isRequest, Body, Fields> const& msg,
WriteHandler&& handler)
{
static_assert(is_AsyncWriteStream<AsyncWriteStream>::value,
static_assert(is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met");
static_assert(is_Body<Body>::value,
"Body requirements not met");

View File

@@ -374,9 +374,9 @@ async_read(
@ref error::end_of_stream is indicated.
@param stream The stream from which the data is to be read.
The type must support the @b `SyncReadStream` concept.
The type must support the @b SyncReadStream concept.
@param dynabuf A @b `DynamicBuffer` holding additional bytes
@param dynabuf A @b DynamicBuffer holding additional bytes
read by the implementation from the stream. This is both
an input and an output parameter; on entry, any data in the
dynamic buffer's input sequence will be given to the parser
@@ -420,9 +420,9 @@ read(
@ref error::end_of_stream is indicated.
@param stream The stream from which the data is to be read.
The type must support the @b `SyncReadStream` concept.
The type must support the @b SyncReadStream concept.
@param dynabuf A @b `DynamicBuffer` holding additional bytes
@param dynabuf A @b DynamicBuffer holding additional bytes
read by the implementation from the stream. This is both
an input and an output parameter; on entry, any data in the
dynamic buffer's input sequence will be given to the parser
@@ -470,9 +470,9 @@ read(
@ref error::end_of_stream is indicated.
@param stream The stream to read the message from.
The type must support the @b `AsyncReadStream` concept.
The type must support the @b AsyncReadStream concept.
@param dynabuf A @b `DynamicBuffer` holding additional bytes
@param dynabuf A @b DynamicBuffer holding additional bytes
read by the implementation from the stream. This is both
an input and an output parameter; on entry, any data in the
dynamic buffer's input sequence will be given to the parser

View File

@@ -21,7 +21,7 @@ namespace http {
/** A Body represented by a std::string.
Meets the requirements of @b `Body`.
Meets the requirements of @b Body.
*/
struct string_body
{

View File

@@ -36,7 +36,7 @@ namespace http {
this function will not return `boost::asio::error::eof`.
@param stream The stream to which the data is to be written.
The type must support the @b `SyncWriteStream` concept.
The type must support the @b SyncWriteStream concept.
@param msg The header to write.
@@ -66,7 +66,7 @@ write(SyncWriteStream& stream,
this function will not return `boost::asio::error::eof`.
@param stream The stream to which the data is to be written.
The type must support the @b `SyncWriteStream` concept.
The type must support the @b SyncWriteStream concept.
@param msg The header to write.
@@ -101,7 +101,7 @@ write(SyncWriteStream& stream,
this function will not return `boost::asio::error::eof`.
@param stream The stream to which the data is to be written.
The type must support the @b `AsyncWriteStream` concept.
The type must support the @b AsyncWriteStream concept.
@param msg The header to write. The object must remain valid
at least until the completion handler is called; ownership is
@@ -148,7 +148,7 @@ async_write(AsyncWriteStream& stream,
function will be `boost::asio::error::eof`.
@param stream The stream to which the data is to be written.
The type must support the @b `SyncWriteStream` concept.
The type must support the @b SyncWriteStream concept.
@param msg The message to write.
@@ -179,7 +179,7 @@ write(SyncWriteStream& stream,
function will be `boost::asio::error::eof`.
@param stream The stream to which the data is to be written.
The type must support the @b `SyncWriteStream` concept.
The type must support the @b SyncWriteStream concept.
@param msg The message to write.
@@ -216,7 +216,7 @@ write(SyncWriteStream& stream,
the error set to `boost::asio::error::eof`.
@param stream The stream to which the data is to be written.
The type must support the @b `AsyncWriteStream` concept.
The type must support the @b AsyncWriteStream concept.
@param msg The message to write. The object must remain valid
at least until the completion handler is called; ownership is

View File

@@ -8,9 +8,9 @@
#ifndef BEAST_WEBSOCKET_DETAIL_UTF8_CHECKER_HPP
#define BEAST_WEBSOCKET_DETAIL_UTF8_CHECKER_HPP
#include <beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/assert.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <algorithm>
#include <cstdint>
@@ -105,7 +105,8 @@ public:
template<class _>
void
utf8_checker_t<_>::reset()
utf8_checker_t<_>::
reset()
{
need_ = 0;
p_ = have_;
@@ -113,7 +114,8 @@ utf8_checker_t<_>::reset()
template<class _>
bool
utf8_checker_t<_>::finish()
utf8_checker_t<_>::
finish()
{
auto const success = need_ == 0;
reset();
@@ -123,7 +125,8 @@ utf8_checker_t<_>::finish()
template<class _>
template<class ConstBufferSequence>
bool
utf8_checker_t<_>::write(ConstBufferSequence const& bs)
utf8_checker_t<_>::
write(ConstBufferSequence const& bs)
{
static_assert(is_const_buffer_sequence<ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
@@ -138,7 +141,8 @@ utf8_checker_t<_>::write(ConstBufferSequence const& bs)
template<class _>
bool
utf8_checker_t<_>::write(std::uint8_t const* in, std::size_t size)
utf8_checker_t<_>::
write(std::uint8_t const* in, std::size_t size)
{
auto const valid =
[](std::uint8_t const*& in)

View File

@@ -301,7 +301,7 @@ void
stream<NextLayer>::
accept()
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
accept(ec);
@@ -315,7 +315,7 @@ void
stream<NextLayer>::
accept_ex(ResponseDecorator const& decorator)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_ResponseDecorator<
ResponseDecorator>::value,
@@ -331,7 +331,7 @@ void
stream<NextLayer>::
accept(error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
reset();
do_accept(&default_decorate_res, ec);
@@ -343,7 +343,7 @@ void
stream<NextLayer>::
accept_ex(ResponseDecorator const& decorator, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_ResponseDecorator<
ResponseDecorator>::value,
@@ -358,7 +358,7 @@ void
stream<NextLayer>::
accept(ConstBufferSequence const& buffers)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -377,7 +377,7 @@ stream<NextLayer>::
accept_ex(ConstBufferSequence const& buffers,
ResponseDecorator const &decorator)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -397,7 +397,7 @@ void
stream<NextLayer>::
accept(ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -419,7 +419,7 @@ stream<NextLayer>::
accept_ex(ConstBufferSequence const& buffers,
ResponseDecorator const& decorator, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -442,7 +442,7 @@ void
stream<NextLayer>::
accept(http::header<true, Fields> const& req)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
accept(req, ec);
@@ -457,7 +457,7 @@ stream<NextLayer>::
accept_ex(http::header<true, Fields> const& req,
ResponseDecorator const& decorator)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_ResponseDecorator<
ResponseDecorator>::value,
@@ -475,7 +475,7 @@ stream<NextLayer>::
accept(http::header<true, Fields> const& req,
error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
reset();
do_accept(req, &default_decorate_res, ec);
@@ -488,7 +488,7 @@ stream<NextLayer>::
accept_ex(http::header<true, Fields> const& req,
ResponseDecorator const& decorator, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_ResponseDecorator<
ResponseDecorator>::value,
@@ -504,7 +504,7 @@ stream<NextLayer>::
accept(http::header<true, Fields> const& req,
ConstBufferSequence const& buffers)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -524,7 +524,7 @@ accept_ex(http::header<true, Fields> const& req,
ConstBufferSequence const& buffers,
ResponseDecorator const& decorator)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -545,7 +545,7 @@ stream<NextLayer>::
accept(http::header<true, Fields> const& req,
ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -569,7 +569,7 @@ accept_ex(http::header<true, Fields> const& req,
ResponseDecorator const& decorator,
error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -595,7 +595,7 @@ async_return_type<
stream<NextLayer>::
async_accept(AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
async_completion<AcceptHandler,
void(error_code)> init{handler};
@@ -614,7 +614,7 @@ stream<NextLayer>::
async_accept_ex(ResponseDecorator const& decorator,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(detail::is_ResponseDecorator<
ResponseDecorator>::value,
@@ -636,7 +636,7 @@ stream<NextLayer>::
async_accept(ConstBufferSequence const& buffers,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -660,7 +660,7 @@ async_accept_ex(ConstBufferSequence const& buffers,
ResponseDecorator const& decorator,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -685,7 +685,7 @@ stream<NextLayer>::
async_accept(http::header<true, Fields> const& req,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
async_completion<AcceptHandler,
void(error_code)> init{handler};
@@ -707,7 +707,7 @@ stream<NextLayer>::
async_accept_ex(http::header<true, Fields> const& req,
ResponseDecorator const& decorator, AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(detail::is_ResponseDecorator<
ResponseDecorator>::value,
@@ -733,7 +733,7 @@ async_accept(http::header<true, Fields> const& req,
ConstBufferSequence const& buffers,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -760,7 +760,7 @@ async_accept_ex(http::header<true, Fields> const& req,
ResponseDecorator const& decorator,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(is_const_buffer_sequence<
ConstBufferSequence>::value,

View File

@@ -11,7 +11,7 @@
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/static_buffer.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <memory>
namespace beast {
@@ -202,7 +202,7 @@ async_return_type<
stream<NextLayer>::
async_close(close_reason const& cr, CloseHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
async_completion<CloseHandler,
void(error_code)> init{handler};
@@ -217,7 +217,7 @@ void
stream<NextLayer>::
close(close_reason const& cr)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
close(cr, ec);
@@ -230,7 +230,7 @@ void
stream<NextLayer>::
close(close_reason const& cr, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
BOOST_ASSERT(! wr_close_);
wr_close_ = true;

View File

@@ -14,7 +14,7 @@
#include <beast/http/write.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/assert.hpp>
#include <memory>
@@ -167,7 +167,7 @@ async_handshake(string_view const& host,
string_view const& target,
HandshakeHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
async_completion<HandshakeHandler,
void(error_code)> init{handler};
@@ -188,7 +188,7 @@ async_handshake(response_type& res,
string_view const& target,
HandshakeHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
async_completion<HandshakeHandler,
void(error_code)> init{handler};
@@ -209,7 +209,7 @@ async_handshake_ex(string_view const& host,
RequestDecorator const& decorator,
HandshakeHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
static_assert(detail::is_RequestDecorator<
RequestDecorator>::value,
@@ -234,7 +234,7 @@ async_handshake_ex(response_type& res,
RequestDecorator const& decorator,
HandshakeHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
static_assert(detail::is_RequestDecorator<
RequestDecorator>::value,
@@ -254,7 +254,7 @@ stream<NextLayer>::
handshake(string_view const& host,
string_view const& target)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
handshake(
@@ -270,7 +270,7 @@ handshake(response_type& res,
string_view const& host,
string_view const& target)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
error_code ec;
handshake(res, host, target, ec);
@@ -286,7 +286,7 @@ handshake_ex(string_view const& host,
string_view const& target,
RequestDecorator const& decorator)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_RequestDecorator<
RequestDecorator>::value,
@@ -306,7 +306,7 @@ handshake_ex(response_type& res,
string_view const& target,
RequestDecorator const& decorator)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_RequestDecorator<
RequestDecorator>::value,
@@ -323,7 +323,7 @@ stream<NextLayer>::
handshake(string_view const& host,
string_view const& target, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
do_handshake(nullptr,
host, target, &default_decorate_req, ec);
@@ -337,7 +337,7 @@ handshake(response_type& res,
string_view const& target,
error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
do_handshake(&res,
host, target, &default_decorate_req, ec);
@@ -352,7 +352,7 @@ handshake_ex(string_view const& host,
RequestDecorator const& decorator,
error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_RequestDecorator<
RequestDecorator>::value,
@@ -371,7 +371,7 @@ handshake_ex(response_type& res,
RequestDecorator const& decorator,
error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(detail::is_RequestDecorator<
RequestDecorator>::value,

View File

@@ -11,7 +11,7 @@
#include <beast/core/bind_handler.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <beast/websocket/detail/frame.hpp>
#include <memory>
@@ -200,7 +200,7 @@ async_return_type<
stream<NextLayer>::
async_ping(ping_data const& payload, WriteHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
async_completion<WriteHandler,
void(error_code)> init{handler};
@@ -217,7 +217,7 @@ async_return_type<
stream<NextLayer>::
async_pong(ping_data const& payload, WriteHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
async_completion<WriteHandler,
void(error_code)> init{handler};

View File

@@ -9,12 +9,11 @@
#define BEAST_WEBSOCKET_IMPL_READ_IPP
#include <beast/websocket/teardown.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/prepare_buffer.hpp>
#include <beast/core/static_buffer.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <beast/core/detail/clamp.hpp>
#include <boost/assert.hpp>
#include <boost/optional.hpp>
@@ -692,7 +691,7 @@ stream<NextLayer>::
async_read_frame(frame_info& fi,
DynamicBuffer& dynabuf, ReadHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -710,7 +709,7 @@ void
stream<NextLayer>::
read_frame(frame_info& fi, DynamicBuffer& dynabuf)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -726,7 +725,7 @@ void
stream<NextLayer>::
read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -1104,7 +1103,7 @@ stream<NextLayer>::
async_read(opcode& op,
DynamicBuffer& dynabuf, ReadHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -1122,7 +1121,7 @@ void
stream<NextLayer>::
read(opcode& op, DynamicBuffer& dynabuf)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
@@ -1138,7 +1137,7 @@ void
stream<NextLayer>::
read(opcode& op, DynamicBuffer& dynabuf, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");

View File

@@ -10,8 +10,8 @@
#include <beast/core/async_result.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_concepts.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/type_traits.hpp>
namespace beast {
namespace websocket {
@@ -139,7 +139,7 @@ async_teardown(teardown_tag,
boost::asio::ssl::stream<AsyncStream>& stream,
TeardownHandler&& handler)
{
static_assert(beast::is_CompletionHandler<
static_assert(beast::is_completion_handler<
TeardownHandler, void(error_code)>::value,
"TeardownHandler requirements not met");
detail::teardown_ssl_op<AsyncStream, typename std::decay<

View File

@@ -16,11 +16,10 @@
#include <beast/http/write.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/core/buffer_cat.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/consuming_buffers.hpp>
#include <beast/core/prepare_buffer.hpp>
#include <beast/core/static_buffer.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <boost/assert.hpp>
#include <boost/endian/buffers.hpp>
@@ -29,6 +28,8 @@
#include <stdexcept>
#include <utility>
#include <iostream>
namespace beast {
namespace websocket {

View File

@@ -9,9 +9,9 @@
#define BEAST_WEBSOCKET_IMPL_TEARDOWN_IPP
#include <beast/core/async_result.hpp>
#include <beast/core/handler_concepts.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/type_traits.hpp>
#include <memory>
namespace beast {
@@ -152,7 +152,7 @@ async_teardown(teardown_tag,
boost::asio::ip::tcp::socket& socket,
TeardownHandler&& handler)
{
static_assert(beast::is_CompletionHandler<
static_assert(beast::is_completion_handler<
TeardownHandler, void(error_code)>::value,
"TeardownHandler requirements not met");
detail::teardown_tcp_op<typename std::decay<

View File

@@ -10,13 +10,12 @@
#include <beast/core/bind_handler.hpp>
#include <beast/core/buffer_cat.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/consuming_buffers.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/prepare_buffer.hpp>
#include <beast/core/static_buffer.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <beast/core/detail/clamp.hpp>
#include <beast/websocket/detail/frame.hpp>
#include <boost/assert.hpp>
@@ -551,7 +550,7 @@ stream<NextLayer>::
async_write_frame(bool fin,
ConstBufferSequence const& bs, WriteHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
static_assert(beast::is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -570,7 +569,7 @@ void
stream<NextLayer>::
write_frame(bool fin, ConstBufferSequence const& buffers)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -588,7 +587,7 @@ stream<NextLayer>::
write_frame(bool fin,
ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -900,7 +899,7 @@ async_return_type<
stream<NextLayer>::
async_write(ConstBufferSequence const& bs, WriteHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
static_assert(beast::is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -919,7 +918,7 @@ void
stream<NextLayer>::
write(ConstBufferSequence const& buffers)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_const_buffer_sequence<
ConstBufferSequence>::value,
@@ -936,7 +935,7 @@ void
stream<NextLayer>::
write(ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_const_buffer_sequence<
ConstBufferSequence>::value,

View File

@@ -30,6 +30,21 @@ namespace websocket {
the request should be routed to an instance of
@ref websocket::stream.
@par Example
@code
void handle_connection(boost::asio::ip::tcp::socket& sock)
{
beast::flat_buffer buffer;
beast::http::request<beast::http::string_body> req;
beast::http::read(sock, buffer, req);
if(beast::websocket::is_upgrade(req))
{
beast::websocket::stream<decltype(sock)> ws{std::move(sock)};
ws.accept(req);
}
}
@endcode
@param req The HTTP Request object to check.
@return `true` if the request is a WebSocket Upgrade.

View File

@@ -81,17 +81,17 @@ struct frame_info
@tparam NextLayer The type representing the next layer, to which
data will be read and written during operations. For synchronous
operations, the type must support the @b `SyncStream` concept.
operations, the type must support the @b SyncStream concept.
For asynchronous operations, the type must support the
@b `AsyncStream` concept.
@b AsyncStream concept.
@note A stream object must not be moved or destroyed while there
are pending asynchronous operations associated with it.
@par Concepts
@b `AsyncStream`,
@b `DynamicBuffer`,
@b `SyncStream`
@b AsyncStream,
@b DynamicBuffer,
@b SyncStream
*/
template<class NextLayer>
class stream : public detail::stream_base

View File

@@ -19,7 +19,6 @@ unit-test core-tests :
core/async_result.cpp
core/bind_handler.cpp
core/buffer_cat.cpp
core/buffer_concepts.cpp
core/buffered_read_stream.cpp
core/buffers_adapter.cpp
core/clamp.cpp
@@ -27,19 +26,17 @@ unit-test core-tests :
core/error.cpp
core/flat_buffer.cpp
core/handler_alloc.cpp
core/handler_concepts.cpp
core/handler_ptr.cpp
core/multi_buffer.cpp
core/ostream.cpp
core/prepare_buffer.cpp
core/static_buffer.cpp
core/static_string.cpp
core/stream_concepts.cpp
core/string_view.cpp
core/type_traits.cpp
core/base64.cpp
core/empty_base_optimization.cpp
core/sha1.cpp
core/type_traits.cpp
;
unit-test http-tests :

View File

@@ -12,7 +12,6 @@ add_executable (core-tests
async_result.cpp
bind_handler.cpp
buffer_cat.cpp
buffer_concepts.cpp
buffers_adapter.cpp
clamp.cpp
consuming_buffers.cpp
@@ -20,23 +19,19 @@ add_executable (core-tests
error.cpp
flat_buffer.cpp
handler_alloc.cpp
handler_concepts.cpp
handler_ptr.cpp
multi_buffer.cpp
ostream.cpp
prepare_buffer.cpp
static_buffer.cpp
static_string.cpp
stream_concepts.cpp
string_view.cpp
type_traits.cpp
base64.cpp
empty_base_optimization.cpp
sha1.cpp
type_traits.cpp
)
if (NOT WIN32)
target_link_libraries(core-tests ${Boost_LIBRARIES} Threads::Threads)
else()
target_link_libraries(core-tests ${Boost_LIBRARIES})
endif()

View File

@@ -1,25 +0,0 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/core/buffer_concepts.hpp>
namespace beast {
namespace {
struct T
{
};
}
static_assert(is_const_buffer_sequence<detail::ConstBufferSequence>::value, "");
static_assert(! is_const_buffer_sequence<T>::value, "");
static_assert(is_mutable_buffer_sequence<detail::MutableBufferSequence>::value, "");
static_assert(! is_mutable_buffer_sequence<T>::value, "");
} // beast

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_TEST_BUFFER_TEST_HPP
#define BEAST_TEST_BUFFER_TEST_HPP
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <type_traits>

View File

@@ -1,23 +0,0 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/core/handler_concepts.hpp>
namespace beast {
namespace {
struct T
{
void operator()(int);
};
}
static_assert(is_CompletionHandler<T, void(int)>::value, "");
static_assert(! is_CompletionHandler<T, void(void)>::value, "");
} // beast

View File

@@ -9,8 +9,8 @@
#include <beast/core/multi_buffer.hpp>
#include "buffer_test.hpp"
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/ostream.hpp>
#include <beast/core/type_traits.hpp>
#include <beast/test/test_allocator.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>

View File

@@ -1,30 +0,0 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/core/stream_concepts.hpp>
#include <boost/asio/ip/tcp.hpp>
namespace beast {
using stream_type = boost::asio::ip::tcp::socket;
static_assert(has_get_io_service<stream_type>::value, "");
static_assert(is_AsyncReadStream<stream_type>::value, "");
static_assert(is_AsyncWriteStream<stream_type>::value, "");
static_assert(is_AsyncStream<stream_type>::value, "");
static_assert(is_SyncReadStream<stream_type>::value, "");
static_assert(is_SyncWriteStream<stream_type>::value, "");
static_assert(is_SyncStream<stream_type>::value, "");
static_assert(! has_get_io_service<int>::value, "");
static_assert(! is_AsyncReadStream<int>::value, "");
static_assert(! is_AsyncWriteStream<int>::value, "");
static_assert(! is_SyncReadStream<int>::value, "");
static_assert(! is_SyncWriteStream<int>::value, "");
} // beast

View File

@@ -6,9 +6,12 @@
//
// Test that header file is self-contained.
#include <beast/core/detail/type_traits.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/ip/tcp.hpp>
namespace beast {
namespace detail {
namespace {
@@ -60,13 +63,8 @@ static_assert(! is_invocable<
// get_lowest_layer
//
struct F1
{
};
struct F2
{
};
struct F1 {};
struct F2 {};
template<class F>
struct F3
@@ -120,4 +118,61 @@ static_assert(std::is_same<
} // (anonymous)
} // detail
//
// buffer concepts
//
namespace {
struct T {};
static_assert(is_const_buffer_sequence<detail::ConstBufferSequence>::value, "");
static_assert(! is_const_buffer_sequence<T>::value, "");
static_assert(is_mutable_buffer_sequence<detail::MutableBufferSequence>::value, "");
static_assert(! is_mutable_buffer_sequence<T>::value, "");
} // (anonymous)
//
// handler concepts
//
namespace {
struct H
{
void operator()(int);
};
} // anonymous
static_assert(is_completion_handler<H, void(int)>::value, "");
static_assert(! is_completion_handler<H, void(void)>::value, "");
//
// stream concepts
//
//namespace {
using stream_type = boost::asio::ip::tcp::socket;
static_assert(has_get_io_service<stream_type>::value, "");
static_assert(is_async_read_stream<stream_type>::value, "");
static_assert(is_async_write_stream<stream_type>::value, "");
static_assert(is_async_stream<stream_type>::value, "");
static_assert(is_sync_read_stream<stream_type>::value, "");
static_assert(is_sync_write_stream<stream_type>::value, "");
static_assert(is_sync_stream<stream_type>::value, "");
static_assert(! has_get_io_service<int>::value, "");
static_assert(! is_async_read_stream<int>::value, "");
static_assert(! is_async_write_stream<int>::value, "");
static_assert(! is_sync_read_stream<int>::value, "");
static_assert(! is_sync_write_stream<int>::value, "");
//} // (anonymous)
} // beast

View File

@@ -12,8 +12,8 @@
#include <beast/http/message.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/error.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/system/error_code.hpp>
#include <cstdint>