From d529d6a16fc2553d53ac8509b13e93baa52cc6d8 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 11 Jun 2017 09:59:13 -0700 Subject: [PATCH] Documentation work --- doc/0_main.qbk | 5 +- doc/1_overview.qbk | 27 ++++---- doc/2_examples.qbk | 46 +++++++------ doc/3_0_core.qbk | 11 +-- doc/3_1_asio.qbk | 9 ++- doc/3_2_streams.qbk | 14 ++-- doc/3_3_buffers.qbk | 26 +++---- doc/3_4_async.qbk | 12 ++-- doc/5_02_message.qbk | 43 +++++++----- doc/5_03_streams.qbk | 24 +++---- doc/5_04_serializer_streams.qbk | 6 +- doc/5_05_parser_streams.qbk | 32 +++++---- doc/5_06_serializer_buffers.qbk | 50 +++++++++----- doc/5_07_parser_buffers.qbk | 26 +++++-- doc/5_08_custom_parsers.qbk | 10 ++- doc/5_09_custom_body.qbk | 101 +++++++++++++++++++--------- doc/6_0_http_examples.qbk | 44 ------------ doc/6_1_file_body.qbk | 52 -------------- doc/8_concepts.qbk | 3 +- doc/Jamfile | 15 ----- doc/concept/Field.qbk | 41 ----------- doc/quickref.xml | 1 - examples/doc_http_samples.hpp | 16 +++-- include/beast/core/async_result.hpp | 2 +- test/http/doc_snippets.cpp | 8 +-- 25 files changed, 282 insertions(+), 342 deletions(-) delete mode 100644 doc/6_1_file_body.qbk delete mode 100644 doc/concept/Field.qbk diff --git a/doc/0_main.qbk b/doc/0_main.qbk index 3b4b3356..61b23914 100644 --- a/doc/0_main.qbk +++ b/doc/0_main.qbk @@ -22,6 +22,7 @@ [template mdash[] '''— '''] [template indexterm1[term1] ''''''[term1]''''''] [template indexterm2[term1 term2] ''''''[term1]''''''[term2]''''''] +[template repo_file[path] ''''''[path]''''''] [def __N3747__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3747.pdf [*N3747]]] [def __N4588__ [@http://cplusplus.github.io/networking-ts/draft.pdf [*N4588]]] @@ -33,7 +34,9 @@ [def __asio_handler_invoke__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]] [def __asio_handler_allocate__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]] [def __io_service__ [@http://www.boost.org/doc/html/boost_asio/reference/io_service.html `io_service`]] -[def __streambuf__ [@http://www.boost.org/doc/html/boost_asio/reference/streambuf.html [*boost::asio::streambuf]]] +[def __socket__ [@http://www.boost.org/doc/html/boost_asio/reference/ip__tcp/socket.html `boost::asio::ip::tcp::socket`]] +[def __ssl_stream__ [@http://www.boost.org/doc/html/boost_asio/reference/ssl_stream.html `boost::asio::ssl::stream`]] +[def __streambuf__ [@http://www.boost.org/doc/html/boost_asio/reference/streambuf.html `boost::asio::streambuf`]] [def __use_future__ [@http://www.boost.org/doc/html/boost_asio/reference/use_future_t.html `boost::asio::use_future`]] [def __void_or_deduced__ [@http://www.boost.org/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]] [def __yield_context__ [@http://www.boost.org/doc/html/boost_asio/reference/yield_context.html `boost::asio::yield_context`]] diff --git a/doc/1_overview.qbk b/doc/1_overview.qbk index c193cde9..ccae7a2b 100644 --- a/doc/1_overview.qbk +++ b/doc/1_overview.qbk @@ -12,15 +12,14 @@ [*low-level HTTP/1, WebSocket, and network protocol] programming using the consistent asynchronous model of __Asio__. Beast is not an HTTP client or HTTP server, but it can be used to build - those things. It is intended to be a foundation for writing other - interoperable libraries by providing HTTP vocabulary types and - algorithms. The provided examples show how clients and servers - might be built. + those things. It is a foundation for writing interoperable + libraries by providing HTTP vocabulary types and algorithms. The + examples show how client and server applications might be built. ] This library is designed for: -* [*Symmetry:] Interfaces are role-agnostic; build clients, servers, or both. +* [*Symmetry:] Algorithms are role-agnostic; build clients, servers, or both. * [*Ease of Use:] __Asio__ users will immediately understand Beast. @@ -29,8 +28,7 @@ This library is designed for: * [*Performance:] Build applications handling thousands of connections or more. -* [*Basis for Further Abstraction.] Components are open-ended and - suited for building higher level libraries. +* [*Basis for Further Abstraction.] Components are well-suited for building upon. [heading Audience] @@ -44,12 +42,11 @@ Asio callbacks or coroutines. An absence of high quality C++ network protocol libraries has led to a patchwork of open-source solutions lacking suitable conciseness -and expressive power for standardization. Part of this problem is -caused by the lack of a standardized C++ networking interface. This -will change soon with the Networking Technical Specification -(__N4588__): a uniform interface for networking on track to become -standardized. This technical specification is modeled closely after -Boost.Asio. +and expressive power for standardization. Part of this problem is a +lack of common C++ networking interfaces. This is changing soon with +the Networking Technical Specification (__N4588__): a uniform interface +on track to become standardized. This technical specification is modeled +closely after Boost.Asio. The HTTP and WebSocket protocols drive most of the World Wide Web. Every web browser implements these protocols to load webpages and to enable client side programs (often written in JavaScript) to @@ -57,8 +54,8 @@ communicate interactively. C++ benefits greatly from having a standardized implementation of these protocols. [note - The Beast roadmap includes a port to the standardized C++ - networking interface based on __N4588__. + The Beast roadmap includes a port to the networking + interface based on __N4588__. ] [heading Requirements] diff --git a/doc/2_examples.qbk b/doc/2_examples.qbk index 2831ef0e..e7b043e6 100644 --- a/doc/2_examples.qbk +++ b/doc/2_examples.qbk @@ -7,9 +7,8 @@ [section:example Example Programs] -These usage examples are intended to quickly impress upon readers the -flavor of the library. They are complete programs which may be built -and run. Source code and build scripts for these programs may be found +These complete programs are intended to quickly impress upon readers the +flavor of the library. Source code and build scripts for them are located in the examples directory. @@ -18,47 +17,47 @@ in the examples directory. Use HTTP to make a GET request to a website and print the response: +File: [repo_file examples/http_example.cpp] + [http_example_get] - - [heading WebSocket] Establish a WebSocket connection, send a message and receive the reply: +File: [repo_file examples/websocket_example.cpp] + [websocket_example_client_echo] - - [heading WebSocket Echo Server] This example demonstrates both synchronous and asynchronous WebSocket server implementations. -* [@examples/websocket_async_echo_server.hpp] -* [@examples/websocket_sync_echo_server.hpp] -* [@examples/websocket_echo.cpp] +* [repo_file examples/websocket_async_echo_server.hpp] +* [repo_file examples/websocket_sync_echo_server.hpp] +* [repo_file examples/websocket_echo.cpp] [heading Secure WebSocket] Establish a WebSocket connection over an encrypted TLS connection, send a message and receive the reply. Requires OpenSSL to build. -* [@examples/websocket_ssl_example.cpp] +* [repo_file examples/ssl/websocket_ssl_example.cpp] [heading HTTPS GET] This example demonstrates sending and receiving HTTP messages over a TLS connection. Requires OpenSSL to build. -* [@examples/http_ssl_example.cpp] +* [repo_file examples/ssl/http_ssl_example.cpp] [heading HTTP Crawl] This example retrieves the page at each of the most popular domains as measured by Alexa. -* [@examples/http_crawl.cpp] +* [repo_file examples/http_crawl.cpp] [heading HTTP Server] @@ -66,10 +65,10 @@ This example demonstrates both synchronous and asynchronous server implementations. It also provides an example of implementing a [*Body] type, in `file_body`. -* [@examples/file_body.hpp] -* [@examples/http_async_server.hpp] -* [@examples/http_sync_server.hpp] -* [@examples/http_server.cpp] +* [repo_file examples/file_body.hpp] +* [repo_file examples/http_async_server.hpp] +* [repo_file examples/http_sync_server.hpp] +* [repo_file examples/http_server.cpp] [heading Composed Operations] @@ -78,13 +77,16 @@ composable asynchronous initiation function with associated composed operation implementation. This is a complete, runnable version of the example described in the Core Foundations document section. -* [@examples/echo_op.cpp] +* [repo_file examples/echo_op.cpp] -[heading Listings] +[heading Documentation Samples] -These are stand-alone listings of the HTTP and WebSocket examples. +Here are all of the example functions and classes presented +throughout the documentation, they can be included and used +in your program without modification -* [@examples/http_example.cpp] -* [@examples/websocket_example.cpp] +* [repo_file examples/doc_core_samples.hpp] + +* [repo_file examples/doc_http_samples.hpp] [endsect] diff --git a/doc/3_0_core.qbk b/doc/3_0_core.qbk index ac2528b0..7e74b6d9 100644 --- a/doc/3_0_core.qbk +++ b/doc/3_0_core.qbk @@ -7,11 +7,12 @@ [section:core Using Networking] -A goal of the library is expose implementation primitives in order that -users may build their own library-like components. These primitives include -traits, buffers, buffer algorithms, and helpers for implementing asynchronous -operations compatible with __Asio__ and described in __N3747__. This section -lists these facilities by group, with descriptions. +This library makes network primitives used by the implementation publicly +available so users can take advantage of them in their own libraries. +These primitives include traits, buffers, buffer algorithms, and helpers +for implementing asynchronous operations compatible with __Asio__ and +described in __N3747__. This section lists these facilities by group, +with descriptions. [important This documentation assumes familiarity with __Asio__. Sample diff --git a/doc/3_1_asio.qbk b/doc/3_1_asio.qbk index d6de9ea3..fb70c99a 100644 --- a/doc/3_1_asio.qbk +++ b/doc/3_1_asio.qbk @@ -15,11 +15,10 @@ left to the interfaces already existing on the underlying streams. ] -Library stream algorithms require an already-connected socket, SSL stream, -or other object which meets the required stream concepts and already has -communication established with an endpoint. This example is provided as a -reminder of how to work -with sockets: +Library stream algorithms require a __socket__, __ssl_stream__, or other +__Stream__ object that has already established communication with an +endpoint. This example is provided as a reminder of how to work with +sockets: [snippet_core_2] diff --git a/doc/3_2_streams.qbk b/doc/3_2_streams.qbk index d2cb03b5..ed52112d 100644 --- a/doc/3_2_streams.qbk +++ b/doc/3_2_streams.qbk @@ -7,17 +7,13 @@ [section:streams Using Streams] -A __Stream__ is a communication channel where data expressed as octet -buffers is transferred sequentially. Streams are either synchronous +A __Stream__ is a communication channel where data is transferred as +an ordered sequence of octet buffers. Streams are either synchronous or asynchronous, and may allow reading, writing, or both. Note that a particular type may model more than one concept. For example, the -Asio types -[@http://www.boost.org/doc/html/boost_asio/reference/ip__tcp/socket.html `boost::asio::ip::tcp::socket`] -and -[@http://www.boost.org/doc/html/boost_asio/reference/ssl__stream.html `boost::asio::ssl::stream`] -support everything. All stream algorithms in Beast are declared as -template functions with specific concept requirements chosen from -this list: +Asio types __socket__ and __ssl_stream__ and support everything. +All stream algorithms in Beast are declared as template functions +with specific concept requirements chosen from this list: [table Stream Concepts [[Concept][Description]] diff --git a/doc/3_3_buffers.qbk b/doc/3_3_buffers.qbk index 288ad04e..0548ef2e 100644 --- a/doc/3_3_buffers.qbk +++ b/doc/3_3_buffers.qbk @@ -11,13 +11,18 @@ __Asio__ provides the __ConstBufferSequence__ and __MutableBufferSequence__ concepts, whose models provide ranges of buffers, as well as the __streambuf__ class which encapsulates memory storage that may be automatically resized as required, where the memory is divided into an input sequence followed by an -output sequence. The Networking TS (__N4588__) generalizes the `streambuf` +output sequence. The Networking TS (__N4588__) generalizes this `streambuf` interface into the __DynamicBuffer__ concept. Beast algorithms which require -resizable buffers accept as parameters dynamic buffer objects. These -metafunctions check types against these buffer concepts: +resizable buffers accept dynamic buffer objects as templated parameters. +These metafunctions check if types match the buffer concepts: [table Buffer Type Checks [[Name][Description]] +[[ + [link beast.ref.is_dynamic_buffer `is_dynamic_buffer`] +][ + Determine if a type meets the requirements of __DynamicBuffer__. +]] [[ [link beast.ref.is_const_buffer_sequence `is_const_buffer_sequence`] ][ @@ -28,11 +33,6 @@ metafunctions check types against these buffer concepts: ][ Determine if a type meets the requirements of __MutableBufferSequence__. ]] -[[ - [link beast.ref.is_dynamic_buffer `is_dynamic_buffer`] -][ - Determine if a type meets the requirements of __DynamicBuffer__. -]] ] To suit various needs, several implementation of dynamic buffer are available: @@ -88,11 +88,11 @@ To suit various needs, several implementation of dynamic buffer are available: Network applications frequently need to manipulate buffer sequences. To facilitate working with buffers the library treats these sequences as a special type of range. Algorithms and wrappers are provided which -transform these buffer sequences ranges efficiently using lazy evaluation. -No memory allocations are used in the transformations; instead, they -create lightweight iterators over the existing, unmodified memory -buffers. Control of buffers is retained by the caller; ownership is -not transferred. +transform these ranges efficiently using lazy evaluation. No memory +allocations are used in the transformations; instead, they create +lightweight iterators over the existing, unmodified memory buffers. +Control of buffers is retained by the caller; ownership is not +transferred. [table Buffer Algorithms [[Name][Description]] diff --git a/doc/3_4_async.qbk b/doc/3_4_async.qbk index e86440ac..ef282b5e 100644 --- a/doc/3_4_async.qbk +++ b/doc/3_4_async.qbk @@ -32,11 +32,13 @@ in this library. Non-trivial applications will want to provide their own asynchronous initiation functions which perform a series of other, intermediate asynchronous operations before invoking the final completion handler. The set of intermediate actions produced by calling an initiation -function is known as a ['composed operation]. To ensure full interoperability -and well-defined behavior, __Asio__ imposes requirements on the implementation -of composed operations. A number of useful classes and macros to facilitate -the development of composed operations and the associated asynchronous -initiation functions used to launch them are available: +function is known as a +[@http://blog.think-async.com/2009/08/composed-operations-coroutines-and-code.html ['composed operation]]. +To ensure full interoperability and well-defined behavior, __Asio__ imposes +requirements on the implementation of composed operations. A number of useful +classes and macros to facilitate the development of composed operations and +the associated asynchronous initiation functions used to launch them are +available: [table Asynchronous Helpers [[Name][Description]] diff --git a/doc/5_02_message.qbk b/doc/5_02_message.qbk index bf9f63d5..a26a2f10 100644 --- a/doc/5_02_message.qbk +++ b/doc/5_02_message.qbk @@ -21,7 +21,7 @@ class message; ``` The container offers value semantics including move and copy if supported -by `Body` and `Fields`. User defined template function parameters can +by __Body__ and __Fields__. User defined template function parameters can accept any message, or can use partial specialization to accept just requests or responses. The default __fields__ is a provided associative container using the standard allocator and supporting modification and @@ -47,17 +47,19 @@ a few members unique to the type. This is implemented by declaring the header classes as partial specializations of `isRequest`. Furthermore, __message__ is derived from __header__; a message may be passed as an argument to a function taking a suitably typed header as a parameter. -This diagram shows the inheritance relationship between header and message, -along with the fields from the different partial specializations for each -possible value of `isRequest`: +Furthermore, `header` is publicly derived from `Fields`; a message +inherits all of the fields member functions. Since `fields` is a +container, iterating a message iterates its header fields. This +diagram shows the inheritance relationship between header and message, +along with the fields from the different partial specializations for +each possible value of `isRequest`: [$images/message.png [width 730px] [height 410px]] The template type aliases [link beast.ref.http__request `request`] and [link beast.ref.http__response `response`] -are provided for notational convenience. They also come with the default -__fields__, a common choice. +are provided for brevity. They specify the common default of `fields`. ``` /// A typical HTTP request @@ -72,21 +74,24 @@ using response = message; [heading:body Body Types] Beast defines the __Body__ concept, which determines both the type of -the `message::body` member (as seen in the diagram above) and may also -include algorithms for transferring buffers in and out. These algorithms -are used during parsing and serialization. These body types are available -within the library, and users may define their own body types which meet -the __Body__ requirements: +the [link beast.ref.http__message.body `message::body`] member +(as seen in the diagram above) and may also include algorithms for +transferring buffers in and out. These algorithms are used during +parsing and serialization. These body types are available within the +library, and users may define their own body types which meet the +__Body__ requirements: [table [[Name][Description]] [[ [link beast.ref.http__buffer_body `buffer_body`] ][ - A body whose `value_type` holds a raw pointer and size to a - caller-provided buffer. This allows for serialization of body data - coming from external sources, and incremental parsing of message - body content using a fixed size buffer. + A body whose + [link beast.ref.http__buffer_body__value_type `value_type`] + holds a raw pointer and size to a caller-provided buffer. + This allows for serialization of body data coming from + external sources, and incremental parsing of message body + content using a fixed size buffer. ]] [[ [link beast.ref.http__dynamic_body `dynamic_body`] @@ -141,7 +146,7 @@ message has a body. The function [link beast.ref.http__message.prepare prepare] automatically sets the Content-Length or Transfer-Encoding field depending on the content and type of the `body` member. The use -of prepare is optional; these fields may also be set. +of prepare is optional; these fields may also be set explicitly. [table Create Response [[Statements] [Serialized Result]] @@ -158,4 +163,10 @@ of prepare is optional; these fields may also be set. ]] ] +The implementation will automatically fill in the obsolete +[@https://tools.ietf.org/html/rfc7230#section-3.1.2 reason-phrase] +from the status code when serializing a message. Or it may +be set directly using +[link beast.ref.http__header.reason.overload2 `header::reason`]. + [endsect] diff --git a/doc/5_03_streams.qbk b/doc/5_03_streams.qbk index e2f5b142..336d2c40 100644 --- a/doc/5_03_streams.qbk +++ b/doc/5_03_streams.qbk @@ -7,11 +7,11 @@ [section:streams Message Stream Operations] -Beast provides synchronous and asynchronous algorithms to serialize and -parse HTTP/1 wire format messages on streams. These functions form a -basic interface for operating on entire messages: +Beast provides synchronous and asynchronous algorithms to parse and +serialize HTTP/1 wire format messages on streams. These functions form +the message-oriented stream interface: -[table Basic Interface +[table Message Stream Operations [[Name][Description]] [[ [link beast.ref.http__read.overload3 [*read]] @@ -54,16 +54,16 @@ message variable, then read a complete HTTP request synchronously: [http_snippet_4] -In this example we used the __flat_buffer__. The parser in Beast is -optimized for structured HTTP data located in a single contiguous memory -buffer ("flat buffer"). Any dynamic buffer will work with reads. However, -when not using a flat buffer the implementation may perform an additional -memory allocation to restructure the input into a single buffer. +This example uses __flat_buffer__. Beast's __basic_parser__ is +optimized for structured HTTP data located in a single contiguous +(['flat]) memory buffer. When not using a flat buffer the implementation +may perform an additional memory allocations to restructure the input +into a single buffer for parsing. [tip - User-defined implementations of __DynamicBuffer__ may avoid additional - parser memory allocation, if those implementations guarantee that - returned buffer sequences will always have length one. + Other Implementations of __DynamicBuffer__ may avoid parser + memory allocation by always returning buffer sequences of + length one. ] Messages may also be read asynchronously. When performing asynchronous diff --git a/doc/5_04_serializer_streams.qbk b/doc/5_04_serializer_streams.qbk index 625adaed..d3dde40a 100644 --- a/doc/5_04_serializer_streams.qbk +++ b/doc/5_04_serializer_streams.qbk @@ -7,8 +7,8 @@ [section:serializer_streams Serializer Stream Operations] -Message oriented stream operations provide for limited control. -Sophisticated algorithms may need to do more, such as: +Non-trivial algorithms need to do more than send entire messages +at once, such as: * Send the header first, and the body later. @@ -108,7 +108,7 @@ is the responsibility of the decorator to manage returned string buffers. The implementation guarantees it will not reference previous strings after subsequent calls. -Here, we declare a decorator which sets an extension variable `x` equal +This defines a decorator which sets an extension variable `x` equal to the size of the chunk in bytes, and returns a single trailer field: [http_snippet_17] diff --git a/doc/5_05_parser_streams.qbk b/doc/5_05_parser_streams.qbk index 2e97e335..cb87fd7b 100644 --- a/doc/5_05_parser_streams.qbk +++ b/doc/5_05_parser_streams.qbk @@ -7,10 +7,11 @@ [section:parser_streams Parser Stream Operations] -Message oriented stream operations provide for limited control. -Sophisticated algorithms may need to do more, such as: +Non-trivial algorithms need to do more than receive entire messages +at once, such as: -* Receive the header first, then the body later. + +* Receive the header first and body later. * Receive a large body using a fixed-size buffer. @@ -18,10 +19,10 @@ Sophisticated algorithms may need to do more, such as: * Defer the commitment to a __Body__ type until after reading the header. -All of these operations require callers to manage the lifetime of state -information associated with the operation, by constructing a class derived -from __basic_parser__. Beast comes with two instances of parsers, and user -defined types deriving from the basic parser are possible: +These types of operations require callers to manage the lifetime of +associated state, by constructing a class derived from __basic_parser__. +Beast comes with the derived instance __parser__ which creates complete +__message__ objects; user-defined parsers are also possible: [table Parser Implementations [[Name][Description]] @@ -33,7 +34,7 @@ defined types deriving from the basic parser are possible: template< bool isRequest, // `true` to parse an HTTP request class Body, // The Body type for the resulting message - class Fields> // The type of container representing the fields + class Fields = fields> // The type of container representing the fields class parser : public basic_parser<...>; ``` @@ -107,12 +108,15 @@ advised to use an instance of __flat_buffer__, __static_buffer__, or __static_buffer_n__ for this purpose, although a user defined instance of __DynamicBuffer__ which produces input sequences of length one is also suitable. -The provided parsers use a "captive object" model, acting as container for -the __message__ produced as a result of parsing. The caller accesses the -contained object, and depending on the types used to instantiate the parser, -it may be possible to acquire ownership of the header or message captive -object and destroy the parser. In this example we read an HTTP response -with a string body using a parser, then print the response: +The parser contains a message constructed internally. Arguments passed +to the parser's constructor are forwarded into the message container. +The caller can access the message inside the parser by calling +[link beast.ref.http__parser.get `parser::get`]. +If the `Fields` and `Body` types are [*MoveConstructible], the caller +can take ownership of the message by calling +[link beast.ref.http__parser.release `parser::release`]. In this example +we read an HTTP response with a string body using a parser, then print +the response: [http_snippet_13] diff --git a/doc/5_06_serializer_buffers.qbk b/doc/5_06_serializer_buffers.qbk index 162a63d6..78c2dc55 100644 --- a/doc/5_06_serializer_buffers.qbk +++ b/doc/5_06_serializer_buffers.qbk @@ -7,26 +7,24 @@ [section:serializer_buffers Buffer-Oriented Serializing] -In extreme cases, users may wish to create an instance of __serializer__ -and invoke its methods directly instead of using the provided stream -algorithms. This could be useful for implementing algorithms on streams -whose interface does not conform to __Stream__. For example, a +An instance of __serializer__ can be invoked directly, without using +the provided stream operations. This could be useful for implementing +algorithms on streams whose interface does not conform to __Stream__. +For example, a [@https://github.com/libuv/libuv *libuv* socket]. -The serializer interface is interactive; the caller invokes it repeatedly to -produce buffers until all of the buffers have been generated. Then the +The serializer interface is interactive; the caller invokes it repeatedly +to produce buffers until all of the buffers have been generated. Then the serializer is destroyed. -After the serializer is created, the buffers are produced by first calling -[link beast.ref.http__serializer.get `serializer::get`] -to obtain a buffer sequence, and then calling +To obtain the serialized next buffer sequence, call +[link beast.ref.http__serializer.get `serializer::get`]. +Then, call [link beast.ref.http__serializer.consume `serializer::consume`] -to indicate how many bytes in the buffer sequence were consumed. -This advanced the internal state of the serializer and prepares the -next set of buffers for delivery. -[link beast.ref.http__serializer.get `serializer::get`] -takes an error code parameter and invokes a visitor argument with the -error code and buffer of unspecified type. In C++14 this is easily -expressed with a generic lambda. The function +to indicate the number of bytes consumed. This updates the next +set of buffers to be returned, if any. +`serializer::get` takes an error code parameter and invokes a visitor +argument with the error code and buffer of unspecified type. In C++14 +this is easily expressed with a generic lambda. The function [link beast.ref.http__serializer.is_done `serializer::is_done`] will return `true` when all the buffers have been produced. This C++14 example prints the buffers to standard output: @@ -50,9 +48,27 @@ with a boolean indicating that when buffers are produced, the last buffer containing serialized header octets will not contain any octets corresponding to the body. The function [link beast.ref.http__serializer.is_header_done `serializer::is_header_done`] -informs the caller whether the header has completed serialization. In this +informs the caller whether the header been serialized fully. In this C++14 example we print the header first, followed by the body: [http_snippet_16] +[heading Example: Write To std::ostream] + +The standard library provides the type `std::ostream` for performing high +level write operations on character streams. The variable `std::cout` is +based on this output stream. This example uses the buffer oriented interface +of __serializer__ to write an HTTP message to a `std::ostream`: + +[http_sample_write_ostream] + +[tip + Serializing to a `std::ostream` could be implemented using an alternate + strategy: adapt the `std::ostream` interface to a __SyncWriteStream__, + enable use with the library's existing stream algorithms. This is + left as an exercise for the reader. +] + + + [endsect] diff --git a/doc/5_07_parser_buffers.qbk b/doc/5_07_parser_buffers.qbk index b834c72e..8d19e5fb 100644 --- a/doc/5_07_parser_buffers.qbk +++ b/doc/5_07_parser_buffers.qbk @@ -7,11 +7,10 @@ [section:parser_buffers Buffer-Oriented Parsing] -In some cases, users may wish to create an instance of __parser__, or a -user-defined type derived from __basic_parser__ and invoke its methods -directly instead of using the provided stream algorithms. This could be -useful for implementing algorithms on objects whose interface does not -conform to any __Stream__. For example, a +A subclass of __basic_parser__ can be invoked directly, without using +the provided stream operations. This could be useful for implementing +algorithms on objects whose interface does not conform to any __Stream__. +For example, a [@http://zeromq.org/ *ZeroMQ* socket]. The basic parser interface is interactive; the caller invokes the function [link beast.ref.http__basic_parser.put `basic_parser::put`] @@ -60,4 +59,21 @@ The parser provides two options which may be set before parsing begins: ]] ] +[heading Example: Read From std::istream] + +The standard library provides the type `std::istream` for performing high +level read operations on character streams. The variable `std::cin` is based +on this input stream. This example uses the buffer oriented interface of +__basic_parser__ to build a stream operation which parses an HTTP message +from a `std::istream`: + +[http_sample_read_istream] + +[tip + Parsing from a `std::istream` could be implemented using an alternate + strategy: adapt the `std::istream` interface to a __SyncReadStream__, + enabling use with the library's existing stream algorithms. This is + left as an exercise for the reader. +] + [endsect] diff --git a/doc/5_08_custom_parsers.qbk b/doc/5_08_custom_parsers.qbk index 7fbc2047..e495f05c 100644 --- a/doc/5_08_custom_parsers.qbk +++ b/doc/5_08_custom_parsers.qbk @@ -14,8 +14,14 @@ elements according to the HTTP/1 protocol specification, while the derived class decides what to do with those elements. In particular, users who create exotic containers for [*Fields] may need to also create their own parser. Custom parsers will work with all of the stream read operations -that work on parsers, as those algorithms use only the basic parser interface. +that work on parsers, as those algorithms use only the basic parser +interface. Some use cases for implementing custom parsers are: +* Inspect incoming header fields and keep or discard them. + +* Use a container provided by an external interface. + +* Store header data in a user-defined __Fields__ type. The basic parser uses the Curiously Recurring Template Pattern ([@https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern CRTP]). @@ -24,7 +30,7 @@ The interface to the parser is event-driven. Member functions of the derived class (termed "callbacks" in this context) are invoked with parsed elements as they become available, requiring either the `friend` declaration as shown above or that the member functions are declared public (not recommended). -Buffers provided by the parser are non-owning references, it is the +Buffers provided by the parser are non-owning references; it is the responsibility of the derived class to copy any information it needs before returning from the callback. diff --git a/doc/5_09_custom_body.qbk b/doc/5_09_custom_body.qbk index 8b263aa6..bd5ef8d3 100644 --- a/doc/5_09_custom_body.qbk +++ b/doc/5_09_custom_body.qbk @@ -22,19 +22,23 @@ The meaning of the nested types is as follows [ Determines the type of the [link beast.ref.http__message.body `message::body`] - member. If this type defines default construction, move, copy, - or swap, then message objects declared with this __Body__ will - have those operations defined. + member. ] ][ [`reader`] [ - An optional nested type meeting the requirements of __BodyReader__. + An optional nested type meeting the requirements of __BodyReader__, + which provides the algorithm for converting the body representation + to a forward range of buffer sequences. + If present this body type may be used with a __serializer__. ] ][ [`writer`] [ - An optional nested type meeting the requirements of __BodyWriter__. + An optional nested type meeting the requirements of __BodyWriter__, + which provides the algorithm for storing a forward range of buffer + sequences in the body representation. + If present, this body type may be used with a __parser__. ] ] ] @@ -44,41 +48,72 @@ The meaning of the nested types is as follows The `value_type` nested type allows the body to define the declaration of the body type as it appears in the message. This can be any type. For example, a body's value type may specify `std::vector` or even -`std::list`. By also providing suitable definitions of -corresponding `reader` and `writer` types, messages with that body -become serializable and parsable respectively. - -A custom body may even set the value type to something that is not a container -for body octets, such as a +`std::list`. A custom body may even set the value type to +something that is not a container for body octets, such as a [@http://www.boost.org/libs/filesystem/doc/reference.html#class-path `boost::filesystem::path`]. -In this case the reader may obtain buffers corresponding to a file on disk, -while the writer may store incoming buffers to a file on disk. +Or, a more structured container may be chosen. This declares a body's +value type as a JSON tree structure produced from a +[@http://www.boost.org/doc/html/property_tree/parsers.html#property_tree.parsers.json_parser `json_parser`]: +``` +#include +#include -Another option is to use a structured container for the value type. For -example, a JSON tree structure such as the property tree produced by Boost's -[@http://www.boost.org/doc/html/property_tree/parsers.html#property_tree.parsers.json_parser `json_parser`] -As long as a suitable reader or writer is available to provide the algorithm -for transferring buffers in and out of the value type, even if abstract, +struct Body +{ + using value_type = boost::property_tree::ptree; + + class reader; + + class writer; +}; +``` + +As long as a suitable reader or writer is available to provide the +algorithm for transferring buffers in and out of the value type, those bodies may be serialized or parsed. -[note - The examples included with this library provide a [*Body] - implementation that serializes message bodies coming from a file. - This is part of the HTTP server example. -] +[heading Example: File Body Type] -[heading Reader] +Use of the flexible __Body__ concept customization point enables authors to +preserve the self-contained nature of the __message__ object while allowing +domain specific behaviors. Common operations for HTTP servers include sending +responses which deliver file contents, and allowing for file uploads. In this +example we build the `file_body` type which supports both reading and writing +to a file on the file system. -The reader provides the algorithm for transferring buffers containing body -octets obtained during parsing into the body container. The requirements -for this type are described in the __BodyReader__ concept. When a body type -defines a reader it may then be parsed using a __parser__. +First we declare the type itself, along with the required members: -[heading Writer] +[http_sample_file_body_1] -The writer provides the algorithm for converting the body container into a -series of buffers. The requirements for this type are described in the -__BodyWriter__ concept. When a body type defines a writer it may then be -serialized using a __serializer__. +The `size` function is a simple call to retrieve the file size: + +[http_sample_file_body_2] + +Our implementation of __BodyReader__ will contain a small buffer +from which the file contents are read. The buffer is provided to +the implementation on each call until everything has been read in. + +[http_sample_file_body_3] + +And here are the definitions for the functions we have declared: + +[http_sample_file_body_4] + +Files can be read now, and the next step is to allow writing to files +by implementing the __BodyWriter__. The style is similar to the reader, +except that buffers are incoming instead of outgoing. Here's the +declaration: + +[http_sample_file_body_5] + +Finally, here is the implementation of the writer member functions: + +[http_sample_file_body_6] + +We have created a full featured body type capable of reading and +writing files on the filesystem, integrating seamlessly with the +HTTP algorithms and message container. Source code for this body +type, and HTTP servers that use it, are available in the examples +directory. [endsect] diff --git a/doc/6_0_http_examples.qbk b/doc/6_0_http_examples.qbk index 2bd133f3..81bd7a7a 100644 --- a/doc/6_0_http_examples.qbk +++ b/doc/6_0_http_examples.qbk @@ -70,10 +70,6 @@ synchronous version of this server action looks like this: -[include 6_1_file_body.qbk] - - - [section HEAD request (Client)] The @@ -121,26 +117,6 @@ and a __parser__ to achieve its goal: -[section Read From std::istream] - -The standard library provides the type `std::istream` for performing high -level read operations on character streams. The variable `std::cin` is based -on this input stream. In this example, we build a stream operation which -parses an HTTP message from a `std::istream`: - -[http_sample_read_istream] - -[tip - Parsing from a `std::istream` could be implemented using an alternate - strategy: adapt the `std::istream` interface to a __SyncReadStream__. - This lets all the library's existing algorithms work on `std::istream`. - We leave this as an exercise for the reader. -] - -[endsect] - - - [section Send Child Process Output] Sometimes it is necessary to send a message whose body is not conveniently @@ -164,24 +140,4 @@ HTTP response. The output of the process is sent as it becomes available: -[section Write To std::ostream] - -The standard library provides the type `std::ostream` for performing high -level write operations on character streams. The variable `std::cout` is -based on this output stream. In this example, we build a stream operation -which serializes an HTTP message to a `std::ostream`: - -[http_sample_write_ostream] - -[tip - Serializing to a `std::ostream` could be implemented using an alternate - strategy: adapt the `std::ostream` interface to a __SyncWriteStream__. - This lets all the library's existing algorithms work on `std::ostream`. - We leave this as an exercise for the reader. -] - -[endsect] - - - [endsect] diff --git a/doc/6_1_file_body.qbk b/doc/6_1_file_body.qbk deleted file mode 100644 index 39f97ca4..00000000 --- a/doc/6_1_file_body.qbk +++ /dev/null @@ -1,52 +0,0 @@ -[/ - Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -] - -[section File Body Type] - -Use of the flexible __Body__ concept customization point enables authors to -preserve the self-contained nature of the __message__ object while allowing -domain specific behaviors. Common operations for HTTP servers include sending -responses which deliver file contents, and allowing for file uploads. In this -example we build the `file_body` type which supports both reading and writing -to a file on the file system. - -First we declare the type itself, along with the required members: - -[http_sample_file_body_1] - -The `size` function is a simple call to retrieve the file size: - -[http_sample_file_body_2] - -Our implementation of __BodyReader__ will contain a small buffer -from which the file contents are read. The buffer is provided to -the implementation on each call until everything has been read in. - -[http_sample_file_body_3] - -And here are the definitions for the functions we have declared: - -[http_sample_file_body_4] - -Files can be read now, and the next step is to allow writing to files -by implementing the __BodyWriter__. The style is similar to the reader, -except that buffers are incoming instead of outgoing. Here's the -declaration: - -[http_sample_file_body_5] - -Finally, here is the implementation of the writer member functions: - -[http_sample_file_body_6] - -We have created a full featured body type capable of reading and -writing files on the filesystem, integrating seamlessly with the -HTTP algorithms and message container. Source code for this body -type, and HTTP servers that use it, are available in the examples -directory. - -[endsect] diff --git a/doc/8_concepts.qbk b/doc/8_concepts.qbk index 6f49bb42..57ec4d35 100644 --- a/doc/8_concepts.qbk +++ b/doc/8_concepts.qbk @@ -7,12 +7,13 @@ [section:concept Concepts] +This section describes all of the concepts defined by the library. + [include concept/Body.qbk] [include concept/BodyReader.qbk] [include concept/BodyWriter.qbk] [include concept/BufferSequence.qbk] [include concept/DynamicBuffer.qbk] -[include concept/Field.qbk] [include concept/Fields.qbk] [include concept/FieldsReader.qbk] [include concept/Streams.qbk] diff --git a/doc/Jamfile b/doc/Jamfile index 2a90bcac..4b21611f 100644 --- a/doc/Jamfile +++ b/doc/Jamfile @@ -49,20 +49,6 @@ install callouts explicit callout ; -install examples - : - [ glob - ../examples/*.cpp - ../examples/*.hpp - ../examples/ssl/*.cpp - ../examples/ssl/*.hpp - ] - : - $(here)/html/examples - ; - -explicit examples ; - xml doc : 0_main.qbk @@ -90,7 +76,6 @@ boostbook boostdoc $(broot)/tools/boostbook/dtd : temp - examples images stylesheets ; diff --git a/doc/concept/Field.qbk b/doc/concept/Field.qbk deleted file mode 100644 index cf508d35..00000000 --- a/doc/concept/Field.qbk +++ /dev/null @@ -1,41 +0,0 @@ -[/ - Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -] - -[section:Field Field] - -A [*Field] represents a single HTTP header field/value pair. - -In this table: - -* `X` denotes a type meeting the requirements of [*Field]. -* `a` denotes a value of type `X`. - -[table Field requirements - -[[expression][type][semantics, pre/post-conditions]] -[ - [`a.name()`] - [[link beast.ref.string_view `string_view`]] - [ - This function returns a value implicitly convertible to - `boost::string_ref` containing the case-insensitive field - name, without leading or trailing white space. - ] -] -[ - [`a.value()`] - [[link beast.ref.string_view `string_view`]] - [ - This function returns a value implicitly convertible to - `boost::string_ref` containing the value for the field. The - value is considered canonical if there is no leading or - trailing whitespace. - ] -] -] - -[endsect] diff --git a/doc/quickref.xml b/doc/quickref.xml index 90314233..fc724f32 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -101,7 +101,6 @@ Body BodyReader BodyWriter - Field Fields FieldsReader diff --git a/examples/doc_http_samples.hpp b/examples/doc_http_samples.hpp index 41e2184c..b3aedfd1 100644 --- a/examples/doc_http_samples.hpp +++ b/examples/doc_http_samples.hpp @@ -686,7 +686,13 @@ read_istream( error_code& ec) { // Create the message parser - parser parser; + // + // Arguments passed to the parser's constructor are + // forwarded to the message constructor. Here, we use + // a move construction in case the caller has constructed + // their message in a non-default way. + // + parser p{std::move(msg)}; do { @@ -729,7 +735,7 @@ read_istream( else { // Inform the parser that we've reached the end of the istream. - parser.put_eof(ec); + p.put_eof(ec); if(ec) return; break; @@ -737,7 +743,7 @@ read_istream( } // Write the data to the parser - auto const bytes_used = parser.put(buffer.data(), ec); + auto const bytes_used = p.put(buffer.data(), ec); // This error means that the parser needs additional octets. if(ec == error::need_more) @@ -748,10 +754,10 @@ read_istream( // Consume the buffer octets that were actually parsed. buffer.consume(bytes_used); } - while(! parser.is_done()); + while(! p.is_done()); // Transfer ownership of the message container in the parser to the caller. - msg = parser.release(); + msg = p.release(); } //] diff --git a/include/beast/core/async_result.hpp b/include/beast/core/async_result.hpp index 8380e7f8..1cad245f 100644 --- a/include/beast/core/async_result.hpp +++ b/include/beast/core/async_result.hpp @@ -59,7 +59,7 @@ namespace beast { // This helper converts the handler into the real handler type async_completion init{handler}; - ... // Create and the composed operation + ... // Create and invoke the composed operation // This provides the return value and executor customization return init.result.get(); diff --git a/test/http/doc_snippets.cpp b/test/http/doc_snippets.cpp index 39561281..f3e6835c 100644 --- a/test/http/doc_snippets.cpp +++ b/test/http/doc_snippets.cpp @@ -179,11 +179,9 @@ send( //[http_snippet_13 -template< - class SyncReadStream> +template void -print_response( - SyncReadStream& stream) +print_response(SyncReadStream& stream) { static_assert(is_sync_read_stream::value, "SyncReadStream requirements not met"); @@ -238,7 +236,7 @@ struct lambda lambda(Serializer& sr_) : sr(sr_) {} template - void operator()(error_code& ec, ConstBufferSequence const& buffer) + void operator()(error_code& ec, ConstBufferSequence const& buffer) const { std::cout << buffers(buffer); sr.consume(boost::asio::buffer_size(buffer));