Documentation work

This commit is contained in:
Vinnie Falco
2017-06-11 09:59:13 -07:00
parent 857fc22667
commit d529d6a16f
25 changed files with 282 additions and 342 deletions

View File

@ -22,6 +22,7 @@
[template mdash[] '''— ''']
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
[template repo_file[path] '''<ulink url="https://github.com/vinniefalco/Beast/blob/master/'''[path]'''">'''[path]'''</ulink>''']
[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]]]
@ -33,7 +34,9 @@
[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 __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 __socket__ [@http://www.boost.org/doc/html/boost_asio/reference/ip__tcp/socket.html `boost::asio::ip::tcp::socket`]]
[def __ssl_stream__ [@http://www.boost.org/doc/html/boost_asio/reference/ssl_stream.html `boost::asio::ssl::stream`]]
[def __streambuf__ [@http://www.boost.org/doc/html/boost_asio/reference/streambuf.html `boost::asio::streambuf`]]
[def __use_future__ [@http://www.boost.org/doc/html/boost_asio/reference/use_future_t.html `boost::asio::use_future`]]
[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 __yield_context__ [@http://www.boost.org/doc/html/boost_asio/reference/yield_context.html `boost::asio::yield_context`]]

View File

@ -12,15 +12,14 @@
[*low-level HTTP/1, WebSocket, and network protocol] programming
using the consistent asynchronous model of __Asio__. Beast is
not an HTTP client or HTTP server, but it can be used to build
those things. It is intended to be a foundation for writing other
interoperable libraries by providing HTTP vocabulary types and
algorithms. The provided examples show how clients and servers
might be built.
those things. It is a foundation for writing interoperable
libraries by providing HTTP vocabulary types and algorithms. The
examples show how client and server applications might be built.
]
This library is designed for:
* [*Symmetry:] Interfaces are role-agnostic; build clients, servers, or both.
* [*Symmetry:] Algorithms are role-agnostic; build clients, servers, or both.
* [*Ease of Use:] __Asio__ users will immediately understand Beast.
@ -29,8 +28,7 @@ This library is designed for:
* [*Performance:] Build applications handling thousands of connections or more.
* [*Basis for Further Abstraction.] Components are open-ended and
suited for building higher level libraries.
* [*Basis for Further Abstraction.] Components are well-suited for building upon.
[heading Audience]
@ -44,12 +42,11 @@ Asio callbacks or coroutines.
An absence of high quality C++ network protocol libraries has led
to a patchwork of open-source solutions lacking suitable conciseness
and expressive power for standardization. Part of this problem is
caused by the lack of a standardized C++ networking interface. This
will change soon with the Networking Technical Specification
(__N4588__): a uniform interface for networking on track to become
standardized. This technical specification is modeled closely after
Boost.Asio.
and expressive power for standardization. Part of this problem is a
lack of common C++ networking interfaces. This is changing soon with
the Networking Technical Specification (__N4588__): a uniform interface
on track to become standardized. This technical specification is modeled
closely after Boost.Asio.
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
@ -57,8 +54,8 @@ communicate interactively. C++ benefits greatly from having a
standardized implementation of these protocols.
[note
The Beast roadmap includes a port to the standardized C++
networking interface based on __N4588__.
The Beast roadmap includes a port to the networking
interface based on __N4588__.
]
[heading Requirements]

View File

@ -7,9 +7,8 @@
[section:example Example Programs]
These usage examples are intended to quickly impress upon readers the
flavor of the library. They are complete programs which may be built
and run. Source code and build scripts for these programs may be found
These complete programs are intended to quickly impress upon readers the
flavor of the library. Source code and build scripts for them are located
in the examples directory.
@ -18,47 +17,47 @@ in the examples directory.
Use HTTP to make a GET request to a website and print the response:
File: [repo_file examples/http_example.cpp]
[http_example_get]
[heading WebSocket]
Establish a WebSocket connection, send a message and receive the reply:
File: [repo_file examples/websocket_example.cpp]
[websocket_example_client_echo]
[heading WebSocket Echo Server]
This example demonstrates both synchronous and asynchronous
WebSocket server implementations.
* [@examples/websocket_async_echo_server.hpp]
* [@examples/websocket_sync_echo_server.hpp]
* [@examples/websocket_echo.cpp]
* [repo_file examples/websocket_async_echo_server.hpp]
* [repo_file examples/websocket_sync_echo_server.hpp]
* [repo_file examples/websocket_echo.cpp]
[heading Secure WebSocket]
Establish a WebSocket connection over an encrypted TLS connection,
send a message and receive the reply. Requires OpenSSL to build.
* [@examples/websocket_ssl_example.cpp]
* [repo_file examples/ssl/websocket_ssl_example.cpp]
[heading HTTPS GET]
This example demonstrates sending and receiving HTTP messages
over a TLS connection. Requires OpenSSL to build.
* [@examples/http_ssl_example.cpp]
* [repo_file examples/ssl/http_ssl_example.cpp]
[heading HTTP Crawl]
This example retrieves the page at each of the most popular domains
as measured by Alexa.
* [@examples/http_crawl.cpp]
* [repo_file examples/http_crawl.cpp]
[heading HTTP Server]
@ -66,10 +65,10 @@ This example demonstrates both synchronous and asynchronous server
implementations. It also provides an example of implementing a [*Body]
type, in `file_body`.
* [@examples/file_body.hpp]
* [@examples/http_async_server.hpp]
* [@examples/http_sync_server.hpp]
* [@examples/http_server.cpp]
* [repo_file examples/file_body.hpp]
* [repo_file examples/http_async_server.hpp]
* [repo_file examples/http_sync_server.hpp]
* [repo_file examples/http_server.cpp]
[heading Composed Operations]
@ -78,13 +77,16 @@ composable asynchronous initiation function with associated composed
operation implementation. This is a complete, runnable version of
the example described in the Core Foundations document section.
* [@examples/echo_op.cpp]
* [repo_file examples/echo_op.cpp]
[heading Listings]
[heading Documentation Samples]
These are stand-alone listings of the HTTP and WebSocket examples.
Here are all of the example functions and classes presented
throughout the documentation, they can be included and used
in your program without modification
* [@examples/http_example.cpp]
* [@examples/websocket_example.cpp]
* [repo_file examples/doc_core_samples.hpp]
* [repo_file examples/doc_http_samples.hpp]
[endsect]

View File

@ -7,11 +7,12 @@
[section:core Using Networking]
A goal of the library is expose implementation primitives in order that
users may build their own library-like components. These primitives include
traits, buffers, buffer algorithms, and helpers for implementing asynchronous
operations compatible with __Asio__ and described in __N3747__. This section
lists these facilities by group, with descriptions.
This library makes network primitives used by the implementation publicly
available so users can take advantage of them in their own libraries.
These primitives include traits, buffers, buffer algorithms, and helpers
for implementing asynchronous operations compatible with __Asio__ and
described in __N3747__. This section lists these facilities by group,
with descriptions.
[important
This documentation assumes familiarity with __Asio__. Sample

View File

@ -15,11 +15,10 @@
left to the interfaces already existing on the underlying streams.
]
Library stream algorithms require an already-connected socket, SSL stream,
or other object which meets the required stream concepts and already has
communication established with an endpoint. This example is provided as a
reminder of how to work
with sockets:
Library stream algorithms require a __socket__, __ssl_stream__, or other
__Stream__ object that has already established communication with an
endpoint. This example is provided as a reminder of how to work with
sockets:
[snippet_core_2]

View File

@ -7,17 +7,13 @@
[section:streams Using Streams]
A __Stream__ is a communication channel where data expressed as octet
buffers is transferred sequentially. Streams are either synchronous
A __Stream__ is a communication channel where data is transferred as
an ordered sequence of octet buffers. 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:
Asio types __socket__ and __ssl_stream__ and 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]]

View File

@ -11,13 +11,18 @@ __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`
output sequence. The Networking TS (__N4588__) generalizes this `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:
resizable buffers accept dynamic buffer objects as templated parameters.
These metafunctions check if types match the buffer concepts:
[table Buffer Type Checks
[[Name][Description]]
[[
[link beast.ref.is_dynamic_buffer `is_dynamic_buffer`]
][
Determine if a type meets the requirements of __DynamicBuffer__.
]]
[[
[link beast.ref.is_const_buffer_sequence `is_const_buffer_sequence`]
][
@ -28,11 +33,6 @@ metafunctions check types against these buffer concepts:
][
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__.
]]
]
To suit various needs, several implementation of dynamic buffer are available:
@ -88,11 +88,11 @@ To suit various needs, several implementation of dynamic buffer are available:
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. Control of buffers is retained by the caller; ownership is
not transferred.
transform these ranges efficiently using lazy evaluation. No memory
allocations are used in the transformations; instead, they create
lightweight iterators over the existing, unmodified memory buffers.
Control of buffers is retained by the caller; ownership is not
transferred.
[table Buffer Algorithms
[[Name][Description]]

View File

@ -32,11 +32,13 @@ in this library. Non-trivial applications will want to provide their own
asynchronous initiation functions which perform a series of other,
intermediate asynchronous operations before invoking the final completion
handler. The set of intermediate actions produced by calling an initiation
function is known as a ['composed operation]. To ensure full interoperability
and well-defined behavior, __Asio__ imposes requirements on the implementation
of composed operations. A number of useful classes and macros to facilitate
the development of composed operations and the associated asynchronous
initiation functions used to launch them are available:
function is known as a
[@http://blog.think-async.com/2009/08/composed-operations-coroutines-and-code.html ['composed operation]].
To ensure full interoperability and well-defined behavior, __Asio__ imposes
requirements on the implementation of composed operations. A number of useful
classes and macros to facilitate the development of composed operations and
the associated asynchronous initiation functions used to launch them are
available:
[table Asynchronous Helpers
[[Name][Description]]

View File

@ -21,7 +21,7 @@ class message;
```
The container offers value semantics including move and copy if supported
by `Body` and `Fields`. User defined template function parameters can
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
@ -47,17 +47,19 @@ 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`:
Furthermore, `header` is publicly derived from `Fields`; a message
inherits all of the fields member functions. Since `fields` is a
container, iterating a message iterates its header fields. 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 730px] [height 410px]]
The template type aliases
[link beast.ref.http__request `request`] and
[link beast.ref.http__response `response`]
are provided for notational convenience. They also come with the default
__fields__, a common choice.
are provided for brevity. They specify the common default of `fields`.
```
/// A typical HTTP request
@ -72,21 +74,24 @@ 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:
the [link beast.ref.http__message.body `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 whose `value_type` holds a raw pointer and size to a
caller-provided buffer. This allows for serialization of body data
coming from external sources, and incremental parsing of message
body content using a fixed size buffer.
A body whose
[link beast.ref.http__buffer_body__value_type `value_type`]
holds a raw pointer and size to a caller-provided buffer.
This allows for serialization of body data coming from
external sources, and incremental parsing of message body
content using a fixed size buffer.
]]
[[
[link beast.ref.http__dynamic_body `dynamic_body`]
@ -141,7 +146,7 @@ message has a body. The function
[link beast.ref.http__message.prepare prepare]
automatically sets the Content-Length or Transfer-Encoding field
depending on the content and type of the `body` member. The use
of prepare is optional; these fields may also be set.
of prepare is optional; these fields may also be set explicitly.
[table Create Response
[[Statements] [Serialized Result]]
@ -158,4 +163,10 @@ of prepare is optional; these fields may also be set.
]]
]
The implementation will automatically fill in the obsolete
[@https://tools.ietf.org/html/rfc7230#section-3.1.2 reason-phrase]
from the status code when serializing a message. Or it may
be set directly using
[link beast.ref.http__header.reason.overload2 `header::reason`].
[endsect]

View File

@ -7,11 +7,11 @@
[section:streams Message Stream Operations]
Beast provides synchronous and asynchronous algorithms to serialize and
parse HTTP/1 wire format messages on streams. These functions form a
basic interface for operating on entire messages:
Beast provides synchronous and asynchronous algorithms to parse and
serialize HTTP/1 wire format messages on streams. These functions form
the message-oriented stream interface:
[table Basic Interface
[table Message Stream Operations
[[Name][Description]]
[[
[link beast.ref.http__read.overload3 [*read]]
@ -54,16 +54,16 @@ message variable, then read a complete HTTP request synchronously:
[http_snippet_4]
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.
This example uses __flat_buffer__. Beast's __basic_parser__ is
optimized for structured HTTP data located in a single contiguous
(['flat]) memory buffer. When not using a flat buffer the implementation
may perform an additional memory allocations to restructure the input
into a single buffer for parsing.
[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.
Other Implementations of __DynamicBuffer__ may avoid parser
memory allocation by always returning buffer sequences of
length one.
]
Messages may also be read asynchronously. When performing asynchronous

View File

@ -7,8 +7,8 @@
[section:serializer_streams Serializer Stream Operations]
Message oriented stream operations provide for limited control.
Sophisticated algorithms may need to do more, such as:
Non-trivial algorithms need to do more than send entire messages
at once, such as:
* Send the header first, and the body later.
@ -108,7 +108,7 @@ 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
This defines a decorator which sets an extension variable `x` equal
to the size of the chunk in bytes, and returns a single trailer field:
[http_snippet_17]

View File

@ -7,10 +7,11 @@
[section:parser_streams Parser Stream Operations]
Message oriented stream operations provide for limited control.
Sophisticated algorithms may need to do more, such as:
Non-trivial algorithms need to do more than receive entire messages
at once, such as:
* Receive the header first, then the body later.
* Receive the header first and body later.
* Receive a large body using a fixed-size buffer.
@ -18,10 +19,10 @@ Sophisticated algorithms may need to do more, such as:
* Defer the commitment to a __Body__ type until after reading the header.
All of these operations require callers to manage the lifetime of state
information associated with the operation, by constructing a class derived
from __basic_parser__. Beast comes with two instances of parsers, and user
defined types deriving from the basic parser are possible:
These types of operations require callers to manage the lifetime of
associated state, by constructing a class derived from __basic_parser__.
Beast comes with the derived instance __parser__ which creates complete
__message__ objects; user-defined parsers are also possible:
[table Parser Implementations
[[Name][Description]]
@ -33,7 +34,7 @@ defined types deriving from the basic parser are possible:
template<
bool isRequest, // `true` to parse an HTTP request
class Body, // The Body type for the resulting message
class Fields> // The type of container representing the fields
class Fields = fields> // The type of container representing the fields
class parser
: public basic_parser<...>;
```
@ -107,12 +108,15 @@ advised to use an instance of __flat_buffer__, __static_buffer__, or
__static_buffer_n__ for this purpose, although a user defined instance of
__DynamicBuffer__ which produces input sequences of length one is also suitable.
The provided parsers use a "captive object" model, acting as container for
the __message__ produced as a result of parsing. The caller accesses the
contained object, and depending on the types used to instantiate the parser,
it may be possible to acquire ownership of the header or message captive
object and destroy the parser. In this example we read an HTTP response
with a string body using a parser, then print the response:
The parser contains a message constructed internally. Arguments passed
to the parser's constructor are forwarded into the message container.
The caller can access the message inside the parser by calling
[link beast.ref.http__parser.get `parser::get`].
If the `Fields` and `Body` types are [*MoveConstructible], the caller
can take ownership of the message by calling
[link beast.ref.http__parser.release `parser::release`]. In this example
we read an HTTP response with a string body using a parser, then print
the response:
[http_snippet_13]

View File

@ -7,26 +7,24 @@
[section:serializer_buffers Buffer-Oriented Serializing]
In extreme cases, users may wish to create an instance of __serializer__
and invoke its methods directly instead of using the provided stream
algorithms. This could be useful for implementing algorithms on streams
whose interface does not conform to __Stream__. For example, a
An instance of __serializer__ can be invoked directly, without using
the provided stream operations. This could be useful for implementing
algorithms on streams whose interface does not conform to __Stream__.
For example, a
[@https://github.com/libuv/libuv *libuv* socket].
The serializer interface is interactive; the caller invokes it repeatedly to
produce buffers until all of the buffers have been generated. Then the
The serializer interface is interactive; the caller invokes it repeatedly
to produce buffers until all of the buffers have been generated. Then the
serializer is destroyed.
After the serializer is created, the buffers are produced by first calling
[link beast.ref.http__serializer.get `serializer::get`]
to obtain a buffer sequence, and then calling
To obtain the serialized next buffer sequence, call
[link beast.ref.http__serializer.get `serializer::get`].
Then, call
[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
to indicate the number of bytes consumed. This updates the next
set of buffers to be returned, if any.
`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 C++14
example prints the buffers to standard output:
@ -50,9 +48,27 @@ 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
informs the caller whether the header been serialized fully. In this
C++14 example we print the header first, followed by the body:
[http_snippet_16]
[heading Example: Write To std::ostream]
The standard library provides the type `std::ostream` for performing high
level write operations on character streams. The variable `std::cout` is
based on this output stream. This example uses the buffer oriented interface
of __serializer__ to write an HTTP message to a `std::ostream`:
[http_sample_write_ostream]
[tip
Serializing to a `std::ostream` could be implemented using an alternate
strategy: adapt the `std::ostream` interface to a __SyncWriteStream__,
enable use with the library's existing stream algorithms. This is
left as an exercise for the reader.
]
[endsect]

View File

@ -7,11 +7,10 @@
[section:parser_buffers Buffer-Oriented Parsing]
In some cases, users may wish to create an instance of __parser__, or a
user-defined type derived from __basic_parser__ and invoke its methods
directly instead of using the provided stream algorithms. This could be
useful for implementing algorithms on objects whose interface does not
conform to any __Stream__. For example, a
A subclass of __basic_parser__ can be invoked directly, without using
the provided stream operations. This could be useful for implementing
algorithms on objects whose interface does not conform to any __Stream__.
For example, a
[@http://zeromq.org/ *ZeroMQ* socket].
The basic parser interface is interactive; the caller invokes the function
[link beast.ref.http__basic_parser.put `basic_parser::put`]
@ -60,4 +59,21 @@ The parser provides two options which may be set before parsing begins:
]]
]
[heading Example: Read From std::istream]
The standard library provides the type `std::istream` for performing high
level read operations on character streams. The variable `std::cin` is based
on this input stream. This example uses the buffer oriented interface of
__basic_parser__ to build a stream operation which parses an HTTP message
from a `std::istream`:
[http_sample_read_istream]
[tip
Parsing from a `std::istream` could be implemented using an alternate
strategy: adapt the `std::istream` interface to a __SyncReadStream__,
enabling use with the library's existing stream algorithms. This is
left as an exercise for the reader.
]
[endsect]

View File

@ -14,8 +14,14 @@ elements according to the HTTP/1 protocol specification, while the derived
class decides what to do with those elements. In particular, users who
create exotic containers for [*Fields] may need to also create their own
parser. Custom parsers will work with all of the stream read operations
that work on parsers, as those algorithms use only the basic parser interface.
that work on parsers, as those algorithms use only the basic parser
interface. Some use cases for implementing custom parsers are:
* Inspect incoming header fields and keep or discard them.
* Use a container provided by an external interface.
* Store header data in a user-defined __Fields__ type.
The basic parser uses the Curiously Recurring Template Pattern
([@https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern CRTP]).
@ -24,7 +30,7 @@ The interface to the parser is event-driven. Member functions of the derived
class (termed "callbacks" in this context) are invoked with parsed elements
as they become available, requiring either the `friend` declaration as shown
above or that the member functions are declared public (not recommended).
Buffers provided by the parser are non-owning references, it is the
Buffers provided by the parser are non-owning references; it is the
responsibility of the derived class to copy any information it needs before
returning from the callback.

View File

@ -22,19 +22,23 @@ The meaning of the nested types is as follows
[
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.
member.
]
][
[`reader`]
[
An optional nested type meeting the requirements of __BodyReader__.
An optional nested type meeting the requirements of __BodyReader__,
which provides the algorithm for converting the body representation
to a forward range of buffer sequences.
If present this body type may be used with a __serializer__.
]
][
[`writer`]
[
An optional nested type meeting the requirements of __BodyWriter__.
An optional nested type meeting the requirements of __BodyWriter__,
which provides the algorithm for storing a forward range of buffer
sequences in the body representation.
If present, this body type may be used with a __parser__.
]
]
]
@ -44,41 +48,72 @@ The meaning of the nested types is as follows
The `value_type` nested type allows the body to define the declaration of
the body type as it appears in the message. This can be any type. For
example, a body's value type may specify `std::vector<char>` or even
`std::list<std::string>`. By also providing suitable definitions of
corresponding `reader` and `writer` types, messages with that body
become serializable and parsable respectively.
A custom body may even set the value type to something that is not a container
for body octets, such as a
`std::list<std::string>`. A custom body may even set the value type to
something that is not a container for body octets, such as a
[@http://www.boost.org/libs/filesystem/doc/reference.html#class-path `boost::filesystem::path`].
In this case the reader may obtain buffers corresponding to a file on disk,
while the writer may store incoming buffers to a file on disk.
Or, a more structured container may be chosen. This declares a body's
value type as a JSON tree structure produced from a
[@http://www.boost.org/doc/html/property_tree/parsers.html#property_tree.parsers.json_parser `json_parser`]:
```
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
Another option is to use a structured container for the value type. For
example, a JSON tree structure such as the property tree produced by Boost's
[@http://www.boost.org/doc/html/property_tree/parsers.html#property_tree.parsers.json_parser `json_parser`]
As long as a suitable reader or writer is available to provide the algorithm
for transferring buffers in and out of the value type, even if abstract,
struct Body
{
using value_type = boost::property_tree::ptree;
class reader;
class writer;
};
```
As long as a suitable reader or writer is available to provide the
algorithm for transferring buffers in and out of the value type,
those bodies may be serialized or parsed.
[note
The examples included with this library provide a [*Body]
implementation that serializes message bodies coming from a file.
This is part of the HTTP server example.
]
[heading Example: File Body Type]
[heading Reader]
Use of the flexible __Body__ concept customization point enables authors to
preserve the self-contained nature of the __message__ object while allowing
domain specific behaviors. Common operations for HTTP servers include sending
responses which deliver file contents, and allowing for file uploads. In this
example we build the `file_body` type which supports both reading and writing
to a file on the file system.
The reader provides the algorithm for transferring buffers containing body
octets obtained during parsing into the body container. The requirements
for this type are described in the __BodyReader__ concept. When a body type
defines a reader it may then be parsed using a __parser__.
First we declare the type itself, along with the required members:
[heading Writer]
[http_sample_file_body_1]
The writer provides the algorithm for converting the body container into a
series of buffers. The requirements for this type are described in the
__BodyWriter__ concept. When a body type defines a writer it may then be
serialized using a __serializer__.
The `size` function is a simple call to retrieve the file size:
[http_sample_file_body_2]
Our implementation of __BodyReader__ will contain a small buffer
from which the file contents are read. The buffer is provided to
the implementation on each call until everything has been read in.
[http_sample_file_body_3]
And here are the definitions for the functions we have declared:
[http_sample_file_body_4]
Files can be read now, and the next step is to allow writing to files
by implementing the __BodyWriter__. The style is similar to the reader,
except that buffers are incoming instead of outgoing. Here's the
declaration:
[http_sample_file_body_5]
Finally, here is the implementation of the writer member functions:
[http_sample_file_body_6]
We have created a full featured body type capable of reading and
writing files on the filesystem, integrating seamlessly with the
HTTP algorithms and message container. Source code for this body
type, and HTTP servers that use it, are available in the examples
directory.
[endsect]

View File

@ -70,10 +70,6 @@ synchronous version of this server action looks like this:
[include 6_1_file_body.qbk]
[section HEAD request (Client)]
The
@ -121,26 +117,6 @@ and a __parser__ to achieve its goal:
[section Read From std::istream]
The standard library provides the type `std::istream` for performing high
level read operations on character streams. The variable `std::cin` is based
on this input stream. In this example, we build a stream operation which
parses an HTTP message from a `std::istream`:
[http_sample_read_istream]
[tip
Parsing from a `std::istream` could be implemented using an alternate
strategy: adapt the `std::istream` interface to a __SyncReadStream__.
This lets all the library's existing algorithms work on `std::istream`.
We leave this as an exercise for the reader.
]
[endsect]
[section Send Child Process Output]
Sometimes it is necessary to send a message whose body is not conveniently
@ -164,24 +140,4 @@ HTTP response. The output of the process is sent as it becomes available:
[section Write To std::ostream]
The standard library provides the type `std::ostream` for performing high
level write operations on character streams. The variable `std::cout` is
based on this output stream. In this example, we build a stream operation
which serializes an HTTP message to a `std::ostream`:
[http_sample_write_ostream]
[tip
Serializing to a `std::ostream` could be implemented using an alternate
strategy: adapt the `std::ostream` interface to a __SyncWriteStream__.
This lets all the library's existing algorithms work on `std::ostream`.
We leave this as an exercise for the reader.
]
[endsect]
[endsect]

View File

@ -1,52 +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 File Body Type]
Use of the flexible __Body__ concept customization point enables authors to
preserve the self-contained nature of the __message__ object while allowing
domain specific behaviors. Common operations for HTTP servers include sending
responses which deliver file contents, and allowing for file uploads. In this
example we build the `file_body` type which supports both reading and writing
to a file on the file system.
First we declare the type itself, along with the required members:
[http_sample_file_body_1]
The `size` function is a simple call to retrieve the file size:
[http_sample_file_body_2]
Our implementation of __BodyReader__ will contain a small buffer
from which the file contents are read. The buffer is provided to
the implementation on each call until everything has been read in.
[http_sample_file_body_3]
And here are the definitions for the functions we have declared:
[http_sample_file_body_4]
Files can be read now, and the next step is to allow writing to files
by implementing the __BodyWriter__. The style is similar to the reader,
except that buffers are incoming instead of outgoing. Here's the
declaration:
[http_sample_file_body_5]
Finally, here is the implementation of the writer member functions:
[http_sample_file_body_6]
We have created a full featured body type capable of reading and
writing files on the filesystem, integrating seamlessly with the
HTTP algorithms and message container. Source code for this body
type, and HTTP servers that use it, are available in the examples
directory.
[endsect]

View File

@ -7,12 +7,13 @@
[section:concept Concepts]
This section describes all of the concepts defined by the library.
[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/Fields.qbk]
[include concept/FieldsReader.qbk]
[include concept/Streams.qbk]

View File

@ -49,20 +49,6 @@ install callouts
explicit callout ;
install examples
:
[ glob
../examples/*.cpp
../examples/*.hpp
../examples/ssl/*.cpp
../examples/ssl/*.hpp
]
:
<location>$(here)/html/examples
;
explicit examples ;
xml doc
:
0_main.qbk
@ -90,7 +76,6 @@ boostbook boostdoc
<include>$(broot)/tools/boostbook/dtd
:
<location>temp
<dependency>examples
<dependency>images
<dependency>stylesheets
;

View File

@ -1,41 +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:Field Field]
A [*Field] represents a single HTTP header field/value pair.
In this table:
* `X` denotes a type meeting the requirements of [*Field].
* `a` denotes a value of type `X`.
[table Field requirements
[[expression][type][semantics, pre/post-conditions]]
[
[`a.name()`]
[[link beast.ref.string_view `string_view`]]
[
This function returns a value implicitly convertible to
`boost::string_ref` containing the case-insensitive field
name, without leading or trailing white space.
]
]
[
[`a.value()`]
[[link beast.ref.string_view `string_view`]]
[
This function returns a value implicitly convertible to
`boost::string_ref` containing the value for the field. The
value is considered canonical if there is no leading or
trailing whitespace.
]
]
]
[endsect]

View File

@ -101,7 +101,6 @@
<member><link linkend="beast.concept.Body">Body</link></member>
<member><link linkend="beast.concept.BodyReader">BodyReader</link></member>
<member><link linkend="beast.concept.BodyWriter">BodyWriter</link></member>
<member><link linkend="beast.concept.Field">Field</link></member>
<member><link linkend="beast.concept.Fields">Fields</link></member>
<member><link linkend="beast.concept.FieldsReader">FieldsReader</link></member>
</simplelist>

View File

@ -686,7 +686,13 @@ read_istream(
error_code& ec)
{
// Create the message parser
parser<isRequest, Body, Fields> parser;
//
// Arguments passed to the parser's constructor are
// forwarded to the message constructor. Here, we use
// a move construction in case the caller has constructed
// their message in a non-default way.
//
parser<isRequest, Body, Fields> p{std::move(msg)};
do
{
@ -729,7 +735,7 @@ read_istream(
else
{
// Inform the parser that we've reached the end of the istream.
parser.put_eof(ec);
p.put_eof(ec);
if(ec)
return;
break;
@ -737,7 +743,7 @@ read_istream(
}
// Write the data to the parser
auto const bytes_used = parser.put(buffer.data(), ec);
auto const bytes_used = p.put(buffer.data(), ec);
// This error means that the parser needs additional octets.
if(ec == error::need_more)
@ -748,10 +754,10 @@ read_istream(
// Consume the buffer octets that were actually parsed.
buffer.consume(bytes_used);
}
while(! parser.is_done());
while(! p.is_done());
// Transfer ownership of the message container in the parser to the caller.
msg = parser.release();
msg = p.release();
}
//]

View File

@ -59,7 +59,7 @@ namespace beast {
// This helper converts the handler into the real handler type
async_completion<WriteHandler, void(error_code)> init{handler};
... // Create and the composed operation
... // Create and invoke the composed operation
// This provides the return value and executor customization
return init.result.get();

View File

@ -179,11 +179,9 @@ send(
//[http_snippet_13
template<
class SyncReadStream>
template<class SyncReadStream>
void
print_response(
SyncReadStream& stream)
print_response(SyncReadStream& stream)
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
@ -238,7 +236,7 @@ struct lambda
lambda(Serializer& sr_) : sr(sr_) {}
template<class ConstBufferSequence>
void operator()(error_code& ec, ConstBufferSequence const& buffer)
void operator()(error_code& ec, ConstBufferSequence const& buffer) const
{
std::cout << buffers(buffer);
sr.consume(boost::asio::buffer_size(buffer));