Documentation work

This commit is contained in:
Vinnie Falco
2017-06-07 16:30:49 -07:00
parent 38c36ac655
commit cff5be3837
31 changed files with 510 additions and 353 deletions

View File

@@ -13,6 +13,7 @@
## Contents ## Contents
- [Introduction](#introduction) - [Introduction](#introduction)
- [Audience](audience)
- [Appearances](#appearances) - [Appearances](#appearances)
- [Description](#description) - [Description](#description)
- [Requirements](#requirements) - [Requirements](#requirements)
@@ -24,37 +25,36 @@
## Introduction ## Introduction
Beast is a header-only, cross-platform C++ library built on Boost.Asio and Beast is a cross-platform, header-only C++11 library for low-level
Boost, containing two modules implementing widely used network protocols. HTTP/1 and WebSocket protocol programming
Beast.HTTP offers a universal model for describing, sending, and receiving using the consistent asynchronous networking model of Boost.Asio.
HTTP messages while Beast.WebSocket provides a complete implementation of Beast is not an HTTP client or HTTP server, but it can be used to
the WebSocket protocol. Their design achieves these goals: 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.
* **Symmetry.** Interfaces are role-agnostic; the same interfaces can be This library is designed for:
used to build clients, servers, or both.
* **Ease of Use.** HTTP messages are modeled using simple, readily * **Symmetry:** Interfaces are role-agnostic; build clients, servers, or both.
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 * **Ease of Use:** Boost.Asio users will immediately understand Beast.
strategies; important decisions such as buffer or thread management are
left to users of the library.
* **Performance.** The implementation performs competitively, making it a * **Flexibility:** Users make the important decisions such as buffer or
realistic choice for building high performance network servers. thread management.
* **Scalability.** Development of network applications that scale to thousands * **Performance:** Build applications handling thousands of connections or more.
of concurrent connections is possible with the implementation.
* **Basis for further abstraction.** The interfaces facilitate the * **Basis for Further Abstraction.** Components are open-ended and
development of other libraries that provide higher levels of abstraction. suited for building higher level libraries.
Beast is used in [rippled](https://github.com/ripple/rippled), an ## Audience
open source server application that implements a decentralized
cryptocurrency system. Beast is for network programmers who have some familiarity with
Boost.Asio. In particular, users who wish to write asynchronous programs
with Beast should already know how to use Asio sockets and streams,
and should know how to create concurrent network programs using
Asio callbacks or coroutines.
## Appearances ## Appearances
@@ -76,17 +76,16 @@ The library has been submitted to the
## Requirements ## Requirements
* Boost 1.58.0 or later * **C++11:** Robust support for most language features.
* C++11 or later * **Boost:** Boost.Asio and some other parts of Boost.
* **OpenSSL:** Optional, for using TLS/Secure sockets.
When using Microsoft Visual C++, Visual Studio 2015 Update 3 or later is required. When using Microsoft Visual C++, Visual Studio 2015 Update 3 or later is required.
These components are optionally required in order to build the These components are required in order to build the tests and examples:
tests and examples:
* OpenSSL (optional) * CMake 3.7.2 or later
* CMake 3.7.2 or later (optional) * Properly configured bjam/b2
* Properly configured bjam/b2 (optional)
## Building ## Building
@@ -210,10 +209,10 @@ int main()
req.method(beast::http::verb::get); req.method(beast::http::verb::get);
req.target("/"); req.target("/");
req.version = 11; req.version = 11;
req.fields.replace("Host", host + ":" + req.insert(beast::http::field::host, host + ":" +
boost::lexical_cast<std::string>(sock.remote_endpoint().port())); boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
req.fields.replace("User-Agent", "Beast"); req.insert(beast::http::field::user_agent, "Beast");
beast::http::prepare(req); req.prepare();
beast::http::write(sock, req); beast::http::write(sock, req);
// Receive and print HTTP response using beast // Receive and print HTTP response using beast

View File

@@ -32,11 +32,11 @@
[def __asio_handler_invoke__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]] [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 __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 __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 __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`]]
[def __AsyncReadStream__ [@http://www.boost.org/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]] [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 __AsyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]]
@@ -68,6 +68,8 @@
[def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]] [def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]]
[def __parser__ [link beast.ref.http__parser `parser`]] [def __parser__ [link beast.ref.http__parser `parser`]]
[def __serializer__ [link beast.ref.http__serializer `serializer`]] [def __serializer__ [link beast.ref.http__serializer `serializer`]]
[def __static_buffer__ [link beast.ref.static_buffer `static_buffer`]]
[def __static_buffer_n__ [link beast.ref.static_buffer_n `static_buffer_n`]]
[import ../examples/http_example.cpp] [import ../examples/http_example.cpp]
[import ../examples/websocket_example.cpp] [import ../examples/websocket_example.cpp]
@@ -75,6 +77,8 @@
[import ../examples/doc_http_samples.hpp] [import ../examples/doc_http_samples.hpp]
[import ../test/core/doc_snippets.cpp] [import ../test/core/doc_snippets.cpp]
[import ../test/http/doc_snippets.cpp] [import ../test/http/doc_snippets.cpp]
[import ../test/websocket/doc_snippets.cpp]
[import ../test/websocket/ssl/doc_snippets.cpp]
[include 1_overview.qbk] [include 1_overview.qbk]
[include 2_examples.qbk] [include 2_examples.qbk]

View File

@@ -8,107 +8,94 @@
[section:overview Introduction] [section:overview Introduction]
[important [important
Beast is a cross-platform, header-only C++11 library for low-level HTTP Beast is a cross-platform, header-only C++11 library for low-level
and WebSocket protocol programming that uses the consistent network and [*HTTP/1 and WebSocket protocol] programming
asynchronous model of __Asio__. using the consistent asynchronous networking model of __Asio__.
Beast is not an HTTP client or HTTP server, but it can be used to Beast is not an HTTP client or HTTP server, but it can be used to
build those things. The library is intended to be a foundation upon build those things. It is intended to be a foundation for writing
which new libraries may be built. It is a goal that other architects other interoperable libraries by providing HTTP vocabulary types
will create interoperable solutions on top of Beast. The provided and algorithms. The provided examples show how clients and servers
example programs shows how a client or server might be built. might be built.
] ]
The design of the library achieves these goals: This library is designed for:
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be * [*Symmetry:] Interfaces are role-agnostic; build clients, servers, or both.
used to build clients, servers, or both.
* [*Ease of Use.] HTTP messages are modeled using a simple, expressive * [*Ease of Use:] __Asio__ users will immediately understand Beast.
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 * [*Flexibility:] Users make the important decisions such as buffer or
strategies; users make the important decisions such as buffer or
thread management. thread management.
* [*Performance.] The implementation performs competitively, making it * [*Performance:] Build applications handling thousands of connections or more.
a realistic choice for building high performance network servers.
* [*Scalability.] Development of network applications that scale to * [*Basis for Further Abstraction.] Components are open-ended and
thousands of concurrent connections is possible with the implementation. suited for building higher level libraries.
* [*Basis for Further Abstraction.] The interfaces facilitate the [heading Audience]
development of other libraries that provide higher levels of abstraction.
Beast is for network programmers who have some familiarity with
__Asio__. In particular, users who wish to write asynchronous programs
with Beast should already know how to use Asio sockets and streams,
and should know how to create concurrent network programs using
Asio callbacks or coroutines.
[heading Motivation]
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.
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.
[note
The Beast roadmap includes a port to the standardized C++
networking interface based on __N4588__.
]
[heading Requirements] [heading Requirements]
Beast requires: Beast requires:
* [*C++11.] A minimum of C++11 is needed. * [*C++11:] Robust support for most language features.
* [*Boost.] Beast is built on Boost, especially Boost.Asio. * [*Boost:] Boost.Asio and some other parts of Boost.
* [*OpenSSL.] If using TLS/Secure sockets (optional). * [*OpenSSL:] Optional, for using TLS/Secure sockets.
[note Supported compilers: msvc-14+, gcc 4.8+, clang 3.6+] [note Supported compilers: msvc-14+, gcc 4.8+, clang 3.6+]
The library is [*header-only]. It is not necessary to add any .cpp files, This library is [*header-only]. To link a program using Beast
or to add commands to your build script for building Beast. To link your successfully, add the
program successfully, you'll need to add the Boost.System library to link [@http://www.boost.org/libs/system/doc/reference.html Boost.System]
with. If you use coroutines you'll also need the Boost.Coroutine library. library to the list of linked libraries. If you use coroutines
Please visit the Boost documentation for instructions on how to do this for you'll also need the
your particular build system. [@http://www.boost.org/libs/coroutine/doc/html/index.html Boost.Coroutine]
library. Please visit the
[@http://www.boost.org/doc/ 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 [note
relies on other Boost parts. There are no immediate plans to offer a Beast does not compile using the
version that works with stand-alone Asio. [@https://github.com/chriskohlhoff/asio stand-alone Asio],
since it relies on other Boost parts. There are no immediate
[heading Motivation] plans to offer a version that works with stand-alone Asio.
]
There is a noted 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.
[heading Credits] [heading Credits]
Boost.Asio is the inspiration behind which all of the interfaces and Boost.Asio is the inspiration behind which all of the interfaces and
implementation strategies are built. Some parts of the documentation are implementation strategies are built. Some parts of the documentation are
written to closely resemble the wording and presentation of Boost.Asio written to closely resemble the wording and presentation of Boost.Asio
documentation. Credit goes to Christopher Kohlhoff for the wonderful documentation. Credit goes to
Asio library and the ideas upon which Beast is built. [@https://github.com/chriskohlhoff Christopher Kohlhoff]
for his wonderful Asio library and the ideas in __N4588__ which power Beast.
Beast would not be possible without the support of Beast would not be possible without the support of
[@https://www.ripple.com Ripple] [@https://www.ripple.com Ripple]
@@ -120,12 +107,12 @@ contributed by
[@https://github.com/miguelportilla Miguel Portilla], [@https://github.com/miguelportilla Miguel Portilla],
[@https://github.com/nbougalis Nik Bougalis], [@https://github.com/nbougalis Nik Bougalis],
[@https://github.com/seelabs Scott Determan], [@https://github.com/seelabs Scott Determan],
[@https://github.com/scottschurr], [@https://github.com/scottschurr Scott Schurr],
Many thanks to Many thanks to
[@https://github.com/K-ballo Agustín Bergé], [@https://github.com/K-ballo Agustín Bergé],
[@http://www.boost.org/users/people/glen_fernandes.html Glen Fernandes], [@http://www.boost.org/users/people/glen_fernandes.html Glen Fernandes],
and and
[https://github.com/pdimov Peter Dimov] [@https://github.com/pdimov Peter Dimov]
for tirelessly answering questions on for tirelessly answering questions on
[@https://cpplang.slack.com/ Cpplang-Slack]. [@https://cpplang.slack.com/ Cpplang-Slack].

View File

@@ -7,6 +7,14 @@
[section:http Using HTTP] [section:http Using HTTP]
[warning
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.
]
This library offers programmers simple and performant models of HTTP messages This library offers programmers simple and performant models of HTTP messages
and their associated operations including synchronous, asynchronous, and and their associated operations including synchronous, asynchronous, and
buffer-oriented parsing and serialization of messages in the HTTP/1 wire buffer-oriented parsing and serialization of messages in the HTTP/1 wire

View File

@@ -24,7 +24,7 @@ Every message contains a set of zero or more field name/value pairs,
collectively called "fields". The names and values are represented using collectively called "fields". The names and values are represented using
text strings with various requirements. A serialized field contains the text strings with various requirements. A serialized field contains the
field name, then a colon followed by a space (`": "`), and finally the field field name, then a colon followed by a space (`": "`), and finally the field
value. value with a trailing CRLF.
When a client and server have established a connection and intend to 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 use HTTP, the client sends a series of requests while the server reads

View File

@@ -53,10 +53,12 @@ possible value of `isRequest`:
[$images/message.png [width 730px] [height 410px]] [$images/message.png [width 730px] [height 410px]]
For notational convenience, the template type aliases The template type aliases
[link beast.ref.http__request `request`] and [link beast.ref.http__request `request`] and
[link beast.ref.http__response `response`] [link beast.ref.http__response `response`]
are provided, which also supply commonly chosen __fields__ type as a default: are provided for notational convenience. They also come with the default
__fields__, a common choice.
``` ```
/// A typical HTTP request /// A typical HTTP request
template<class Body, class Fields = fields> template<class Body, class Fields = fields>
@@ -138,8 +140,8 @@ Here we create an HTTP response indicating success. Note that this
message has a body. The function message has a body. The function
[link beast.ref.http__message.prepare prepare] [link beast.ref.http__message.prepare prepare]
automatically sets the Content-Length or Transfer-Encoding field automatically sets the Content-Length or Transfer-Encoding field
depending on the body type. The use of prepare is optional, the depending on the content and type of the `body` member. The use
fields may be set manually if desired. of prepare is optional; these fields may also be set.
[table Create Response [table Create Response
[[Statements] [Serialized Result]] [[Statements] [Serialized Result]]

View File

@@ -8,31 +8,30 @@
[section:streams Message Stream Operations] [section:streams Message Stream Operations]
Beast provides synchronous and asynchronous algorithms to serialize and Beast provides synchronous and asynchronous algorithms to serialize and
parse HTTP/1 wire format messages on streams. These functions form the parse HTTP/1 wire format messages on streams. These functions form a
basic interface which works on the entire header or message at once, basic interface for operating on entire messages:
requiring no separately managed state objects:
[table Basic Interface [table Basic Interface
[[Name][Description]] [[Name][Description]]
[[ [[
[link beast.ref.http__read.overload3 [*read]] [link beast.ref.http__read.overload3 [*read]]
][ ][
Parse a __message__ from a __SyncReadStream__. Read a __message__ from a __SyncReadStream__.
]] ]]
[[ [[
[link beast.ref.http__async_read.overload2 [*async_read]] [link beast.ref.http__async_read.overload2 [*async_read]]
][ ][
Parse a __message__ from an __AsyncReadStream__. Read a __message__ from an __AsyncReadStream__.
]] ]]
[[ [[
[link beast.ref.http__write.overload1 [*write]] [link beast.ref.http__write.overload1 [*write]]
][ ][
Serialize a __message__ to a __SyncWriteStream__. Write a __message__ to a __SyncWriteStream__.
]] ]]
[[ [[
[link beast.ref.http__async_write [*async_write]] [link beast.ref.http__async_write [*async_write]]
][ ][
Serialize a __message__ to an __AsyncWriteStream__. Write a __message__ to an __AsyncWriteStream__.
]] ]]
] ]
@@ -45,13 +44,13 @@ occurs this argument will be set to contain the error code.
[heading Reading] [heading Reading]
Because a serialized header is not length-prefixed, algorithms which parse Because a serialized header is not length-prefixed, algorithms which
messages from a stream may read past the end of a message for efficiency. parse messages from a stream may read past the end of a message for
To hold this surplus data, all stream read operations use a passed-in efficiency. To hold this surplus data, all stream read operations use
__DynamicBuffer__ which persists between calls. Each read operation may a passed-in __DynamicBuffer__ which must be persisted between calls.
consume bytes remaining in the buffer, and leave behind new bytes. In this Each read operation may consume bytes remaining in the buffer, and
example we declare the buffer and a message variable, then read a complete leave behind new bytes. In this example we declare the buffer and a
HTTP request synchronously: message variable, then read a complete HTTP request synchronously:
[http_snippet_4] [http_snippet_4]

View File

@@ -7,21 +7,20 @@
[section:serializer_streams Serializer Stream Operations] [section:serializer_streams Serializer Stream Operations]
Algorithms for sending entire messages to streams are intended for light Message oriented stream operations provide for limited control.
duty use-cases such as simple clients and low utilization servers. Sophisticated algorithms may need to do more, such as:
Sophisticated algorithms will need to do more:
* Send the message header first. * Send the header first, and the body later.
* Set chunk extensions or trailers using a chunk decorator.
* Send a message incrementally: bounded work in each I/O cycle. * Send a message incrementally: bounded work in each I/O cycle.
* Use a custom chunk decorator or allocator when sending messages.
* Use a series of caller-provided buffers to represent the body. * Use a series of caller-provided buffers to represent the body.
All of these operations require callers to manage the lifetime of state These tasks may be performed by using the serializer stream interfaces.
information associated with the operation, by constructing a __serializer__ To use these interfaces, first construct a __serializer__ object with
object with the message to be sent. The serializer type has this declaration: the message to be sent. The serializer type has this declaration:
[http_snippet_9] [http_snippet_9]
@@ -30,10 +29,9 @@ This code creates an HTTP response and the corresponding serializer:
[http_snippet_10] [http_snippet_10]
The convenience function The function
[link beast.ref.http__make_serializer `make_serializer`] [link beast.ref.http__make_serializer `make_serializer`]
is provided to avoid repetition of template argument types. The declaration is provided to simplify creation of variables:
for `sr` in the code above may be written as:
[http_snippet_11] [http_snippet_11]
@@ -64,12 +62,12 @@ The stream operations which work on serializers are:
[[ [[
[link beast.ref.http__write_some.overload1 [*write_some]] [link beast.ref.http__write_some.overload1 [*write_some]]
][ ][
Send some __serializer__ buffer data to a __SyncWriteStream__. Send part of a __serializer__ to a __SyncWriteStream__.
]] ]]
[[ [[
[link beast.ref.http__async_write_some [*async_write_some]] [link beast.ref.http__async_write_some [*async_write_some]]
][ ][
Send some __serializer__ buffer data asynchronously to an __AsyncWriteStream__. Send part of a __serializer__ asynchronously to an __AsyncWriteStream__.
]] ]]
] ]
@@ -78,4 +76,41 @@ synchronously. This performs the same operation as calling `write(stream, m)`:
[http_snippet_12] [http_snippet_12]
[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 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 by __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:
[http_snippet_17]
[endsect] [endsect]

View File

@@ -7,15 +7,15 @@
[section:parser_streams Parser Stream Operations] [section:parser_streams Parser Stream Operations]
Algorithms for receiving entire messages from streams are helpful for simple Message oriented stream operations provide for limited control.
use-cases. Sophisticated algorithms will need to do more: Sophisticated algorithms may need to do more, such as:
* Receive the message header first. * Receive the header first, then the body later.
* Receive a large body using a fixed-size buffer.
* Receive a message incrementally: bounded work in each I/O cycle. * Receive a message incrementally: bounded work in each I/O cycle.
* Receive an arbitrarily-sized body using a fixed-size buffer.
* Defer the commitment to a __Body__ type until after reading the header. * Defer the commitment to a __Body__ type until after reading the header.
All of these operations require callers to manage the lifetime of state All of these operations require callers to manage the lifetime of state
@@ -99,21 +99,20 @@ The stream operations which work on parsers are:
]] ]]
] ]
As with the stream parse algorithms which operate on entire messages, stream As with message stream operations, parser stream operations require a
operations for parsers require a passed-in __DynamicBuffer__ which persists persisted __DynamicBuffer__ for holding unused octets from the stream.
between calls to hold unused octets from the stream. The basic parser The basic parser implementation is optimized for the case where this dynamic
implementation is optimized for the case where this dynamic buffer stores buffer stores its input sequence in a single contiguous memory buffer. It is
its input sequence in a single contiguous memory buffer. It is advised to advised to use an instance of __flat_buffer__, __static_buffer__, or
use an instance of __flat_buffer__ for this purpose, although a user defined __static_buffer_n__ for this purpose, although a user defined instance of
instance of __DynamicBuffer__ which produces input sequences of length one __DynamicBuffer__ which produces input sequences of length one is also suitable.
is also suitable.
The provided parsers use a "captive object" model, acting as container for The provided parsers use a "captive object" model, acting as container for
the __message__ or __header__ produced as a result of parsing. The caller the __message__ produced as a result of parsing. The caller accesses the
accesses the contained object, and depending on the types used to instantiate contained object, and depending on the types used to instantiate the parser,
the parser, it may be possible to acquire ownership of the header or message it may be possible to acquire ownership of the header or message captive
captive object and destroy the parser. In this example we read an HTTP object and destroy the parser. In this example we read an HTTP response
response with a string body using a parser, then print the response: with a string body using a parser, then print the response:
[http_snippet_13] [http_snippet_13]

View File

@@ -55,41 +55,4 @@ C++14 example we print the header first, followed by the body:
[http_snippet_16] [http_snippet_16]
[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 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 by __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:
[http_snippet_17]
[endsect] [endsect]

View File

@@ -10,7 +10,7 @@
In some cases, users may wish to create an instance of __parser__, or a 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 user-defined type derived from __basic_parser__ and invoke its methods
directly instead of using the provided stream algorithms. This could be directly instead of using the provided stream algorithms. This could be
useful for implementing algorithms on streams whose interface does not useful for implementing algorithms on objects whose interface does not
conform to any __Stream__. For example, a conform to any __Stream__. For example, a
[@http://zeromq.org/ *ZeroMQ* socket]. [@http://zeromq.org/ *ZeroMQ* socket].
The basic parser interface is interactive; the caller invokes the function The basic parser interface is interactive; the caller invokes the function

View File

@@ -7,6 +7,10 @@
[section HTTP Examples] [section HTTP Examples]
These examples in this section are working functions that may be found
in the examples directory. They demonstrate the usage of the library for
a variety of scenarios.
[section Expect 100-continue (Client)] [section Expect 100-continue (Client)]
The Expect field with the value "100-continue" in a request is special. It The Expect field with the value "100-continue" in a request is special. It

View File

@@ -19,12 +19,12 @@ Beast provides developers with a robust WebSocket implementation built on
Boost.Asio with a consistent asynchronous model using a modern C++ approach. Boost.Asio with a consistent asynchronous model using a modern C++ approach.
[note [note
The WebSocket documentation assumes familiarity the WebSocket protocol This documentation assumes familiarity with __Asio__ and
specification described in __rfc6455__. Code appearing in these the protocol specification described in __rfc6455__.
sections is written as if the following declarations are in effect: Sample code and identifiers appearing in this section is written
``` as if these declarations are in effect:
#include <beast/websocket.hpp>
``` [ws_snippet_1]
] ]
[include 6_1_streams.qbk] [include 6_1_streams.qbk]

View File

@@ -8,7 +8,7 @@
[section:streams Creating Streams] [section:streams Creating Streams]
The interface to the WebSocket implementation is a single template class The interface to the WebSocket implementation is a single template class
[link beast.ref.websocket__stream `websocket::stream`] [link beast.ref.websocket__stream `stream`]
which wraps an existing network transport object or other type of which wraps an existing network transport object or other type of
octet oriented stream. The wrapped object is called the "next layer" octet oriented stream. The wrapped object is called the "next layer"
and must meet the requirements of __SyncStream__ if synchronous and must meet the requirements of __SyncStream__ if synchronous
@@ -19,28 +19,21 @@ the stream wrapper are passed to next layer's constructor.
Here we declare a websocket stream over a TCP/IP socket with ownership Here we declare a websocket stream over a TCP/IP socket with ownership
of the socket. The `io_service` argument is forwarded to the wrapped of the socket. The `io_service` argument is forwarded to the wrapped
socket's constructor: socket's constructor:
```
boost::asio::io_service ios; [ws_snippet_2]
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
```
[heading Using SSL] [heading Using SSL]
To use WebSockets over SSL, use an instance of the `boost::asio::ssl::stream` To use WebSockets over SSL, use an instance of the `boost::asio::ssl::stream`
class template as the template type for the stream. The required `io_service` class template as the template type for the stream. The required `io_service`
and `ssl::context` arguments are forwarded to the wrapped stream's constructor: and `ssl::context` arguments are forwarded to the wrapped stream's constructor:
```
#include <beast/websocket/ssl.hpp>
#include <boost/asio/ssl.hpp>
boost::asio::io_service ios; [wss_snippet_1]
boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23}; [wss_snippet_2]
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ws{ios, ctx};
```
[note [note
Code which declares stream objects using Asio SSL types must Code which declares stream objects using Asio SSL types
to include the file `<beast/websocket/ssl.hpp>`. must include the file `<beast/websocket/ssl.hpp>`.
] ]
[heading Non-owning References] [heading Non-owning References]
@@ -48,27 +41,20 @@ and `ssl::context` arguments are forwarded to the wrapped stream's constructor:
If a socket type supports move construction, a websocket stream may be If a socket type supports move construction, a websocket stream may be
constructed around the already existing socket by invoking the move constructed around the already existing socket by invoking the move
constructor signature: constructor signature:
```
... [ws_snippet_3]
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{std::move(sock)};
```
Or, the wrapper can be constructed with a non-owning reference. In Or, the wrapper can be constructed with a non-owning reference. In
this case, the caller is responsible for managing the lifetime of the this case, the caller is responsible for managing the lifetime of the
underlying socket being wrapped: underlying socket being wrapped:
```
... [ws_snippet_4]
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
```
Once the WebSocket stream wrapper is created, the wrapped object may be Once the WebSocket stream wrapper is created, the wrapped object may be
accessed by calling [link beast.ref.websocket__stream.next_layer.overload1 `stream::next_layer`]: accessed by calling
``` [link beast.ref.websocket__stream.next_layer.overload1 `stream::next_layer`]:
boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws{ios, ctx}; [ws_snippet_5]
...
ws.next_layer().shutdown(); // ssl::stream shutdown
```
[warning [warning
Initiating operations on the next layer while websocket Initiating operations on the next layer while websocket

View File

@@ -10,42 +10,20 @@
Connections are established by invoking functions directly on the next layer Connections are established by invoking functions directly on the next layer
object. For example, to make an outgoing connection using a standard TCP/IP object. For example, to make an outgoing connection using a standard TCP/IP
socket: socket:
```
std::string const host = "mywebapp.com"; [ws_snippet_6]
boost::asio::io_service ios;
boost::asio::ip::tcp::resolver r{ios};
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
boost::asio::connect(ws.next_layer(),
r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"}));
```
Similarly, to accept an incoming connection using a standard TCP/IP Similarly, to accept an incoming connection using a standard TCP/IP
socket, pass the next layer object to the acceptor: socket, pass the next layer object to the acceptor:
```
void do_accept(boost::asio::ip::tcp::acceptor& acceptor) [ws_snippet_7]
{
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{acceptor.get_io_service()};
acceptor.accept(ws.next_layer());
}
```
When using SSL, which itself wraps a next layer object that is usually a When using SSL, which itself wraps a next layer object that is usually a
TCP/IP socket, multiple calls to retrieve the next layer may be required. TCP/IP socket, multiple calls to retrieve the next layer may be required.
In this example, the websocket stream wraps the SSL stream which wraps In this example, the websocket stream wraps the SSL stream which wraps
the TCP/IP socket: the TCP/IP socket:
```
beast::websocket::stream<boost::asio::ssl::stream<
boost::asio::ip::tcp::socket>> ws{ios, ctx};
// connect the underlying TCP/IP socket [wss_snippet_3]
ws.next_layer().next_layer().connect(ep);
// perform SSL handshake
ws.next_layer().handshake(boost::asio::ssl::stream_base::client);
// perform WebSocket handshake
ws.handshake("localhost", "/");
```
[note [note
Examples use synchronous interfaces for clarity of exposition. Examples use synchronous interfaces for clarity of exposition.

View File

@@ -7,13 +7,9 @@
#include <beast.hpp> #include <beast.hpp>
/* // Contains the HTTP Examples from the documentation.
This file contains all of the example code snippets contained
in the documentation, which directly includes this source code.
*/
// The documentation assumes the beast::http namespace // The documentation assumes the beast::http namespace
namespace beast { namespace beast {
namespace http { namespace http {
@@ -194,7 +190,7 @@ send_cgi_response(
// Set up the response. We use the buffer_body type, // Set up the response. We use the buffer_body type,
// allowing serialization to use manually provided buffers. // allowing serialization to use manually provided buffers.
message<false, buffer_body, fields> res; response<buffer_body> res;
res.result(status::ok); res.result(status::ok);
res.version = 11; res.version = 11;

View File

@@ -0,0 +1,19 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <beast.hpp>
// Contains the WebSocket Examples from the documentation.
// The documentation assumes the beast::websocket namespace
namespace beast {
namespace websocket {
} // websocket
} // beast

View File

@@ -29,9 +29,9 @@ int main()
req.method(beast::http::verb::get); req.method(beast::http::verb::get);
req.target("/"); req.target("/");
req.version = 11; req.version = 11;
req.replace("Host", host + ":" + req.insert(beast::http::field::host, host + ":" +
boost::lexical_cast<std::string>(sock.remote_endpoint().port())); boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
req.replace("User-Agent", "Beast"); req.insert(beast::http::field::user_agent, "Beast");
req.prepare(); req.prepare();
beast::http::write(sock, req); beast::http::write(sock, req);

View File

@@ -39,7 +39,11 @@ namespace http {
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -86,7 +90,11 @@ read_some(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
The function returns the number of bytes processed from the dynamic The function returns the number of bytes processed from the dynamic
buffer. The caller should remove these bytes by calling `consume` on buffer. The caller should remove these bytes by calling `consume` on
@@ -141,7 +149,11 @@ read_some(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b AsyncReadStream concept. The type must support the @b AsyncReadStream concept.
@@ -212,7 +224,11 @@ async_read_some(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -261,7 +277,11 @@ read_header(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -314,7 +334,11 @@ read_header(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b AsyncReadStream concept. The type must support the @b AsyncReadStream concept.
@@ -383,7 +407,11 @@ async_read_header(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -432,7 +460,11 @@ read(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -485,7 +517,11 @@ read(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b AsyncReadStream concept. The type must support the @b AsyncReadStream concept.
@@ -553,7 +589,11 @@ async_read(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -599,7 +639,11 @@ read(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -650,7 +694,11 @@ read(
@li @ref error::end_of_stream if no octets were parsed, or @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed. @li @ref error::partial_message if any octets were parsed but the
message was incomplete, otherwise:
@li A successful result. A subsequent attempt to read will
return @ref error::end_of_stream
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b AsyncReadStream concept. The type must support the @b AsyncReadStream concept.

View File

@@ -39,8 +39,7 @@ class stream<NextLayer>::response_op
{ {
bool cont; bool cont;
stream<NextLayer>& ws; stream<NextLayer>& ws;
http::message<false, http::response<http::empty_body> res;
http::empty_body, http::fields> res;
int state = 0; int state = 0;
template<class Fields, class Decorator> template<class Fields, class Decorator>

View File

@@ -39,8 +39,7 @@ class stream<NextLayer>::handshake_op
stream<NextLayer>& ws; stream<NextLayer>& ws;
response_type* res_p; response_type* res_p;
detail::sec_ws_key_type key; detail::sec_ws_key_type key;
http::message<true, http::request<http::empty_body> req;
http::empty_body, http::fields> req;
response_type res; response_type res;
int state = 0; int state = 0;

View File

@@ -70,6 +70,7 @@ unit-test http-bench :
unit-test websocket-tests : unit-test websocket-tests :
../extras/beast/unit_test/main.cpp ../extras/beast/unit_test/main.cpp
websocket/doc_snippets.cpp
websocket/error.cpp websocket/error.cpp
websocket/option.cpp websocket/option.cpp
websocket/rfc6455.cpp websocket/rfc6455.cpp

View File

@@ -122,7 +122,6 @@ void fxx() {
//[http_snippet_10 //[http_snippet_10
response<string_body> res; response<string_body> res;
serializer<false, string_body, fields> sr{res}; serializer<false, string_body, fields> sr{res};
//] //]

View File

@@ -74,63 +74,63 @@ public:
testMessage() testMessage()
{ {
BOOST_STATIC_ASSERT(std::is_constructible< BOOST_STATIC_ASSERT(std::is_constructible<
message<true, default_body, fields>>::value); request<default_body>>::value);
BOOST_STATIC_ASSERT(std::is_constructible< BOOST_STATIC_ASSERT(std::is_constructible<
message<true, one_arg_body, fields>, Arg1>::value); request<one_arg_body>, Arg1>::value);
BOOST_STATIC_ASSERT(std::is_constructible< BOOST_STATIC_ASSERT(std::is_constructible<
message<true, one_arg_body, fields>, Arg1 const>::value); request<one_arg_body>, Arg1 const>::value);
BOOST_STATIC_ASSERT(std::is_constructible< BOOST_STATIC_ASSERT(std::is_constructible<
message<true, one_arg_body, fields>, Arg1 const&>::value); request<one_arg_body>, Arg1 const&>::value);
BOOST_STATIC_ASSERT(std::is_constructible< BOOST_STATIC_ASSERT(std::is_constructible<
message<true, one_arg_body, fields>, Arg1&&>::value); request<one_arg_body>, Arg1&&>::value);
BOOST_STATIC_ASSERT(! std::is_constructible< BOOST_STATIC_ASSERT(! std::is_constructible<
message<true, one_arg_body, fields>>::value); request<one_arg_body>>::value);
BOOST_STATIC_ASSERT(std::is_constructible< BOOST_STATIC_ASSERT(std::is_constructible<
message<true, one_arg_body, fields>, request<one_arg_body>,
Arg1, fields::allocator_type>::value); Arg1, fields::allocator_type>::value);
BOOST_STATIC_ASSERT(std::is_constructible< BOOST_STATIC_ASSERT(std::is_constructible<
message<true, one_arg_body, fields>, std::piecewise_construct_t, request<one_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1>>::value); std::tuple<Arg1>>::value);
BOOST_STATIC_ASSERT(std::is_constructible< BOOST_STATIC_ASSERT(std::is_constructible<
message<true, two_arg_body, fields>, std::piecewise_construct_t, request<two_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>>::value); std::tuple<Arg1, Arg2>>::value);
BOOST_STATIC_ASSERT(std::is_constructible< BOOST_STATIC_ASSERT(std::is_constructible<
message<true, two_arg_body, fields>, std::piecewise_construct_t, request<two_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>, std::tuple<fields::allocator_type>>::value); std::tuple<Arg1, Arg2>, std::tuple<fields::allocator_type>>::value);
{ {
Arg1 arg1; Arg1 arg1;
message<true, one_arg_body, fields>{std::move(arg1)}; request<one_arg_body>{std::move(arg1)};
BEAST_EXPECT(arg1.moved); BEAST_EXPECT(arg1.moved);
} }
{ {
header<true, fields> h; header<true> h;
h.insert(field::user_agent, "test"); h.insert(field::user_agent, "test");
message<true, one_arg_body, fields> m{Arg1{}, h}; request<one_arg_body> m{Arg1{}, h};
BEAST_EXPECT(h["User-Agent"] == "test"); BEAST_EXPECT(h["User-Agent"] == "test");
BEAST_EXPECT(m["User-Agent"] == "test"); BEAST_EXPECT(m["User-Agent"] == "test");
} }
{ {
header<true, fields> h; header<true> h;
h.insert(field::user_agent, "test"); h.insert(field::user_agent, "test");
message<true, one_arg_body, fields> m{Arg1{}, std::move(h)}; request<one_arg_body> m{Arg1{}, std::move(h)};
BEAST_EXPECT(! h.exists("User-Agent")); BEAST_EXPECT(! h.exists("User-Agent"));
BEAST_EXPECT(m["User-Agent"] == "test"); BEAST_EXPECT(m["User-Agent"] == "test");
} }
// swap // swap
message<true, string_body, fields> m1; request<string_body> m1;
message<true, string_body, fields> m2; request<string_body> m2;
m1.target("u"); m1.target("u");
m1.body = "1"; m1.body = "1";
m1.insert("h", "v"); m1.insert("h", "v");
@@ -197,8 +197,8 @@ public:
void void
testSwap() testSwap()
{ {
message<false, string_body, fields> m1; response<string_body> m1;
message<false, string_body, fields> m2; response<string_body> m2;
m1.result(status::ok); m1.result(status::ok);
m1.version = 10; m1.version = 10;
m1.body = "1"; m1.body = "1";

View File

@@ -336,7 +336,7 @@ public:
"GET / HTTP/1.1\r\n\r\n"}; "GET / HTTP/1.1\r\n\r\n"};
BEAST_EXPECT(handler::count() == 0); BEAST_EXPECT(handler::count() == 0);
multi_buffer b; multi_buffer b;
message<true, dynamic_body, fields> m; request<dynamic_body> m;
async_read(is, b, m, handler{}); async_read(is, b, m, handler{});
BEAST_EXPECT(handler::count() > 0); BEAST_EXPECT(handler::count() > 0);
ios.stop(); ios.stop();
@@ -355,7 +355,7 @@ public:
"GET / HTTP/1.1\r\n\r\n"}; "GET / HTTP/1.1\r\n\r\n"};
BEAST_EXPECT(handler::count() == 0); BEAST_EXPECT(handler::count() == 0);
multi_buffer b; multi_buffer b;
message<true, dynamic_body, fields> m; request<dynamic_body> m;
async_read(is, b, m, handler{}); async_read(is, b, m, handler{});
BEAST_EXPECT(handler::count() > 0); BEAST_EXPECT(handler::count() > 0);
} }

View File

@@ -289,7 +289,7 @@ public:
testAsyncWrite(yield_context do_yield) testAsyncWrite(yield_context do_yield)
{ {
{ {
message<false, string_body, fields> m; response<string_body> m;
m.version = 10; m.version = 10;
m.result(status::ok); m.result(status::ok);
m.reason("OK"); m.reason("OK");
@@ -308,7 +308,7 @@ public:
"*****"); "*****");
} }
{ {
message<false, string_body, fields> m; response<string_body> m;
m.version = 11; m.version = 11;
m.result(status::ok); m.result(status::ok);
m.reason("OK"); m.reason("OK");
@@ -341,7 +341,7 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
test::string_ostream> fs(fc, ios_); test::string_ostream> fs(fc, ios_);
message<true, fail_body, fields> m{fc}; request<fail_body> m{fc};
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 10; m.version = 10;
@@ -372,7 +372,7 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
test::string_ostream> fs(fc, ios_); test::string_ostream> fs(fc, ios_);
message<true, fail_body, fields> m{fc}; request<fail_body> m{fc};
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 10; m.version = 10;
@@ -405,7 +405,7 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
test::string_ostream> fs(fc, ios_); test::string_ostream> fs(fc, ios_);
message<true, fail_body, fields> m{fc}; request<fail_body> m{fc};
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 10; m.version = 10;
@@ -438,7 +438,7 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
test::string_ostream> fs(fc, ios_); test::string_ostream> fs(fc, ios_);
message<true, fail_body, fields> m{fc}; request<fail_body> m{fc};
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 10; m.version = 10;
@@ -466,7 +466,7 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
test::string_ostream> fs(fc, ios_); test::string_ostream> fs(fc, ios_);
message<true, fail_body, fields> m{fc}; request<fail_body> m{fc};
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 10; m.version = 10;
@@ -495,7 +495,7 @@ public:
{ {
// auto content-length HTTP/1.0 // auto content-length HTTP/1.0
{ {
message<true, string_body, fields> m; request<string_body> m;
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 10; m.version = 10;
@@ -512,7 +512,7 @@ public:
} }
// no content-length HTTP/1.0 // no content-length HTTP/1.0
{ {
message<true, unsized_body, fields> m; request<unsized_body> m;
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 10; m.version = 10;
@@ -532,7 +532,7 @@ public:
} }
// auto content-length HTTP/1.1 // auto content-length HTTP/1.1
{ {
message<true, string_body, fields> m; request<string_body> m;
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 11; m.version = 11;
@@ -549,7 +549,7 @@ public:
} }
// no content-length HTTP/1.1 // no content-length HTTP/1.1
{ {
message<true, unsized_body, fields> m; request<unsized_body> m;
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 11; m.version = 11;
@@ -574,7 +574,7 @@ public:
void test_std_ostream() void test_std_ostream()
{ {
// Conversion to std::string via operator<< // Conversion to std::string via operator<<
message<true, string_body, fields> m; request<string_body> m;
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 11; m.version = 11;
@@ -604,7 +604,7 @@ public:
boost::asio::io_service ios; boost::asio::io_service ios;
test::string_ostream os{ios}; test::string_ostream os{ios};
BEAST_EXPECT(handler::count() == 0); BEAST_EXPECT(handler::count() == 0);
message<true, string_body, fields> m; request<string_body> m;
m.method(verb::get); m.method(verb::get);
m.version = 11; m.version = 11;
m.target("/"); m.target("/");
@@ -626,7 +626,7 @@ public:
boost::asio::io_service ios; boost::asio::io_service ios;
test::string_ostream is{ios}; test::string_ostream is{ios};
BEAST_EXPECT(handler::count() == 0); BEAST_EXPECT(handler::count() == 0);
message<true, string_body, fields> m; request<string_body> m;
m.method(verb::get); m.method(verb::get);
m.version = 11; m.version = 11;
m.target("/"); m.target("/");
@@ -708,7 +708,7 @@ public:
test::pipe p{ios_}; test::pipe p{ios_};
p.client.write_size(3); p.client.write_size(3);
message<false, Body, fields> m0; response<Body> m0;
m0.version = 11; m0.version = 11;
m0.result(status::ok); m0.result(status::ok);
m0.reason("OK"); m0.reason("OK");

View File

@@ -10,6 +10,7 @@ add_executable (websocket-tests
../../extras/beast/unit_test/main.cpp ../../extras/beast/unit_test/main.cpp
websocket_async_echo_server.hpp websocket_async_echo_server.hpp
websocket_sync_echo_server.hpp websocket_sync_echo_server.hpp
doc_snippets.cpp
error.cpp error.cpp
option.cpp option.cpp
rfc6455.cpp rfc6455.cpp

View File

@@ -0,0 +1,72 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <beast/core.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <thread>
using namespace beast;
//[ws_snippet_1
#include <beast/websocket.hpp>
using namespace beast::websocket;
//]
namespace doc_ws_snippets {
void fxx() {
boost::asio::io_service ios;
boost::asio::io_service::work work{ios};
std::thread t{[&](){ ios.run(); }};
error_code ec;
boost::asio::ip::tcp::socket sock{ios};
{
//[ws_snippet_2
stream<boost::asio::ip::tcp::socket> ws{ios};
//]
}
{
//[ws_snippet_3
stream<boost::asio::ip::tcp::socket> ws{std::move(sock)};
//]
}
{
//[ws_snippet_4
stream<boost::asio::ip::tcp::socket&> ws{sock};
//]
//[ws_snippet_5
ws.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_send);
//]
}
{
//[ws_snippet_6
std::string const host = "mywebapp.com";
boost::asio::ip::tcp::resolver r{ios};
stream<boost::asio::ip::tcp::socket> ws{ios};
boost::asio::connect(ws.next_layer(),
r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"}));
//]
}
{
//[ws_snippet_7
boost::asio::ip::tcp::acceptor acceptor{ios};
stream<boost::asio::ip::tcp::socket> ws{acceptor.get_io_service()};
acceptor.accept(ws.next_layer());
//]
}
} // fxx()
} // doc_ws_snippets

View File

@@ -11,6 +11,7 @@ add_executable (websocket-ssl-tests
${BEAST_INCLUDES} ${BEAST_INCLUDES}
${EXTRAS_INCLUDES} ${EXTRAS_INCLUDES}
../../../extras/beast/unit_test/main.cpp ../../../extras/beast/unit_test/main.cpp
doc_snippets.cpp
websocket_async_ssl_echo_server.hpp websocket_async_ssl_echo_server.hpp
ssl_server.cpp ssl_server.cpp
) )

View File

@@ -0,0 +1,58 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <beast/core.hpp>
#include <beast/websocket.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <thread>
using namespace beast;
using namespace beast::websocket;
//[wss_snippet_1
#include <beast/websocket/ssl.hpp>
#include <boost/asio/ssl.hpp>
//]
namespace doc_wss_snippets {
void fxx() {
boost::asio::io_service ios;
boost::asio::io_service::work work{ios};
std::thread t{[&](){ ios.run(); }};
error_code ec;
boost::asio::ip::tcp::socket sock{ios};
{
//[wss_snippet_2
boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> wss{ios, ctx};
//]
}
{
//[wss_snippet_3
boost::asio::ip::tcp::endpoint ep;
boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws{ios, ctx};
// connect the underlying TCP/IP socket
ws.next_layer().next_layer().connect(ep);
// perform SSL handshake
ws.next_layer().handshake(boost::asio::ssl::stream_base::client);
// perform WebSocket handshake
ws.handshake("localhost", "/");
//]
}
} // fxx()
} // doc_wss_snippets