diff --git a/README.md b/README.md index cd798fba..b5b449f8 100644 --- a/README.md +++ b/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(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 diff --git a/doc/0_main.qbk b/doc/0_main.qbk index b33b0eea..aa5ec904 100644 --- a/doc/0_main.qbk +++ b/doc/0_main.qbk @@ -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] diff --git a/doc/1_overview.qbk b/doc/1_overview.qbk index bd5f435c..3ba5a6d9 100644 --- a/doc/1_overview.qbk +++ b/doc/1_overview.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]. diff --git a/doc/4_00_http.qbk b/doc/4_00_http.qbk index da98332d..5d604db1 100644 --- a/doc/4_00_http.qbk +++ b/doc/4_00_http.qbk @@ -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 diff --git a/doc/4_01_primer.qbk b/doc/4_01_primer.qbk index 1031932e..b42e9e7b 100644 --- a/doc/4_01_primer.qbk +++ b/doc/4_01_primer.qbk @@ -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 diff --git a/doc/4_02_message.qbk b/doc/4_02_message.qbk index 11ee8707..bf9f63d5 100644 --- a/doc/4_02_message.qbk +++ b/doc/4_02_message.qbk @@ -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 @@ -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]] diff --git a/doc/4_03_streams.qbk b/doc/4_03_streams.qbk index d49c7743..e2f5b142 100644 --- a/doc/4_03_streams.qbk +++ b/doc/4_03_streams.qbk @@ -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] diff --git a/doc/4_04_serializer_streams.qbk b/doc/4_04_serializer_streams.qbk index 36ef7dd2..625adaed 100644 --- a/doc/4_04_serializer_streams.qbk +++ b/doc/4_04_serializer_streams.qbk @@ -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] diff --git a/doc/4_05_parser_streams.qbk b/doc/4_05_parser_streams.qbk index e75af846..2e97e335 100644 --- a/doc/4_05_parser_streams.qbk +++ b/doc/4_05_parser_streams.qbk @@ -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] diff --git a/doc/4_06_serializer_buffers.qbk b/doc/4_06_serializer_buffers.qbk index 99602a2f..162a63d6 100644 --- a/doc/4_06_serializer_buffers.qbk +++ b/doc/4_06_serializer_buffers.qbk @@ -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] diff --git a/doc/4_07_parser_buffers.qbk b/doc/4_07_parser_buffers.qbk index 3e07e02e..b834c72e 100644 --- a/doc/4_07_parser_buffers.qbk +++ b/doc/4_07_parser_buffers.qbk @@ -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 diff --git a/doc/5_http_examples.qbk b/doc/5_http_examples.qbk index f7dc75ff..6eb5310e 100644 --- a/doc/5_http_examples.qbk +++ b/doc/5_http_examples.qbk @@ -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 diff --git a/doc/6_0_websocket.qbk b/doc/6_0_websocket.qbk index 4ca14788..da97aea1 100644 --- a/doc/6_0_websocket.qbk +++ b/doc/6_0_websocket.qbk @@ -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 - ``` + 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] diff --git a/doc/6_1_streams.qbk b/doc/6_1_streams.qbk index 8537d306..85534eaa 100644 --- a/doc/6_1_streams.qbk +++ b/doc/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 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 - #include - boost::asio::io_service ios; - boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23}; - beast::websocket::stream ws{ios, ctx}; -``` +[wss_snippet_1] +[wss_snippet_2] [note - Code which declares stream objects using Asio SSL types must - to include the file ``. + Code which declares stream objects using Asio SSL types + must include the file ``. ] [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 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 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> 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 diff --git a/doc/6_2_connect.qbk b/doc/6_2_connect.qbk index f5c97592..19716b77 100644 --- a/doc/6_2_connect.qbk +++ b/doc/6_2_connect.qbk @@ -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 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 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> 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. diff --git a/examples/doc_http_samples.hpp b/examples/doc_http_samples.hpp index f42e7c6e..9cfacffd 100644 --- a/examples/doc_http_samples.hpp +++ b/examples/doc_http_samples.hpp @@ -7,13 +7,9 @@ #include -/* - 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 res; + response res; res.result(status::ok); res.version = 11; diff --git a/examples/doc_websocket_samples.hpp b/examples/doc_websocket_samples.hpp new file mode 100644 index 00000000..7977fedb --- /dev/null +++ b/examples/doc_websocket_samples.hpp @@ -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 + +// Contains the WebSocket Examples from the documentation. + + +// The documentation assumes the beast::websocket namespace + +namespace beast { +namespace websocket { + +} // websocket +} // beast diff --git a/examples/http_example.cpp b/examples/http_example.cpp index a190bd7a..b2c4fe07 100644 --- a/examples/http_example.cpp +++ b/examples/http_example.cpp @@ -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(sock.remote_endpoint().port())); - req.replace("User-Agent", "Beast"); + req.insert(beast::http::field::user_agent, "Beast"); req.prepare(); beast::http::write(sock, req); diff --git a/include/beast/http/read.hpp b/include/beast/http/read.hpp index 2d28f07b..6b2902e2 100644 --- a/include/beast/http/read.hpp +++ b/include/beast/http/read.hpp @@ -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. diff --git a/include/beast/websocket/impl/accept.ipp b/include/beast/websocket/impl/accept.ipp index 5381e091..ae9c4523 100644 --- a/include/beast/websocket/impl/accept.ipp +++ b/include/beast/websocket/impl/accept.ipp @@ -39,8 +39,7 @@ class stream::response_op { bool cont; stream& ws; - http::message res; + http::response res; int state = 0; template diff --git a/include/beast/websocket/impl/handshake.ipp b/include/beast/websocket/impl/handshake.ipp index 3dfad407..1231b4a8 100644 --- a/include/beast/websocket/impl/handshake.ipp +++ b/include/beast/websocket/impl/handshake.ipp @@ -39,8 +39,7 @@ class stream::handshake_op stream& ws; response_type* res_p; detail::sec_ws_key_type key; - http::message req; + http::request req; response_type res; int state = 0; diff --git a/test/Jamfile b/test/Jamfile index 12165f8a..a669bab2 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -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 diff --git a/test/core/doc_snippets.cpp b/test/core/doc_snippets.cpp index 26142c70..9a38c1ce 100644 --- a/test/core/doc_snippets.cpp +++ b/test/core/doc_snippets.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}; //] diff --git a/test/http/doc_snippets.cpp b/test/http/doc_snippets.cpp index 473330ac..39561281 100644 --- a/test/http/doc_snippets.cpp +++ b/test/http/doc_snippets.cpp @@ -122,7 +122,6 @@ void fxx() { //[http_snippet_10 response res; - serializer sr{res}; //] diff --git a/test/http/message.cpp b/test/http/message.cpp index 32babbf4..fec951aa 100644 --- a/test/http/message.cpp +++ b/test/http/message.cpp @@ -74,63 +74,63 @@ public: testMessage() { BOOST_STATIC_ASSERT(std::is_constructible< - message>::value); + request>::value); BOOST_STATIC_ASSERT(std::is_constructible< - message, Arg1>::value); + request, Arg1>::value); BOOST_STATIC_ASSERT(std::is_constructible< - message, Arg1 const>::value); + request, Arg1 const>::value); BOOST_STATIC_ASSERT(std::is_constructible< - message, Arg1 const&>::value); + request, Arg1 const&>::value); BOOST_STATIC_ASSERT(std::is_constructible< - message, Arg1&&>::value); + request, Arg1&&>::value); BOOST_STATIC_ASSERT(! std::is_constructible< - message>::value); + request>::value); BOOST_STATIC_ASSERT(std::is_constructible< - message, + request, Arg1, fields::allocator_type>::value); BOOST_STATIC_ASSERT(std::is_constructible< - message, std::piecewise_construct_t, + request, std::piecewise_construct_t, std::tuple>::value); BOOST_STATIC_ASSERT(std::is_constructible< - message, std::piecewise_construct_t, + request, std::piecewise_construct_t, std::tuple>::value); BOOST_STATIC_ASSERT(std::is_constructible< - message, std::piecewise_construct_t, + request, std::piecewise_construct_t, std::tuple, std::tuple>::value); { Arg1 arg1; - message{std::move(arg1)}; + request{std::move(arg1)}; BEAST_EXPECT(arg1.moved); } { - header h; + header h; h.insert(field::user_agent, "test"); - message m{Arg1{}, h}; + request m{Arg1{}, h}; BEAST_EXPECT(h["User-Agent"] == "test"); BEAST_EXPECT(m["User-Agent"] == "test"); } { - header h; + header h; h.insert(field::user_agent, "test"); - message m{Arg1{}, std::move(h)}; + request m{Arg1{}, std::move(h)}; BEAST_EXPECT(! h.exists("User-Agent")); BEAST_EXPECT(m["User-Agent"] == "test"); } // swap - message m1; - message m2; + request m1; + request m2; m1.target("u"); m1.body = "1"; m1.insert("h", "v"); @@ -197,8 +197,8 @@ public: void testSwap() { - message m1; - message m2; + response m1; + response m2; m1.result(status::ok); m1.version = 10; m1.body = "1"; diff --git a/test/http/read.cpp b/test/http/read.cpp index 91453e59..937b522c 100644 --- a/test/http/read.cpp +++ b/test/http/read.cpp @@ -336,7 +336,7 @@ public: "GET / HTTP/1.1\r\n\r\n"}; BEAST_EXPECT(handler::count() == 0); multi_buffer b; - message m; + request 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 m; + request m; async_read(is, b, m, handler{}); BEAST_EXPECT(handler::count() > 0); } diff --git a/test/http/write.cpp b/test/http/write.cpp index d2b11948..564ed892 100644 --- a/test/http/write.cpp +++ b/test/http/write.cpp @@ -289,7 +289,7 @@ public: testAsyncWrite(yield_context do_yield) { { - message m; + response m; m.version = 10; m.result(status::ok); m.reason("OK"); @@ -308,7 +308,7 @@ public: "*****"); } { - message m; + response 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 m{fc}; + request 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 m{fc}; + request 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 m{fc}; + request 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 m{fc}; + request 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 m{fc}; + request m{fc}; m.method(verb::get); m.target("/"); m.version = 10; @@ -495,7 +495,7 @@ public: { // auto content-length HTTP/1.0 { - message m; + request m; m.method(verb::get); m.target("/"); m.version = 10; @@ -512,7 +512,7 @@ public: } // no content-length HTTP/1.0 { - message m; + request m; m.method(verb::get); m.target("/"); m.version = 10; @@ -532,7 +532,7 @@ public: } // auto content-length HTTP/1.1 { - message m; + request m; m.method(verb::get); m.target("/"); m.version = 11; @@ -549,7 +549,7 @@ public: } // no content-length HTTP/1.1 { - message m; + request 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 m; + request 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 m; + request 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 m; + request 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 m0; + response m0; m0.version = 11; m0.result(status::ok); m0.reason("OK"); diff --git a/test/websocket/CMakeLists.txt b/test/websocket/CMakeLists.txt index 5d2856ed..d6c5a034 100644 --- a/test/websocket/CMakeLists.txt +++ b/test/websocket/CMakeLists.txt @@ -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 diff --git a/test/websocket/doc_snippets.cpp b/test/websocket/doc_snippets.cpp new file mode 100644 index 00000000..0787c228 --- /dev/null +++ b/test/websocket/doc_snippets.cpp @@ -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 +#include +#include +#include + +using namespace beast; + +//[ws_snippet_1 +#include +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 ws{ios}; +//] +} + +{ +//[ws_snippet_3 + stream ws{std::move(sock)}; +//] +} + +{ +//[ws_snippet_4 + stream 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 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 ws{acceptor.get_io_service()}; + acceptor.accept(ws.next_layer()); +//] +} + +} // fxx() + +} // doc_ws_snippets diff --git a/test/websocket/ssl/CMakeLists.txt b/test/websocket/ssl/CMakeLists.txt index 9c972179..4132e4c6 100644 --- a/test/websocket/ssl/CMakeLists.txt +++ b/test/websocket/ssl/CMakeLists.txt @@ -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 ) diff --git a/test/websocket/ssl/doc_snippets.cpp b/test/websocket/ssl/doc_snippets.cpp new file mode 100644 index 00000000..8c3c2256 --- /dev/null +++ b/test/websocket/ssl/doc_snippets.cpp @@ -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 +#include +#include +#include +#include + +using namespace beast; +using namespace beast::websocket; + +//[wss_snippet_1 +#include +#include +//] + +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> wss{ios, ctx}; +//] +} + +{ +//[wss_snippet_3 + boost::asio::ip::tcp::endpoint ep; + boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23}; + stream> 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