diff --git a/doc/0_main.qbk b/doc/0_main.qbk new file mode 100644 index 00000000..9d03c9a1 --- /dev/null +++ b/doc/0_main.qbk @@ -0,0 +1,142 @@ +[/ + Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[library Beast + [quickbook 1.6] + [copyright 2013 - 2017 Vinnie Falco] + [purpose Networking Protocol Library] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@http://www.boost.org/LICENSE_1_0.txt]) + ] + [authors [Falco, Vinnie]] + [category template] + [category generic] +] + +[template mdash[] '''— '''] +[template indexterm1[term1] ''''''[term1]''''''] +[template indexterm2[term1 term2] ''''''[term1]''''''[term2]''''''] + +[def __N3747__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3747.pdf [*N3747]]] +[def __N4588__ [@http://cplusplus.github.io/networking-ts/draft.pdf [*N4588]]] +[def __rfc6455__ [@https://tools.ietf.org/html/rfc6455 rfc6455]] +[def __rfc7230__ [@https://tools.ietf.org/html/rfc7230 rfc7230]] + +[def __Asio__ [@http://www.boost.org/doc/html/boost_asio.html Boost.Asio]] + +[def __asio_handler_invoke__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]] +[def __asio_handler_allocate__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]] +[def __void_or_deduced__ [@http://www.boost.org/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]] +[def __use_future__ [@http://www.boost.org/doc/html/boost_asio/reference/use_future_t.html `boost::asio::use_future`]] +[def __yield_context__ [@http://www.boost.org/doc/html/boost_asio/reference/yield_context.html `boost::asio::yield_context`]] +[def __io_service__ [@http://www.boost.org/doc/html/boost_asio/reference/io_service.html `io_service`]] +[def __streambuf__ [@http://www.boost.org/doc/html/boost_asio/reference/streambuf.html [*boost::asio::streambuf]]] + +[def __AsyncReadStream__ [@http://www.boost.org/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]] +[def __AsyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]] +[def __CompletionHandler__ [@http://www.boost.org/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]] +[def __ConstBufferSequence__ [@http://www.boost.org/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]] +[def __Handler__ [@http://www.boost.org/doc/html/boost_asio/reference/Handler.html [*Handler]]] +[def __MutableBufferSequence__ [@http://www.boost.org/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]] +[def __SyncReadStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]] +[def __SyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]] + +[def __AsyncStream__ [link beast.ref.streams.AsyncStream [*AsyncStream]]] +[def __Body__ [link beast.ref.Body [*Body]]] +[def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]] +[def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]] +[def __Stream__ [link beast.ref.streams [*Stream]]] +[def __SyncStream__ [link beast.ref.streams.SyncStream [*SyncStream]]] + +[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]] +[def __basic_multi_buffer__ [link beast.ref.basic_multi_buffer `basic_multi_buffer`]] +[def __basic_parser__ [link beast.ref.http__basic_parser `basic_parser`]] +[def __fields__ [link beast.ref.http__fields `fields`]] +[def __flat_buffer__ [link beast.ref.flat_buffer `flat_buffer`]] +[def __header__ [link beast.ref.http__header `header`]] +[def __message__ [link beast.ref.http__message `message`]] +[def __message_parser__ [link beast.ref.http__message_parser `message_parser`]] +[def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]] +[def __serializer__ [link beast.ref.http__serializer `serializer`]] + +Beast is a cross-platform, header-only C++11 library for low-level HTTP +and WebSocket protocol programming that uses the consistent network and +asynchronous model of __Asio__. + +[variablelist + [[ + [link beast.overview Overview] + ][ + An explanation of requirements, audience, features, and credits. + ]] + [[ + [link beast.core Core Concepts] + ][ + Library-wide concepts for working with buffers and streams. + ]] + [[ + [link beast.http Using HTTP] + ][ + How to use the basic algorithms in your applications. + ]] + [[ + [link beast.adv_http Advanced HTTP] + ][ + A discussion of the advanced interfaces. + ]] + [[ + [link beast.websocket Using WebSocket] + ][ + How to use the WebSocket interfaces in your applications. + ]] + [[ + [link beast.example Examples] + ][ + Examples that illustrate usage for typical scenarios. + ]] + [[ + [link beast.design Design] + ][ + Design rationale, answers to questions, + library comparisons, and Boost Formal Review FAQ. + ]] + [[ + [link beast.ref Reference] + ][ + Detailed class and function reference. + ]] + [[ + [link beast.index Index] + ][ + Book-style text index of Beast documentation. + ]] +] + +[include 1_overview.qbk] +[include 2_core.qbk] +[include 3_0_http.qbk] +[include 4_0_adv_http.qbk] +[include 5_websocket.qbk] +[include 6_examples.qbk] +[include 7_0_design.qbk] + +[section:ref Reference] +[xinclude quickref.xml] +[include concept/Body.qbk] +[include concept/BodyReader.qbk] +[include concept/BodyWriter.qbk] +[include concept/BufferSequence.qbk] +[include concept/DynamicBuffer.qbk] +[include concept/Field.qbk] +[include concept/FieldSequence.qbk] +[include concept/Streams.qbk] +[include reference.qbk] +[endsect] + +[xinclude index.xml] diff --git a/doc/1_overview.qbk b/doc/1_overview.qbk new file mode 100644 index 00000000..a44f96f7 --- /dev/null +++ b/doc/1_overview.qbk @@ -0,0 +1,126 @@ +[/ + Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[section:overview Introduction] + +Beast is a cross-platform, header-only C++11 library for low-level HTTP +and WebSocket protocol programming that uses the consistent networking +and asynchronous model of __Asio__. The design of the library achieves +these goals: + +* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be +used to build clients, servers, or both. + +* [*Ease of Use.] HTTP messages are modeled using a simple, expressive + container. Algorithms used to send and receive HTTP or WebSocket + messages are designed to make users already familiar with __Asio__ + immediately comfortable using this library. + +* [*Flexibility.] Interfaces do not mandate specific implementation + strategies; users make the important decisions such as buffer or + thread management. + +* [*Performance.] The implementation performs competitively, making it + a realistic choice for building high performance network servers. + +* [*Scalability.] Development of network applications that scale to + thousands of concurrent connections is possible with the implementation. + +* [*Basis for Further Abstraction.] The interfaces facilitate the + development of other libraries that provide higher levels of abstraction. + +[heading Requirements] + +Beast requires: + +* [*C++11.] A minimum of C++11 is needed. +* [*Boost.] Beast is built on Boost, especially Boost.Asio. +* [*OpenSSL.] If using TLS/Secure sockets (optional). + +[note Tested compilers: msvc-14+, gcc 4.8+, clang 3.6+] + +The library is [*header-only]. It is not necessary to add any .cpp files, +or to add commands to your build script for building Beast. To link your +program successfully, you'll need to add the Boost.System library to link +with. If you use coroutines you'll also need the Boost.Coroutine library. +Please visit the Boost documentation for instructions on how to do this for +your particular build system. + +Beast does not compile using the stand-alone version of Asio, since it +relies on other Boost parts. There are no immediate plans to offer a +version that works with stand-alone Asio. + +[heading Motivation] + +There is a noticable shortage of high quality C++ networking libraries, +especially for the HTTP and WebSocket protocols. The author theorizes +that previous attempts to build such libraries focused too much on end +user needs instead of applying principles of computer science to solve +the problem more formally. Another factor is that there no current +standardized interface for networking. This may change soon; with the +the introduction of the Networking Technical Specification (__N4588__), +a uniform interface for networking is on track to become standardized. +This technical specification is modeled closely after Boost.Asio. +Beast is built on Boost.Asio, with plans to adapt it to the networking +interfaces which become part of the C++ Standard. + +The HTTP and WebSocket protocols drive most of the World Wide Web. Every +web browser implements these protocols to load webpages and to enable +client side programs (often written in JavaScript) to communicate +interactively. C++ benefits greatly from having a standardized +implementation of these protocols. + +[heading Audience] + +Beast is for network programmers who have some familiarity with __Asio__. +In particular, users who wish to write asynchronous programs with Beast +should already have knowledge and experience with Asio's asynchronous +model and style of asynchronous programming using callbacks or coroutines. +The protocol interfaces are low level. There are no out of the box solutions +for implementing clients or servers. For example, users must provide their +own code to make connections, handle timeouts, reconnect a dropped connection, +accept incoming connections, or manage connection resources on a server. + +The HTTP interfaces provide functionality only for modelling HTTP +messages and serializing or parsing them on streams, including TCP/IP +sockets or OpenSSL streams. Higher level functions such as Basic +Authentication, mime/multipart encoding, cookies, automatic handling +of redirects, gzipped transfer encodings, caching, or proxying (to name +a few) are not directly provided, but nothing stops users from creating +these features using Beast's HTTP message types. + +The library is intended to be the foundation upon which other networking +libraries are built. It is a goal that other architects will build +interoperable solutions on top of Beast. + +[heading Credits] + +Boost.Asio is the inspiration behind which all of the interfaces and +implementation strategies are built. Some parts of the documentation are +written to closely resemble the wording and presentation of Boost.Asio +documentation. Credit goes to Christopher Kohlhoff for the wonderful +Asio library and the ideas upon which Beast is built. + +Beast would not be possible without the considerable time and patience +contributed by +David Schwartz, +Edward Hennis, +[@https://github.com/howardhinnant Howard Hinnant], +Miguel Portilla, +Nikolaos Bougalis, +Scott Determan, +Scott Schurr, +and +[@https://www.ripple.com Ripple Labs] +for supporting its early development. Also thanks to +Agustín Bergé, +Glen Fernandes, +and +Peter Dimov +for helping me considerably on Slack. + +[endsect] diff --git a/doc/core.qbk b/doc/2_core.qbk similarity index 67% rename from doc/core.qbk rename to doc/2_core.qbk index c736eae6..11b47205 100644 --- a/doc/core.qbk +++ b/doc/2_core.qbk @@ -9,34 +9,151 @@ [block ''' - Concepts - DynamicBuffer - Buffer Algorithms - Asynchronous Model - Tutorial + Working With Asio + Stream Concepts + Buffer Concepts + Asynchronous Utilities + Asynchronous Composed Operation Tutorial '''] -In addition to network protocols, Beast provides users with robust concepts, -implementations, and algorithms which can be used to design higher level -abstractions that interoperate with Boost.Asio. In the sections that follow -are descriptions of these concepts, followed by algorithms using the concepts, -and then concluding with a tutorial on developing composed asynchronous -operations which are compatible with the Extensible Asynchronous Model provided -in Boost.Asio, __N3747__, and __N4588__. +A goal of the library is expose implementation primitives in order that +users may build their own library-like components. These primitives include +traits, buffers, buffer algorithms, and helpers for implementing asynchronous +operations compatible with __Asio__ and described in __N3747__. This section +lists these facilities by group, with descriptions. + +[important + This documentation assumes familiarity with __Asio__. Sample + code and identifiers used throughout are written as if the + following declarations are in effect: + ``` + #include + #include + #include + #include + + using namespace beast; + + boost::asio::io_service ios; + boost::asio::io_service work{ios}; + std::thread t{[&](){ ios.run(); }}; + + error_code ec; + + ``` +] -[section:concepts Concepts] +[heading:asio Working With Asio] -Beast provides template metaprogramming functions to allow users to perform -concept checks on parameters, preventing undefined or illegal use. These trait -traits are used in the implementation of the library and part of its public -interface so users may build on the library using the same features. Use of -concept checks benefit users by providing accurate, concise compilation error -diagnostics. +Beast does not manage sockets, make outgoing connections, accept incoming +connections, or handle any aspect of connection management. In order to +invoke library algorithms it is necessary to first have a connected socket, +SSL stream, or other object which meets the required stream concepts. This +example is provided as a reminder of how to work with sockets: +``` +auto host = "www.example.com"; +boost::asio::ip::tcp::resolver r{ios}; +boost::asio::ip::tcp::socket sock{ios}; +boost::asio::connect(sock, r.resolve( + boost::asio::ip::tcp::resolver::query{host, "http"})); -[table Type Traits +// At this point `sock` is a connected to a remote +// host and may be used to perform stream operations. +``` + +Throughout this documentation identifiers with the following names have +special meaning: + +[table Global Variables +[[Name][Description]] +[[ + [@http://www.boost.org/doc/html/boost_asio/reference/io_service.html [*`ios`]] +][ + A variable of type + [@http://www.boost.org/doc/html/boost_asio/reference/io_service.html `boost::asio::io_service`] + which is running on one separate thread, and upon which a + [@http://www.boost.org/doc/html/boost_asio/reference/io_service__work.html `boost::asio::io_service::work`] + object has been constructed. +]] +[[ + [@http://www.boost.org/doc/html/boost_asio/reference/ip__tcp/socket.html [*`sock`]] +][ + A variable of type + [@http://www.boost.org/doc/html/boost_asio/reference/ip__tcp/socket.html `boost::asio::ip::tcp::socket`] + which has already been connected to a remote host. +]] +[[ + [@http://www.boost.org/doc/html/boost_asio/reference/ssl__stream.html [*`ssl_sock`]] +][ + A variable of type + [@http://www.boost.org/doc/html/boost_asio/reference/ssl__stream.html `boost::asio::ssl::stream`] + which is already connected and has handshaked with a remote host. +]] +] + + + + +[heading:streams Stream Concepts] + +A __Stream__ is communication channel where data expressed as octet +buffers is transferred sequentially. Streams are either synchronous +or asynchronous, and may allow reading, writing, or both. Note that +a particular type may model more than one concept. For example, the +Asio types +[@http://www.boost.org/doc/html/boost_asio/reference/ip__tcp/socket.html `boost::asio::ip::tcp::socket`] +and +[@http://www.boost.org/doc/html/boost_asio/reference/ssl__stream.html `boost::asio::ssl::stream`] +support everything. All stream algorithms in Beast are declared as +template functions with specific concept requirements chosen from +this list: + +[table Stream Concepts +[[Concept][Description]] +[ + [__SyncReadStream__] + [ + Supports buffer-oriented blocking reads. + ] +][ + [__SyncWriteStream__] + [ + Supports buffer-oriented blocking writes. + ] +][ + [__SyncStream__] + [ + A stream supporting buffer-oriented blocking reads and writes. + ] +][ + [__AsyncReadStream__] + [ + Supports buffer-oriented asynchronous reads. + ] +][ + [__AsyncWriteStream__] + [ + Supports buffer-oriented asynchronous writes. + ] +][ + [__AsyncStream__] + [ + A stream supporting buffer-oriented asynchronous reads and writes. + ] +] +] + +These template metafunctions check whether a given type meets the +requirements for the various stream concepts, and some additional +useful utilities. The library uses these type checks internally +and also provides them as public interfaces so users may use the +same techniques to augment their own code. The use of these type +checks helps provide more concise errors during compilation: + +[table Stream Type Checks [[Name][Description]] [[ [link beast.ref.get_lowest_layer `get_lowest_layer`] @@ -46,8 +163,8 @@ diagnostics. [[ [link beast.ref.has_get_io_service `has_get_io_service`] ][ - Determine if the `get_io_service` member function is present with the - correct signature. + Determine if the `get_io_service` member function is present, + and returns an __io_service__. ]] [[ [link beast.ref.is_async_read_stream `is_async_read_stream`] @@ -71,21 +188,6 @@ diagnostics. Determine if a type meets the requirements of __CompletionHandler__, and is callable with a specified signature. ]] -[[ - [link beast.ref.is_const_buffer_sequence `is_const_buffer_sequence`] -][ - Determine if a type meets the requirements of __ConstBufferSequence__. -]] -[[ - [link beast.ref.is_dynamic_buffer `is_dynamic_buffer`] -][ - Determine if a type meets the requirements of __DynamicBuffer__. -]] -[[ - [link beast.ref.is_mutable_buffer_sequence `is_mutable_buffer_sequence`] -][ - Determine if a type meets the requirements of __MutableBufferSequence__. -]] [[ [link beast.ref.is_sync_read_stream `is_sync_read_stream`] ][ @@ -104,25 +206,55 @@ diagnostics. ]] ] -[endsect] +Using the type checks with `static_assert` on function or class template +types will provide users with helpful error messages and prevent undefined +behaviors. This example shows how a template function which writes to a +synchronous stream may check its argument: +``` +template +void write_string(SyncWriteStream& stream, string_view s) +{ + static_assert(is_sync_write_stream::value, + "SyncWriteStream requirements not met"); + boost::asio::write(stream, boost::asio::const_buffers_1(s.data(), s.size())); +} +``` +[heading:buffers Buffer Concepts] -[section:dynamic_buffer DynamicBuffer] +__Asio__ provides the __ConstBufferSequence__ and __MutableBufferSequence__ +concepts, whose models provide ranges of buffers, as well as the __streambuf__ +class which encapsulates memory storage that may be automatically resized as +required, where the memory is divided into an input sequence followed by an +output sequence. The Networking TS (__N4588__) generalizes the `streambuf` +interface into the __DynamicBuffer__ concept. Beast algorithms which require +resizable buffers accept as parameters dynamic buffer objects. These +metafunctions check types against these buffer concepts: -The networking technical specification described in __N4588__ provides a -concept called a __DynamicBuffer__. Instances of this concept define -an output area expressed as a __MutableBufferSequence__ and an input area -expressed as a __ConstBufferSequence__. Octets may be moved from the output -area to the input area through a structured interface, and later consumed -from the input area when the data is no longer needed. Beast adopts this -concept by providing a concise definition taken directly from the technical -specification and using it as the interface for operations which require -dynamically sized buffers. Several classes are provided which implement the -dynamic buffer concept using various strategies: +[table Buffer Type Checks +[[Name][Description]] +[[ + [link beast.ref.is_const_buffer_sequence `is_const_buffer_sequence`] +][ + Determine if a type meets the requirements of __ConstBufferSequence__. +]] +[[ + [link beast.ref.is_mutable_buffer_sequence `is_mutable_buffer_sequence`] +][ + Determine if a type meets the requirements of __MutableBufferSequence__. +]] +[[ + [link beast.ref.is_dynamic_buffer `is_dynamic_buffer`] +][ + Determine if a type meets the requirements of __DynamicBuffer__. +]] +] -[table Dynamic buffer implementations +To suit various needs, several implementation of dynamic buffer are available: + +[table Dynamic Buffer Implementations [[Name][Description]] [[ [link beast.ref.buffers_adapter `buffers_adapter`] @@ -161,20 +293,16 @@ dynamic buffer concept using various strategies: ]] ] -[endsect] +Network applications frequently need to manipulate buffer sequences. To +facilitate working with buffers the library treats these sequences as +a special type of range. Algorithms and wrappers are provided which +transform these buffer sequences ranges efficiently using lazy evaluation. +No memory allocations are used in the transformations; instead, they +create lightweight iterators over the existing, unmodified memory +buffers. The lifetime of the transformed buffers is retained by the +caller; ownership is not transferred. - - -[section:algorithms Buffer Algorithms] - -Beast provides a collection of algorithms to work on __ConstBufferSequence__ -or __MutableBufferSequence__ objects. These algorithms allow composition of -new algorithms which work on any objects meeting the buffer sequence -requirements, in an efficient way: no memory allocations are performed; -instead, the algorithms implement lightweight iterators over the existing -underlying memory, whose lifetime is retained by the caller. - -[table Buffer algorithms +[table Buffer Algorithms [[Name][Description]] [[ [link beast.ref.buffer_cat `buffer_cat`] @@ -195,8 +323,8 @@ underlying memory, whose lifetime is retained by the caller. [[ [link beast.ref.buffer_cat `buffers_view`] ][ - This class represents a buffer sequence which represents the concatenation - of two or more buffer sequences. This is type of object returned by + This class represents the buffer sequence formed by concatenating + two or more buffer sequences. This is type of object returned by [link beast.ref.buffer_cat `buffer_cat`]. ]] [[ @@ -209,18 +337,36 @@ underlying memory, whose lifetime is retained by the caller. ]] ] -[endsect] +These two functions facilitate buffer interoperability with standard +output streams. + +[table Buffer Output Streams +[[Name][Description]] +[[ + [link beast.ref.buffers `buffers`] +][ + This function wraps a __ConstBufferSequence__ so it may be + used with `operator<<` and `std::ostream`. +]] +[[ + [link beast.ref.ostream `ostream`] +][ + This function returns a `std::ostream` which wraps a dynamic buffer. + Characters sent to the stream using `operator<<` is stored in the + dynamic buffer. +]] +] -[section:async Asynchronous Model] +[heading:async Asynchronous Utilities] Asynchronous operations are started by calling a free function or member function known as an ['asynchronous initiation function]. The initiation function accepts parameters specific to the operation as well as a "completion token." This token is either a completion handler, or another type allowing for customization of how the result of the asynchronous operation is conveyed to -callers. Boost.Asio allows the special completion tokens __use_future__ and +callers. __Asio__ allows the special completion tokens __use_future__ and objects of type __yield_context__ to allow callers to specify the use of futures and coroutines respectively. This system, where the return value and method of indicating completion may be customize at the call site of the asynchronous @@ -229,21 +375,22 @@ in __N3747__, and built-in to __N4588__. [note A full explanation of completion handlers, the Extensible Asynchronous - Model and how Boost.Asio's asynchronous interfaces are used is beyond the - scope of this document. Readers should consult the Boost.Asio documentation - for a comprehensive treatment. + Model and how these asynchronous interfaces are used is beyond the + scope of this document. Interested readers should consult the + __Asio__ documentation. ] -Since Beast is low level, authors of libraries may wish to create higher level -interfaces using the primitives found in this library. Non-trivial applications -will want to provide their own asychronous initiation functions which perform -a series of other, intermediate asynchronous operations before invoking the -final completion handler. The set of intermediate actions produced by calling -an initiation function is known as a ['composed operation]. To ensure full -interoperability and well-defined behavior, Boost.Asio imposes requirements on -the implementation of composed operations. Beast provides a number of useful -classes and macros to facilitate the development of composed operations and -the associated asynchronous initiation functions used to launch them. +Since the interfaces provided here are low level, authors of libraries +may wish to create higher level interfaces using the primitives found +in this library. Non-trivial applications will want to provide their own +asychronous initiation functions which perform a series of other, +intermediate asynchronous operations before invoking the final completion +handler. The set of intermediate actions produced by calling an initiation +function is known as a ['composed operation]. To ensure full interoperability +and well-defined behavior, __Asio__ imposes requirements on the implementation +of composed operations. A number of useful classes and macros to facilitate +the development of composed operations and the associated asynchronous +initiation functions used to launch them are available: [table Asynchronous Helpers [[Name][Description]] @@ -306,11 +453,9 @@ the associated asynchronous initiation functions used to launch them. ]] ] -[endsect] - -[section:tutorial Tutorial] +[section:tutorial Asynchronous Composed Operation Tutorial] To illustrate the usage of the asynchronous helpers in the core section of this library, we will develop a simple asynchronous composed operation called @@ -352,8 +497,7 @@ operation by constructing the object and invoking it. async_echo(AsyncStream& stream, CompletionToken&& token) { // Make sure stream meets the requirements. We use static_assert - // instead of letting the compiler generate several pages of hard - // to read error messages. + // to cause a friendly message instead of an error novel. // static_assert(beast::is_async_stream::value, "AsyncStream requirements not met"); @@ -365,7 +509,7 @@ operation by constructing the object and invoking it. beast::async_completion init{token}; // Create the composed operation and launch it. This is a constructor - // call followed by invocation of operator(). We use BEAST_HANDLER_TYPE + // call followed by invocation of operator(). We use handler_type // to convert the completion token into the correct handler type, // allowing user defined specializations of the async result template // to take effect. @@ -388,7 +532,7 @@ return value type using the helper, and creating and launching the composed operation object. The [*`echo_op`] object does most of the work here, and has a somewhat non-trivial structure. This structure is necessary to meet the stringent requirements of composed operations (described in more detail in -the Boost.Asio documentation). We will touch on these requirements without +the __Asio__ documentation). We will touch on these requirements without explaining them in depth. First we will create boilerplate which is present in all composed operations @@ -548,17 +692,20 @@ this echo operation: case 1: // write everything back p.step = 2; - return boost::asio::async_write(p.stream, p.buffer.data(), std::move(*this)); + // async_read_until could have read past the newline, + // use buffer_prefix to make sure we only send one line + return boost::asio::async_write(p.stream, + beast::buffer_prefix(bytes_transferred, p.buffer.data()), std::move(*this)); case 2: + p.buffer.consume(bytes_transferred); break; } // Invoke the final handler. If we wanted to pass any arguments // which come from our state, they would have to be moved to the // stack first, since the `handler_ptr` guarantees that the state - // is destroyed before - // the handler is invoked. + // is destroyed before the handler is invoked. // p_.invoke(ec); return; diff --git a/doc/3_0_http.qbk b/doc/3_0_http.qbk new file mode 100644 index 00000000..635cb467 --- /dev/null +++ b/doc/3_0_http.qbk @@ -0,0 +1,83 @@ +[/ + Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[section:http Using HTTP] + +[block ''' + + HTTP Primer + Message Containers + Stream Operations + +'''] + +This library offers programmers simple and performant models of HTTP +messages and their associated operations including synchronous and +asynchronous parsing and serialization of messages in the HTTP/1 wire +format using __Asio__. Specifically, the library provides: + +[variablelist +[ + [Message Containers] + [ + Complete HTTP messages are modeled using the __message__ class, + with possible user customizations. + ] +][ + [Stream Reading] + [ + The functions + [link beast.ref.http__read `read`], + [link beast.ref.http__read_some `read_some`], + [link beast.ref.http__async_read `async_read`], and + [link beast.ref.http__async_read_some `async_read_some`] + read a __message__ from a + [link beast.ref.streams stream]. +] +][ + [Stream Writing] + [ + The functions + [link beast.ref.http__write `write`], + [link beast.ref.http__write_some `write_some`], + [link beast.ref.http__async_write `async_write`], and + [link beast.ref.http__async_write_some `async_write_some`] + write a __message__ to a + [link beast.ref.streams stream]. + ] +][ + [Serialization] + [ + The __serializer__ produces a series of octet buffers + conforming to the __rfc7230__ wire representation of + a __message__. + ] +][ + [Parsing] + [ + The __message_parser__ attempts to convert a series of + octet buffers into a __message__. + ] +] +] + +[note + The following documentation assumes some familiarity with __Asio__ and + the HTTP protocol specification described in __rfc7230__. Sample code + and identifiers mentioned in the HTTP documentation sections are + written as if these declarations are in effect: + ``` + #include + using namespace beast::http; + ``` +] + +[include 3_1_primer.qbk] +[include 3_2_message.qbk] +[include 3_3_streams.qbk] + +[endsect] diff --git a/doc/3_1_primer.qbk b/doc/3_1_primer.qbk new file mode 100644 index 00000000..4ffceeab --- /dev/null +++ b/doc/3_1_primer.qbk @@ -0,0 +1,144 @@ +[/ + Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[section:primer HTTP Primer] + +The HTTP protocol defines the +[@https://tools.ietf.org/html/rfc7230#section-2.1 client and server roles]: +clients send requests and servers send back responses. A request +or response is an +[@https://tools.ietf.org/html/rfc7230#section-3 HTTP message] +(referred to hereafter as "message"), with two parts: +a header containing structured metadata and an optional variable-length +body containing arbitrary data. A serialized header is one or more text +lines where each line ends in a carriage return followed by linefeed +(`"\r\n"`). An empty line marks the end of the header. The first line +in the header is called the ['start-line]. The start line contents are +different for requests and responses. + +Every message contains a set of zero or more field name/value pairs, +collectively called "fields". The names and values are represented using +text strings with various requirements. A serialized field contains the +field name, then a colon followed by a space (`": "`), and finally the field +value. + +When a client and server have established a connection and intend to +use HTTP, the client sends a series of requests while the server reads +sends back at least one response for each request in the order those +requests were received. + +[heading Requests] + +Clients send requests, which contain a +[@https://tools.ietf.org/html/rfc7230#section-3.1.1 method] +and +[@https://tools.ietf.org/html/rfc7230#section-5.3 request-target], +and +[@https://tools.ietf.org/html/rfc7230#section-2.6 HTTP-version]. +The method identifies the operation to be performed while the target +identifies the object on the server to which the operation applies. +The version is almost always 1.1, but older programs sometimes use 1.0. + +[table +[[Serialized Request][Description]] +[[ +``` + GET / HTTP/1.1\r\n + User-Agent: Beast\r\n + \r\n +``` +][ + This request has a method of "GET", a target of "/", and indicates + HTTP version 1.1. It contains a single field called "User-Agent" + whose value is "Beast". There is no message body. +]] +] + +[heading Responses] + +Servers send responses, which contain a +[@https://tools.ietf.org/html/rfc7231#section-6 status-code], +[@https://tools.ietf.org/html/rfc7230#section-3.1.2 reason-phrase], and +[@https://tools.ietf.org/html/rfc7230#section-2.6 HTTP-version]. +The reason phrase is +[@https://tools.ietf.org/html/rfc7230#section-3.1.2 obsolete]: +clients SHOULD ignore the reason-phrase content. Here is a response which +includes a body. The special +[@https://tools.ietf.org/html/rfc7230#section-3.3.2 Content-Length] +field informs the remote host of the size of the body which follows. + +[table +[[Serialized Response][Description]] +[[ +``` + HTTP/1.1 200 OK\r\n + Server: Beast\r\n + Content-Length: 13\r\n + \r\n + Hello, world! +``` +][ + This response has a + [@https://tools.ietf.org/html/rfc7231#section-6 200 status code] + meaning the operation requested completed successfully. The obsolete + reason phrase is "OK". It has specifies HTTP version 1.1, and contains + a body 13 octets in size with the text "Hello, world!". +]] +] + +[heading Special Fields] + +Certain fields appearing in messages are special. The library understands +these fields when performing serialization and parsing, taking automatic +action as needed when the fields are present: + +[table Special Fields +[[Field][Description]] +[ + [ + [@https://tools.ietf.org/html/rfc7230#section-6.1 [*`Connection`]] + + [@https://tools.ietf.org/html/rfc7230#appendix-A.1.2 [*`Proxy-Connection`]] + ][ + This field allows the sender to indicate desired control options + for the current connection. Common values include "close", + "keep-alive", and "upgrade". + ] +][ + [ + [@https://tools.ietf.org/html/rfc7230#section-3.3.2 [*`Content-Length`]] + ][ + When present, this field informs the recipient about the exact + size in bytes of the body which follows the message header. + ] +][ + [ + [@https://tools.ietf.org/html/rfc7230#section-3.3.1 [*`Transfer-Encoding`]] + ][ + This optional field lists the names of the sequence of transfer codings + that have been (or will be) applied to the content payload to form + the message body. + + Beast understands the "chunked" coding scheme when it is the last + (outermost) applied coding. The library will automatically apply + chunked encoding when the content length is not known ahead of time + during serialization, and the library will automatically removed chunked + encoding from parsed messages. + ] +][ + [ + [@https://tools.ietf.org/html/rfc7230#section-6.7 [*`Upgrade`]] + ][ + The Upgrade header field provides a mechanism to transition from + HTTP/1.1 to another protocol on the same connection. For example, it + is the mechanism used by WebSocket's initial HTTP handshake to + establish a WebSocket connection. + ] +] +] + +[endsect] diff --git a/doc/3_2_message.qbk b/doc/3_2_message.qbk new file mode 100644 index 00000000..3300dc0f --- /dev/null +++ b/doc/3_2_message.qbk @@ -0,0 +1,173 @@ +[/ + Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[section:message Message Containers] + +Beast provides a single class template __message__ which models +HTTP/1 and +[@https://tools.ietf.org/html/rfc7540 HTTP/2] +messages: +``` +/// An HTTP message +template< + bool isRequest, // `true` for requests, `false` for responses + class Body, // Controls the container and algorithms used for the body + class Fields = fields> // The type of container to store the fields +class message; +``` + +The container offers value semantics including move and copy if supported +by `Body` and `Fields`. User defined template function parameters can +accept any message, or can use partial specialization to accept just +requests or responses. The default __fields__ is a provided associative +container using the standard allocator and supporting modification and +inspection of fields. As per __rfc7230__, a non-case-sensitive comparison +is used for field names. User defined types for fields are possible. This +is discussed in +[link beast.adv_http.fields Advanced Fields]. +The `Body` type determines the type of the container used to represent the +body as well as the algorithms for transferring buffers to and from the +the container. The library comes with a collection of common body types, +described in +[link beast.http.message.body Body Types]. +As with fields, user defined body types are possible. This is described in +[link beast.adv_http.body Advanced Body]. + + + +Sometimes it is desired to only work with a header. Beast provides a single +class template __header__ to model HTTP/1 and HTTP/2 headers: +``` +/// An HTTP header +template< + bool isRequest, // `true` for requests, `false` for responses + class Fields = fields> // The type of container to store the fields +class header; +``` + +Requests and responses share the version, fields, and body but have +a few members unique to the type. This is implemented by declaring the +header classes as partial specializations of `isRequest`. Furthermore, +__message__ is derived from __header__; a message may be passed as an +argument to a function taking a suitably typed header as a parameter. +This diagram shows the inheritance relationship between header and message, +along with the fields from the different partial specializations for each +possible value of `isRequest`: + +[$images/message.png [width 711px] [height 424px]] + +For notational convenience, the template type aliases +[link beast.ref.http__request `request`] and +[link beast.ref.http__response `response`] +are provided, which also supply commonly chosen __fields__ type as a default: +``` +/// A typical HTTP request +template +using request = message; + +/// A typical HTTP response +template +using response = message; +``` + +[heading:body Body Types] + +Beast defines the __Body__ concept, which determines both the type of +the `message::body` member (as seen in the diagram above) and may also +include algorithms for transferring buffers in and out. These algorithms +are used during parsing and serialization. These body types are available +within the library, and users may define their own body types which meet +the __Body__ requirements: + +[table +[[Name][Description]] +[[ + [link beast.ref.http__buffer_body `buffer_body`] +][ + A body with `value_type` holding a __ConstBufferSequence__ holding + caller provided buffers which must be updated during incremental + serialization. Messages with this body type only support serialization. +]] +[[ + [link beast.ref.http__dynamic_body `dynamic_body`] + + [link beast.ref.http__basic_dynamic_body `basic_dynamic_body`] +][ + A body whose `value_type` is a __DynamicBuffer__. It inherits + the insertion complexity of the underlying choice of dynamic buffer. + Messages with this body type may be serialized and parsed. +]] +[[ + [link beast.ref.http__empty_body `empty_body`] +][ + A special body with an empty `value_type` indicating that the + message has no body. Messages with this body may be serialized + and parsed; however, body octets received while parsing a message + with this body will generate a unique error. +]] +[[ + [link beast.ref.http__string_body `string_body`] +][ + A body whose `value_type` is `std::string`. Insertion complexity + is amortized constant time, while capacity grows geometrically. + Messages with this body type may be serialized and parsed. This + is the type of body used in the examples. +]] +] + +[heading Usage] + +The code examples below show how to create and fill in request and response +objects: + +[table Create Request +[[Statements] [Serialized Result]] +[[ +``` + request req; + req.version = 11; // HTTP/1.1 + req.method("GET"); + req.target("/index.htm"); + req.fields.insert("Accept", "text/html"); + req.fields.insert("Connection", "keep-alive"); + req.fields.insert("User-Agent", "Beast"); +``` +][ +``` + GET /index.htm HTTP/1.1\r\n + Accept: text/html\r\n + Connection: keep-alive\r\n + User-Agent: Beast\r\n + \r\n +``` +]] +] + +[table Create Response +[[Statements] [Serialized Result]] +[[ +``` + response res; + res.version = 11; // HTTP/1.1 + res.status = 200; + res.reason("OK"); + res.body = "Hello, world!"; + res.fields.insert("Server", "Beast"); + res.fields.insert("Content-Length", res.body.size()); +``` +][ +``` + 200 OK HTTP/1.1\r\n + Server: Beast\r\n + Content-Length: 13\r\n + \r\n + Hello, world! +``` +]] +] + +[endsect] diff --git a/doc/3_3_streams.qbk b/doc/3_3_streams.qbk new file mode 100644 index 00000000..92c3ed55 --- /dev/null +++ b/doc/3_3_streams.qbk @@ -0,0 +1,140 @@ +[/ + Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[section:streams Stream Operations] + +Beast provides synchronous and asynchronous algorithms to serialize and +parse HTTP/1 wire format messages on streams. These functions form the +basic interface which works on the entire header or message at once, +requiring no separately managed state objects: + +[table Basic Interface +[[Name][Description]] +[[ + [link beast.ref.http__read.overload3 [*read]] +][ + Parse a __message__ from a __SyncReadStream__. +]] +[[ + [link beast.ref.http__write.overload1 [*write]] +][ + Serialize a __message__ to a __SyncWriteStream__. +]] +[[ + [link beast.ref.http__async_read.overload2 [*async_read]] +][ + Parse a __message__ from an __AsyncReadStream__. +]] +[[ + [link beast.ref.http__async_write [*async_write]] +][ + Serialize a __message__ to an __AsyncWriteStream__. +]] +] + +Synchronous stream operations come in two varieties. One which throws +an exception upon error, and another which accepts as the last parameter an +argument of type [link beast.ref.error_code `error_code&`]. If an error +occurs this argument will be set to contain the error code. + +[heading Writing] + +A set of free functions allow serialization of an entire HTTP message to +a stream. This function sends a message synchronously on the socket, +throwing an exception if an error occurs: +``` +template +void send(response const& res) +{ + write(sock, res); +} +``` + +If a response has no declared content length, and no chunked transfer +encoding, the end of the message is indicated by the server closing +the connection. When sending such a response, Beast will return the +error `boost::asio::error::eof` from the write algorithm to indicate +to the caller that the connection should be closed. This example +constructs and sends a response whose body length is determined by +the number of octets received prior to the server closing the connection: +``` +void send() +{ + response res; + res.version = 11; + res.status = 200; + res.reason("OK"); + res.fields.insert("Server", "Beast"); + res.body = "Hello, world!"; + + error_code ec; + write(sock, res, ec); + if(ec == boost::asio::error::eof) + sock.close(); + else + BOOST_ASSERT(ec); +} +``` + +An asynchronous version is also available: + +``` +template +void send_async(response const& res) +{ + async_write(sock, res, + [&](error_code) + { + if(ec) + std::cerr << ec.message() << std::endl; + }); +} +``` + +[heading Reading] + +Because a serialized header is not length-prefixed, algorithms which parse +messages from a stream may read past the end of a message for efficiency. +To hold this surplus data, all stream read operations use a passed-in +__DynamicBuffer__. Each read operation may consume bytes remaining in the +buffer, and leave behind new bytes. In this example we declare the buffer +and a message variable, then read a complete HTTP request synchronously: +``` + flat_buffer buffer; // (The parser is optimized for flat buffers) + request req; + read(sock, buffer, req); +``` + +In this example we used the __flat_buffer__. The parser in Beast is +optimized for structured HTTP data located in a single contiguous memory +buffer ("flat buffer"). Any dynamic buffer will work with reads. However, +when not using a flat buffer the implementation may perform an additional +memory allocation to restructure the input into a single buffer. + +[tip + User-defined implementations of __DynamicBuffer__ may avoid additional + parser memory allocation, if those implementations guarantee that + returned buffer sequences will always have length one. +] + +Messages may also be read asynchronously. When performing asynchronous +stream read operations, the buffer and message variables must remain +valid until the operation has completed. Beast asynchronous initiation +functions use Asio's completion handler model. Here we read a message +asynchronously. When the operation completes the message in the error +code indicating the result is printed: +``` + flat_buffer buffer; + response res; + async_read(sock, buffer, + [&](error_code ec) + { + std::cerr << ec.message() << std::endl; + }); +``` + +[endsect] diff --git a/doc/4_0_adv_http.qbk b/doc/4_0_adv_http.qbk new file mode 100644 index 00000000..c8514451 --- /dev/null +++ b/doc/4_0_adv_http.qbk @@ -0,0 +1,339 @@ +[/ + Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[section:adv_http Advanced HTTP] + +[block ''' + + Serialization + Parsing + Field Containers + Body Types + +'''] + +The basic interfaces for reading and writing complete messages are +simple to use and convenient, but may not serve the needs of advanced +use cases, including: + +* Parsing a message from caller-provided buffers + +* Serializing a message to caller-provided buffers + +* Reading a message from a stream incrementally + +* Writing a message to a stream incrementally + +In some cases, users may wish to provide their own implementation for +the fields container and the body type. In the advanced sections we +discuss the buffer oriented message algorithms, incremental stream +algorithms, and customization points for messages. + + + +[section:serialize Serialization (Advanced HTTP)] + +Beast uses the __serializer__ class internally to generate a sequence of +buffers corresponding to the serialized representation of a __message__. +The basic algorithms send the entire set of buffers at once while the +incremental algorithms allow the caller to write a bounded amount to +the stream at each iteration. In between calls to generate buffers or +write buffers to the stream, the internal state of the serialization +must be saved. A __serializer__ initializes this internal state and +stores it in between calls to produce buffers, until all the message +buffers have been produced. Afterwards, the state object may be destroyed. + +The serializer is a class template constructed from an existing +message. The template types used to instantiate the serializer must +match the types in the message. Here we declare a request and construct +an accompanying serializer: +``` +request req; +serializer sr{req}; +``` + +The buffers are produced by first calling +[link beast.ref.http__serializer.get `serializer::get`] +to obtain a buffer sequence, and then calling +[link beast.ref.http__serializer.consume `serializer::consume`] +to indicate how many bytes in the buffer sequence were consumed. +This advanced the internal state of the serializer and prepares the +next set of buffers for delivery. +[link beast.ref.http__serializer.get `serializer::get`] +takes an error code parameter and invokes a visitor argument with the +error code and buffer of unspecified type. In C++14 this is easily +expressed with a generic lambda. The function +[link beast.ref.http__serializer.is_done `serializer::is_done`] +will return `true` when all the buffers have been produced. This example +prints the buffers to standard output: +``` +template +void print(message const& m) +{ + error_code ec; + serializer sr{m}; + do + { + sr.get(ec, + [&sr](error_code& ec, auto const& buffer) + { + std::cout << buffers(buffer); + sr.consume(boost::asio::buffer_size(buffer)); + }); + } + while(! ec && ! sr.is_done()); + if(! ec) + std::cout << std::endl; + else + std::cerr << ec.message() << std::endl; +} +``` + +Generic lambda expressions are not available in C++11, so a functor with +a templated function call operator is necessary: +``` +template +struct lambda +{ + Serializer& sr; + + lambda(Serializer& sr_) : sr(sr_) {} + + template + void operator()(error_code& ec, ConstBufferSequence const& buffer) + { + std::cout << buffers(buffer); + sr.consume(boost::asio::buffer_size(buffer)); + } +}; + +template +void print(message const& m) +{ + error_code ec; + serializer sr{m}; + do + { + sr.get(ec, lambda{sr}); + } + while(! ec && ! sr.is_done()); + if(! ec) + std::cout << std::endl; + else + std::cerr << ec.message() << std::endl; +} +``` + +[heading Stream Operations] + +When working with streams, the use of an explicitly declared serializer +allows control over the amount of network activity performed in each +system call. This allows for better application level flow control and +predictable timeouts. These advanced stream write operations work on +an object of type __serializer__ which has already been constructed, +and which must remain valid until the operation is complete: + +[table Advanced Streaming +[[Name][Description]] +[[ + [link beast.ref.http__write_some.overload1 [*write_some]] +][ + Send __serializer__ buffer data to a __SyncWriteStream__. +]] +[[ + [link beast.ref.http__async_write_some [*async_write_some]] +][ + Send some __serializer__ buffer data to an __AsyncWriteStream__. +]] +] + +Here is an example which synchronously sends a message on a stream using +a serializer: +``` +template +void send(SyncWriteStream& stream, message const& m) +{ + static_assert(is_sync_write_stream::value, + "SyncWriteStream requirements not met"); + serializer sr{m}; + do + { + write_some(stream, sr); + } + while(! sr.is_done()); +} +``` + +[heading Split Serialization] + +In some cases, such as the handling of the +[@https://tools.ietf.org/html/rfc7231#section-5.1.1 Expect: 100-continue] +field, it may be desired to first serialize the header, perform some other +action, and then continue with serialization of the body. This is +accomplished by calling +[link beast.ref.http__serializer.split `serializer::split`] +with a boolean indicating that when buffers are produced, the last buffer +containing serialized header octets will not contain any octets corresponding +to the body. The function +[link beast.ref.http__serializer.is_header_done `serializer::is_header_done`] +informs the caller whether the header has completed serialization. In this +C++14 example we print the header first, followed by the body: +``` +template +void print(message const& m) +{ + error_code ec; + serializer sr{m}; + sr.split(true); + std::cout << "Header:" << std::endl; + do + { + sr.get(ec, + [&sr](error_code& ec, auto const& buffer) + { + std::cout << buffers(buffer); + sr.consume(boost::asio::buffer_size(buffer)); + }); + } + while(! sr.is_header_done()); + if(! ec && ! sr.is_done()) + { + std::cout << "Body:" << std::endl; + do + { + sr.get(ec, + [&sr](error_code& ec, auto const& buffer) + { + std::cout << buffers(buffer); + sr.consume(boost::asio::buffer_size(buffer)); + }); + } + while(! ec && ! sr.is_done()); + } + if(ec) + std::cerr << ec.message() << std::endl; +} +``` + +[heading Chunk Decorators] + +When the message used to construct the serializer indicates the chunked +transfer encoding, the serializer will automatically generate the proper +encoding in the output buffers. __rfc7230__ defines additional fields +called the +[@https://tools.ietf.org/html/rfc7230#section-4.1.1 chunk extensions] +in chunks with body octets, and the +[@https://tools.ietf.org/html/rfc7230#section-4.1.2 chunked trailer part] +for the final chunk. Applications that wish to emit chunk extensions +and trailers may instantiate the serializer with a "chunk decorator" type, +and pass an instance of the type upon construction. This decorator is +a function object which, when invoked with a __ConstBufferSequence__, +returns a +[link beast.ref.string_view `string_view`] containing either the extensions +or the trailer. For chunks containing body data, the passed buffer will +contain one or more corresponding body octets. The decorator may use this +information as needed. For example, to compute a digest on the data and +store it as a chunk extension. For the trailers, the serializer will +invoke the decorator with a buffer sequence of size zero. Or more +specifically, with an object of type +[@http://www.boost.org/doc/html/boost_asio/reference/null_buffers.html `boost::asio::null_buffers`]. + +For body chunks the string returned by the decorator must end in a +CRLF (`"\r\n"`) and follow the +[@https://tools.ietf.org/html/rfc7230#section-4.1.1 correct syntax] +for the entire chunk extension. For the trailer, the returned string +should consist of zero or more lines ending in a CRLF and containing +a field name/value pair in the format prescribed in __rfc7230__. It +is the responsibility of the decorator to manage returned string buffers. +The implementation guarantees it will not reference previous strings +after subsequent calls. + +Here, we declare a decorator which sets an extension variable `x` equal +to the size of the chunk in bytes, and returns a single trailer field: +``` +struct decorator +{ + std::string s; + + template + string_view + operator()(ConstBufferSequence const& buffer) const + { + s = ";x=" + std::to_string(boost::asio::buffer_size(buffer)) + "\r\n"; + return s; + } + + string_view + operator()(boost::asio::null_buffers) const + { + return "Result: OK\r\n"; + } +}; +``` + +[endsect] + + + +[section:parsing Parsing (Advanced HTTP)] + +[endsect] + + + +[section:fields Field Containers (Advanced HTTP)] + +[endsect] + + + +[section:body Body Types (Advanced HTTP)] + +User-defined types are possible for the message body, where the type meets the +[link beast.ref.Body [*`Body`]] requirements. This simplified class declaration +shows the customization points available to user-defined body types: + +[$images/body.png [width 525px] [height 190px]] + +The meanin of the nested types is as follows + +[table Body Type Members +[[Name][Description]] +[ + [`value_type`] + [ + Determines the type of the + [link beast.ref.http__message.body `message::body`] member. If this + type defines default construction, move, copy, or swap, then message objects + declared with this [*Body] will have those operations defined. + ] +][ + [`body_writer`] + [ + An optional nested type meeting the requirements of + [link beast.ref.BodyWriter [*BodyWriter]]. If present, this defines the + algorithm used to transfer parsed octets into buffers representing the + body. + ] +][ + [`body_reader`] + [ + An optional nested type meeting the requirements of + [link beast.ref.BodyReader [*BodyReader]]. If present, this defines + the algorithm used to obtain buffers representing a body of this type. + ] +] +] + +The examples included with this library provide a [*Body] implementation that +serializing message bodies that come from a file. + +[endsect] + + + +[endsect] diff --git a/doc/websocket.qbk b/doc/5_websocket.qbk similarity index 100% rename from doc/websocket.qbk rename to doc/5_websocket.qbk diff --git a/doc/examples.qbk b/doc/6_examples.qbk similarity index 100% rename from doc/examples.qbk rename to doc/6_examples.qbk diff --git a/doc/design.qbk b/doc/7_0_design.qbk similarity index 88% rename from doc/design.qbk rename to doc/7_0_design.qbk index 055dcf43..a024f7db 100644 --- a/doc/design.qbk +++ b/doc/7_0_design.qbk @@ -26,7 +26,7 @@ libraries: * Don't sacrifice performance. -* Mimic Boost.Asio; familiarity breeds confidence. +* Mimic __Asio__; familiarity breeds confidence. * Role-symmetric interfaces; client and server the same (or close to it). @@ -34,8 +34,8 @@ libraries: managing flow control. Beast uses the __DynamicBuffer__ concept presented in the Networking TS -(__N4588__), and relies heavily on the Boost.Asio __ConstBufferSequence__ -and __MutableBufferSequence__ concepts for passing buffers to functions. +(__N4588__), and relies heavily on the __ConstBufferSequence__ and +__MutableBufferSequence__ concepts for passing buffers to functions. The authors have found the dynamic buffer and buffer sequence interfaces to be optimal for interacting with Asio, and for other tasks such as incremental parsing of data in buffers (for example, parsing websocket frames stored @@ -59,9 +59,9 @@ start. Other design goals: * Allow for customizations, if the user needs it. -[include design/http_message.qbk] -[include design/http_comparison.qbk] -[include design/websocket_zaphoyd.qbk] -[include design/review.qbk] +[include 7_1_http_message.qbk] +[include 7_2_http_comparison.qbk] +[include 7_3_websocket_zaphoyd.qbk] +[include 7_4_review.qbk] [endsect] diff --git a/doc/design/http_message.qbk b/doc/7_1_http_message.qbk similarity index 74% rename from doc/design/http_message.qbk rename to doc/7_1_http_message.qbk index 3071e34f..aa9f6087 100644 --- a/doc/design/http_message.qbk +++ b/doc/7_1_http_message.qbk @@ -11,19 +11,33 @@ In this section we describe the problem of modeling HTTP messages and explain how the library arrived at its solution, with a discussion of the benefits and drawbacks of the design choices. The goal for creating a message model is to create a container with value semantics, possibly movable and/or -copyable, that completely describes the message. More formally, the container -has all of the information necessary for the serialization algorithms to -represent the entire message as a series of octets, and that the parsing -algorithms store all of the captured information about an entire message -in the container. +copyable, that contains all the information needed to serialize, or all +of the information captured during parsing. More formally, given: -In addition to capturing the entirety of a message, we would like the message -container to contain enough customization points to permit the following: -allocator support, user-defined containers to represent header fields, and -user-defined containers to represent the body. And finally, because requests -and responses have slightly different information in the ['start-line], we -would like the containers for requests and responses to be represented by -different types. +* `m` is an instance of an HTTP message container + +* `x` is a series of octets describing a valid HTTP message in + the serialized format decribed in __rfc7230__. + +* `S(m)` is a serialization function which produces a series of octets + from a message container. + +* `P(x)` is a parsing function which produces a message container from + a series of octets. + +These relations are true: + +* `S(m) == x` + +* `P(S(m)) == m` + +We would also like our message container to have customization points +permitting the following: full allocator support, user-defined containers +to represent header fields, and user-defined types and algorithms to +represent the body. And finally, because requests and responses have +different fields in the ['start-line], we would like the containers for +requests and responses to be represented by different types for function +overloading. Here is our first attempt at declaring some message containers: @@ -57,21 +71,20 @@ struct response ]] ] -Here we have accomplished a few things. Request and response objects are -different types. The user can choose the container used to represent the -fields. And the user can choose the [*Body] type, which is a concept -defining not only the type of `body` member but also the algorithms used -to transfer information in and out of that member when performing -serialization and parsing. +These containers are capable of representing everything in the model +of HTTP requests and responses described in __rfc7230__. Request and +response objects are different types. The user can choose the container +used to represent the fields. And the user can choose the [*Body] type, +which is a concept defining not only the type of `body` member but also +the algorithms used to transfer information in and out of that member +when performing serialization and parsing. However, a problem arises. How do we write a function which can accept an object that is either a request or a response? As written, the only -ovious solution is to make the message a template type. Additional traits +obvious solution is to make the message a template type. Additional traits classes would then be needed to make sure that the passed object has a -valid type which meets the requirements. We can avoid those complexities -by renaming the containers and making them partial specializations of a -single class, like this: - +valid type which meets the requirements. Instead, bypass those complexities +by making each container a partial specialization of one class: ``` /// An HTTP message template @@ -90,7 +103,7 @@ struct message /// An HTTP response template -struct response +struct message { int version; int status; @@ -168,8 +181,8 @@ of the `message` class. But to achieve all our goals we will need to make sure that there are enough constructor overloads to not only provide for the special copy and move members if the instantiated types support it, but also allow the fields container and body container to be constructed -with arbitrary variadic lists of parameters. This allows those members -to properly support allocators. +with arbitrary variadic lists of parameters. This allows the container +to fully support allocators. The solution used in the library is to treat the message like a `std::pair` for the purposes of construction, except that instead of `first` and `last` @@ -181,18 +194,16 @@ interested readers can view the declarations in the corresponding header file. There is now significant progress with our message container but a stumbling -block remains. The presence of `std::string` members is an obstacle to our -goal of making messages allocator-aware. One obvious solution is to add an -allocator to the template parameter list of the header and message classes, -and allow the string based members to construct with instances of those -allocators. This is unsatisfying because of the combinatorial explosion of -constructor variations needed to support the scheme. It also means that -request messages could have [*four] different allocators: two for the fields -and body, and two for the method and target strings. A better solution is -needed. +block remains. There is no way to control the allocator for the `std::string` +members. We could add an allocator to the template parameter list of the +header and message classes, use it for those strings. This is unsatisfying +because of the combinatorial explosion of constructor variations needed to +support the scheme. It also means that request messages could have [*four] +different allocators: two for the fields and body, and two for the method +and target strings. A better solution is needed. -To make allocators workable, we make a simple change to the interface and -then engineer a clever concession. First, the interface change: +To get around this we make a simple change to the interface and then +engineer a clever concession. First, the interface change: ``` /// An HTTP request header template @@ -218,8 +229,8 @@ struct header }; ``` -This approach replaces public data members with traditional accessors -using non-owning references to string buffers. Now we make a concession: +The start-line data members are replaced traditional accessors using +non-owning references to string buffers. Now we make a concession: management of the corresponding string is delegated to the [*Fields] container, which can already be allocator aware and constructed with the necessary allocator parameter via the provided constructor overloads for @@ -247,6 +258,7 @@ struct header } Fields fields; +}; ``` An advantage of this technique is that user-provided implementations of diff --git a/doc/design/http_comparison.qbk b/doc/7_2_http_comparison.qbk similarity index 100% rename from doc/design/http_comparison.qbk rename to doc/7_2_http_comparison.qbk diff --git a/doc/design/websocket_zaphoyd.qbk b/doc/7_3_websocket_zaphoyd.qbk similarity index 100% rename from doc/design/websocket_zaphoyd.qbk rename to doc/7_3_websocket_zaphoyd.qbk diff --git a/doc/design/review.qbk b/doc/7_4_review.qbk similarity index 98% rename from doc/design/review.qbk rename to doc/7_4_review.qbk index bc234493..2369625f 100644 --- a/doc/design/review.qbk +++ b/doc/7_4_review.qbk @@ -120,7 +120,7 @@ about Beast and other HTTP libraries that have gone through formal review. been optimized or designed with optimization in mind. The slow parts of WebSocket processing have been optimized, and the HTTP parser design is lifted from another extremely popular project which has performance - as a design goal (see https://github.com/h2o/picohttpparser). + as a design goal (see [@https://github.com/h2o/picohttpparser]). From: [@http://www.boost.org/development/requirements.html] @@ -139,9 +139,10 @@ about Beast and other HTTP libraries that have gone through formal review. believing they could perform an HTTP request on a URL or put up a WebSocket client or server in a couple of lines of code. Where would the core utilities go? Very likely it would step on the - owner of Boost.Asio's toes to put things in the Boost.Asio - repository; at the very least, it would create unrequested, + owner of Boost.Asio's toes to put things in the boost/asio + directory; at the very least, it would create unrequested, additional work for the foreign repository. + "Beast" is sufficiently vague as to not suggest any particular functionality, while acting as a memorable umbrella term for a family of low level containers and algorithms. People in the know diff --git a/doc/Jamfile.v2 b/doc/Jamfile similarity index 99% rename from doc/Jamfile.v2 rename to doc/Jamfile index 39e9ecfb..47cd0da5 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile @@ -65,7 +65,7 @@ explicit examples ; xml doc : - master.qbk + 0_main.qbk : temp $(broot)/tools/boostbook/dtd diff --git a/doc/http.qbk b/doc/http.qbk deleted file mode 100644 index 79ea2d6b..00000000 --- a/doc/http.qbk +++ /dev/null @@ -1,333 +0,0 @@ -[/ - Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -] - -[section:http Using HTTP] - -[block ''' - - Message - Fields - Body - Algorithms - -'''] - -Beast offers programmers simple and performant models of HTTP messages and -their associated operations including synchronous and asynchronous reading and -writing of messages and headers in the HTTP/1 wire format using Boost.Asio. - -[note - The following documentation assumes familiarity with both Boost.Asio - and the HTTP protocol specification described in __rfc7230__. Sample code - and identifiers mentioned in this section are written as if the following - declarations are in effect: - ``` - #include - #include - using namespace beast; - using namespace beast::http; - ``` -] - - - -[section:message Message] - -The HTTP protocol defines the client and server roles: clients send messages -called requests and servers send back messages called responses. A HTTP message -(referred to hereafter as "message") contains request or response specific -attributes (contained in the "Start Line"), a series of zero or more name/value -pairs (collectively termed "Fields"), and an optional series of octets called -the message body which may be zero in length. The start line for a HTTP request -includes a string called the method, a string called the URL, and a version -number indicating HTTP/1.0 or HTTP/1.1. For a response, the start line contains -an integer status code and a string called the reason phrase. Alternatively, a -HTTP message can be viewed as two parts: a header, followed by a body. - -[note - The Reason-Phrase is obsolete as of rfc7230. -] - -The __header__ class template models the header for HTTP/1 and HTTP/2 messages. -This class template is a family of specializations, one for requests and one -for responses, depending on the [*`isRequest`] template value. -The [*`Fields`] template type determines the type of associative container -used to store the field values. The provided __basic_fields__ class template -and __fields__ type alias are typical choices for the [*`Fields`] type, but -advanced applications may supply user defined types which meet the requirements. -The __message__ class template models the header and optional body for HTTP/1 -and HTTP/2 requests and responses. It is derived from the __header__ class -template with the same shared template parameters, and adds the `body` data -member. The message class template requires an additional template argument -type [*`Body`]. This type controls the container used to represent the body, -if any, as well as the algorithms needed to serialize and parse bodies of -that type. - -This illustration shows the declarations and members of the __header__ and -__message__ class templates, as well as the inheritance relationship: - -[$images/message.png [width 711px] [height 424px]] - -For notational convenience, these template type aliases are provided which -supply typical choices for the [*`Fields`] type: -``` -/// A typical HTTP request -template -using request = message; - -/// A typical HTTP response -template -using response = message; -``` - -The code examples below show how to create and fill in request and response -objects: - -[table Create Message -[[HTTP Request] [HTTP Response]] -[[ - ``` - request req; - req.version = 11; // HTTP/1.1 - req.method("GET"); - req.target("/index.htm"); - req.fields.insert("Accept", "text/html"); - req.fields.insert("Connection", "keep-alive"); - req.fields.insert("User-Agent", "Beast"); - ``` -][ - ``` - response res; - res.version = 11; // HTTP/1.1 - res.status = 200; - res.reason("OK"); - res.fields.insert("Server", "Beast"); - res.fields.insert("Content-Length", 4); - res.body = "****"; - ``` -]]] - -In the serialized format of a HTTP message, the header is represented as a -series of text lines ending in CRLF (`"\r\n"`). The end of the header is -indicated by a line containing only CRLF. Here are examples of serialized HTTP -request and response objects. The objects created above will produce these -results when serialized. Note that only the response has a body: - -[table Serialized HTTP Request and Response -[[HTTP Request] [HTTP Response]] -[[ - ``` - GET /index.htm HTTP/1.1\r\n - Accept: text/html\r\n - Connection: keep-alive\r\n - User-Agent: Beast\r\n - \r\n - ``` -][ - ``` - 200 OK HTTP/1.1\r\n - Server: Beast\r\n - Content-Length: 4\r\n - \r\n - **** - ``` -]]] - -[endsect] - - - -[section:fields Fields] - -The [*`Fields`] type represents a container that can set or retrieve the -fields in a message. Beast provides the -[link beast.ref.http__basic_fields `basic_fields`] class which serves -the needs for most users. It supports modification and inspection of values. -The field names are not case-sensitive. - -These statements change the values of the headers in the message passed: -``` - template - void set_fields(request& req) - { - if(! req.exists("User-Agent")) - req.insert("User-Agent", "myWebClient"); - - if(req.exists("Accept-Charset")) - req.erase("Accept-Charset"); - - req.replace("Accept", "text/plain"); - } -``` - -User defined [*`Fields`] types are possible. To support serialization, the -type must meet the requirements of __FieldSequence__. To support parsing using -the provided parser, the type must provide the `insert` member function. - -[endsect] - - - -[section:body Body] - -The message [*`Body`] template parameter controls both the type of the data -member of the resulting message object, and the algorithms used during parsing -and serialization. Beast provides three very common [*`Body`] types: - -* [link beast.ref.http__string_body [*`string_body`:]] A body with a -`value_type` as `std::string`. Useful for quickly putting together a request -or response with simple text in the message body (such as an error message). -Has the same insertion complexity of `std::string`. This is the type of body -used in the examples: -``` - response res; - static_assert(std::is_same::value); - res.body = "Here is the data you requested"; -``` - -* [link beast.ref.http__dynamic_body [*`dynamic_body`:]] A body with a -`value_type` of [link beast.ref.multi_buffer `multi_buffer`]: an efficient storage -object which uses multiple octet arrays of varying lengths to represent data. - -* [link beast.ref.http__buffer_body [*`buffer_body`:]] A write-only body -with a `value_type` representing a __ConstBufferSequence__. This special -body allows the caller to implement their own write loop for advanced -use-cases such as relaying. - -* [link beast.ref.http__empty_body [*`empty_body`:]] A write-only body -with an empty `value_type` representing an HTTP message with no content -body. - -[heading Advanced] - -User-defined types are possible for the message body, where the type meets the -[link beast.ref.Body [*`Body`]] requirements. This simplified class declaration -shows the customization points available to user-defined body types: - -[$images/body.png [width 510px] [height 210px]] - -* [*`value_type`]: Determines the type of the - [link beast.ref.http__message.body `message::body`] member. If this - type defines default construction, move, copy, or swap, then message objects - declared with this [*Body] will have those operations defined. - -* [*`body_writer`]: An optional nested type meeting the requirements of - [link beast.ref.BodyWriter [*BodyWriter]]. If present, this defines the - algorithm used to transfer parsed octets into buffers representing the - body. - -* [*`body_reader`]: An optional nested type meeting the requirements of - [link beast.ref.BodyReader [*BodyReader]]. If present, this defines - the algorithm used to obtain buffers representing a body of this type. - -The examples included with this library provide a [*Body] implementation that -serializing message bodies that come from a file. - -[endsect] - - - -[section:algorithms Algorithms] - -Algorithms are provided to serialize and deserialize HTTP/1 messages on -streams. - -* [link beast.ref.http__read [*read]]: Deserialize a HTTP/1 __header__ or __message__ from a stream. -* [link beast.ref.http__write [*write]]: Serialize a HTTP/1 __header__ or __message__ to a stream. - -Asynchronous versions of these algorithms are also available: - -* [link beast.ref.http__async_read [*async_read]]: Deserialize a HTTP/1 __header__ or __message__ asynchronously from a stream. -* [link beast.ref.http__async_write [*async_write]]: Serialize a HTTP/1 __header__ or __message__ asynchronously to a stream. - -[heading Using Sockets] - -The free function algorithms are modeled after Boost.Asio to send and receive -messages on TCP/IP sockets, SSL streams, or any object which meets the -Boost.Asio type requirements (__SyncReadStream__, __SyncWriteStream__, -__AsyncReadStream__, and __AsyncWriteStream__ depending on the types of -operations performed). To send messages synchronously, use one of the -[link beast.ref.http__write `write`] functions: -``` - void send_request(boost::asio::ip::tcp::socket& sock) - { - request req; - req.version = 11; - req.method("GET"); - req.target("/index.html"); - ... - write(sock, req); // Throws exception on error - ... - // Alternatively - boost::system::error:code ec; - write(sock, req, ec); - if(ec) - std::cerr << "error writing http message: " << ec.message(); - } -``` - -An asynchronous interface is available: -``` - void handle_write(boost::system::error_code); - ... - request req; - ... - async_write(sock, req, std::bind(&handle_write, std::placeholders::_1)); -``` - -When the implementation reads messages from a socket, it can read bytes lying -after the end of the message if they are present (the alternative is to read -a single byte at a time which is unsuitable for performance reasons). To -store and re-use these extra bytes on subsequent messages, the read interface -requires an additional parameter: a [link beast.ref.DynamicBuffer [*`DynamicBuffer`]] -object. This example reads a message from the socket, with the extra bytes -stored in the `streambuf` parameter for use in a subsequent call to read: -``` - boost::asio::streambuf sb; - ... - response res; - read(sock, sb, res); // Throws exception on error - ... - // Alternatively - boost::system::error:code ec; - read(sock, sb, res, ec); - if(ec) - std::cerr << "error reading http message: " << ec.message(); -``` - -As with the write function, an asynchronous interface is available. The -stream buffer parameter must remain valid until the completion handler is -called: -``` - void handle_read(boost::system::error_code); - ... - boost::asio::streambuf sb; - response res; - ... - async_read(sock, res, std::bind(&handle_read, std::placeholders::_1)); -``` - -An alternative to using a `boost::asio::streambuf` is to use a -__multi_buffer__, which meets the requirements of __DynamicBuffer__ and -is optimized for performance: -``` - void handle_read(boost::system::error_code); - ... - beast::multi_buffer sb; - response res; - read(sock, sb, res); -``` - -The `read` implementation can use any object meeting the requirements of -__DynamicBuffer__, allowing callers to define custom -memory management strategies used by the implementation. - -[endsect] - - - -[endsect] diff --git a/doc/images/body.png b/doc/images/body.png index 54d05550..581bc57c 100644 Binary files a/doc/images/body.png and b/doc/images/body.png differ diff --git a/doc/images/body.psd b/doc/images/body.psd index 3d8dca09..ab83b5d5 100644 Binary files a/doc/images/body.psd and b/doc/images/body.psd differ diff --git a/doc/master.qbk b/doc/master.qbk deleted file mode 100644 index 6fc23f46..00000000 --- a/doc/master.qbk +++ /dev/null @@ -1,125 +0,0 @@ -[/ - Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -] - -[library Beast - [quickbook 1.6] - [copyright 2013 - 2017 Vinnie Falco] - [purpose Networking Protocol Library] - [license - Distributed under the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - [@http://www.boost.org/LICENSE_1_0.txt]) - ] - [authors [Falco, Vinnie]] - [category template] - [category generic] -] - -[template mdash[] '''— '''] -[template indexterm1[term1] ''''''[term1]''''''] -[template indexterm2[term1 term2] ''''''[term1]''''''[term2]''''''] - -[def __N3747__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3747.pdf [*N3747]]] -[def __N4588__ [@http://cplusplus.github.io/networking-ts/draft.pdf [*N4588]]] -[def __rfc6455__ [@https://tools.ietf.org/html/rfc6455 rfc6455]] -[def __rfc7230__ [@https://tools.ietf.org/html/rfc7230 rfc7230]] - -[def __asio_handler_invoke__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]] -[def __asio_handler_allocate__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]] -[def __void_or_deduced__ [@http://www.boost.org/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]] -[def __use_future__ [@http://www.boost.org/doc/html/boost_asio/reference/use_future_t.html `boost::asio::use_future`]] -[def __yield_context__ [@http://www.boost.org/doc/html/boost_asio/reference/yield_context.html `boost::asio::yield_context`]] - -[def __AsyncReadStream__ [@http://www.boost.org/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]] -[def __AsyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]] -[def __CompletionHandler__ [@http://www.boost.org/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]] -[def __ConstBufferSequence__ [@http://www.boost.org/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]] -[def __Handler__ [@http://www.boost.org/doc/html/boost_asio/reference/Handler.html [*Handler]]] -[def __MutableBufferSequence__ [@http://www.boost.org/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]] -[def __SyncReadStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]] -[def __SyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]] - -[def __Body__ [link beast.ref.Body [*Body]]] -[def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]] -[def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]] - -[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]] -[def __fields__ [link beast.ref.http__fields `fields`]] -[def __flat_buffer__ [link beast.ref.flat_buffer `flat_buffer`]] -[def __header__ [link beast.ref.http__header `header`]] -[def __message__ [link beast.ref.http__message `message`]] -[def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]] -[def __basic_multi_buffer__ [link beast.ref.basic_multi_buffer `basic_multi_buffer`]] - -Beast is a cross-platform, header-only C++ library built on Boost.Asio that -provides implementations of the HTTP and WebSocket protocols. - -[variablelist - [[ - [link beast.overview Overview] - ][ - An introduction with features, requirements, and credits. - ]] - [[ - [link beast.core Core Concepts] - ][ - Library-wide concepts, classes, functions, and traits. - ]] - [[ - [link beast.http Using HTTP] - ][ - How to use Beast's HTTP interfaces in your applications. - ]] - [[ - [link beast.websocket Using WebSocket] - ][ - How to use Beast's WebSocket interfaces in your applications. - ]] - [[ - [link beast.example Examples] - ][ - Examples that illustrate the use of Beast in more complex applications. - ]] - [[ - [link beast.design Design] - ][ - Design rationale, answers to questions, library comparisons, - and special considerations for Boost Formal Review participants. - ]] - [[ - [link beast.ref Reference] - ][ - Detailed class and function reference. - ]] - [[ - [link beast.index Index] - ][ - Book-style text index of Beast documentation. - ]] -] - -[include overview.qbk] -[include core.qbk] -[include http.qbk] -[include websocket.qbk] -[include examples.qbk] -[include design.qbk] - -[section:ref Reference] -[xinclude quickref.xml] -[include concept/Body.qbk] -[include concept/BodyReader.qbk] -[include concept/BodyWriter.qbk] -[include concept/BufferSequence.qbk] -[include concept/DynamicBuffer.qbk] -[include concept/Field.qbk] -[include concept/FieldSequence.qbk] -[include concept/Streams.qbk] -[include reference.qbk] -[endsect] - -[xinclude index.xml] diff --git a/doc/overview.qbk b/doc/overview.qbk deleted file mode 100644 index 9464fd2d..00000000 --- a/doc/overview.qbk +++ /dev/null @@ -1,145 +0,0 @@ -[/ - Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -] - -[section:overview Introduction] - -Beast is a header-only, cross-platform C++ library built on Boost.Asio and -parts of Boost, containing two modules implementing widely used network -protocols. Beast offers a universal HTTP message model, plus algorithms for -parsing and serializing HTTP/1 messages. Beast.WebSocket provides a complete -implementation of the WebSocket protocol. Their design achieves these goals: - -* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be -used to build clients, servers, or both. - -* [*Ease of Use.] HTTP messages are modeled using simple, readily -accessible objects. Functions and classes used to send and receive HTTP -or WebSocket messages are designed to resemble Boost.Asio as closely as -possible. Users familiar with Boost.Asio will be immediately comfortable -using this library. - -* [*Flexibility.] Interfaces do not mandate specific implementation -strategies; important decisions such as buffer or thread management are -left to users of the library. - -* [*Performance.] The implementation performs competitively, making it a -realistic choice for building high performance network servers. - -* [*Scalability.] Development of network applications that scale to thousands -of concurrent connections is possible with the implementation. - -* [*Basis for further abstraction.] The interfaces facilitate the -development of other libraries that provide higher levels of abstraction. - -[heading Requirements] - -Beast requires: - -* [*C++11.] A minimum of C++11 is needed. -* [*Boost.] Beast is built on Boost, especially Boost.Asio. -* [*OpenSSL.] If using TLS/Secure sockets (optional). - -[note Tested compilers: msvc-14+, gcc 4.8+, clang 3.6+] - -The library is [*header-only]. It is not necessary to add any .cpp files, -or to add commands to your build script for building Beast. To link your -program successfully, you'll need to add the Boost.System library to link -with. If you use coroutines you'll also need the Boost.Coroutine library. -Please visit the Boost documentation for instructions on how to do this for -your particular build system. - -There are no provisions for enabling Beast to compile using the stand-alone -version of Asio. Beast relies on other parts of Boost in addition to Asio. -There are no immediate plans to offer a version of Beast that works with -the stand-alone Asio. - -[heading Audience] - -Beast is aimed at network programmers who have know some Boost.Asio. While -experience is not strictly necessary, the documentation and interfaces assume -a reasonable grasp of how Asio works. In particular, users who wish to write -asynchronous programs with Beast should already have knowledge and experience -of Asio's asynchronous interfaces and general style of asynchronous programming -using callbacks or coroutines. - -The supplied WebSocket and HTTP interfaces are low-level. The library does not -provide out of the box solutions for implementing clients or servers. For -example, users must provide their own code to make connections, handle -timeouts, reconnect a dropped connection, accept incoming connections, or -manage connection resources on a server. - -Beast's HTTP interfaces are similarly low level, providing functionality -only for modelling HTTP messages and reading and writing them to sockets or -streams. Higher level functions such as HTTP Basic Authentication, -mime/multipart encoding, cookies, automatic handling of redirects, gzipped -transfer encodings, caching, or proxying (to name a few) are not directly -provided, but nothing stops users from creating these features using -Beast's HTTP message types. - -Instead, the library is intended to be a building block for creating higher -level libraries. It implements just enough of the HTTP and WebSocket protocol -to allow users to create useful objects and algorithms which may then be -composed to produce useful applications. It is the desire of the author that -this library will become the foundation for a new generation of network -libraries. - -[heading Motivation] - -Beast is built on Boost.Asio. A proposal to add networking functionality to the -C++ standard library, based on Boost.Asio, is under consideration by the -committee and on track for standardization. Since the final approved networking -interface for the C++ standard library will likely closely resemble the current -interface of Boost.Asio, the choice of Boost.Asio as the network transport -layer is prudent. - -The HTTP protocol is pervasive in network applications. As C++ is a logical -choice for high performance network servers, there is great utility in solid -building blocks for manipulating, sending, and receiving HTTP messages -compliant with the Hypertext Transfer Protocol and the supplements that -follow. Unfortunately reliable implementations or industry standards do not -exist in C++. The development of higher level libraries is stymied by the -lack of a common set of low-level algorithms and types for interacting with -the HTTP protocol. - -Today's web applications increasingly rely on alternatives to standard HTTP -to achieve performance and/or responsiveness. While WebSocket implementations -are widely available in common web development languages such as Javascript, -good implementations in C++ are scarce. A survey of existing C++ WebSocket -solutions reveals interfaces which lack symmetry, impose performance penalties, -and needlessly restrict implementation strategies. - -Beast.WebSocket takes advantage of Boost.Asio's extensible asynchronous -model, handler allocation, and handler invocation hooks. Calls to -Beast.WebSocket asynchronous initiation functions allow callers the choice -of using a completion handler, stackful or stackless coroutines, futures, -or user defined customizations (for example, Boost.Fiber). The -implementation uses handler invocation hooks (__asio_handler_invoke__), -providing execution guarantees on composed operations in a manner identical -to Boost.Asio. The implementation also uses handler allocation hooks -(__asio_handler_allocate__) when allocating memory internally for composed -operations. - -There is no need for inheritance or virtual members in a -[link beast.ref.websocket__stream `websocket::stream`]. -All operations are templated and transparent to the compiler, allowing for -maximum inlining and optimization. - -[heading Credits] - -Boost.Asio is the inspiration behind which all of the interfaces and -implementation strategies are built. Some parts of the documentation are -written to closely resemble the wording and presentation of Boost.Asio -documentation. Credit goes to Christopher Kohlhoff for the wonderful -Asio library and the ideas upon which Beast is built. - -Beast would not be possible without the considerable time and patience -contributed by David Schwartz, Edward Hennis, Howard Hinnant, Miguel Portilla, -Nikolaos Bougalis, Scott Determan, Scott Schurr, and Ripple Labs for -supporting its early development. Also thanks to Agustín Bergé, Glen Fernandes -and Peter Dimov for putting up with my endless C++ questions on Slack. - -[endsect] diff --git a/examples/echo_op.cpp b/examples/echo_op.cpp index 67919cc7..5fd0b025 100644 --- a/examples/echo_op.cpp +++ b/examples/echo_op.cpp @@ -151,17 +151,20 @@ operator()(beast::error_code ec, std::size_t bytes_transferred) case 1: // write everything back p.step = 2; - return boost::asio::async_write(p.stream, p.buffer.data(), std::move(*this)); + // async_read_until could have read past the newline, + // use buffer_prefix to make sure we only send one line + return boost::asio::async_write(p.stream, + beast::buffer_prefix(bytes_transferred, p.buffer.data()), std::move(*this)); case 2: + p.buffer.consume(bytes_transferred); break; } // Invoke the final handler. If we wanted to pass any arguments // which come from our state, they would have to be moved to the // stack first, since the `handler_ptr` guarantees that the state - // is destroyed before - // the handler is invoked. + // is destroyed before the handler is invoked. // p_.invoke(ec); return; @@ -174,8 +177,7 @@ beast::async_return_type async_echo(AsyncStream& stream, CompletionToken&& token) { // Make sure stream meets the requirements. We use static_assert - // instead of letting the compiler generate several pages of hard - // to read error messages. + // to cause a friendly message instead of an error novel. // static_assert(beast::is_async_stream::value, "AsyncStream requirements not met"); @@ -187,7 +189,7 @@ async_echo(AsyncStream& stream, CompletionToken&& token) beast::async_completion init{token}; // Create the composed operation and launch it. This is a constructor - // call followed by invocation of operator(). We use BEAST_HANDLER_TYPE + // call followed by invocation of operator(). We use handler_type // to convert the completion token into the correct handler type, // allowing user defined specializations of the async result template // to take effect. @@ -213,14 +215,12 @@ int main() // the echo, and then shut everything down and exit. boost::asio::io_service ios; socket_type sock{ios}; - { - boost::asio::ip::tcp::acceptor acceptor{ios}; - endpoint_type ep{address_type::from_string("0.0.0.0"), 0}; - acceptor.open(ep.protocol()); - acceptor.bind(ep); - acceptor.listen(); - acceptor.accept(sock); - } + boost::asio::ip::tcp::acceptor acceptor{ios}; + endpoint_type ep{address_type::from_string("0.0.0.0"), 0}; + acceptor.open(ep.protocol()); + acceptor.bind(ep); + acceptor.listen(); + acceptor.accept(sock); async_echo(sock, [&](beast::error_code ec) { diff --git a/include/beast/http/fields.hpp b/include/beast/http/fields.hpp index c22b09ea..ab84dd1d 100644 --- a/include/beast/http/fields.hpp +++ b/include/beast/http/fields.hpp @@ -26,7 +26,7 @@ namespace http { /** A container for storing HTTP header fields. This container is designed to store the field value pairs that make - up the fields and trailers in a HTTP message. Objects of this type + up the fields and trailers in an HTTP message. Objects of this type are iterable, with each element holding the field name and field value. diff --git a/include/beast/http/message.hpp b/include/beast/http/message.hpp index 8719c060..5ee7589c 100644 --- a/include/beast/http/message.hpp +++ b/include/beast/http/message.hpp @@ -20,7 +20,7 @@ namespace beast { namespace http { -/** A container for a HTTP request or response header. +/** A container for an HTTP request or response header. A header includes the Start Line and Fields. @@ -160,7 +160,7 @@ struct header } }; -/** A container for a HTTP request or response header. +/** A container for an HTTP request or response header. A header includes the Start Line and Fields. @@ -510,7 +510,7 @@ enum class connection upgrade }; -/** Prepare a HTTP message. +/** Prepare an HTTP message. This function will adjust the Content-Length, Transfer-Encoding, and Connection fields of the message based on the properties of diff --git a/include/beast/http/read.hpp b/include/beast/http/read.hpp index f2c9daad..56f3e661 100644 --- a/include/beast/http/read.hpp +++ b/include/beast/http/read.hpp @@ -208,7 +208,7 @@ async_read_some( //------------------------------------------------------------------------------ -/** Read an HTTP/1 message from a stream. +/** Read into an HTTP/1 parser from a stream. This function synchronously reads from a stream and passes data to the specified parser. The call will block until one @@ -252,7 +252,7 @@ read( DynamicBuffer& buffer, basic_parser& parser); -/** Read an HTTP/1 message from a stream. +/** Read into an HTTP/1 parser from a stream. This function synchronously reads from a stream and passes data to the specified parser. The call will block until one @@ -297,7 +297,7 @@ read( basic_parser& parser, error_code& ec); -/** Start an asynchronous operation to read an HTTP/1 message from a stream. +/** Read into an HTTP/1 parser asynchronously from a stream. This function is used to asynchronously read from a stream and pass the data to the specified parser. The function call always @@ -406,7 +406,7 @@ read( DynamicBuffer& buffer, message& msg); -/** Read a HTTP/1 message from a stream. +/** Read an HTTP/1 message from a stream. This function is used to synchronously read a message from a stream. The call blocks until one of the following conditions @@ -453,7 +453,7 @@ read( message& msg, error_code& ec); -/** Read a HTTP/1 message asynchronously from a stream. +/** Read an HTTP/1 message asynchronously from a stream. This function is used to asynchronously read a message from a stream. The function call always returns immediately. The diff --git a/include/beast/http/rfc7230.hpp b/include/beast/http/rfc7230.hpp index b20ab920..b16c6f0f 100644 --- a/include/beast/http/rfc7230.hpp +++ b/include/beast/http/rfc7230.hpp @@ -15,9 +15,9 @@ namespace beast { namespace http { -/** A list of parameters in a HTTP extension field value. +/** A list of parameters in an HTTP extension field value. - This container allows iteration of the parameter list in a HTTP + This container allows iteration of the parameter list in an HTTP extension. The parameter list is a series of name/value pairs with each pair starting with a semicolon. The value is optional. @@ -99,7 +99,7 @@ public: /** A list of extensions in a comma separated HTTP field value. - This container allows iteration of the extensions in a HTTP + This container allows iteration of the extensions in an HTTP field value. The extension list is a comma separated list of token parameter list pairs. diff --git a/include/beast/http/serializer.hpp b/include/beast/http/serializer.hpp index ec6a4550..8bc65e94 100644 --- a/include/beast/http/serializer.hpp +++ b/include/beast/http/serializer.hpp @@ -201,8 +201,8 @@ class serializer public: /** Constructor - @param msg The message to serialize. The message object - must remain valid for the lifetime of the write stream. + @param msg The message to serialize, which must + remain valid for the lifetime of the serializer. @param decorator An optional decorator to use. @@ -213,7 +213,7 @@ public: Decorator const& decorator = Decorator{}, Allocator const& alloc = Allocator{}); - /** Returns `true` if we will pause after writing the header. + /** Returns `true` if we will pause after writing the complete header. */ bool split() const @@ -227,8 +227,8 @@ public: write only the octets corresponding to the serialized header first. If the header has already been written, this function will have no effect on output. This function should be called - before any writes take place, otherwise the behavior is - undefined. + before retrieving any buffers using @ref get, otherwise the + behavior is undefined. */ void split(bool v) @@ -238,9 +238,8 @@ public: /** Return `true` if serialization of the header is complete. - This function indicates whether or not all octets - corresponding to the serialized representation of the - header have been successfully delivered to the stream. + This function indicates whether or not all buffers containing + serialized header octets have been retrieved. */ bool is_header_done() const @@ -248,11 +247,11 @@ public: return header_done_; } - /** Return `true` if serialization is complete + /** Return `true` if serialization is complete. The operation is complete when all octets corresponding to the serialized representation of the message have been - successfully delivered to the stream. + successfully retrieved. */ bool is_done() const @@ -262,9 +261,11 @@ public: /** Return `true` if Connection: close semantic is indicated. - After serialization is complete, if there is an - underlying network connection then it should be closed if - this function returns `true`. + Depending on the contents of the message, the end of + the body may be indicated by the end of file. In order + for the recipient (if any) to receive a complete message, + the underlying network connection must be closed when this + function returns `true`. */ bool needs_close() const @@ -288,7 +289,8 @@ public: @param visit The function to call. The equivalent function signature of this object must be: - @code template + @code + template void visit(error_code&, ConstBufferSequence const&); @endcode The function is not copied, if no error occurs it will be diff --git a/include/beast/http/write.hpp b/include/beast/http/write.hpp index 969d090e..169b3886 100644 --- a/include/beast/http/write.hpp +++ b/include/beast/http/write.hpp @@ -132,7 +132,7 @@ async_write_some(AsyncWriteStream& stream, serializer< isRequest, Body, Fields, Decorator, Allocator>& sr, WriteHandler&& handler); -/** Write a HTTP/1 message to a stream. +/** Write an HTTP/1 message to a stream. This function is used to write a message to a stream. The call will block until one of the following conditions is true: @@ -163,7 +163,7 @@ void write(SyncWriteStream& stream, message const& msg); -/** Write a HTTP/1 message on a stream. +/** Write an HTTP/1 message to a stream. This function is used to write a message to a stream. The call will block until one of the following conditions is true: @@ -195,7 +195,7 @@ write(SyncWriteStream& stream, message const& msg, error_code& ec); -/** Write a HTTP/1 message asynchronously to a stream. +/** Write an HTTP/1 message asynchronously to a stream. This function is used to asynchronously write a message to a stream. The function call always returns immediately. The @@ -247,7 +247,7 @@ async_write(AsyncWriteStream& stream, //------------------------------------------------------------------------------ -/** Serialize a HTTP/1 header to a `std::ostream`. +/** Serialize an HTTP/1 header to a `std::ostream`. The function converts the header to its HTTP/1 serialized representation and stores the result in the output stream. @@ -261,7 +261,7 @@ std::ostream& operator<<(std::ostream& os, header const& msg); -/** Serialize a HTTP/1 message to a `std::ostream`. +/** Serialize an HTTP/1 message to a `std::ostream`. The function converts the message to its HTTP/1 serialized representation and stores the result in the output stream.