mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 05:17:26 +02:00
Documentation work
This commit is contained in:
142
doc/0_main.qbk
Normal file
142
doc/0_main.qbk
Normal 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
126
doc/1_overview.qbk
Normal 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]
|
@ -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
83
doc/3_0_http.qbk
Normal 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
144
doc/3_1_primer.qbk
Normal 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
173
doc/3_2_message.qbk
Normal 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
140
doc/3_3_streams.qbk
Normal 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
339
doc/4_0_adv_http.qbk
Normal 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]
|
@ -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]
|
@ -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
|
@ -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
|
@ -65,7 +65,7 @@ explicit examples ;
|
||||
|
||||
xml doc
|
||||
:
|
||||
master.qbk
|
||||
0_main.qbk
|
||||
:
|
||||
<location>temp
|
||||
<include>$(broot)/tools/boostbook/dtd
|
333
doc/http.qbk
333
doc/http.qbk
@ -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.
125
doc/master.qbk
125
doc/master.qbk
@ -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[] '''— ''']
|
||||
[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]
|
145
doc/overview.qbk
145
doc/overview.qbk
@ -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]
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
Reference in New Issue
Block a user