mirror of
https://github.com/boostorg/beast.git
synced 2025-08-01 05:44:38 +02:00
Documentation work
This commit is contained in:
67
README.md
67
README.md
@@ -13,6 +13,7 @@
|
||||
## Contents
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Audience](audience)
|
||||
- [Appearances](#appearances)
|
||||
- [Description](#description)
|
||||
- [Requirements](#requirements)
|
||||
@@ -24,37 +25,36 @@
|
||||
|
||||
## Introduction
|
||||
|
||||
Beast is a header-only, cross-platform C++ library built on Boost.Asio and
|
||||
Boost, containing two modules implementing widely used network protocols.
|
||||
Beast.HTTP offers a universal model for describing, sending, and receiving
|
||||
HTTP messages while Beast.WebSocket provides a complete implementation of
|
||||
the WebSocket protocol. Their design achieves these goals:
|
||||
Beast is a cross-platform, header-only C++11 library for low-level
|
||||
HTTP/1 and WebSocket protocol programming
|
||||
using the consistent asynchronous networking model of Boost.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.
|
||||
|
||||
* **Symmetry.** Interfaces are role-agnostic; the same interfaces can be
|
||||
used to build clients, servers, or both.
|
||||
This library is designed for:
|
||||
|
||||
* **Ease of Use.** HTTP messages are modeled using simple, readily
|
||||
accessible objects. Functions and classes used to send and receive HTTP
|
||||
or WebSocket messages are designed to resemble Boost.Asio as closely as
|
||||
possible. Users familiar with Boost.Asio will be immediately comfortable
|
||||
using this library.
|
||||
* **Symmetry:** Interfaces are role-agnostic; build clients, servers, or both.
|
||||
|
||||
* **Flexibility.** Interfaces do not mandate specific implementation
|
||||
strategies; important decisions such as buffer or thread management are
|
||||
left to users of the library.
|
||||
* **Ease of Use:** Boost.Asio users will immediately understand Beast.
|
||||
|
||||
* **Performance.** The implementation performs competitively, making it a
|
||||
realistic choice for building high performance network servers.
|
||||
* **Flexibility:** Users make the important decisions such as buffer or
|
||||
thread management.
|
||||
|
||||
* **Scalability.** Development of network applications that scale to thousands
|
||||
of concurrent connections is possible with the implementation.
|
||||
* **Performance:** Build applications handling thousands of connections or more.
|
||||
|
||||
* **Basis for further abstraction.** The interfaces facilitate the
|
||||
development of other libraries that provide higher levels of abstraction.
|
||||
* **Basis for Further Abstraction.** Components are open-ended and
|
||||
suited for building higher level libraries.
|
||||
|
||||
Beast is used in [rippled](https://github.com/ripple/rippled), an
|
||||
open source server application that implements a decentralized
|
||||
cryptocurrency system.
|
||||
## Audience
|
||||
|
||||
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
|
||||
|
||||
@@ -76,17 +76,16 @@ The library has been submitted to the
|
||||
|
||||
## Requirements
|
||||
|
||||
* Boost 1.58.0 or later
|
||||
* C++11 or later
|
||||
* **C++11:** Robust support for most language features.
|
||||
* **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.
|
||||
|
||||
These components are optionally required in order to build the
|
||||
tests and examples:
|
||||
These components are required in order to build the tests and examples:
|
||||
|
||||
* OpenSSL (optional)
|
||||
* CMake 3.7.2 or later (optional)
|
||||
* Properly configured bjam/b2 (optional)
|
||||
* CMake 3.7.2 or later
|
||||
* Properly configured bjam/b2
|
||||
|
||||
## Building
|
||||
|
||||
@@ -210,10 +209,10 @@ int main()
|
||||
req.method(beast::http::verb::get);
|
||||
req.target("/");
|
||||
req.version = 11;
|
||||
req.fields.replace("Host", host + ":" +
|
||||
req.insert(beast::http::field::host, host + ":" +
|
||||
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||
req.fields.replace("User-Agent", "Beast");
|
||||
beast::http::prepare(req);
|
||||
req.insert(beast::http::field::user_agent, "Beast");
|
||||
req.prepare();
|
||||
beast::http::write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
|
@@ -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_allocate__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]]
|
||||
[def __void_or_deduced__ [@http://www.boost.org/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]]
|
||||
[def __use_future__ [@http://www.boost.org/doc/html/boost_asio/reference/use_future_t.html `boost::asio::use_future`]]
|
||||
[def __yield_context__ [@http://www.boost.org/doc/html/boost_asio/reference/yield_context.html `boost::asio::yield_context`]]
|
||||
[def __io_service__ [@http://www.boost.org/doc/html/boost_asio/reference/io_service.html `io_service`]]
|
||||
[def __streambuf__ [@http://www.boost.org/doc/html/boost_asio/reference/streambuf.html [*boost::asio::streambuf]]]
|
||||
[def __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 __AsyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]]
|
||||
@@ -47,27 +47,29 @@
|
||||
[def __SyncReadStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]]
|
||||
[def __SyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]]
|
||||
|
||||
[def __AsyncStream__ [link beast.concept.streams.AsyncStream [*AsyncStream]]]
|
||||
[def __Body__ [link beast.concept.Body [*Body]]]
|
||||
[def __BodyReader__ [link beast.concept.BodyReader [*BodyReader]]]
|
||||
[def __BodyWriter__ [link beast.concept.BodyWriter [*BodyWriter]]]
|
||||
[def __DynamicBuffer__ [link beast.concept.DynamicBuffer [*DynamicBuffer]]]
|
||||
[def __Fields__ [link beast.concept.Fields [*Fields]]]
|
||||
[def __FieldsReader__ [link beast.concept.FieldsReader [*FieldsReader]]]
|
||||
[def __Stream__ [link beast.concept.streams [*Stream]]]
|
||||
[def __SyncStream__ [link beast.concept.streams.SyncStream [*SyncStream]]]
|
||||
[def __AsyncStream__ [link beast.concept.streams.AsyncStream [*AsyncStream]]]
|
||||
[def __Body__ [link beast.concept.Body [*Body]]]
|
||||
[def __BodyReader__ [link beast.concept.BodyReader [*BodyReader]]]
|
||||
[def __BodyWriter__ [link beast.concept.BodyWriter [*BodyWriter]]]
|
||||
[def __DynamicBuffer__ [link beast.concept.DynamicBuffer [*DynamicBuffer]]]
|
||||
[def __Fields__ [link beast.concept.Fields [*Fields]]]
|
||||
[def __FieldsReader__ [link beast.concept.FieldsReader [*FieldsReader]]]
|
||||
[def __Stream__ [link beast.concept.streams [*Stream]]]
|
||||
[def __SyncStream__ [link beast.concept.streams.SyncStream [*SyncStream]]]
|
||||
|
||||
[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]]
|
||||
[def __basic_multi_buffer__ [link beast.ref.basic_multi_buffer `basic_multi_buffer`]]
|
||||
[def __basic_parser__ [link beast.ref.http__basic_parser `basic_parser`]]
|
||||
[def __buffer_body__ [link beast.ref.http__buffer_body `buffer_body`]]
|
||||
[def __fields__ [link beast.ref.http__fields `fields`]]
|
||||
[def __flat_buffer__ [link beast.ref.flat_buffer `flat_buffer`]]
|
||||
[def __header__ [link beast.ref.http__header `header`]]
|
||||
[def __message__ [link beast.ref.http__message `message`]]
|
||||
[def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]]
|
||||
[def __parser__ [link beast.ref.http__parser `parser`]]
|
||||
[def __serializer__ [link beast.ref.http__serializer `serializer`]]
|
||||
[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]]
|
||||
[def __basic_multi_buffer__ [link beast.ref.basic_multi_buffer `basic_multi_buffer`]]
|
||||
[def __basic_parser__ [link beast.ref.http__basic_parser `basic_parser`]]
|
||||
[def __buffer_body__ [link beast.ref.http__buffer_body `buffer_body`]]
|
||||
[def __fields__ [link beast.ref.http__fields `fields`]]
|
||||
[def __flat_buffer__ [link beast.ref.flat_buffer `flat_buffer`]]
|
||||
[def __header__ [link beast.ref.http__header `header`]]
|
||||
[def __message__ [link beast.ref.http__message `message`]]
|
||||
[def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]]
|
||||
[def __parser__ [link beast.ref.http__parser `parser`]]
|
||||
[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/websocket_example.cpp]
|
||||
@@ -75,6 +77,8 @@
|
||||
[import ../examples/doc_http_samples.hpp]
|
||||
[import ../test/core/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 2_examples.qbk]
|
||||
|
@@ -8,107 +8,94 @@
|
||||
[section:overview Introduction]
|
||||
|
||||
[important
|
||||
Beast is a cross-platform, header-only C++11 library for low-level HTTP
|
||||
and WebSocket protocol programming that uses the consistent network and
|
||||
asynchronous model of __Asio__.
|
||||
|
||||
Beast is a cross-platform, header-only C++11 library for low-level
|
||||
[*HTTP/1 and WebSocket protocol] programming
|
||||
using the consistent asynchronous networking model of __Asio__.
|
||||
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
|
||||
which new libraries may be built. It is a goal that other architects
|
||||
will create interoperable solutions on top of Beast. The provided
|
||||
example programs shows how a client or server might be built.
|
||||
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.
|
||||
]
|
||||
|
||||
The design of the library achieves these goals:
|
||||
This library is designed for:
|
||||
|
||||
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
|
||||
used to build clients, servers, or both.
|
||||
* [*Symmetry:] Interfaces are role-agnostic; build clients, servers, or both.
|
||||
|
||||
* [*Ease of Use.] HTTP messages are modeled using a simple, expressive
|
||||
container. Algorithms used to send and receive HTTP or WebSocket
|
||||
messages are designed to make users already familiar with __Asio__
|
||||
immediately comfortable using this library.
|
||||
* [*Ease of Use:] __Asio__ users will immediately understand Beast.
|
||||
|
||||
* [*Flexibility.] Interfaces do not mandate specific implementation
|
||||
strategies; users make the important decisions such as buffer or
|
||||
* [*Flexibility:] Users make the important decisions such as buffer or
|
||||
thread management.
|
||||
|
||||
* [*Performance.] The implementation performs competitively, making it
|
||||
a realistic choice for building high performance network servers.
|
||||
* [*Performance:] Build applications handling thousands of connections or more.
|
||||
|
||||
* [*Scalability.] Development of network applications that scale to
|
||||
thousands of concurrent connections is possible with the implementation.
|
||||
* [*Basis for Further Abstraction.] Components are open-ended and
|
||||
suited for building higher level libraries.
|
||||
|
||||
* [*Basis for Further Abstraction.] The interfaces facilitate the
|
||||
development of other libraries that provide higher levels of abstraction.
|
||||
[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 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]
|
||||
|
||||
Beast requires:
|
||||
|
||||
* [*C++11.] A minimum of C++11 is needed.
|
||||
* [*Boost.] Beast is built on Boost, especially Boost.Asio.
|
||||
* [*OpenSSL.] If using TLS/Secure sockets (optional).
|
||||
* [*C++11:] Robust support for most language features.
|
||||
* [*Boost:] Boost.Asio and some other parts of Boost.
|
||||
* [*OpenSSL:] Optional, for using TLS/Secure sockets.
|
||||
|
||||
[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,
|
||||
or to add commands to your build script for building Beast. To link your
|
||||
program successfully, you'll need to add the Boost.System library to link
|
||||
with. If you use coroutines you'll also need the Boost.Coroutine library.
|
||||
Please visit the Boost documentation for instructions on how to do this for
|
||||
your particular build system.
|
||||
This library is [*header-only]. To link a program using Beast
|
||||
successfully, add the
|
||||
[@http://www.boost.org/libs/system/doc/reference.html Boost.System]
|
||||
library to the list of linked libraries. If you use coroutines
|
||||
you'll also need the
|
||||
[@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
|
||||
relies on other Boost parts. There are no immediate plans to offer a
|
||||
version that works with stand-alone Asio.
|
||||
|
||||
[heading Motivation]
|
||||
|
||||
There is a 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.
|
||||
[note
|
||||
Beast does not compile using the
|
||||
[@https://github.com/chriskohlhoff/asio stand-alone Asio],
|
||||
since it relies on other Boost parts. There are no immediate
|
||||
plans to offer a version that works with stand-alone Asio.
|
||||
]
|
||||
|
||||
[heading Credits]
|
||||
|
||||
Boost.Asio is the inspiration behind which all of the interfaces and
|
||||
implementation strategies are built. Some parts of the documentation are
|
||||
written to closely resemble the wording and presentation of Boost.Asio
|
||||
documentation. Credit goes to Christopher Kohlhoff for the wonderful
|
||||
Asio library and the ideas upon which Beast is built.
|
||||
documentation. Credit goes to
|
||||
[@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
|
||||
[@https://www.ripple.com Ripple]
|
||||
@@ -120,12 +107,12 @@ contributed by
|
||||
[@https://github.com/miguelportilla Miguel Portilla],
|
||||
[@https://github.com/nbougalis Nik Bougalis],
|
||||
[@https://github.com/seelabs Scott Determan],
|
||||
[@https://github.com/scottschurr],
|
||||
[@https://github.com/scottschurr Scott Schurr],
|
||||
Many thanks to
|
||||
[@https://github.com/K-ballo Agustín Bergé],
|
||||
[@http://www.boost.org/users/people/glen_fernandes.html Glen Fernandes],
|
||||
and
|
||||
[https://github.com/pdimov Peter Dimov]
|
||||
[@https://github.com/pdimov Peter Dimov]
|
||||
for tirelessly answering questions on
|
||||
[@https://cpplang.slack.com/ Cpplang-Slack].
|
||||
|
||||
|
@@ -7,6 +7,14 @@
|
||||
|
||||
[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
|
||||
and their associated operations including synchronous, asynchronous, and
|
||||
buffer-oriented parsing and serialization of messages in the HTTP/1 wire
|
||||
|
@@ -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
|
||||
text strings with various requirements. A serialized field contains the
|
||||
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
|
||||
use HTTP, the client sends a series of requests while the server reads
|
||||
|
@@ -53,10 +53,12 @@ possible value of `isRequest`:
|
||||
|
||||
[$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__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
|
||||
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
|
||||
[link beast.ref.http__message.prepare prepare]
|
||||
automatically sets the Content-Length or Transfer-Encoding field
|
||||
depending on the body type. The use of prepare is optional, the
|
||||
fields may be set manually if desired.
|
||||
depending on the content and type of the `body` member. The use
|
||||
of prepare is optional; these fields may also be set.
|
||||
|
||||
[table Create Response
|
||||
[[Statements] [Serialized Result]]
|
||||
|
@@ -8,31 +8,30 @@
|
||||
[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 the
|
||||
basic interface which works on the entire header or message at once,
|
||||
requiring no separately managed state objects:
|
||||
parse HTTP/1 wire format messages on streams. These functions form a
|
||||
basic interface for operating on entire messages:
|
||||
|
||||
[table Basic Interface
|
||||
[[Name][Description]]
|
||||
[[
|
||||
[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]]
|
||||
][
|
||||
Parse a __message__ from an __AsyncReadStream__.
|
||||
Read a __message__ from an __AsyncReadStream__.
|
||||
]]
|
||||
[[
|
||||
[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]]
|
||||
][
|
||||
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]
|
||||
|
||||
Because a serialized header is not length-prefixed, algorithms which parse
|
||||
messages from a stream may read past the end of a message for efficiency.
|
||||
To hold this surplus data, all stream read operations use a passed-in
|
||||
__DynamicBuffer__ which persists between calls. Each read operation may
|
||||
consume bytes remaining in the buffer, and leave behind new bytes. In this
|
||||
example we declare the buffer and a message variable, then read a complete
|
||||
HTTP request synchronously:
|
||||
Because a serialized header is not length-prefixed, algorithms which
|
||||
parse messages from a stream may read past the end of a message for
|
||||
efficiency. To hold this surplus data, all stream read operations use
|
||||
a passed-in __DynamicBuffer__ which must be persisted between calls.
|
||||
Each read operation may consume bytes remaining in the buffer, and
|
||||
leave behind new bytes. In this example we declare the buffer and a
|
||||
message variable, then read a complete HTTP request synchronously:
|
||||
|
||||
[http_snippet_4]
|
||||
|
||||
|
@@ -7,21 +7,20 @@
|
||||
|
||||
[section:serializer_streams Serializer Stream Operations]
|
||||
|
||||
Algorithms for sending entire messages to streams are intended for light
|
||||
duty use-cases such as simple clients and low utilization servers.
|
||||
Sophisticated algorithms will need to do more:
|
||||
Message oriented stream operations provide for limited control.
|
||||
Sophisticated algorithms may need to do more, such as:
|
||||
|
||||
* 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.
|
||||
|
||||
* Use a custom chunk decorator or allocator when sending messages.
|
||||
|
||||
* Use a series of caller-provided buffers to represent the body.
|
||||
|
||||
All of these operations require callers to manage the lifetime of state
|
||||
information associated with the operation, by constructing a __serializer__
|
||||
object with the message to be sent. The serializer type has this declaration:
|
||||
These tasks may be performed by using the serializer stream interfaces.
|
||||
To use these interfaces, first construct a __serializer__ object with
|
||||
the message to be sent. The serializer type has this declaration:
|
||||
|
||||
[http_snippet_9]
|
||||
|
||||
@@ -30,10 +29,9 @@ This code creates an HTTP response and the corresponding serializer:
|
||||
|
||||
[http_snippet_10]
|
||||
|
||||
The convenience function
|
||||
The function
|
||||
[link beast.ref.http__make_serializer `make_serializer`]
|
||||
is provided to avoid repetition of template argument types. The declaration
|
||||
for `sr` in the code above may be written as:
|
||||
is provided to simplify creation of variables:
|
||||
|
||||
[http_snippet_11]
|
||||
|
||||
@@ -64,12 +62,12 @@ The stream operations which work on serializers are:
|
||||
[[
|
||||
[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]]
|
||||
][
|
||||
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]
|
||||
|
||||
[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]
|
||||
|
@@ -7,15 +7,15 @@
|
||||
|
||||
[section:parser_streams Parser Stream Operations]
|
||||
|
||||
Algorithms for receiving entire messages from streams are helpful for simple
|
||||
use-cases. Sophisticated algorithms will need to do more:
|
||||
Message oriented stream operations provide for limited control.
|
||||
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 an arbitrarily-sized body using a fixed-size buffer.
|
||||
|
||||
* Defer the commitment to a __Body__ type until after reading the header.
|
||||
|
||||
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
|
||||
operations for parsers require a passed-in __DynamicBuffer__ which persists
|
||||
between calls to hold unused octets from the stream. The basic parser
|
||||
implementation is optimized for the case where this dynamic buffer stores
|
||||
its input sequence in a single contiguous memory buffer. It is advised to
|
||||
use an instance of __flat_buffer__ for this purpose, although a user defined
|
||||
instance of __DynamicBuffer__ which produces input sequences of length one
|
||||
is also suitable.
|
||||
As with message stream operations, parser stream operations require a
|
||||
persisted __DynamicBuffer__ for holding unused octets from the stream.
|
||||
The basic parser implementation is optimized for the case where this dynamic
|
||||
buffer stores its input sequence in a single contiguous memory buffer. It is
|
||||
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__ or __header__ 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 __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:
|
||||
|
||||
[http_snippet_13]
|
||||
|
||||
|
@@ -55,41 +55,4 @@ C++14 example we print the header first, followed by the body:
|
||||
|
||||
[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]
|
||||
|
@@ -10,7 +10,7 @@
|
||||
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 streams whose interface does not
|
||||
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
|
||||
|
@@ -7,6 +7,10 @@
|
||||
|
||||
[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)]
|
||||
|
||||
The Expect field with the value "100-continue" in a request is special. It
|
||||
|
@@ -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.
|
||||
|
||||
[note
|
||||
The WebSocket documentation assumes familiarity the WebSocket protocol
|
||||
specification described in __rfc6455__. Code appearing in these
|
||||
sections is written as if the following declarations are in effect:
|
||||
```
|
||||
#include <beast/websocket.hpp>
|
||||
```
|
||||
This documentation assumes familiarity with __Asio__ and
|
||||
the protocol specification described in __rfc6455__.
|
||||
Sample code and identifiers appearing in this section is written
|
||||
as if these declarations are in effect:
|
||||
|
||||
[ws_snippet_1]
|
||||
]
|
||||
|
||||
[include 6_1_streams.qbk]
|
||||
|
@@ -8,7 +8,7 @@
|
||||
[section:streams Creating Streams]
|
||||
|
||||
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
|
||||
octet oriented stream. The wrapped object is called the "next layer"
|
||||
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
|
||||
of the socket. The `io_service` argument is forwarded to the wrapped
|
||||
socket's constructor:
|
||||
```
|
||||
boost::asio::io_service ios;
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||
```
|
||||
|
||||
[ws_snippet_2]
|
||||
|
||||
[heading Using SSL]
|
||||
|
||||
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`
|
||||
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;
|
||||
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};
|
||||
```
|
||||
[wss_snippet_1]
|
||||
[wss_snippet_2]
|
||||
|
||||
[note
|
||||
Code which declares stream objects using Asio SSL types must
|
||||
to include the file `<beast/websocket/ssl.hpp>`.
|
||||
Code which declares stream objects using Asio SSL types
|
||||
must include the file `<beast/websocket/ssl.hpp>`.
|
||||
]
|
||||
|
||||
[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
|
||||
constructed around the already existing socket by invoking the move
|
||||
constructor signature:
|
||||
```
|
||||
...
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{std::move(sock)};
|
||||
```
|
||||
|
||||
[ws_snippet_3]
|
||||
|
||||
Or, the wrapper can be constructed with a non-owning reference. In
|
||||
this case, the caller is responsible for managing the lifetime of the
|
||||
underlying socket being wrapped:
|
||||
```
|
||||
...
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
```
|
||||
|
||||
[ws_snippet_4]
|
||||
|
||||
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`]:
|
||||
```
|
||||
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.next_layer().shutdown(); // ssl::stream shutdown
|
||||
```
|
||||
accessed by calling
|
||||
[link beast.ref.websocket__stream.next_layer.overload1 `stream::next_layer`]:
|
||||
|
||||
[ws_snippet_5]
|
||||
|
||||
[warning
|
||||
Initiating operations on the next layer while websocket
|
||||
|
@@ -10,42 +10,20 @@
|
||||
Connections are established by invoking functions directly on the next layer
|
||||
object. For example, to make an outgoing connection using a standard TCP/IP
|
||||
socket:
|
||||
```
|
||||
std::string const host = "mywebapp.com";
|
||||
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"}));
|
||||
```
|
||||
|
||||
[ws_snippet_6]
|
||||
|
||||
Similarly, to accept an incoming connection using a standard TCP/IP
|
||||
socket, pass the next layer object to the acceptor:
|
||||
```
|
||||
void do_accept(boost::asio::ip::tcp::acceptor& acceptor)
|
||||
{
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{acceptor.get_io_service()};
|
||||
acceptor.accept(ws.next_layer());
|
||||
}
|
||||
```
|
||||
|
||||
[ws_snippet_7]
|
||||
|
||||
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.
|
||||
In this example, the websocket stream wraps the SSL stream which wraps
|
||||
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
|
||||
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", "/");
|
||||
```
|
||||
[wss_snippet_3]
|
||||
|
||||
[note
|
||||
Examples use synchronous interfaces for clarity of exposition.
|
||||
|
@@ -7,13 +7,9 @@
|
||||
|
||||
#include <beast.hpp>
|
||||
|
||||
/*
|
||||
This file contains all of the example code snippets contained
|
||||
in the documentation, which directly includes this source code.
|
||||
*/
|
||||
// Contains the HTTP Examples from the documentation.
|
||||
|
||||
// The documentation assumes the beast::http namespace
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
@@ -194,7 +190,7 @@ send_cgi_response(
|
||||
|
||||
// Set up the response. We use the buffer_body type,
|
||||
// allowing serialization to use manually provided buffers.
|
||||
message<false, buffer_body, fields> res;
|
||||
response<buffer_body> res;
|
||||
|
||||
res.result(status::ok);
|
||||
res.version = 11;
|
||||
|
19
examples/doc_websocket_samples.hpp
Normal file
19
examples/doc_websocket_samples.hpp
Normal 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
|
@@ -29,9 +29,9 @@ int main()
|
||||
req.method(beast::http::verb::get);
|
||||
req.target("/");
|
||||
req.version = 11;
|
||||
req.replace("Host", host + ":" +
|
||||
req.insert(beast::http::field::host, host + ":" +
|
||||
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||
req.replace("User-Agent", "Beast");
|
||||
req.insert(beast::http::field::user_agent, "Beast");
|
||||
req.prepare();
|
||||
beast::http::write(sock, req);
|
||||
|
||||
|
@@ -39,7 +39,11 @@ namespace http {
|
||||
|
||||
@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.
|
||||
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::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
|
||||
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::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.
|
||||
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::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.
|
||||
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::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.
|
||||
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::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.
|
||||
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::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.
|
||||
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::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.
|
||||
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::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.
|
||||
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::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.
|
||||
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::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.
|
||||
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::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.
|
||||
The type must support the @b AsyncReadStream concept.
|
||||
|
@@ -39,8 +39,7 @@ class stream<NextLayer>::response_op
|
||||
{
|
||||
bool cont;
|
||||
stream<NextLayer>& ws;
|
||||
http::message<false,
|
||||
http::empty_body, http::fields> res;
|
||||
http::response<http::empty_body> res;
|
||||
int state = 0;
|
||||
|
||||
template<class Fields, class Decorator>
|
||||
|
@@ -39,8 +39,7 @@ class stream<NextLayer>::handshake_op
|
||||
stream<NextLayer>& ws;
|
||||
response_type* res_p;
|
||||
detail::sec_ws_key_type key;
|
||||
http::message<true,
|
||||
http::empty_body, http::fields> req;
|
||||
http::request<http::empty_body> req;
|
||||
response_type res;
|
||||
int state = 0;
|
||||
|
||||
|
@@ -70,6 +70,7 @@ unit-test http-bench :
|
||||
|
||||
unit-test websocket-tests :
|
||||
../extras/beast/unit_test/main.cpp
|
||||
websocket/doc_snippets.cpp
|
||||
websocket/error.cpp
|
||||
websocket/option.cpp
|
||||
websocket/rfc6455.cpp
|
||||
|
@@ -23,14 +23,14 @@ void fxx()
|
||||
|
||||
//[snippet_core_1b
|
||||
//
|
||||
using namespace beast;
|
||||
using namespace beast;
|
||||
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::io_service::work work{ios};
|
||||
std::thread t{[&](){ ios.run(); }};
|
||||
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};
|
||||
error_code ec;
|
||||
boost::asio::ip::tcp::socket sock{ios};
|
||||
|
||||
//]
|
||||
|
||||
|
@@ -122,7 +122,6 @@ void fxx() {
|
||||
//[http_snippet_10
|
||||
|
||||
response<string_body> res;
|
||||
|
||||
serializer<false, string_body, fields> sr{res};
|
||||
|
||||
//]
|
||||
|
@@ -74,63 +74,63 @@ public:
|
||||
testMessage()
|
||||
{
|
||||
BOOST_STATIC_ASSERT(std::is_constructible<
|
||||
message<true, default_body, fields>>::value);
|
||||
request<default_body>>::value);
|
||||
|
||||
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<
|
||||
message<true, one_arg_body, fields>, Arg1 const>::value);
|
||||
request<one_arg_body>, Arg1 const>::value);
|
||||
|
||||
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<
|
||||
message<true, one_arg_body, fields>, Arg1&&>::value);
|
||||
request<one_arg_body>, Arg1&&>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(! std::is_constructible<
|
||||
message<true, one_arg_body, fields>>::value);
|
||||
request<one_arg_body>>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(std::is_constructible<
|
||||
message<true, one_arg_body, fields>,
|
||||
request<one_arg_body>,
|
||||
Arg1, fields::allocator_type>::value);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
{
|
||||
Arg1 arg1;
|
||||
message<true, one_arg_body, fields>{std::move(arg1)};
|
||||
request<one_arg_body>{std::move(arg1)};
|
||||
BEAST_EXPECT(arg1.moved);
|
||||
}
|
||||
|
||||
{
|
||||
header<true, fields> h;
|
||||
header<true> h;
|
||||
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(m["User-Agent"] == "test");
|
||||
}
|
||||
{
|
||||
header<true, fields> h;
|
||||
header<true> h;
|
||||
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(m["User-Agent"] == "test");
|
||||
}
|
||||
|
||||
// swap
|
||||
message<true, string_body, fields> m1;
|
||||
message<true, string_body, fields> m2;
|
||||
request<string_body> m1;
|
||||
request<string_body> m2;
|
||||
m1.target("u");
|
||||
m1.body = "1";
|
||||
m1.insert("h", "v");
|
||||
@@ -197,8 +197,8 @@ public:
|
||||
void
|
||||
testSwap()
|
||||
{
|
||||
message<false, string_body, fields> m1;
|
||||
message<false, string_body, fields> m2;
|
||||
response<string_body> m1;
|
||||
response<string_body> m2;
|
||||
m1.result(status::ok);
|
||||
m1.version = 10;
|
||||
m1.body = "1";
|
||||
|
@@ -336,7 +336,7 @@ public:
|
||||
"GET / HTTP/1.1\r\n\r\n"};
|
||||
BEAST_EXPECT(handler::count() == 0);
|
||||
multi_buffer b;
|
||||
message<true, dynamic_body, fields> m;
|
||||
request<dynamic_body> m;
|
||||
async_read(is, b, m, handler{});
|
||||
BEAST_EXPECT(handler::count() > 0);
|
||||
ios.stop();
|
||||
@@ -355,7 +355,7 @@ public:
|
||||
"GET / HTTP/1.1\r\n\r\n"};
|
||||
BEAST_EXPECT(handler::count() == 0);
|
||||
multi_buffer b;
|
||||
message<true, dynamic_body, fields> m;
|
||||
request<dynamic_body> m;
|
||||
async_read(is, b, m, handler{});
|
||||
BEAST_EXPECT(handler::count() > 0);
|
||||
}
|
||||
|
@@ -289,7 +289,7 @@ public:
|
||||
testAsyncWrite(yield_context do_yield)
|
||||
{
|
||||
{
|
||||
message<false, string_body, fields> m;
|
||||
response<string_body> m;
|
||||
m.version = 10;
|
||||
m.result(status::ok);
|
||||
m.reason("OK");
|
||||
@@ -308,7 +308,7 @@ public:
|
||||
"*****");
|
||||
}
|
||||
{
|
||||
message<false, string_body, fields> m;
|
||||
response<string_body> m;
|
||||
m.version = 11;
|
||||
m.result(status::ok);
|
||||
m.reason("OK");
|
||||
@@ -341,7 +341,7 @@ public:
|
||||
test::fail_counter fc(n);
|
||||
test::fail_stream<
|
||||
test::string_ostream> fs(fc, ios_);
|
||||
message<true, fail_body, fields> m{fc};
|
||||
request<fail_body> m{fc};
|
||||
m.method(verb::get);
|
||||
m.target("/");
|
||||
m.version = 10;
|
||||
@@ -372,7 +372,7 @@ public:
|
||||
test::fail_counter fc(n);
|
||||
test::fail_stream<
|
||||
test::string_ostream> fs(fc, ios_);
|
||||
message<true, fail_body, fields> m{fc};
|
||||
request<fail_body> m{fc};
|
||||
m.method(verb::get);
|
||||
m.target("/");
|
||||
m.version = 10;
|
||||
@@ -405,7 +405,7 @@ public:
|
||||
test::fail_counter fc(n);
|
||||
test::fail_stream<
|
||||
test::string_ostream> fs(fc, ios_);
|
||||
message<true, fail_body, fields> m{fc};
|
||||
request<fail_body> m{fc};
|
||||
m.method(verb::get);
|
||||
m.target("/");
|
||||
m.version = 10;
|
||||
@@ -438,7 +438,7 @@ public:
|
||||
test::fail_counter fc(n);
|
||||
test::fail_stream<
|
||||
test::string_ostream> fs(fc, ios_);
|
||||
message<true, fail_body, fields> m{fc};
|
||||
request<fail_body> m{fc};
|
||||
m.method(verb::get);
|
||||
m.target("/");
|
||||
m.version = 10;
|
||||
@@ -466,7 +466,7 @@ public:
|
||||
test::fail_counter fc(n);
|
||||
test::fail_stream<
|
||||
test::string_ostream> fs(fc, ios_);
|
||||
message<true, fail_body, fields> m{fc};
|
||||
request<fail_body> m{fc};
|
||||
m.method(verb::get);
|
||||
m.target("/");
|
||||
m.version = 10;
|
||||
@@ -495,7 +495,7 @@ public:
|
||||
{
|
||||
// auto content-length HTTP/1.0
|
||||
{
|
||||
message<true, string_body, fields> m;
|
||||
request<string_body> m;
|
||||
m.method(verb::get);
|
||||
m.target("/");
|
||||
m.version = 10;
|
||||
@@ -512,7 +512,7 @@ public:
|
||||
}
|
||||
// no content-length HTTP/1.0
|
||||
{
|
||||
message<true, unsized_body, fields> m;
|
||||
request<unsized_body> m;
|
||||
m.method(verb::get);
|
||||
m.target("/");
|
||||
m.version = 10;
|
||||
@@ -532,7 +532,7 @@ public:
|
||||
}
|
||||
// auto content-length HTTP/1.1
|
||||
{
|
||||
message<true, string_body, fields> m;
|
||||
request<string_body> m;
|
||||
m.method(verb::get);
|
||||
m.target("/");
|
||||
m.version = 11;
|
||||
@@ -549,7 +549,7 @@ public:
|
||||
}
|
||||
// no content-length HTTP/1.1
|
||||
{
|
||||
message<true, unsized_body, fields> m;
|
||||
request<unsized_body> m;
|
||||
m.method(verb::get);
|
||||
m.target("/");
|
||||
m.version = 11;
|
||||
@@ -574,7 +574,7 @@ public:
|
||||
void test_std_ostream()
|
||||
{
|
||||
// Conversion to std::string via operator<<
|
||||
message<true, string_body, fields> m;
|
||||
request<string_body> m;
|
||||
m.method(verb::get);
|
||||
m.target("/");
|
||||
m.version = 11;
|
||||
@@ -604,7 +604,7 @@ public:
|
||||
boost::asio::io_service ios;
|
||||
test::string_ostream os{ios};
|
||||
BEAST_EXPECT(handler::count() == 0);
|
||||
message<true, string_body, fields> m;
|
||||
request<string_body> m;
|
||||
m.method(verb::get);
|
||||
m.version = 11;
|
||||
m.target("/");
|
||||
@@ -626,7 +626,7 @@ public:
|
||||
boost::asio::io_service ios;
|
||||
test::string_ostream is{ios};
|
||||
BEAST_EXPECT(handler::count() == 0);
|
||||
message<true, string_body, fields> m;
|
||||
request<string_body> m;
|
||||
m.method(verb::get);
|
||||
m.version = 11;
|
||||
m.target("/");
|
||||
@@ -708,7 +708,7 @@ public:
|
||||
test::pipe p{ios_};
|
||||
p.client.write_size(3);
|
||||
|
||||
message<false, Body, fields> m0;
|
||||
response<Body> m0;
|
||||
m0.version = 11;
|
||||
m0.result(status::ok);
|
||||
m0.reason("OK");
|
||||
|
@@ -10,6 +10,7 @@ add_executable (websocket-tests
|
||||
../../extras/beast/unit_test/main.cpp
|
||||
websocket_async_echo_server.hpp
|
||||
websocket_sync_echo_server.hpp
|
||||
doc_snippets.cpp
|
||||
error.cpp
|
||||
option.cpp
|
||||
rfc6455.cpp
|
||||
|
72
test/websocket/doc_snippets.cpp
Normal file
72
test/websocket/doc_snippets.cpp
Normal 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
|
@@ -11,6 +11,7 @@ add_executable (websocket-ssl-tests
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
../../../extras/beast/unit_test/main.cpp
|
||||
doc_snippets.cpp
|
||||
websocket_async_ssl_echo_server.hpp
|
||||
ssl_server.cpp
|
||||
)
|
||||
|
58
test/websocket/ssl/doc_snippets.cpp
Normal file
58
test/websocket/ssl/doc_snippets.cpp
Normal 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
|
Reference in New Issue
Block a user