Documentation work

This commit is contained in:
Vinnie Falco
2017-05-28 19:49:41 -07:00
parent 060f4a007b
commit 0056c97d94
28 changed files with 1495 additions and 789 deletions

142
doc/0_main.qbk Normal file
View File

@ -0,0 +1,142 @@
[/
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)
]
[library Beast
[quickbook 1.6]
[copyright 2013 - 2017 Vinnie Falco]
[purpose Networking Protocol Library]
[license
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])
]
[authors [Falco, Vinnie]]
[category template]
[category generic]
]
[template mdash[] '''— ''']
[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__ [@http://www.boost.org/doc/html/boost_asio.html Boost.Asio]]
[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 __io_service__ [@http://www.boost.org/doc/html/boost_asio/reference/io_service.html `io_service`]]
[def __streambuf__ [@http://www.boost.org/doc/html/boost_asio/reference/streambuf.html [*boost::asio::streambuf]]]
[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 __AsyncStream__ [link beast.ref.streams.AsyncStream [*AsyncStream]]]
[def __Body__ [link beast.ref.Body [*Body]]]
[def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]]
[def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]]
[def __Stream__ [link beast.ref.streams [*Stream]]]
[def __SyncStream__ [link beast.ref.streams.SyncStream [*SyncStream]]]
[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]]
[def __basic_multi_buffer__ [link beast.ref.basic_multi_buffer `basic_multi_buffer`]]
[def __basic_parser__ [link beast.ref.http__basic_parser `basic_parser`]]
[def __fields__ [link beast.ref.http__fields `fields`]]
[def __flat_buffer__ [link beast.ref.flat_buffer `flat_buffer`]]
[def __header__ [link beast.ref.http__header `header`]]
[def __message__ [link beast.ref.http__message `message`]]
[def __message_parser__ [link beast.ref.http__message_parser `message_parser`]]
[def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]]
[def __serializer__ [link beast.ref.http__serializer `serializer`]]
Beast is a cross-platform, header-only C++11 library for low-level HTTP
and WebSocket protocol programming that uses the consistent network and
asynchronous model of __Asio__.
[variablelist
[[
[link beast.overview Overview]
][
An explanation of requirements, audience, features, and credits.
]]
[[
[link beast.core Core Concepts]
][
Library-wide concepts for working with buffers and streams.
]]
[[
[link beast.http Using HTTP]
][
How to use the basic algorithms in your applications.
]]
[[
[link beast.adv_http Advanced HTTP]
][
A discussion of the advanced interfaces.
]]
[[
[link beast.websocket Using WebSocket]
][
How to use the WebSocket interfaces in your applications.
]]
[[
[link beast.example Examples]
][
Examples that illustrate usage for typical scenarios.
]]
[[
[link beast.design Design]
][
Design rationale, answers to questions,
library comparisons, and Boost Formal Review FAQ.
]]
[[
[link beast.ref Reference]
][
Detailed class and function reference.
]]
[[
[link beast.index Index]
][
Book-style text index of Beast documentation.
]]
]
[include 1_overview.qbk]
[include 2_core.qbk]
[include 3_0_http.qbk]
[include 4_0_adv_http.qbk]
[include 5_websocket.qbk]
[include 6_examples.qbk]
[include 7_0_design.qbk]
[section:ref Reference]
[xinclude quickref.xml]
[include concept/Body.qbk]
[include concept/BodyReader.qbk]
[include concept/BodyWriter.qbk]
[include concept/BufferSequence.qbk]
[include concept/DynamicBuffer.qbk]
[include concept/Field.qbk]
[include concept/FieldSequence.qbk]
[include concept/Streams.qbk]
[include reference.qbk]
[endsect]
[xinclude index.xml]

126
doc/1_overview.qbk Normal file
View File

@ -0,0 +1,126 @@
[/
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:overview Introduction]
Beast is a cross-platform, header-only C++11 library for low-level HTTP
and WebSocket protocol programming that uses the consistent networking
and asynchronous model of __Asio__. The design of the library achieves
these goals:
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
used to build clients, servers, or both.
* [*Ease of Use.] HTTP messages are modeled using a simple, expressive
container. Algorithms used to send and receive HTTP or WebSocket
messages are designed to make users already familiar with __Asio__
immediately comfortable using this library.
* [*Flexibility.] Interfaces do not mandate specific implementation
strategies; users make the important decisions such as buffer or
thread management.
* [*Performance.] The implementation performs competitively, making it
a realistic choice for building high performance network servers.
* [*Scalability.] Development of network applications that scale to
thousands of concurrent connections is possible with the implementation.
* [*Basis for Further Abstraction.] The interfaces facilitate the
development of other libraries that provide higher levels of abstraction.
[heading Requirements]
Beast requires:
* [*C++11.] A minimum of C++11 is needed.
* [*Boost.] Beast is built on Boost, especially Boost.Asio.
* [*OpenSSL.] If using TLS/Secure sockets (optional).
[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
program successfully, you'll need to add the Boost.System library to link
with. If you use coroutines you'll also need the Boost.Coroutine library.
Please visit the Boost documentation for instructions on how to do this for
your particular build system.
Beast does not compile using the stand-alone version of Asio, since it
relies on other Boost parts. There are no immediate plans to offer a
version that works with stand-alone Asio.
[heading Motivation]
There is a noticable shortage of high quality C++ networking libraries,
especially for the HTTP and WebSocket protocols. The author theorizes
that previous attempts to build such libraries focused too much on end
user needs instead of applying principles of computer science to solve
the problem more formally. Another factor is that there no current
standardized interface for networking. This may change soon; with the
the introduction of the Networking Technical Specification (__N4588__),
a uniform interface for networking is on track to become standardized.
This technical specification is modeled closely after Boost.Asio.
Beast is built on Boost.Asio, with plans to adapt it to the networking
interfaces which become part of the C++ Standard.
The HTTP and WebSocket protocols drive most of the World Wide Web. Every
web browser implements these protocols to load webpages and to enable
client side programs (often written in JavaScript) to communicate
interactively. C++ benefits greatly from having a standardized
implementation of these protocols.
[heading Audience]
Beast is for network programmers who have some familiarity with __Asio__.
In particular, users who wish to write asynchronous programs with Beast
should already have knowledge and experience with Asio's asynchronous
model and style of asynchronous programming using callbacks or coroutines.
The protocol interfaces are low level. There are no out of the box solutions
for implementing clients or servers. For example, users must provide their
own code to make connections, handle timeouts, reconnect a dropped connection,
accept incoming connections, or manage connection resources on a server.
The HTTP interfaces provide functionality only for modelling HTTP
messages and serializing or parsing them on streams, including TCP/IP
sockets or OpenSSL streams. Higher level functions such as Basic
Authentication, mime/multipart encoding, cookies, automatic handling
of redirects, gzipped transfer encodings, caching, or proxying (to name
a few) are not directly provided, but nothing stops users from creating
these features using Beast's HTTP message types.
The library is intended to be the foundation upon which other networking
libraries are built. It is a goal that other architects will build
interoperable solutions on top of Beast.
[heading Credits]
Boost.Asio is the inspiration behind which all of the interfaces and
implementation strategies are built. Some parts of the documentation are
written to closely resemble the wording and presentation of Boost.Asio
documentation. Credit goes to Christopher Kohlhoff for the wonderful
Asio library and the ideas upon which Beast is built.
Beast would not be possible without the considerable time and patience
contributed by
David Schwartz,
Edward Hennis,
[@https://github.com/howardhinnant Howard Hinnant],
Miguel Portilla,
Nikolaos Bougalis,
Scott Determan,
Scott Schurr,
and
[@https://www.ripple.com Ripple Labs]
for supporting its early development. Also thanks to
Agustín Bergé,
Glen Fernandes,
and
Peter Dimov
for helping me considerably on Slack.
[endsect]

View File

@ -9,34 +9,151 @@
[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>
<member><link linkend="beast.core.asio">Working With Asio</link></member>
<member><link linkend="beast.core.streams">Stream Concepts</link></member>
<member><link linkend="beast.core.buffers">Buffer Concepts</link></member>
<member><link linkend="beast.core.async">Asynchronous Utilities</link></member>
<member><link linkend="beast.core.tutorial">Asynchronous Composed Operation 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__.
A goal of the library is expose implementation primitives in order that
users may build their own library-like components. These primitives include
traits, buffers, buffer algorithms, and helpers for implementing asynchronous
operations compatible with __Asio__ and described in __N3747__. This section
lists these facilities by group, with descriptions.
[important
This documentation assumes familiarity with __Asio__. Sample
code and identifiers used throughout are written as if the
following declarations are in effect:
```
#include <beast/core.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <thread>
using namespace beast;
boost::asio::io_service ios;
boost::asio::io_service work{ios};
std::thread t{[&](){ ios.run(); }};
error_code ec;
```
]
[section:concepts Concepts]
[heading:asio Working With Asio]
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.
Beast does not manage sockets, make outgoing connections, accept incoming
connections, or handle any aspect of connection management. In order to
invoke library algorithms it is necessary to first have a connected socket,
SSL stream, or other object which meets the required stream concepts. This
example is provided as a reminder of how to work with sockets:
```
auto host = "www.example.com";
boost::asio::ip::tcp::resolver r{ios};
boost::asio::ip::tcp::socket sock{ios};
boost::asio::connect(sock, r.resolve(
boost::asio::ip::tcp::resolver::query{host, "http"}));
[table Type Traits
// At this point `sock` is a connected to a remote
// host and may be used to perform stream operations.
```
Throughout this documentation identifiers with the following names have
special meaning:
[table Global Variables
[[Name][Description]]
[[
[@http://www.boost.org/doc/html/boost_asio/reference/io_service.html [*`ios`]]
][
A variable of type
[@http://www.boost.org/doc/html/boost_asio/reference/io_service.html `boost::asio::io_service`]
which is running on one separate thread, and upon which a
[@http://www.boost.org/doc/html/boost_asio/reference/io_service__work.html `boost::asio::io_service::work`]
object has been constructed.
]]
[[
[@http://www.boost.org/doc/html/boost_asio/reference/ip__tcp/socket.html [*`sock`]]
][
A variable of type
[@http://www.boost.org/doc/html/boost_asio/reference/ip__tcp/socket.html `boost::asio::ip::tcp::socket`]
which has already been connected to a remote host.
]]
[[
[@http://www.boost.org/doc/html/boost_asio/reference/ssl__stream.html [*`ssl_sock`]]
][
A variable of type
[@http://www.boost.org/doc/html/boost_asio/reference/ssl__stream.html `boost::asio::ssl::stream<boost::asio::ip::tcp::socket>`]
which is already connected and has handshaked with a remote host.
]]
]
[heading:streams Stream Concepts]
A __Stream__ is communication channel where data expressed as octet
buffers is transferred sequentially. Streams are either synchronous
or asynchronous, and may allow reading, writing, or both. Note that
a particular type may model more than one concept. For example, the
Asio types
[@http://www.boost.org/doc/html/boost_asio/reference/ip__tcp/socket.html `boost::asio::ip::tcp::socket`]
and
[@http://www.boost.org/doc/html/boost_asio/reference/ssl__stream.html `boost::asio::ssl::stream`]
support everything. All stream algorithms in Beast are declared as
template functions with specific concept requirements chosen from
this list:
[table Stream Concepts
[[Concept][Description]]
[
[__SyncReadStream__]
[
Supports buffer-oriented blocking reads.
]
][
[__SyncWriteStream__]
[
Supports buffer-oriented blocking writes.
]
][
[__SyncStream__]
[
A stream supporting buffer-oriented blocking reads and writes.
]
][
[__AsyncReadStream__]
[
Supports buffer-oriented asynchronous reads.
]
][
[__AsyncWriteStream__]
[
Supports buffer-oriented asynchronous writes.
]
][
[__AsyncStream__]
[
A stream supporting buffer-oriented asynchronous reads and writes.
]
]
]
These template metafunctions check whether a given type meets the
requirements for the various stream concepts, and some additional
useful utilities. The library uses these type checks internally
and also provides them as public interfaces so users may use the
same techniques to augment their own code. The use of these type
checks helps provide more concise errors during compilation:
[table Stream Type Checks
[[Name][Description]]
[[
[link beast.ref.get_lowest_layer `get_lowest_layer`]
@ -46,8 +163,8 @@ diagnostics.
[[
[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.
Determine if the `get_io_service` member function is present,
and returns an __io_service__.
]]
[[
[link beast.ref.is_async_read_stream `is_async_read_stream`]
@ -71,21 +188,6 @@ diagnostics.
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`]
][
@ -104,25 +206,55 @@ diagnostics.
]]
]
[endsect]
Using the type checks with `static_assert` on function or class template
types will provide users with helpful error messages and prevent undefined
behaviors. This example shows how a template function which writes to a
synchronous stream may check its argument:
```
template<class SyncWriteStream>
void write_string(SyncWriteStream& stream, string_view s)
{
static_assert(is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
boost::asio::write(stream, boost::asio::const_buffers_1(s.data(), s.size()));
}
```
[heading:buffers Buffer Concepts]
[section:dynamic_buffer DynamicBuffer]
__Asio__ provides the __ConstBufferSequence__ and __MutableBufferSequence__
concepts, whose models provide ranges of buffers, as well as the __streambuf__
class which encapsulates memory storage that may be automatically resized as
required, where the memory is divided into an input sequence followed by an
output sequence. The Networking TS (__N4588__) generalizes the `streambuf`
interface into the __DynamicBuffer__ concept. Beast algorithms which require
resizable buffers accept as parameters dynamic buffer objects. These
metafunctions check types against these buffer concepts:
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 Buffer Type Checks
[[Name][Description]]
[[
[link beast.ref.is_const_buffer_sequence `is_const_buffer_sequence`]
][
Determine if a type meets the requirements of __ConstBufferSequence__.
]]
[[
[link beast.ref.is_mutable_buffer_sequence `is_mutable_buffer_sequence`]
][
Determine if a type meets the requirements of __MutableBufferSequence__.
]]
[[
[link beast.ref.is_dynamic_buffer `is_dynamic_buffer`]
][
Determine if a type meets the requirements of __DynamicBuffer__.
]]
]
[table Dynamic buffer implementations
To suit various needs, several implementation of dynamic buffer are available:
[table Dynamic Buffer Implementations
[[Name][Description]]
[[
[link beast.ref.buffers_adapter `buffers_adapter`]
@ -161,20 +293,16 @@ dynamic buffer concept using various strategies:
]]
]
[endsect]
Network applications frequently need to manipulate buffer sequences. To
facilitate working with buffers the library treats these sequences as
a special type of range. Algorithms and wrappers are provided which
transform these buffer sequences ranges efficiently using lazy evaluation.
No memory allocations are used in the transformations; instead, they
create lightweight iterators over the existing, unmodified memory
buffers. The lifetime of the transformed buffers is retained by the
caller; ownership is not transferred.
[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
[table Buffer Algorithms
[[Name][Description]]
[[
[link beast.ref.buffer_cat `buffer_cat`]
@ -195,8 +323,8 @@ underlying memory, whose lifetime is retained by the caller.
[[
[link beast.ref.buffer_cat `buffers_view`]
][
This class represents a buffer sequence which represents the concatenation
of two or more buffer sequences. This is type of object returned by
This class represents the buffer sequence formed by concatenating
two or more buffer sequences. This is type of object returned by
[link beast.ref.buffer_cat `buffer_cat`].
]]
[[
@ -209,18 +337,36 @@ underlying memory, whose lifetime is retained by the caller.
]]
]
[endsect]
These two functions facilitate buffer interoperability with standard
output streams.
[table Buffer Output Streams
[[Name][Description]]
[[
[link beast.ref.buffers `buffers`]
][
This function wraps a __ConstBufferSequence__ so it may be
used with `operator<<` and `std::ostream`.
]]
[[
[link beast.ref.ostream `ostream`]
][
This function returns a `std::ostream` which wraps a dynamic buffer.
Characters sent to the stream using `operator<<` is stored in the
dynamic buffer.
]]
]
[section:async Asynchronous Model]
[heading:async Asynchronous Utilities]
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
callers. __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
@ -229,21 +375,22 @@ 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.
Model and how these asynchronous interfaces are used is beyond the
scope of this document. Interested readers should consult the
__Asio__ documentation.
]
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.
Since the interfaces provided here are 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, __Asio__ imposes requirements on the implementation
of composed operations. A number of useful classes and macros to facilitate
the development of composed operations and the associated asynchronous
initiation functions used to launch them are available:
[table Asynchronous Helpers
[[Name][Description]]
@ -306,11 +453,9 @@ the associated asynchronous initiation functions used to launch them.
]]
]
[endsect]
[section:tutorial Tutorial]
[section:tutorial Asynchronous Composed Operation 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
@ -352,8 +497,7 @@ operation by constructing the object and invoking it.
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.
// to cause a friendly message instead of an error novel.
//
static_assert(beast::is_async_stream<AsyncStream>::value,
"AsyncStream requirements not met");
@ -365,7 +509,7 @@ operation by constructing the object and invoking it.
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
// call followed by invocation of operator(). We use handler_type
// to convert the completion token into the correct handler type,
// allowing user defined specializations of the async result template
// to take effect.
@ -388,7 +532,7 @@ 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
the __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
@ -548,17 +692,20 @@ this echo operation:
case 1:
// write everything back
p.step = 2;
return boost::asio::async_write(p.stream, p.buffer.data(), std::move(*this));
// async_read_until could have read past the newline,
// use buffer_prefix to make sure we only send one line
return boost::asio::async_write(p.stream,
beast::buffer_prefix(bytes_transferred, p.buffer.data()), std::move(*this));
case 2:
p.buffer.consume(bytes_transferred);
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.
// is destroyed before the handler is invoked.
//
p_.invoke(ec);
return;

83
doc/3_0_http.qbk Normal file
View File

@ -0,0 +1,83 @@
[/
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:http Using HTTP]
[block '''
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
<member><link linkend="beast.http.primer">HTTP Primer</link></member>
<member><link linkend="beast.http.message">Message Containers</link></member>
<member><link linkend="beast.http.streams">Stream Operations</link></member>
</simplelist></entry></row></tbody></tgroup></informaltable>
''']
This library offers programmers simple and performant models of HTTP
messages and their associated operations including synchronous and
asynchronous parsing and serialization of messages in the HTTP/1 wire
format using __Asio__. Specifically, the library provides:
[variablelist
[
[Message Containers]
[
Complete HTTP messages are modeled using the __message__ class,
with possible user customizations.
]
][
[Stream Reading]
[
The functions
[link beast.ref.http__read `read`],
[link beast.ref.http__read_some `read_some`],
[link beast.ref.http__async_read `async_read`], and
[link beast.ref.http__async_read_some `async_read_some`]
read a __message__ from a
[link beast.ref.streams stream].
]
][
[Stream Writing]
[
The functions
[link beast.ref.http__write `write`],
[link beast.ref.http__write_some `write_some`],
[link beast.ref.http__async_write `async_write`], and
[link beast.ref.http__async_write_some `async_write_some`]
write a __message__ to a
[link beast.ref.streams stream].
]
][
[Serialization]
[
The __serializer__ produces a series of octet buffers
conforming to the __rfc7230__ wire representation of
a __message__.
]
][
[Parsing]
[
The __message_parser__ attempts to convert a series of
octet buffers into a __message__.
]
]
]
[note
The following documentation assumes some familiarity with __Asio__ and
the HTTP protocol specification described in __rfc7230__. Sample code
and identifiers mentioned in the HTTP documentation sections are
written as if these declarations are in effect:
```
#include <beast/http.hpp>
using namespace beast::http;
```
]
[include 3_1_primer.qbk]
[include 3_2_message.qbk]
[include 3_3_streams.qbk]
[endsect]

144
doc/3_1_primer.qbk Normal file
View File

@ -0,0 +1,144 @@
[/
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:primer HTTP Primer]
The HTTP protocol defines the
[@https://tools.ietf.org/html/rfc7230#section-2.1 client and server roles]:
clients send requests and servers send back responses. A request
or response is an
[@https://tools.ietf.org/html/rfc7230#section-3 HTTP message]
(referred to hereafter as "message"), with two parts:
a header containing structured metadata and an optional variable-length
body containing arbitrary data. A serialized header is one or more text
lines where each line ends in a carriage return followed by linefeed
(`"\r\n"`). An empty line marks the end of the header. The first line
in the header is called the ['start-line]. The start line contents are
different for requests and responses.
Every message contains a set of zero or more field name/value pairs,
collectively called "fields". The names and values are represented using
text strings with various requirements. A serialized field contains the
field name, then a colon followed by a space (`": "`), and finally the field
value.
When a client and server have established a connection and intend to
use HTTP, the client sends a series of requests while the server reads
sends back at least one response for each request in the order those
requests were received.
[heading Requests]
Clients send requests, which contain a
[@https://tools.ietf.org/html/rfc7230#section-3.1.1 method]
and
[@https://tools.ietf.org/html/rfc7230#section-5.3 request-target],
and
[@https://tools.ietf.org/html/rfc7230#section-2.6 HTTP-version].
The method identifies the operation to be performed while the target
identifies the object on the server to which the operation applies.
The version is almost always 1.1, but older programs sometimes use 1.0.
[table
[[Serialized Request][Description]]
[[
```
GET / HTTP/1.1\r\n
User-Agent: Beast\r\n
\r\n
```
][
This request has a method of "GET", a target of "/", and indicates
HTTP version 1.1. It contains a single field called "User-Agent"
whose value is "Beast". There is no message body.
]]
]
[heading Responses]
Servers send responses, which contain a
[@https://tools.ietf.org/html/rfc7231#section-6 status-code],
[@https://tools.ietf.org/html/rfc7230#section-3.1.2 reason-phrase], and
[@https://tools.ietf.org/html/rfc7230#section-2.6 HTTP-version].
The reason phrase is
[@https://tools.ietf.org/html/rfc7230#section-3.1.2 obsolete]:
clients SHOULD ignore the reason-phrase content. Here is a response which
includes a body. The special
[@https://tools.ietf.org/html/rfc7230#section-3.3.2 Content-Length]
field informs the remote host of the size of the body which follows.
[table
[[Serialized Response][Description]]
[[
```
HTTP/1.1 200 OK\r\n
Server: Beast\r\n
Content-Length: 13\r\n
\r\n
Hello, world!
```
][
This response has a
[@https://tools.ietf.org/html/rfc7231#section-6 200 status code]
meaning the operation requested completed successfully. The obsolete
reason phrase is "OK". It has specifies HTTP version 1.1, and contains
a body 13 octets in size with the text "Hello, world!".
]]
]
[heading Special Fields]
Certain fields appearing in messages are special. The library understands
these fields when performing serialization and parsing, taking automatic
action as needed when the fields are present:
[table Special Fields
[[Field][Description]]
[
[
[@https://tools.ietf.org/html/rfc7230#section-6.1 [*`Connection`]]
[@https://tools.ietf.org/html/rfc7230#appendix-A.1.2 [*`Proxy-Connection`]]
][
This field allows the sender to indicate desired control options
for the current connection. Common values include "close",
"keep-alive", and "upgrade".
]
][
[
[@https://tools.ietf.org/html/rfc7230#section-3.3.2 [*`Content-Length`]]
][
When present, this field informs the recipient about the exact
size in bytes of the body which follows the message header.
]
][
[
[@https://tools.ietf.org/html/rfc7230#section-3.3.1 [*`Transfer-Encoding`]]
][
This optional field lists the names of the sequence of transfer codings
that have been (or will be) applied to the content payload to form
the message body.
Beast understands the "chunked" coding scheme when it is the last
(outermost) applied coding. The library will automatically apply
chunked encoding when the content length is not known ahead of time
during serialization, and the library will automatically removed chunked
encoding from parsed messages.
]
][
[
[@https://tools.ietf.org/html/rfc7230#section-6.7 [*`Upgrade`]]
][
The Upgrade header field provides a mechanism to transition from
HTTP/1.1 to another protocol on the same connection. For example, it
is the mechanism used by WebSocket's initial HTTP handshake to
establish a WebSocket connection.
]
]
]
[endsect]

173
doc/3_2_message.qbk Normal file
View File

@ -0,0 +1,173 @@
[/
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:message Message Containers]
Beast provides a single class template __message__ which models
HTTP/1 and
[@https://tools.ietf.org/html/rfc7540 HTTP/2]
messages:
```
/// An HTTP message
template<
bool isRequest, // `true` for requests, `false` for responses
class Body, // Controls the container and algorithms used for the body
class Fields = fields> // The type of container to store the fields
class message;
```
The container offers value semantics including move and copy if supported
by `Body` and `Fields`. User defined template function parameters can
accept any message, or can use partial specialization to accept just
requests or responses. The default __fields__ is a provided associative
container using the standard allocator and supporting modification and
inspection of fields. As per __rfc7230__, a non-case-sensitive comparison
is used for field names. User defined types for fields are possible. This
is discussed in
[link beast.adv_http.fields Advanced Fields].
The `Body` type determines the type of the container used to represent the
body as well as the algorithms for transferring buffers to and from the
the container. The library comes with a collection of common body types,
described in
[link beast.http.message.body Body Types].
As with fields, user defined body types are possible. This is described in
[link beast.adv_http.body Advanced Body].
Sometimes it is desired to only work with a header. Beast provides a single
class template __header__ to model HTTP/1 and HTTP/2 headers:
```
/// An HTTP header
template<
bool isRequest, // `true` for requests, `false` for responses
class Fields = fields> // The type of container to store the fields
class header;
```
Requests and responses share the version, fields, and body but have
a few members unique to the type. This is implemented by declaring the
header classes as partial specializations of `isRequest`. Furthermore,
__message__ is derived from __header__; a message may be passed as an
argument to a function taking a suitably typed header as a parameter.
This diagram shows the inheritance relationship between header and message,
along with the fields from the different partial specializations for each
possible value of `isRequest`:
[$images/message.png [width 711px] [height 424px]]
For notational convenience, the template type aliases
[link beast.ref.http__request `request`] and
[link beast.ref.http__response `response`]
are provided, which also supply commonly chosen __fields__ type as a default:
```
/// A typical HTTP request
template<class Body, class Fields = fields>
using request = message<true, Body, Fields>;
/// A typical HTTP response
template<class Body, class Fields = fields>
using response = message<false, Body, Fields>;
```
[heading:body Body Types]
Beast defines the __Body__ concept, which determines both the type of
the `message::body` member (as seen in the diagram above) and may also
include algorithms for transferring buffers in and out. These algorithms
are used during parsing and serialization. These body types are available
within the library, and users may define their own body types which meet
the __Body__ requirements:
[table
[[Name][Description]]
[[
[link beast.ref.http__buffer_body `buffer_body`]
][
A body with `value_type` holding a __ConstBufferSequence__ holding
caller provided buffers which must be updated during incremental
serialization. Messages with this body type only support serialization.
]]
[[
[link beast.ref.http__dynamic_body `dynamic_body`]
[link beast.ref.http__basic_dynamic_body `basic_dynamic_body`]
][
A body whose `value_type` is a __DynamicBuffer__. It inherits
the insertion complexity of the underlying choice of dynamic buffer.
Messages with this body type may be serialized and parsed.
]]
[[
[link beast.ref.http__empty_body `empty_body`]
][
A special body with an empty `value_type` indicating that the
message has no body. Messages with this body may be serialized
and parsed; however, body octets received while parsing a message
with this body will generate a unique error.
]]
[[
[link beast.ref.http__string_body `string_body`]
][
A body whose `value_type` is `std::string`. Insertion complexity
is amortized constant time, while capacity grows geometrically.
Messages with this body type may be serialized and parsed. This
is the type of body used in the examples.
]]
]
[heading Usage]
The code examples below show how to create and fill in request and response
objects:
[table Create Request
[[Statements] [Serialized Result]]
[[
```
request<string_body> req;
req.version = 11; // HTTP/1.1
req.method("GET");
req.target("/index.htm");
req.fields.insert("Accept", "text/html");
req.fields.insert("Connection", "keep-alive");
req.fields.insert("User-Agent", "Beast");
```
][
```
GET /index.htm HTTP/1.1\r\n
Accept: text/html\r\n
Connection: keep-alive\r\n
User-Agent: Beast\r\n
\r\n
```
]]
]
[table Create Response
[[Statements] [Serialized Result]]
[[
```
response<string_body> res;
res.version = 11; // HTTP/1.1
res.status = 200;
res.reason("OK");
res.body = "Hello, world!";
res.fields.insert("Server", "Beast");
res.fields.insert("Content-Length", res.body.size());
```
][
```
200 OK HTTP/1.1\r\n
Server: Beast\r\n
Content-Length: 13\r\n
\r\n
Hello, world!
```
]]
]
[endsect]

140
doc/3_3_streams.qbk Normal file
View File

@ -0,0 +1,140 @@
[/
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:streams Stream Operations]
Beast provides synchronous and asynchronous algorithms to serialize and
parse HTTP/1 wire format messages on streams. These functions form the
basic interface which works on the entire header or message at once,
requiring no separately managed state objects:
[table Basic Interface
[[Name][Description]]
[[
[link beast.ref.http__read.overload3 [*read]]
][
Parse a __message__ from a __SyncReadStream__.
]]
[[
[link beast.ref.http__write.overload1 [*write]]
][
Serialize a __message__ to a __SyncWriteStream__.
]]
[[
[link beast.ref.http__async_read.overload2 [*async_read]]
][
Parse a __message__ from an __AsyncReadStream__.
]]
[[
[link beast.ref.http__async_write [*async_write]]
][
Serialize a __message__ to an __AsyncWriteStream__.
]]
]
Synchronous stream operations come in two varieties. One which throws
an exception upon error, and another which accepts as the last parameter an
argument of type [link beast.ref.error_code `error_code&`]. If an error
occurs this argument will be set to contain the error code.
[heading Writing]
A set of free functions allow serialization of an entire HTTP message to
a stream. This function sends a message synchronously on the socket,
throwing an exception if an error occurs:
```
template<class Body, class Fields>
void send(response<Body, Fields> const& res)
{
write(sock, res);
}
```
If a response has no declared content length, and no chunked transfer
encoding, the end of the message is indicated by the server closing
the connection. When sending such a response, Beast will return the
error `boost::asio::error::eof` from the write algorithm to indicate
to the caller that the connection should be closed. This example
constructs and sends a response whose body length is determined by
the number of octets received prior to the server closing the connection:
```
void send()
{
response<string_body> res;
res.version = 11;
res.status = 200;
res.reason("OK");
res.fields.insert("Server", "Beast");
res.body = "Hello, world!";
error_code ec;
write(sock, res, ec);
if(ec == boost::asio::error::eof)
sock.close();
else
BOOST_ASSERT(ec);
}
```
An asynchronous version is also available:
```
template<class Body, class Fields>
void send_async(response<Body, Fields> const& res)
{
async_write(sock, res,
[&](error_code)
{
if(ec)
std::cerr << ec.message() << std::endl;
});
}
```
[heading Reading]
Because a serialized header is not length-prefixed, algorithms which parse
messages from a stream may read past the end of a message for efficiency.
To hold this surplus data, all stream read operations use a passed-in
__DynamicBuffer__. Each read operation may consume bytes remaining in the
buffer, and leave behind new bytes. In this example we declare the buffer
and a message variable, then read a complete HTTP request synchronously:
```
flat_buffer buffer; // (The parser is optimized for flat buffers)
request<string_body> req;
read(sock, buffer, req);
```
In this example we used the __flat_buffer__. The parser in Beast is
optimized for structured HTTP data located in a single contiguous memory
buffer ("flat buffer"). Any dynamic buffer will work with reads. However,
when not using a flat buffer the implementation may perform an additional
memory allocation to restructure the input into a single buffer.
[tip
User-defined implementations of __DynamicBuffer__ may avoid additional
parser memory allocation, if those implementations guarantee that
returned buffer sequences will always have length one.
]
Messages may also be read asynchronously. When performing asynchronous
stream read operations, the buffer and message variables must remain
valid until the operation has completed. Beast asynchronous initiation
functions use Asio's completion handler model. Here we read a message
asynchronously. When the operation completes the message in the error
code indicating the result is printed:
```
flat_buffer buffer;
response<string_body> res;
async_read(sock, buffer,
[&](error_code ec)
{
std::cerr << ec.message() << std::endl;
});
```
[endsect]

339
doc/4_0_adv_http.qbk Normal file
View File

@ -0,0 +1,339 @@
[/
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:adv_http Advanced HTTP]
[block '''
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
<member><link linkend="beast.adv_http.serialize">Serialization</link></member>
<member><link linkend="beast.adv_http.parsing">Parsing</link></member>
<member><link linkend="beast.adv_http.fields">Field Containers</link></member>
<member><link linkend="beast.adv_http.body">Body Types</link></member>
</simplelist></entry></row></tbody></tgroup></informaltable>
''']
The basic interfaces for reading and writing complete messages are
simple to use and convenient, but may not serve the needs of advanced
use cases, including:
* Parsing a message from caller-provided buffers
* Serializing a message to caller-provided buffers
* Reading a message from a stream incrementally
* Writing a message to a stream incrementally
In some cases, users may wish to provide their own implementation for
the fields container and the body type. In the advanced sections we
discuss the buffer oriented message algorithms, incremental stream
algorithms, and customization points for messages.
[section:serialize Serialization (Advanced HTTP)]
Beast uses the __serializer__ class internally to generate a sequence of
buffers corresponding to the serialized representation of a __message__.
The basic algorithms send the entire set of buffers at once while the
incremental algorithms allow the caller to write a bounded amount to
the stream at each iteration. In between calls to generate buffers or
write buffers to the stream, the internal state of the serialization
must be saved. A __serializer__ initializes this internal state and
stores it in between calls to produce buffers, until all the message
buffers have been produced. Afterwards, the state object may be destroyed.
The serializer is a class template constructed from an existing
message. The template types used to instantiate the serializer must
match the types in the message. Here we declare a request and construct
an accompanying serializer:
```
request<string_body> req;
serializer<true, string_body, fields> sr{req};
```
The buffers are produced by first calling
[link beast.ref.http__serializer.get `serializer::get`]
to obtain a buffer sequence, and then calling
[link beast.ref.http__serializer.consume `serializer::consume`]
to indicate how many bytes in the buffer sequence were consumed.
This advanced the internal state of the serializer and prepares the
next set of buffers for delivery.
[link beast.ref.http__serializer.get `serializer::get`]
takes an error code parameter and invokes a visitor argument with the
error code and buffer of unspecified type. In C++14 this is easily
expressed with a generic lambda. The function
[link beast.ref.http__serializer.is_done `serializer::is_done`]
will return `true` when all the buffers have been produced. This example
prints the buffers to standard output:
```
template<bool isRequest, class Body, class Fields>
void print(message<isRequest, Body, Fields> const& m)
{
error_code ec;
serializer<isRequest, Body, Fields> sr{m};
do
{
sr.get(ec,
[&sr](error_code& ec, auto const& buffer)
{
std::cout << buffers(buffer);
sr.consume(boost::asio::buffer_size(buffer));
});
}
while(! ec && ! sr.is_done());
if(! ec)
std::cout << std::endl;
else
std::cerr << ec.message() << std::endl;
}
```
Generic lambda expressions are not available in C++11, so a functor with
a templated function call operator is necessary:
```
template<class Serializer>
struct lambda
{
Serializer& sr;
lambda(Serializer& sr_) : sr(sr_) {}
template<class ConstBufferSequence>
void operator()(error_code& ec, ConstBufferSequence const& buffer)
{
std::cout << buffers(buffer);
sr.consume(boost::asio::buffer_size(buffer));
}
};
template<bool isRequest, class Body, class Fields>
void print(message<isRequest, Body, Fields> const& m)
{
error_code ec;
serializer<isRequest, Body, Fields> sr{m};
do
{
sr.get(ec, lambda<decltype(sr)>{sr});
}
while(! ec && ! sr.is_done());
if(! ec)
std::cout << std::endl;
else
std::cerr << ec.message() << std::endl;
}
```
[heading Stream Operations]
When working with streams, the use of an explicitly declared serializer
allows control over the amount of network activity performed in each
system call. This allows for better application level flow control and
predictable timeouts. These advanced stream write operations work on
an object of type __serializer__ which has already been constructed,
and which must remain valid until the operation is complete:
[table Advanced Streaming
[[Name][Description]]
[[
[link beast.ref.http__write_some.overload1 [*write_some]]
][
Send __serializer__ buffer data to a __SyncWriteStream__.
]]
[[
[link beast.ref.http__async_write_some [*async_write_some]]
][
Send some __serializer__ buffer data to an __AsyncWriteStream__.
]]
]
Here is an example which synchronously sends a message on a stream using
a serializer:
```
template<class SyncWriteStream, bool isRequest, class Body, class Fields>
void send(SyncWriteStream& stream, message<isRequest, Body, Fields> const& m)
{
static_assert(is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
serializer<isRequest, Body, Fields> sr{m};
do
{
write_some(stream, sr);
}
while(! sr.is_done());
}
```
[heading Split Serialization]
In some cases, such as the handling of the
[@https://tools.ietf.org/html/rfc7231#section-5.1.1 Expect: 100-continue]
field, it may be desired to first serialize the header, perform some other
action, and then continue with serialization of the body. This is
accomplished by calling
[link beast.ref.http__serializer.split `serializer::split`]
with a boolean indicating that when buffers are produced, the last buffer
containing serialized header octets will not contain any octets corresponding
to the body. The function
[link beast.ref.http__serializer.is_header_done `serializer::is_header_done`]
informs the caller whether the header has completed serialization. In this
C++14 example we print the header first, followed by the body:
```
template<bool isRequest, class Body, class Fields>
void print(message<isRequest, Body, Fields> const& m)
{
error_code ec;
serializer<isRequest, Body, Fields> sr{m};
sr.split(true);
std::cout << "Header:" << std::endl;
do
{
sr.get(ec,
[&sr](error_code& ec, auto const& buffer)
{
std::cout << buffers(buffer);
sr.consume(boost::asio::buffer_size(buffer));
});
}
while(! sr.is_header_done());
if(! ec && ! sr.is_done())
{
std::cout << "Body:" << std::endl;
do
{
sr.get(ec,
[&sr](error_code& ec, auto const& buffer)
{
std::cout << buffers(buffer);
sr.consume(boost::asio::buffer_size(buffer));
});
}
while(! ec && ! sr.is_done());
}
if(ec)
std::cerr << ec.message() << std::endl;
}
```
[heading Chunk Decorators]
When the message used to construct the serializer indicates the chunked
transfer encoding, the serializer will automatically generate the proper
encoding in the output buffers. __rfc7230__ defines additional fields
called the
[@https://tools.ietf.org/html/rfc7230#section-4.1.1 chunk extensions]
in chunks with body octets, and the
[@https://tools.ietf.org/html/rfc7230#section-4.1.2 chunked trailer part]
for the final chunk. Applications that wish to emit chunk extensions
and trailers may instantiate the serializer with a "chunk decorator" type,
and pass an instance of the type upon construction. This decorator is
a function object which, when invoked with a __ConstBufferSequence__,
returns a
[link beast.ref.string_view `string_view`] containing either the extensions
or the trailer. For chunks containing body data, the passed buffer will
contain one or more corresponding body octets. The decorator may use this
information as needed. For example, to compute a digest on the data and
store it as a chunk extension. For the trailers, the serializer will
invoke the decorator with a buffer sequence of size zero. Or more
specifically, with an object of type
[@http://www.boost.org/doc/html/boost_asio/reference/null_buffers.html `boost::asio::null_buffers`].
For body chunks the string returned by the decorator must end in a
CRLF (`"\r\n"`) and follow the
[@https://tools.ietf.org/html/rfc7230#section-4.1.1 correct syntax]
for the entire chunk extension. For the trailer, the returned string
should consist of zero or more lines ending in a CRLF and containing
a field name/value pair in the format prescribed in __rfc7230__. It
is the responsibility of the decorator to manage returned string buffers.
The implementation guarantees it will not reference previous strings
after subsequent calls.
Here, we declare a decorator which sets an extension variable `x` equal
to the size of the chunk in bytes, and returns a single trailer field:
```
struct decorator
{
std::string s;
template<class ConstBufferSequence>
string_view
operator()(ConstBufferSequence const& buffer) const
{
s = ";x=" + std::to_string(boost::asio::buffer_size(buffer)) + "\r\n";
return s;
}
string_view
operator()(boost::asio::null_buffers) const
{
return "Result: OK\r\n";
}
};
```
[endsect]
[section:parsing Parsing (Advanced HTTP)]
[endsect]
[section:fields Field Containers (Advanced HTTP)]
[endsect]
[section:body Body Types (Advanced HTTP)]
User-defined types are possible for the message body, where the type meets the
[link beast.ref.Body [*`Body`]] requirements. This simplified class declaration
shows the customization points available to user-defined body types:
[$images/body.png [width 525px] [height 190px]]
The meanin of the nested types is as follows
[table Body Type Members
[[Name][Description]]
[
[`value_type`]
[
Determines the type of the
[link beast.ref.http__message.body `message::body`] member. If this
type defines default construction, move, copy, or swap, then message objects
declared with this [*Body] will have those operations defined.
]
][
[`body_writer`]
[
An optional nested type meeting the requirements of
[link beast.ref.BodyWriter [*BodyWriter]]. If present, this defines the
algorithm used to transfer parsed octets into buffers representing the
body.
]
][
[`body_reader`]
[
An optional nested type meeting the requirements of
[link beast.ref.BodyReader [*BodyReader]]. If present, this defines
the algorithm used to obtain buffers representing a body of this type.
]
]
]
The examples included with this library provide a [*Body] implementation that
serializing message bodies that come from a file.
[endsect]
[endsect]

View File

@ -26,7 +26,7 @@ libraries:
* Don't sacrifice performance.
* Mimic Boost.Asio; familiarity breeds confidence.
* Mimic __Asio__; familiarity breeds confidence.
* Role-symmetric interfaces; client and server the same (or close to it).
@ -34,8 +34,8 @@ libraries:
managing flow control.
Beast uses the __DynamicBuffer__ concept presented in the Networking TS
(__N4588__), and relies heavily on the Boost.Asio __ConstBufferSequence__
and __MutableBufferSequence__ concepts for passing buffers to functions.
(__N4588__), and relies heavily on the __ConstBufferSequence__ and
__MutableBufferSequence__ concepts for passing buffers to functions.
The authors have found the dynamic buffer and buffer sequence interfaces to
be optimal for interacting with Asio, and for other tasks such as incremental
parsing of data in buffers (for example, parsing websocket frames stored
@ -59,9 +59,9 @@ start. Other design goals:
* Allow for customizations, if the user needs it.
[include design/http_message.qbk]
[include design/http_comparison.qbk]
[include design/websocket_zaphoyd.qbk]
[include design/review.qbk]
[include 7_1_http_message.qbk]
[include 7_2_http_comparison.qbk]
[include 7_3_websocket_zaphoyd.qbk]
[include 7_4_review.qbk]
[endsect]

View File

@ -11,19 +11,33 @@ In this section we describe the problem of modeling HTTP messages and explain
how the library arrived at its solution, with a discussion of the benefits
and drawbacks of the design choices. The goal for creating a message model
is to create a container with value semantics, possibly movable and/or
copyable, that completely describes the message. More formally, the container
has all of the information necessary for the serialization algorithms to
represent the entire message as a series of octets, and that the parsing
algorithms store all of the captured information about an entire message
in the container.
copyable, that contains all the information needed to serialize, or all
of the information captured during parsing. More formally, given:
In addition to capturing the entirety of a message, we would like the message
container to contain enough customization points to permit the following:
allocator support, user-defined containers to represent header fields, and
user-defined containers to represent the body. And finally, because requests
and responses have slightly different information in the ['start-line], we
would like the containers for requests and responses to be represented by
different types.
* `m` is an instance of an HTTP message container
* `x` is a series of octets describing a valid HTTP message in
the serialized format decribed in __rfc7230__.
* `S(m)` is a serialization function which produces a series of octets
from a message container.
* `P(x)` is a parsing function which produces a message container from
a series of octets.
These relations are true:
* `S(m) == x`
* `P(S(m)) == m`
We would also like our message container to have customization points
permitting the following: full allocator support, user-defined containers
to represent header fields, and user-defined types and algorithms to
represent the body. And finally, because requests and responses have
different fields in the ['start-line], we would like the containers for
requests and responses to be represented by different types for function
overloading.
Here is our first attempt at declaring some message containers:
@ -57,21 +71,20 @@ struct response
]]
]
Here we have accomplished a few things. Request and response objects are
different types. The user can choose the container used to represent the
fields. And the user can choose the [*Body] type, which is a concept
defining not only the type of `body` member but also the algorithms used
to transfer information in and out of that member when performing
serialization and parsing.
These containers are capable of representing everything in the model
of HTTP requests and responses described in __rfc7230__. Request and
response objects are different types. The user can choose the container
used to represent the fields. And the user can choose the [*Body] type,
which is a concept defining not only the type of `body` member but also
the algorithms used to transfer information in and out of that member
when performing serialization and parsing.
However, a problem arises. How do we write a function which can accept
an object that is either a request or a response? As written, the only
ovious solution is to make the message a template type. Additional traits
obvious solution is to make the message a template type. Additional traits
classes would then be needed to make sure that the passed object has a
valid type which meets the requirements. We can avoid those complexities
by renaming the containers and making them partial specializations of a
single class, like this:
valid type which meets the requirements. Instead, bypass those complexities
by making each container a partial specialization of one class:
```
/// An HTTP message
template<bool isRequest, class Fields, class Body>
@ -90,7 +103,7 @@ struct message<true, Fields, Body>
/// An HTTP response
template<bool isRequest, class Fields, class Body>
struct response<false, Fields, Body>
struct message<false, Fields, Body>
{
int version;
int status;
@ -168,8 +181,8 @@ of the `message` class. But to achieve all our goals we will need to make
sure that there are enough constructor overloads to not only provide for
the special copy and move members if the instantiated types support it,
but also allow the fields container and body container to be constructed
with arbitrary variadic lists of parameters. This allows those members
to properly support allocators.
with arbitrary variadic lists of parameters. This allows the container
to fully support allocators.
The solution used in the library is to treat the message like a `std::pair`
for the purposes of construction, except that instead of `first` and `last`
@ -181,18 +194,16 @@ interested readers can view the declarations in the corresponding header
file.
There is now significant progress with our message container but a stumbling
block remains. The presence of `std::string` members is an obstacle to our
goal of making messages allocator-aware. One obvious solution is to add an
allocator to the template parameter list of the header and message classes,
and allow the string based members to construct with instances of those
allocators. This is unsatisfying because of the combinatorial explosion of
constructor variations needed to support the scheme. It also means that
request messages could have [*four] different allocators: two for the fields
and body, and two for the method and target strings. A better solution is
needed.
block remains. There is no way to control the allocator for the `std::string`
members. We could add an allocator to the template parameter list of the
header and message classes, use it for those strings. This is unsatisfying
because of the combinatorial explosion of constructor variations needed to
support the scheme. It also means that request messages could have [*four]
different allocators: two for the fields and body, and two for the method
and target strings. A better solution is needed.
To make allocators workable, we make a simple change to the interface and
then engineer a clever concession. First, the interface change:
To get around this we make a simple change to the interface and then
engineer a clever concession. First, the interface change:
```
/// An HTTP request header
template<class Fields>
@ -218,8 +229,8 @@ struct header<false, Fields>
};
```
This approach replaces public data members with traditional accessors
using non-owning references to string buffers. Now we make a concession:
The start-line data members are replaced traditional accessors using
non-owning references to string buffers. Now we make a concession:
management of the corresponding string is delegated to the [*Fields]
container, which can already be allocator aware and constructed with the
necessary allocator parameter via the provided constructor overloads for
@ -247,6 +258,7 @@ struct header<false, Fields>
}
Fields fields;
};
```
An advantage of this technique is that user-provided implementations of

View File

@ -120,7 +120,7 @@ about Beast and other HTTP libraries that have gone through formal review.
been optimized or designed with optimization in mind. The slow parts
of WebSocket processing have been optimized, and the HTTP parser design
is lifted from another extremely popular project which has performance
as a design goal (see https://github.com/h2o/picohttpparser).
as a design goal (see [@https://github.com/h2o/picohttpparser]).
From: [@http://www.boost.org/development/requirements.html]
@ -139,9 +139,10 @@ about Beast and other HTTP libraries that have gone through formal review.
believing they could perform an HTTP request on a URL or put up a
WebSocket client or server in a couple of lines of code. Where
would the core utilities go? Very likely it would step on the
owner of Boost.Asio's toes to put things in the Boost.Asio
repository; at the very least, it would create unrequested,
owner of Boost.Asio's toes to put things in the boost/asio
directory; at the very least, it would create unrequested,
additional work for the foreign repository.
"Beast" is sufficiently vague as to not suggest any particular
functionality, while acting as a memorable umbrella term for a
family of low level containers and algorithms. People in the know

View File

@ -65,7 +65,7 @@ explicit examples ;
xml doc
:
master.qbk
0_main.qbk
:
<location>temp
<include>$(broot)/tools/boostbook/dtd

View File

@ -1,333 +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)
]
[section:http Using HTTP]
[block '''
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
<member><link linkend="beast.http.message">Message</link></member>
<member><link linkend="beast.http.fields">Fields</link></member>
<member><link linkend="beast.http.body">Body</link></member>
<member><link linkend="beast.http.algorithms">Algorithms</link></member>
</simplelist></entry></row></tbody></tgroup></informaltable>
''']
Beast offers programmers simple and performant models of HTTP messages and
their associated operations including synchronous and asynchronous reading and
writing of messages and headers in the HTTP/1 wire format using Boost.Asio.
[note
The following documentation assumes familiarity with both Boost.Asio
and the HTTP protocol specification described in __rfc7230__. Sample code
and identifiers mentioned in this section are written as if the following
declarations are in effect:
```
#include <beast/core.hpp>
#include <beast/http.hpp>
using namespace beast;
using namespace beast::http;
```
]
[section:message Message]
The HTTP protocol defines the client and server roles: clients send messages
called requests and servers send back messages called responses. A HTTP message
(referred to hereafter as "message") contains request or response specific
attributes (contained in the "Start Line"), a series of zero or more name/value
pairs (collectively termed "Fields"), and an optional series of octets called
the message body which may be zero in length. The start line for a HTTP request
includes a string called the method, a string called the URL, and a version
number indicating HTTP/1.0 or HTTP/1.1. For a response, the start line contains
an integer status code and a string called the reason phrase. Alternatively, a
HTTP message can be viewed as two parts: a header, followed by a body.
[note
The Reason-Phrase is obsolete as of rfc7230.
]
The __header__ class template models the header for HTTP/1 and HTTP/2 messages.
This class template is a family of specializations, one for requests and one
for responses, depending on the [*`isRequest`] template value.
The [*`Fields`] template type determines the type of associative container
used to store the field values. The provided __basic_fields__ class template
and __fields__ type alias are typical choices for the [*`Fields`] type, but
advanced applications may supply user defined types which meet the requirements.
The __message__ class template models the header and optional body for HTTP/1
and HTTP/2 requests and responses. It is derived from the __header__ class
template with the same shared template parameters, and adds the `body` data
member. The message class template requires an additional template argument
type [*`Body`]. This type controls the container used to represent the body,
if any, as well as the algorithms needed to serialize and parse bodies of
that type.
This illustration shows the declarations and members of the __header__ and
__message__ class templates, as well as the inheritance relationship:
[$images/message.png [width 711px] [height 424px]]
For notational convenience, these template type aliases are provided which
supply typical choices for the [*`Fields`] type:
```
/// A typical HTTP request
template<class Body, class Fields = fields>
using request = message<true, Body, Fields>;
/// A typical HTTP response
template<class Body, class Fields = fields>
using response = message<false, Body, Fields>;
```
The code examples below show how to create and fill in request and response
objects:
[table Create Message
[[HTTP Request] [HTTP Response]]
[[
```
request<string_body> req;
req.version = 11; // HTTP/1.1
req.method("GET");
req.target("/index.htm");
req.fields.insert("Accept", "text/html");
req.fields.insert("Connection", "keep-alive");
req.fields.insert("User-Agent", "Beast");
```
][
```
response<string_body> res;
res.version = 11; // HTTP/1.1
res.status = 200;
res.reason("OK");
res.fields.insert("Server", "Beast");
res.fields.insert("Content-Length", 4);
res.body = "****";
```
]]]
In the serialized format of a HTTP message, the header is represented as a
series of text lines ending in CRLF (`"\r\n"`). The end of the header is
indicated by a line containing only CRLF. Here are examples of serialized HTTP
request and response objects. The objects created above will produce these
results when serialized. Note that only the response has a body:
[table Serialized HTTP Request and Response
[[HTTP Request] [HTTP Response]]
[[
```
GET /index.htm HTTP/1.1\r\n
Accept: text/html\r\n
Connection: keep-alive\r\n
User-Agent: Beast\r\n
\r\n
```
][
```
200 OK HTTP/1.1\r\n
Server: Beast\r\n
Content-Length: 4\r\n
\r\n
****
```
]]]
[endsect]
[section:fields Fields]
The [*`Fields`] type represents a container that can set or retrieve the
fields in a message. Beast provides the
[link beast.ref.http__basic_fields `basic_fields`] class which serves
the needs for most users. It supports modification and inspection of values.
The field names are not case-sensitive.
These statements change the values of the headers in the message passed:
```
template<class Body>
void set_fields(request<Body>& req)
{
if(! req.exists("User-Agent"))
req.insert("User-Agent", "myWebClient");
if(req.exists("Accept-Charset"))
req.erase("Accept-Charset");
req.replace("Accept", "text/plain");
}
```
User defined [*`Fields`] types are possible. To support serialization, the
type must meet the requirements of __FieldSequence__. To support parsing using
the provided parser, the type must provide the `insert` member function.
[endsect]
[section:body Body]
The message [*`Body`] template parameter controls both the type of the data
member of the resulting message object, and the algorithms used during parsing
and serialization. Beast provides three very common [*`Body`] types:
* [link beast.ref.http__string_body [*`string_body`:]] A body with a
`value_type` as `std::string`. Useful for quickly putting together a request
or response with simple text in the message body (such as an error message).
Has the same insertion complexity of `std::string`. This is the type of body
used in the examples:
```
response<string_body> res;
static_assert(std::is_same<decltype(res.body), std::string>::value);
res.body = "Here is the data you requested";
```
* [link beast.ref.http__dynamic_body [*`dynamic_body`:]] A body with a
`value_type` of [link beast.ref.multi_buffer `multi_buffer`]: an efficient storage
object which uses multiple octet arrays of varying lengths to represent data.
* [link beast.ref.http__buffer_body [*`buffer_body`:]] A write-only body
with a `value_type` representing a __ConstBufferSequence__. This special
body allows the caller to implement their own write loop for advanced
use-cases such as relaying.
* [link beast.ref.http__empty_body [*`empty_body`:]] A write-only body
with an empty `value_type` representing an HTTP message with no content
body.
[heading Advanced]
User-defined types are possible for the message body, where the type meets the
[link beast.ref.Body [*`Body`]] requirements. This simplified class declaration
shows the customization points available to user-defined body types:
[$images/body.png [width 510px] [height 210px]]
* [*`value_type`]: Determines the type of the
[link beast.ref.http__message.body `message::body`] member. If this
type defines default construction, move, copy, or swap, then message objects
declared with this [*Body] will have those operations defined.
* [*`body_writer`]: An optional nested type meeting the requirements of
[link beast.ref.BodyWriter [*BodyWriter]]. If present, this defines the
algorithm used to transfer parsed octets into buffers representing the
body.
* [*`body_reader`]: An optional nested type meeting the requirements of
[link beast.ref.BodyReader [*BodyReader]]. If present, this defines
the algorithm used to obtain buffers representing a body of this type.
The examples included with this library provide a [*Body] implementation that
serializing message bodies that come from a file.
[endsect]
[section:algorithms Algorithms]
Algorithms are provided to serialize and deserialize HTTP/1 messages on
streams.
* [link beast.ref.http__read [*read]]: Deserialize a HTTP/1 __header__ or __message__ from a stream.
* [link beast.ref.http__write [*write]]: Serialize a HTTP/1 __header__ or __message__ to a stream.
Asynchronous versions of these algorithms are also available:
* [link beast.ref.http__async_read [*async_read]]: Deserialize a HTTP/1 __header__ or __message__ asynchronously from a stream.
* [link beast.ref.http__async_write [*async_write]]: Serialize a HTTP/1 __header__ or __message__ asynchronously to a stream.
[heading Using Sockets]
The free function algorithms are modeled after Boost.Asio to send and receive
messages on TCP/IP sockets, SSL streams, or any object which meets the
Boost.Asio type requirements (__SyncReadStream__, __SyncWriteStream__,
__AsyncReadStream__, and __AsyncWriteStream__ depending on the types of
operations performed). To send messages synchronously, use one of the
[link beast.ref.http__write `write`] functions:
```
void send_request(boost::asio::ip::tcp::socket& sock)
{
request<string_body> req;
req.version = 11;
req.method("GET");
req.target("/index.html");
...
write(sock, req); // Throws exception on error
...
// Alternatively
boost::system::error:code ec;
write(sock, req, ec);
if(ec)
std::cerr << "error writing http message: " << ec.message();
}
```
An asynchronous interface is available:
```
void handle_write(boost::system::error_code);
...
request<string_body> req;
...
async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
```
When the implementation reads messages from a socket, it can read bytes lying
after the end of the message if they are present (the alternative is to read
a single byte at a time which is unsuitable for performance reasons). To
store and re-use these extra bytes on subsequent messages, the read interface
requires an additional parameter: a [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]
object. This example reads a message from the socket, with the extra bytes
stored in the `streambuf` parameter for use in a subsequent call to read:
```
boost::asio::streambuf sb;
...
response<string_body> res;
read(sock, sb, res); // Throws exception on error
...
// Alternatively
boost::system::error:code ec;
read(sock, sb, res, ec);
if(ec)
std::cerr << "error reading http message: " << ec.message();
```
As with the write function, an asynchronous interface is available. The
stream buffer parameter must remain valid until the completion handler is
called:
```
void handle_read(boost::system::error_code);
...
boost::asio::streambuf sb;
response<string_body> res;
...
async_read(sock, res, std::bind(&handle_read, std::placeholders::_1));
```
An alternative to using a `boost::asio::streambuf` is to use a
__multi_buffer__, which meets the requirements of __DynamicBuffer__ and
is optimized for performance:
```
void handle_read(boost::system::error_code);
...
beast::multi_buffer sb;
response<string_body> res;
read(sock, sb, res);
```
The `read` implementation can use any object meeting the requirements of
__DynamicBuffer__, allowing callers to define custom
memory management strategies used by the implementation.
[endsect]
[endsect]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

View File

@ -1,125 +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)
]
[library Beast
[quickbook 1.6]
[copyright 2013 - 2017 Vinnie Falco]
[purpose Networking Protocol Library]
[license
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])
]
[authors [Falco, Vinnie]]
[category template]
[category generic]
]
[template mdash[] '''&mdash; ''']
[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/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/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]]]
[def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]]
[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]]
[def __fields__ [link beast.ref.http__fields `fields`]]
[def __flat_buffer__ [link beast.ref.flat_buffer `flat_buffer`]]
[def __header__ [link beast.ref.http__header `header`]]
[def __message__ [link beast.ref.http__message `message`]]
[def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]]
[def __basic_multi_buffer__ [link beast.ref.basic_multi_buffer `basic_multi_buffer`]]
Beast is a cross-platform, header-only C++ library built on Boost.Asio that
provides implementations of the HTTP and WebSocket protocols.
[variablelist
[[
[link beast.overview Overview]
][
An introduction with features, requirements, and credits.
]]
[[
[link beast.core Core Concepts]
][
Library-wide concepts, classes, functions, and traits.
]]
[[
[link beast.http Using HTTP]
][
How to use Beast's HTTP interfaces in your applications.
]]
[[
[link beast.websocket Using WebSocket]
][
How to use Beast's WebSocket interfaces in your applications.
]]
[[
[link beast.example Examples]
][
Examples that illustrate the use of Beast in more complex applications.
]]
[[
[link beast.design Design]
][
Design rationale, answers to questions, library comparisons,
and special considerations for Boost Formal Review participants.
]]
[[
[link beast.ref Reference]
][
Detailed class and function reference.
]]
[[
[link beast.index Index]
][
Book-style text index of Beast documentation.
]]
]
[include overview.qbk]
[include core.qbk]
[include http.qbk]
[include websocket.qbk]
[include examples.qbk]
[include design.qbk]
[section:ref Reference]
[xinclude quickref.xml]
[include concept/Body.qbk]
[include concept/BodyReader.qbk]
[include concept/BodyWriter.qbk]
[include concept/BufferSequence.qbk]
[include concept/DynamicBuffer.qbk]
[include concept/Field.qbk]
[include concept/FieldSequence.qbk]
[include concept/Streams.qbk]
[include reference.qbk]
[endsect]
[xinclude index.xml]

View File

@ -1,145 +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)
]
[section:overview Introduction]
Beast is a header-only, cross-platform C++ library built on Boost.Asio and
parts of Boost, containing two modules implementing widely used network
protocols. Beast offers a universal HTTP message model, plus algorithms for
parsing and serializing HTTP/1 messages. Beast.WebSocket provides a complete
implementation of the WebSocket protocol. Their design achieves these goals:
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
used to build clients, servers, or both.
* [*Ease of Use.] HTTP messages are modeled using simple, readily
accessible objects. Functions and classes used to send and receive HTTP
or WebSocket messages are designed to resemble Boost.Asio as closely as
possible. Users familiar with Boost.Asio will be immediately comfortable
using this library.
* [*Flexibility.] Interfaces do not mandate specific implementation
strategies; important decisions such as buffer or thread management are
left to users of the library.
* [*Performance.] The implementation performs competitively, making it a
realistic choice for building high performance network servers.
* [*Scalability.] Development of network applications that scale to thousands
of concurrent connections is possible with the implementation.
* [*Basis for further abstraction.] The interfaces facilitate the
development of other libraries that provide higher levels of abstraction.
[heading Requirements]
Beast requires:
* [*C++11.] A minimum of C++11 is needed.
* [*Boost.] Beast is built on Boost, especially Boost.Asio.
* [*OpenSSL.] If using TLS/Secure sockets (optional).
[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
program successfully, you'll need to add the Boost.System library to link
with. If you use coroutines you'll also need the Boost.Coroutine library.
Please visit the Boost documentation for instructions on how to do this for
your particular build system.
There are no provisions for enabling Beast to compile using the stand-alone
version of Asio. Beast relies on other parts of Boost in addition to Asio.
There are no immediate plans to offer a version of Beast that works with
the stand-alone Asio.
[heading Audience]
Beast is aimed at network programmers who have know some Boost.Asio. While
experience is not strictly necessary, the documentation and interfaces assume
a reasonable grasp of how Asio works. In particular, users who wish to write
asynchronous programs with Beast should already have knowledge and experience
of Asio's asynchronous interfaces and general style of asynchronous programming
using callbacks or coroutines.
The supplied WebSocket and HTTP interfaces are low-level. The library does not
provide out of the box solutions for implementing clients or servers. For
example, users must provide their own code to make connections, handle
timeouts, reconnect a dropped connection, accept incoming connections, or
manage connection resources on a server.
Beast's HTTP interfaces are similarly low level, providing functionality
only for modelling HTTP messages and reading and writing them to sockets or
streams. Higher level functions such as HTTP Basic Authentication,
mime/multipart encoding, cookies, automatic handling of redirects, gzipped
transfer encodings, caching, or proxying (to name a few) are not directly
provided, but nothing stops users from creating these features using
Beast's HTTP message types.
Instead, the library is intended to be a building block for creating higher
level libraries. It implements just enough of the HTTP and WebSocket protocol
to allow users to create useful objects and algorithms which may then be
composed to produce useful applications. It is the desire of the author that
this library will become the foundation for a new generation of network
libraries.
[heading Motivation]
Beast is built on Boost.Asio. A proposal to add networking functionality to the
C++ standard library, based on Boost.Asio, is under consideration by the
committee and on track for standardization. Since the final approved networking
interface for the C++ standard library will likely closely resemble the current
interface of Boost.Asio, the choice of Boost.Asio as the network transport
layer is prudent.
The HTTP protocol is pervasive in network applications. As C++ is a logical
choice for high performance network servers, there is great utility in solid
building blocks for manipulating, sending, and receiving HTTP messages
compliant with the Hypertext Transfer Protocol and the supplements that
follow. Unfortunately reliable implementations or industry standards do not
exist in C++. The development of higher level libraries is stymied by the
lack of a common set of low-level algorithms and types for interacting with
the HTTP protocol.
Today's web applications increasingly rely on alternatives to standard HTTP
to achieve performance and/or responsiveness. While WebSocket implementations
are widely available in common web development languages such as Javascript,
good implementations in C++ are scarce. A survey of existing C++ WebSocket
solutions reveals interfaces which lack symmetry, impose performance penalties,
and needlessly restrict implementation strategies.
Beast.WebSocket takes advantage of Boost.Asio's extensible asynchronous
model, handler allocation, and handler invocation hooks. Calls to
Beast.WebSocket asynchronous initiation functions allow callers the choice
of using a completion handler, stackful or stackless coroutines, futures,
or user defined customizations (for example, Boost.Fiber). The
implementation uses handler invocation hooks (__asio_handler_invoke__),
providing execution guarantees on composed operations in a manner identical
to Boost.Asio. The implementation also uses handler allocation hooks
(__asio_handler_allocate__) when allocating memory internally for composed
operations.
There is no need for inheritance or virtual members in a
[link beast.ref.websocket__stream `websocket::stream`].
All operations are templated and transparent to the compiler, allowing for
maximum inlining and optimization.
[heading Credits]
Boost.Asio is the inspiration behind which all of the interfaces and
implementation strategies are built. Some parts of the documentation are
written to closely resemble the wording and presentation of Boost.Asio
documentation. Credit goes to Christopher Kohlhoff for the wonderful
Asio library and the ideas upon which Beast is built.
Beast would not be possible without the considerable time and patience
contributed by David Schwartz, Edward Hennis, Howard Hinnant, Miguel Portilla,
Nikolaos Bougalis, Scott Determan, Scott Schurr, and Ripple Labs for
supporting its early development. Also thanks to Agustín Bergé, Glen Fernandes
and Peter Dimov for putting up with my endless C++ questions on Slack.
[endsect]

View File

@ -151,17 +151,20 @@ operator()(beast::error_code ec, std::size_t bytes_transferred)
case 1:
// write everything back
p.step = 2;
return boost::asio::async_write(p.stream, p.buffer.data(), std::move(*this));
// async_read_until could have read past the newline,
// use buffer_prefix to make sure we only send one line
return boost::asio::async_write(p.stream,
beast::buffer_prefix(bytes_transferred, p.buffer.data()), std::move(*this));
case 2:
p.buffer.consume(bytes_transferred);
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.
// is destroyed before the handler is invoked.
//
p_.invoke(ec);
return;
@ -174,8 +177,7 @@ 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.
// to cause a friendly message instead of an error novel.
//
static_assert(beast::is_async_stream<AsyncStream>::value,
"AsyncStream requirements not met");
@ -187,7 +189,7 @@ async_echo(AsyncStream& stream, CompletionToken&& token)
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
// call followed by invocation of operator(). We use handler_type
// to convert the completion token into the correct handler type,
// allowing user defined specializations of the async result template
// to take effect.
@ -213,14 +215,12 @@ int main()
// 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);
}
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)
{

View File

@ -26,7 +26,7 @@ namespace http {
/** A container for storing HTTP header fields.
This container is designed to store the field value pairs that make
up the fields and trailers in a HTTP message. Objects of this type
up the fields and trailers in an HTTP message. Objects of this type
are iterable, with each element holding the field name and field
value.

View File

@ -20,7 +20,7 @@
namespace beast {
namespace http {
/** A container for a HTTP request or response header.
/** A container for an HTTP request or response header.
A header includes the Start Line and Fields.
@ -160,7 +160,7 @@ struct header<true, Fields>
}
};
/** A container for a HTTP request or response header.
/** A container for an HTTP request or response header.
A header includes the Start Line and Fields.
@ -510,7 +510,7 @@ enum class connection
upgrade
};
/** Prepare a HTTP message.
/** Prepare an HTTP message.
This function will adjust the Content-Length, Transfer-Encoding,
and Connection fields of the message based on the properties of

View File

@ -208,7 +208,7 @@ async_read_some(
//------------------------------------------------------------------------------
/** Read an HTTP/1 message from a stream.
/** Read into an HTTP/1 parser from a stream.
This function synchronously reads from a stream and passes
data to the specified parser. The call will block until one
@ -252,7 +252,7 @@ read(
DynamicBuffer& buffer,
basic_parser<isRequest, isDirect, Derived>& parser);
/** Read an HTTP/1 message from a stream.
/** Read into an HTTP/1 parser from a stream.
This function synchronously reads from a stream and passes
data to the specified parser. The call will block until one
@ -297,7 +297,7 @@ read(
basic_parser<isRequest, isDirect, Derived>& parser,
error_code& ec);
/** Start an asynchronous operation to read an HTTP/1 message from a stream.
/** Read into an HTTP/1 parser asynchronously from a stream.
This function is used to asynchronously read from a stream and
pass the data to the specified parser. The function call always
@ -406,7 +406,7 @@ read(
DynamicBuffer& buffer,
message<isRequest, Body, Fields>& msg);
/** Read a HTTP/1 message from a stream.
/** Read an HTTP/1 message from a stream.
This function is used to synchronously read a message from
a stream. The call blocks until one of the following conditions
@ -453,7 +453,7 @@ read(
message<isRequest, Body, Fields>& msg,
error_code& ec);
/** Read a HTTP/1 message asynchronously from a stream.
/** Read an HTTP/1 message asynchronously from a stream.
This function is used to asynchronously read a message from
a stream. The function call always returns immediately. The

View File

@ -15,9 +15,9 @@
namespace beast {
namespace http {
/** A list of parameters in a HTTP extension field value.
/** A list of parameters in an HTTP extension field value.
This container allows iteration of the parameter list in a HTTP
This container allows iteration of the parameter list in an HTTP
extension. The parameter list is a series of name/value pairs
with each pair starting with a semicolon. The value is optional.
@ -99,7 +99,7 @@ public:
/** A list of extensions in a comma separated HTTP field value.
This container allows iteration of the extensions in a HTTP
This container allows iteration of the extensions in an HTTP
field value. The extension list is a comma separated list of
token parameter list pairs.

View File

@ -201,8 +201,8 @@ class serializer
public:
/** Constructor
@param msg The message to serialize. The message object
must remain valid for the lifetime of the write stream.
@param msg The message to serialize, which must
remain valid for the lifetime of the serializer.
@param decorator An optional decorator to use.
@ -213,7 +213,7 @@ public:
Decorator const& decorator = Decorator{},
Allocator const& alloc = Allocator{});
/** Returns `true` if we will pause after writing the header.
/** Returns `true` if we will pause after writing the complete header.
*/
bool
split() const
@ -227,8 +227,8 @@ public:
write only the octets corresponding to the serialized header
first. If the header has already been written, this function
will have no effect on output. This function should be called
before any writes take place, otherwise the behavior is
undefined.
before retrieving any buffers using @ref get, otherwise the
behavior is undefined.
*/
void
split(bool v)
@ -238,9 +238,8 @@ public:
/** Return `true` if serialization of the header is complete.
This function indicates whether or not all octets
corresponding to the serialized representation of the
header have been successfully delivered to the stream.
This function indicates whether or not all buffers containing
serialized header octets have been retrieved.
*/
bool
is_header_done() const
@ -248,11 +247,11 @@ public:
return header_done_;
}
/** Return `true` if serialization is complete
/** Return `true` if serialization is complete.
The operation is complete when all octets corresponding
to the serialized representation of the message have been
successfully delivered to the stream.
successfully retrieved.
*/
bool
is_done() const
@ -262,9 +261,11 @@ public:
/** Return `true` if Connection: close semantic is indicated.
After serialization is complete, if there is an
underlying network connection then it should be closed if
this function returns `true`.
Depending on the contents of the message, the end of
the body may be indicated by the end of file. In order
for the recipient (if any) to receive a complete message,
the underlying network connection must be closed when this
function returns `true`.
*/
bool
needs_close() const
@ -288,7 +289,8 @@ public:
@param visit The function to call. The equivalent function
signature of this object must be:
@code template<class ConstBufferSequence>
@code
template<class ConstBufferSequence>
void visit(error_code&, ConstBufferSequence const&);
@endcode
The function is not copied, if no error occurs it will be

View File

@ -132,7 +132,7 @@ async_write_some(AsyncWriteStream& stream, serializer<
isRequest, Body, Fields, Decorator, Allocator>& sr,
WriteHandler&& handler);
/** Write a HTTP/1 message to a stream.
/** Write an HTTP/1 message to a stream.
This function is used to write a message to a stream. The call
will block until one of the following conditions is true:
@ -163,7 +163,7 @@ void
write(SyncWriteStream& stream,
message<isRequest, Body, Fields> const& msg);
/** Write a HTTP/1 message on a stream.
/** Write an HTTP/1 message to a stream.
This function is used to write a message to a stream. The call
will block until one of the following conditions is true:
@ -195,7 +195,7 @@ write(SyncWriteStream& stream,
message<isRequest, Body, Fields> const& msg,
error_code& ec);
/** Write a HTTP/1 message asynchronously to a stream.
/** Write an HTTP/1 message asynchronously to a stream.
This function is used to asynchronously write a message to
a stream. The function call always returns immediately. The
@ -247,7 +247,7 @@ async_write(AsyncWriteStream& stream,
//------------------------------------------------------------------------------
/** Serialize a HTTP/1 header to a `std::ostream`.
/** Serialize an HTTP/1 header to a `std::ostream`.
The function converts the header to its HTTP/1 serialized
representation and stores the result in the output stream.
@ -261,7 +261,7 @@ std::ostream&
operator<<(std::ostream& os,
header<isRequest, Fields> const& msg);
/** Serialize a HTTP/1 message to a `std::ostream`.
/** Serialize an HTTP/1 message to a `std::ostream`.
The function converts the message to its HTTP/1 serialized
representation and stores the result in the output stream.