mirror of
https://github.com/boostorg/beast.git
synced 2025-08-01 05:44:38 +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 '''
|
[block '''
|
||||||
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
<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.asio">Working With Asio</link></member>
|
||||||
<member><link linkend="beast.core.dynamic_buffer">DynamicBuffer</link></member>
|
<member><link linkend="beast.core.streams">Stream Concepts</link></member>
|
||||||
<member><link linkend="beast.core.algorithms">Buffer Algorithms</link></member>
|
<member><link linkend="beast.core.buffers">Buffer Concepts</link></member>
|
||||||
<member><link linkend="beast.core.async">Asynchronous Model</link></member>
|
<member><link linkend="beast.core.async">Asynchronous Utilities</link></member>
|
||||||
<member><link linkend="beast.core.tutorial">Tutorial</link></member>
|
<member><link linkend="beast.core.tutorial">Asynchronous Composed Operation Tutorial</link></member>
|
||||||
</simplelist></entry></row></tbody></tgroup></informaltable>
|
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||||
''']
|
''']
|
||||||
|
|
||||||
In addition to network protocols, Beast provides users with robust concepts,
|
A goal of the library is expose implementation primitives in order that
|
||||||
implementations, and algorithms which can be used to design higher level
|
users may build their own library-like components. These primitives include
|
||||||
abstractions that interoperate with Boost.Asio. In the sections that follow
|
traits, buffers, buffer algorithms, and helpers for implementing asynchronous
|
||||||
are descriptions of these concepts, followed by algorithms using the concepts,
|
operations compatible with __Asio__ and described in __N3747__. This section
|
||||||
and then concluding with a tutorial on developing composed asynchronous
|
lists these facilities by group, with descriptions.
|
||||||
operations which are compatible with the Extensible Asynchronous Model provided
|
|
||||||
in Boost.Asio, __N3747__, and __N4588__.
|
[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
|
Beast does not manage sockets, make outgoing connections, accept incoming
|
||||||
concept checks on parameters, preventing undefined or illegal use. These trait
|
connections, or handle any aspect of connection management. In order to
|
||||||
traits are used in the implementation of the library and part of its public
|
invoke library algorithms it is necessary to first have a connected socket,
|
||||||
interface so users may build on the library using the same features. Use of
|
SSL stream, or other object which meets the required stream concepts. This
|
||||||
concept checks benefit users by providing accurate, concise compilation error
|
example is provided as a reminder of how to work with sockets:
|
||||||
diagnostics.
|
```
|
||||||
|
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]]
|
[[Name][Description]]
|
||||||
[[
|
[[
|
||||||
[link beast.ref.get_lowest_layer `get_lowest_layer`]
|
[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`]
|
[link beast.ref.has_get_io_service `has_get_io_service`]
|
||||||
][
|
][
|
||||||
Determine if the `get_io_service` member function is present with the
|
Determine if the `get_io_service` member function is present,
|
||||||
correct signature.
|
and returns an __io_service__.
|
||||||
]]
|
]]
|
||||||
[[
|
[[
|
||||||
[link beast.ref.is_async_read_stream `is_async_read_stream`]
|
[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__,
|
Determine if a type meets the requirements of __CompletionHandler__,
|
||||||
and is callable with a specified signature.
|
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`]
|
[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
|
[table Buffer Type Checks
|
||||||
concept called a __DynamicBuffer__. Instances of this concept define
|
[[Name][Description]]
|
||||||
an output area expressed as a __MutableBufferSequence__ and an input area
|
[[
|
||||||
expressed as a __ConstBufferSequence__. Octets may be moved from the output
|
[link beast.ref.is_const_buffer_sequence `is_const_buffer_sequence`]
|
||||||
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
|
Determine if a type meets the requirements of __ConstBufferSequence__.
|
||||||
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
|
[link beast.ref.is_mutable_buffer_sequence `is_mutable_buffer_sequence`]
|
||||||
dynamic buffer concept using various strategies:
|
][
|
||||||
|
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]]
|
[[Name][Description]]
|
||||||
[[
|
[[
|
||||||
[link beast.ref.buffers_adapter `buffers_adapter`]
|
[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.
|
||||||
|
|
||||||
|
[table Buffer Algorithms
|
||||||
|
|
||||||
[section:algorithms Buffer Algorithms]
|
|
||||||
|
|
||||||
Beast provides a collection of algorithms to work on __ConstBufferSequence__
|
|
||||||
or __MutableBufferSequence__ objects. These algorithms allow composition of
|
|
||||||
new algorithms which work on any objects meeting the buffer sequence
|
|
||||||
requirements, in an efficient way: no memory allocations are performed;
|
|
||||||
instead, the algorithms implement lightweight iterators over the existing
|
|
||||||
underlying memory, whose lifetime is retained by the caller.
|
|
||||||
|
|
||||||
[table Buffer algorithms
|
|
||||||
[[Name][Description]]
|
[[Name][Description]]
|
||||||
[[
|
[[
|
||||||
[link beast.ref.buffer_cat `buffer_cat`]
|
[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`]
|
[link beast.ref.buffer_cat `buffers_view`]
|
||||||
][
|
][
|
||||||
This class represents a buffer sequence which represents the concatenation
|
This class represents the buffer sequence formed by concatenating
|
||||||
of two or more buffer sequences. This is type of object returned by
|
two or more buffer sequences. This is type of object returned by
|
||||||
[link beast.ref.buffer_cat `buffer_cat`].
|
[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
|
Asynchronous operations are started by calling a free function or member
|
||||||
function known as an ['asynchronous initiation function]. The initiation
|
function known as an ['asynchronous initiation function]. The initiation
|
||||||
function accepts parameters specific to the operation as well as a "completion
|
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
|
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
|
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
|
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
|
and coroutines respectively. This system, where the return value and method of
|
||||||
indicating completion may be customize at the call site of the asynchronous
|
indicating completion may be customize at the call site of the asynchronous
|
||||||
@@ -229,21 +375,22 @@ in __N3747__, and built-in to __N4588__.
|
|||||||
|
|
||||||
[note
|
[note
|
||||||
A full explanation of completion handlers, the Extensible Asynchronous
|
A full explanation of completion handlers, the Extensible Asynchronous
|
||||||
Model and how Boost.Asio's asynchronous interfaces are used is beyond the
|
Model and how these asynchronous interfaces are used is beyond the
|
||||||
scope of this document. Readers should consult the Boost.Asio documentation
|
scope of this document. Interested readers should consult the
|
||||||
for a comprehensive treatment.
|
__Asio__ documentation.
|
||||||
]
|
]
|
||||||
|
|
||||||
Since Beast is low level, authors of libraries may wish to create higher level
|
Since the interfaces provided here are low level, authors of libraries
|
||||||
interfaces using the primitives found in this library. Non-trivial applications
|
may wish to create higher level interfaces using the primitives found
|
||||||
will want to provide their own asychronous initiation functions which perform
|
in this library. Non-trivial applications will want to provide their own
|
||||||
a series of other, intermediate asynchronous operations before invoking the
|
asychronous initiation functions which perform a series of other,
|
||||||
final completion handler. The set of intermediate actions produced by calling
|
intermediate asynchronous operations before invoking the final completion
|
||||||
an initiation function is known as a ['composed operation]. To ensure full
|
handler. The set of intermediate actions produced by calling an initiation
|
||||||
interoperability and well-defined behavior, Boost.Asio imposes requirements on
|
function is known as a ['composed operation]. To ensure full interoperability
|
||||||
the implementation of composed operations. Beast provides a number of useful
|
and well-defined behavior, __Asio__ imposes requirements on the implementation
|
||||||
classes and macros to facilitate the development of composed operations and
|
of composed operations. A number of useful classes and macros to facilitate
|
||||||
the associated asynchronous initiation functions used to launch them.
|
the development of composed operations and the associated asynchronous
|
||||||
|
initiation functions used to launch them are available:
|
||||||
|
|
||||||
[table Asynchronous Helpers
|
[table Asynchronous Helpers
|
||||||
[[Name][Description]]
|
[[Name][Description]]
|
||||||
@@ -306,11 +453,9 @@ the associated asynchronous initiation functions used to launch them.
|
|||||||
]]
|
]]
|
||||||
]
|
]
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
[section:tutorial Asynchronous Composed Operation Tutorial]
|
||||||
[section:tutorial Tutorial]
|
|
||||||
|
|
||||||
To illustrate the usage of the asynchronous helpers in the core section of
|
To illustrate the usage of the asynchronous helpers in the core section of
|
||||||
this library, we will develop a simple asynchronous composed operation called
|
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)
|
async_echo(AsyncStream& stream, CompletionToken&& token)
|
||||||
{
|
{
|
||||||
// Make sure stream meets the requirements. We use static_assert
|
// Make sure stream meets the requirements. We use static_assert
|
||||||
// instead of letting the compiler generate several pages of hard
|
// to cause a friendly message instead of an error novel.
|
||||||
// to read error messages.
|
|
||||||
//
|
//
|
||||||
static_assert(beast::is_async_stream<AsyncStream>::value,
|
static_assert(beast::is_async_stream<AsyncStream>::value,
|
||||||
"AsyncStream requirements not met");
|
"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};
|
beast::async_completion<CompletionToken, void(beast::error_code)> init{token};
|
||||||
|
|
||||||
// Create the composed operation and launch it. This is a constructor
|
// 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,
|
// to convert the completion token into the correct handler type,
|
||||||
// allowing user defined specializations of the async result template
|
// allowing user defined specializations of the async result template
|
||||||
// to take effect.
|
// 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
|
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
|
a somewhat non-trivial structure. This structure is necessary to meet the
|
||||||
stringent requirements of composed operations (described in more detail in
|
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.
|
explaining them in depth.
|
||||||
|
|
||||||
First we will create boilerplate which is present in all composed operations
|
First we will create boilerplate which is present in all composed operations
|
||||||
@@ -548,17 +692,20 @@ this echo operation:
|
|||||||
case 1:
|
case 1:
|
||||||
// write everything back
|
// write everything back
|
||||||
p.step = 2;
|
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:
|
case 2:
|
||||||
|
p.buffer.consume(bytes_transferred);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke the final handler. If we wanted to pass any arguments
|
// Invoke the final handler. If we wanted to pass any arguments
|
||||||
// which come from our state, they would have to be moved to the
|
// which come from our state, they would have to be moved to the
|
||||||
// stack first, since the `handler_ptr` guarantees that the state
|
// stack first, since the `handler_ptr` guarantees that the state
|
||||||
// is destroyed before
|
// is destroyed before the handler is invoked.
|
||||||
// the handler is invoked.
|
|
||||||
//
|
//
|
||||||
p_.invoke(ec);
|
p_.invoke(ec);
|
||||||
return;
|
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.
|
* 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).
|
* Role-symmetric interfaces; client and server the same (or close to it).
|
||||||
|
|
||||||
@@ -34,8 +34,8 @@ libraries:
|
|||||||
managing flow control.
|
managing flow control.
|
||||||
|
|
||||||
Beast uses the __DynamicBuffer__ concept presented in the Networking TS
|
Beast uses the __DynamicBuffer__ concept presented in the Networking TS
|
||||||
(__N4588__), and relies heavily on the Boost.Asio __ConstBufferSequence__
|
(__N4588__), and relies heavily on the __ConstBufferSequence__ and
|
||||||
and __MutableBufferSequence__ concepts for passing buffers to functions.
|
__MutableBufferSequence__ concepts for passing buffers to functions.
|
||||||
The authors have found the dynamic buffer and buffer sequence interfaces to
|
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
|
be optimal for interacting with Asio, and for other tasks such as incremental
|
||||||
parsing of data in buffers (for example, parsing websocket frames stored
|
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.
|
* Allow for customizations, if the user needs it.
|
||||||
|
|
||||||
[include design/http_message.qbk]
|
[include 7_1_http_message.qbk]
|
||||||
[include design/http_comparison.qbk]
|
[include 7_2_http_comparison.qbk]
|
||||||
[include design/websocket_zaphoyd.qbk]
|
[include 7_3_websocket_zaphoyd.qbk]
|
||||||
[include design/review.qbk]
|
[include 7_4_review.qbk]
|
||||||
|
|
||||||
[endsect]
|
[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
|
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
|
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
|
is to create a container with value semantics, possibly movable and/or
|
||||||
copyable, that completely describes the message. More formally, the container
|
copyable, that contains all the information needed to serialize, or all
|
||||||
has all of the information necessary for the serialization algorithms to
|
of the information captured during parsing. More formally, given:
|
||||||
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.
|
|
||||||
|
|
||||||
In addition to capturing the entirety of a message, we would like the message
|
* `m` is an instance of an HTTP message container
|
||||||
container to contain enough customization points to permit the following:
|
|
||||||
allocator support, user-defined containers to represent header fields, and
|
* `x` is a series of octets describing a valid HTTP message in
|
||||||
user-defined containers to represent the body. And finally, because requests
|
the serialized format decribed in __rfc7230__.
|
||||||
and responses have slightly different information in the ['start-line], we
|
|
||||||
would like the containers for requests and responses to be represented by
|
* `S(m)` is a serialization function which produces a series of octets
|
||||||
different types.
|
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:
|
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
|
These containers are capable of representing everything in the model
|
||||||
different types. The user can choose the container used to represent the
|
of HTTP requests and responses described in __rfc7230__. Request and
|
||||||
fields. And the user can choose the [*Body] type, which is a concept
|
response objects are different types. The user can choose the container
|
||||||
defining not only the type of `body` member but also the algorithms used
|
used to represent the fields. And the user can choose the [*Body] type,
|
||||||
to transfer information in and out of that member when performing
|
which is a concept defining not only the type of `body` member but also
|
||||||
serialization and parsing.
|
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
|
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
|
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
|
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
|
valid type which meets the requirements. Instead, bypass those complexities
|
||||||
by renaming the containers and making them partial specializations of a
|
by making each container a partial specialization of one class:
|
||||||
single class, like this:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
/// An HTTP message
|
/// An HTTP message
|
||||||
template<bool isRequest, class Fields, class Body>
|
template<bool isRequest, class Fields, class Body>
|
||||||
@@ -90,7 +103,7 @@ struct message<true, Fields, Body>
|
|||||||
|
|
||||||
/// An HTTP response
|
/// An HTTP response
|
||||||
template<bool isRequest, class Fields, class Body>
|
template<bool isRequest, class Fields, class Body>
|
||||||
struct response<false, Fields, Body>
|
struct message<false, Fields, Body>
|
||||||
{
|
{
|
||||||
int version;
|
int version;
|
||||||
int status;
|
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
|
sure that there are enough constructor overloads to not only provide for
|
||||||
the special copy and move members if the instantiated types support it,
|
the special copy and move members if the instantiated types support it,
|
||||||
but also allow the fields container and body container to be constructed
|
but also allow the fields container and body container to be constructed
|
||||||
with arbitrary variadic lists of parameters. This allows those members
|
with arbitrary variadic lists of parameters. This allows the container
|
||||||
to properly support allocators.
|
to fully support allocators.
|
||||||
|
|
||||||
The solution used in the library is to treat the message like a `std::pair`
|
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`
|
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.
|
file.
|
||||||
|
|
||||||
There is now significant progress with our message container but a stumbling
|
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
|
block remains. There is no way to control the allocator for the `std::string`
|
||||||
goal of making messages allocator-aware. One obvious solution is to add an
|
members. We could add an allocator to the template parameter list of the
|
||||||
allocator to the template parameter list of the header and message classes,
|
header and message classes, use it for those strings. This is unsatisfying
|
||||||
and allow the string based members to construct with instances of those
|
because of the combinatorial explosion of constructor variations needed to
|
||||||
allocators. This is unsatisfying because of the combinatorial explosion of
|
support the scheme. It also means that request messages could have [*four]
|
||||||
constructor variations needed to support the scheme. It also means that
|
different allocators: two for the fields and body, and two for the method
|
||||||
request messages could have [*four] different allocators: two for the fields
|
and target strings. A better solution is needed.
|
||||||
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
|
To get around this we make a simple change to the interface and then
|
||||||
then engineer a clever concession. First, the interface change:
|
engineer a clever concession. First, the interface change:
|
||||||
```
|
```
|
||||||
/// An HTTP request header
|
/// An HTTP request header
|
||||||
template<class Fields>
|
template<class Fields>
|
||||||
@@ -218,8 +229,8 @@ struct header<false, Fields>
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
This approach replaces public data members with traditional accessors
|
The start-line data members are replaced traditional accessors using
|
||||||
using non-owning references to string buffers. Now we make a concession:
|
non-owning references to string buffers. Now we make a concession:
|
||||||
management of the corresponding string is delegated to the [*Fields]
|
management of the corresponding string is delegated to the [*Fields]
|
||||||
container, which can already be allocator aware and constructed with the
|
container, which can already be allocator aware and constructed with the
|
||||||
necessary allocator parameter via the provided constructor overloads for
|
necessary allocator parameter via the provided constructor overloads for
|
||||||
@@ -247,6 +258,7 @@ struct header<false, Fields>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Fields fields;
|
Fields fields;
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
An advantage of this technique is that user-provided implementations of
|
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
|
been optimized or designed with optimization in mind. The slow parts
|
||||||
of WebSocket processing have been optimized, and the HTTP parser design
|
of WebSocket processing have been optimized, and the HTTP parser design
|
||||||
is lifted from another extremely popular project which has performance
|
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]
|
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
|
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
|
WebSocket client or server in a couple of lines of code. Where
|
||||||
would the core utilities go? Very likely it would step on the
|
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
|
owner of Boost.Asio's toes to put things in the boost/asio
|
||||||
repository; at the very least, it would create unrequested,
|
directory; at the very least, it would create unrequested,
|
||||||
additional work for the foreign repository.
|
additional work for the foreign repository.
|
||||||
|
|
||||||
"Beast" is sufficiently vague as to not suggest any particular
|
"Beast" is sufficiently vague as to not suggest any particular
|
||||||
functionality, while acting as a memorable umbrella term for a
|
functionality, while acting as a memorable umbrella term for a
|
||||||
family of low level containers and algorithms. People in the know
|
family of low level containers and algorithms. People in the know
|
@@ -65,7 +65,7 @@ explicit examples ;
|
|||||||
|
|
||||||
xml doc
|
xml doc
|
||||||
:
|
:
|
||||||
master.qbk
|
0_main.qbk
|
||||||
:
|
:
|
||||||
<location>temp
|
<location>temp
|
||||||
<include>$(broot)/tools/boostbook/dtd
|
<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:
|
case 1:
|
||||||
// write everything back
|
// write everything back
|
||||||
p.step = 2;
|
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:
|
case 2:
|
||||||
|
p.buffer.consume(bytes_transferred);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke the final handler. If we wanted to pass any arguments
|
// Invoke the final handler. If we wanted to pass any arguments
|
||||||
// which come from our state, they would have to be moved to the
|
// which come from our state, they would have to be moved to the
|
||||||
// stack first, since the `handler_ptr` guarantees that the state
|
// stack first, since the `handler_ptr` guarantees that the state
|
||||||
// is destroyed before
|
// is destroyed before the handler is invoked.
|
||||||
// the handler is invoked.
|
|
||||||
//
|
//
|
||||||
p_.invoke(ec);
|
p_.invoke(ec);
|
||||||
return;
|
return;
|
||||||
@@ -174,8 +177,7 @@ beast::async_return_type<CompletionToken, void(beast::error_code)>
|
|||||||
async_echo(AsyncStream& stream, CompletionToken&& token)
|
async_echo(AsyncStream& stream, CompletionToken&& token)
|
||||||
{
|
{
|
||||||
// Make sure stream meets the requirements. We use static_assert
|
// Make sure stream meets the requirements. We use static_assert
|
||||||
// instead of letting the compiler generate several pages of hard
|
// to cause a friendly message instead of an error novel.
|
||||||
// to read error messages.
|
|
||||||
//
|
//
|
||||||
static_assert(beast::is_async_stream<AsyncStream>::value,
|
static_assert(beast::is_async_stream<AsyncStream>::value,
|
||||||
"AsyncStream requirements not met");
|
"AsyncStream requirements not met");
|
||||||
@@ -187,7 +189,7 @@ async_echo(AsyncStream& stream, CompletionToken&& token)
|
|||||||
beast::async_completion<CompletionToken, void(beast::error_code)> init{token};
|
beast::async_completion<CompletionToken, void(beast::error_code)> init{token};
|
||||||
|
|
||||||
// Create the composed operation and launch it. This is a constructor
|
// 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,
|
// to convert the completion token into the correct handler type,
|
||||||
// allowing user defined specializations of the async result template
|
// allowing user defined specializations of the async result template
|
||||||
// to take effect.
|
// to take effect.
|
||||||
@@ -213,14 +215,12 @@ int main()
|
|||||||
// the echo, and then shut everything down and exit.
|
// the echo, and then shut everything down and exit.
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
socket_type sock{ios};
|
socket_type sock{ios};
|
||||||
{
|
boost::asio::ip::tcp::acceptor acceptor{ios};
|
||||||
boost::asio::ip::tcp::acceptor acceptor{ios};
|
endpoint_type ep{address_type::from_string("0.0.0.0"), 0};
|
||||||
endpoint_type ep{address_type::from_string("0.0.0.0"), 0};
|
acceptor.open(ep.protocol());
|
||||||
acceptor.open(ep.protocol());
|
acceptor.bind(ep);
|
||||||
acceptor.bind(ep);
|
acceptor.listen();
|
||||||
acceptor.listen();
|
acceptor.accept(sock);
|
||||||
acceptor.accept(sock);
|
|
||||||
}
|
|
||||||
async_echo(sock,
|
async_echo(sock,
|
||||||
[&](beast::error_code ec)
|
[&](beast::error_code ec)
|
||||||
{
|
{
|
||||||
|
@@ -26,7 +26,7 @@ namespace http {
|
|||||||
/** A container for storing HTTP header fields.
|
/** A container for storing HTTP header fields.
|
||||||
|
|
||||||
This container is designed to store the field value pairs that make
|
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
|
are iterable, with each element holding the field name and field
|
||||||
value.
|
value.
|
||||||
|
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
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.
|
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.
|
A header includes the Start Line and Fields.
|
||||||
|
|
||||||
@@ -510,7 +510,7 @@ enum class connection
|
|||||||
upgrade
|
upgrade
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Prepare a HTTP message.
|
/** Prepare an HTTP message.
|
||||||
|
|
||||||
This function will adjust the Content-Length, Transfer-Encoding,
|
This function will adjust the Content-Length, Transfer-Encoding,
|
||||||
and Connection fields of the message based on the properties of
|
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
|
This function synchronously reads from a stream and passes
|
||||||
data to the specified parser. The call will block until one
|
data to the specified parser. The call will block until one
|
||||||
@@ -252,7 +252,7 @@ read(
|
|||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, isDirect, Derived>& parser);
|
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
|
This function synchronously reads from a stream and passes
|
||||||
data to the specified parser. The call will block until one
|
data to the specified parser. The call will block until one
|
||||||
@@ -297,7 +297,7 @@ read(
|
|||||||
basic_parser<isRequest, isDirect, Derived>& parser,
|
basic_parser<isRequest, isDirect, Derived>& parser,
|
||||||
error_code& ec);
|
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
|
This function is used to asynchronously read from a stream and
|
||||||
pass the data to the specified parser. The function call always
|
pass the data to the specified parser. The function call always
|
||||||
@@ -406,7 +406,7 @@ read(
|
|||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
message<isRequest, Body, Fields>& msg);
|
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
|
This function is used to synchronously read a message from
|
||||||
a stream. The call blocks until one of the following conditions
|
a stream. The call blocks until one of the following conditions
|
||||||
@@ -453,7 +453,7 @@ read(
|
|||||||
message<isRequest, Body, Fields>& msg,
|
message<isRequest, Body, Fields>& msg,
|
||||||
error_code& ec);
|
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
|
This function is used to asynchronously read a message from
|
||||||
a stream. The function call always returns immediately. The
|
a stream. The function call always returns immediately. The
|
||||||
|
@@ -15,9 +15,9 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
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
|
extension. The parameter list is a series of name/value pairs
|
||||||
with each pair starting with a semicolon. The value is optional.
|
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.
|
/** 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
|
field value. The extension list is a comma separated list of
|
||||||
token parameter list pairs.
|
token parameter list pairs.
|
||||||
|
|
||||||
|
@@ -201,8 +201,8 @@ class serializer
|
|||||||
public:
|
public:
|
||||||
/** Constructor
|
/** Constructor
|
||||||
|
|
||||||
@param msg The message to serialize. The message object
|
@param msg The message to serialize, which must
|
||||||
must remain valid for the lifetime of the write stream.
|
remain valid for the lifetime of the serializer.
|
||||||
|
|
||||||
@param decorator An optional decorator to use.
|
@param decorator An optional decorator to use.
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@ public:
|
|||||||
Decorator const& decorator = Decorator{},
|
Decorator const& decorator = Decorator{},
|
||||||
Allocator const& alloc = Allocator{});
|
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
|
bool
|
||||||
split() const
|
split() const
|
||||||
@@ -227,8 +227,8 @@ public:
|
|||||||
write only the octets corresponding to the serialized header
|
write only the octets corresponding to the serialized header
|
||||||
first. If the header has already been written, this function
|
first. If the header has already been written, this function
|
||||||
will have no effect on output. This function should be called
|
will have no effect on output. This function should be called
|
||||||
before any writes take place, otherwise the behavior is
|
before retrieving any buffers using @ref get, otherwise the
|
||||||
undefined.
|
behavior is undefined.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
split(bool v)
|
split(bool v)
|
||||||
@@ -238,9 +238,8 @@ public:
|
|||||||
|
|
||||||
/** Return `true` if serialization of the header is complete.
|
/** Return `true` if serialization of the header is complete.
|
||||||
|
|
||||||
This function indicates whether or not all octets
|
This function indicates whether or not all buffers containing
|
||||||
corresponding to the serialized representation of the
|
serialized header octets have been retrieved.
|
||||||
header have been successfully delivered to the stream.
|
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
is_header_done() const
|
is_header_done() const
|
||||||
@@ -248,11 +247,11 @@ public:
|
|||||||
return header_done_;
|
return header_done_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return `true` if serialization is complete
|
/** Return `true` if serialization is complete.
|
||||||
|
|
||||||
The operation is complete when all octets corresponding
|
The operation is complete when all octets corresponding
|
||||||
to the serialized representation of the message have been
|
to the serialized representation of the message have been
|
||||||
successfully delivered to the stream.
|
successfully retrieved.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
is_done() const
|
is_done() const
|
||||||
@@ -262,9 +261,11 @@ public:
|
|||||||
|
|
||||||
/** Return `true` if Connection: close semantic is indicated.
|
/** Return `true` if Connection: close semantic is indicated.
|
||||||
|
|
||||||
After serialization is complete, if there is an
|
Depending on the contents of the message, the end of
|
||||||
underlying network connection then it should be closed if
|
the body may be indicated by the end of file. In order
|
||||||
this function returns `true`.
|
for the recipient (if any) to receive a complete message,
|
||||||
|
the underlying network connection must be closed when this
|
||||||
|
function returns `true`.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
needs_close() const
|
needs_close() const
|
||||||
@@ -288,7 +289,8 @@ public:
|
|||||||
|
|
||||||
@param visit The function to call. The equivalent function
|
@param visit The function to call. The equivalent function
|
||||||
signature of this object must be:
|
signature of this object must be:
|
||||||
@code template<class ConstBufferSequence>
|
@code
|
||||||
|
template<class ConstBufferSequence>
|
||||||
void visit(error_code&, ConstBufferSequence const&);
|
void visit(error_code&, ConstBufferSequence const&);
|
||||||
@endcode
|
@endcode
|
||||||
The function is not copied, if no error occurs it will be
|
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,
|
isRequest, Body, Fields, Decorator, Allocator>& sr,
|
||||||
WriteHandler&& handler);
|
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
|
This function is used to write a message to a stream. The call
|
||||||
will block until one of the following conditions is true:
|
will block until one of the following conditions is true:
|
||||||
@@ -163,7 +163,7 @@ void
|
|||||||
write(SyncWriteStream& stream,
|
write(SyncWriteStream& stream,
|
||||||
message<isRequest, Body, Fields> const& msg);
|
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
|
This function is used to write a message to a stream. The call
|
||||||
will block until one of the following conditions is true:
|
will block until one of the following conditions is true:
|
||||||
@@ -195,7 +195,7 @@ write(SyncWriteStream& stream,
|
|||||||
message<isRequest, Body, Fields> const& msg,
|
message<isRequest, Body, Fields> const& msg,
|
||||||
error_code& ec);
|
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
|
This function is used to asynchronously write a message to
|
||||||
a stream. The function call always returns immediately. The
|
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
|
The function converts the header to its HTTP/1 serialized
|
||||||
representation and stores the result in the output stream.
|
representation and stores the result in the output stream.
|
||||||
@@ -261,7 +261,7 @@ std::ostream&
|
|||||||
operator<<(std::ostream& os,
|
operator<<(std::ostream& os,
|
||||||
header<isRequest, Fields> const& msg);
|
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
|
The function converts the message to its HTTP/1 serialized
|
||||||
representation and stores the result in the output stream.
|
representation and stores the result in the output stream.
|
||||||
|
Reference in New Issue
Block a user