From 313620ce7e4968a1354d5e4e48c0f2e888b7690e Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 1 May 2016 12:33:35 -0400 Subject: [PATCH] Tidy up tests, build scripts, and documentation: * Concepts split up into individual files * Function definitions moved to .ipp files * Add more tests to fill gaps in coverage * Fix documentation Xsl --- TODO.txt | 10 +- doc/beast.dox | 7 +- doc/beast.qbk | 7 +- doc/core_types.qbk | 118 +++ doc/design.qbk | 6 +- doc/http.qbk | 77 +- doc/{types.qbk => http_types.qbk} | 81 +- doc/quickref.xml | 41 +- doc/reference.xsl | 352 +++++--- examples/file_body.hpp | 2 +- include/beast/async_completion.hpp | 32 +- include/beast/basic_streambuf.hpp | 129 +-- include/beast/bind_handler.hpp | 112 +-- include/beast/buffer_cat.hpp | 461 +---------- include/beast/buffer_concepts.hpp | 61 ++ include/beast/buffers_adapter.hpp | 37 +- include/beast/consuming_buffers.hpp | 18 +- include/beast/detail/bind_handler.hpp | 113 +++ include/beast/detail/buffer_cat.hpp | 473 +++++++++++ include/beast/detail/buffer_concepts.hpp | 140 ++++ include/beast/detail/stream_concepts.hpp | 140 ++++ include/beast/detail/write_streambuf.hpp | 1 + include/beast/doc_debug.hpp | 170 ++++ include/beast/handler_alloc.hpp | 22 +- include/beast/handler_concepts.hpp | 27 + include/beast/http.hpp | 6 +- include/beast/http/basic_headers.hpp | 16 +- include/beast/http/basic_parser_v1.hpp | 42 +- .../http/{body_writer.hpp => body_type.hpp} | 8 +- include/beast/http/empty_body.hpp | 4 +- include/beast/http/error.hpp | 1 + include/beast/http/impl/basic_headers.ipp | 2 - include/beast/http/impl/basic_parser_v1.ipp | 9 +- include/beast/http/impl/message_v1.ipp | 1 - include/beast/http/impl/read.ipp | 1 + include/beast/http/impl/write.ipp | 3 +- include/beast/http/message.hpp | 1 - include/beast/http/message_v1.hpp | 3 +- include/beast/http/read.hpp | 78 +- include/beast/http/streambuf_body.hpp | 10 +- include/beast/http/string_body.hpp | 8 +- include/beast/http/write.hpp | 83 +- include/beast/impl/basic_streambuf.ipp | 32 +- include/beast/impl/buffers_adapter.ipp | 78 +- include/beast/impl/consuming_buffers.ipp | 54 +- include/beast/impl/streambuf_readstream.ipp | 7 +- include/beast/static_streambuf.hpp | 26 +- include/beast/static_string.hpp | 12 +- include/beast/stream_concepts.hpp | 76 ++ include/beast/streambuf.hpp | 9 + include/beast/streambuf_readstream.hpp | 34 +- include/beast/to_string.hpp | 10 +- include/beast/type_check.hpp | 356 -------- include/beast/websocket/detail/debug.hpp | 7 +- include/beast/websocket/detail/error.hpp | 4 +- include/beast/websocket/error.hpp | 5 +- .../beast/websocket/impl/read_frame_op.ipp | 4 +- include/beast/websocket/impl/ssl.ipp | 4 +- include/beast/websocket/impl/stream.ipp | 17 +- include/beast/websocket/impl/teardown.ipp | 4 +- include/beast/websocket/option.hpp | 40 +- include/beast/websocket/rfc6455.hpp | 17 +- include/beast/websocket/ssl.hpp | 6 +- include/beast/websocket/stream.hpp | 771 ++++++++++++------ include/beast/websocket/teardown.hpp | 14 +- include/beast/write_streambuf.hpp | 12 +- test/CMakeLists.txt | 12 +- test/Jamfile | 12 +- test/basic_streambuf.cpp | 9 +- test/bind_handler.cpp | 2 - test/buffer_cat.cpp | 2 - test/buffer_concepts.cpp | 25 + test/buffers_adapter.cpp | 2 - test/consuming_buffers.cpp | 4 +- test/detail/base64.cpp | 2 +- test/detail/empty_base_optimization.cpp | 2 +- test/handler_alloc.cpp | 21 +- test/handler_concepts.cpp | 23 + test/{type_check.cpp => http.cpp} | 2 +- test/http/body_type.cpp | 9 + test/http/body_writer.cpp | 9 + test/http/nodejs_parser.hpp | 2 +- test/http/{parser.cpp => parser_v1.cpp} | 4 +- test/prepare_buffers.cpp | 4 +- test/sig_wait.hpp | 4 +- test/static_streambuf.cpp | 4 +- test/static_string.cpp | 4 +- test/stream_concepts.cpp | 30 + test/to_string.cpp | 1 + test/version.cpp | 9 + test/websocket.cpp | 9 + test/websocket/stream.cpp | 4 +- 92 files changed, 2915 insertions(+), 1808 deletions(-) create mode 100644 doc/core_types.qbk rename doc/{types.qbk => http_types.qbk} (86%) create mode 100644 include/beast/buffer_concepts.hpp create mode 100644 include/beast/detail/bind_handler.hpp create mode 100644 include/beast/detail/buffer_cat.hpp create mode 100644 include/beast/detail/buffer_concepts.hpp create mode 100644 include/beast/detail/stream_concepts.hpp create mode 100644 include/beast/doc_debug.hpp create mode 100644 include/beast/handler_concepts.hpp rename include/beast/http/{body_writer.hpp => body_type.hpp} (67%) create mode 100644 include/beast/stream_concepts.hpp delete mode 100644 include/beast/type_check.hpp create mode 100644 test/buffer_concepts.cpp create mode 100644 test/handler_concepts.cpp rename test/{type_check.cpp => http.cpp} (89%) create mode 100644 test/http/body_type.cpp create mode 100644 test/http/body_writer.cpp rename test/http/{parser.cpp => parser_v1.cpp} (94%) create mode 100644 test/stream_concepts.cpp create mode 100644 test/version.cpp create mode 100644 test/websocket.cpp diff --git a/TODO.txt b/TODO.txt index 4b63533c..17bf16ac 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,3 +1,5 @@ +* Add writer::prepare(msg&) interface to set Content-Type + General: * Use SFINAE on return values (search for "class =") @@ -13,18 +15,21 @@ Docs: * melpon sandbox? * Check DOXYGEN, GENERATIC_DOCS directives in source - See if we can include them now that xsl is fixed +* Implement cleanup-param to remove spaces around template arguments + e.g. in basic_streambuf move constructor members Core: * Replace Jamroot with Jamfile * Fix bidirectional buffers iterators operator->() -* Tidy up type_checks - - Derive from std::integral_constant * Complete allocator testing in basic_streambuf, basic_headers WebSocket: * optimized versions of key/masking, choose prepared_key size * invokable unit test * Finish up all of static_string including tests +* Don't rely on default constructible mutable buffers + type in read_frame_op (smb_type). To see the error, use + boost::asio::streambuf in websocket_async_echo_peer HTTP: * Define Parser concept in HTTP @@ -37,3 +42,4 @@ HTTP: * HTTP parser trailers with test * URL parser, strong URL checking in HTTP parser * Update for rfc7230 +* Consider rename to MessageBody concept diff --git a/doc/beast.dox b/doc/beast.dox index ef29bbdf..3861cf30 100644 --- a/doc/beast.dox +++ b/doc/beast.dox @@ -103,6 +103,11 @@ WARN_LOGFILE = # Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = \ + ../include/beast/ \ + ../include/beast/http \ + ../include/beast/websocket \ + ../include/beast/doc_debug.hpp \ + ../include/beast/async_completion.hpp \ ../include/beast/basic_streambuf.hpp \ ../include/beast/bind_handler.hpp \ @@ -121,7 +126,7 @@ INPUT = \ ../include/beast/websocket.hpp \ ../include/beast/write_streambuf.hpp \ ../include/beast/http/basic_headers.hpp \ - ../include/beast/http/basic_parser.hpp \ + ../include/beast/http/basic_parser_v1.hpp \ ../include/beast/http/body_writer.hpp \ ../include/beast/http/chunk_encode.hpp \ ../include/beast/http/empty_body.hpp \ diff --git a/doc/beast.qbk b/doc/beast.qbk index d64a4024..2038bf9f 100644 --- a/doc/beast.qbk +++ b/doc/beast.qbk @@ -186,7 +186,12 @@ documentation is based. [include http.qbk] [include websocket.qbk] -[include types.qbk] + +[section:types Type Requirements] +[include core_types.qbk] +[include http_types.qbk] +[endsect] + [include design.qbk] [section:quickref Quick Reference] [xinclude quickref.xml] diff --git a/doc/core_types.qbk b/doc/core_types.qbk new file mode 100644 index 00000000..1efe460b --- /dev/null +++ b/doc/core_types.qbk @@ -0,0 +1,118 @@ +[/ + Copyright (c) 2013-2016 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:BufferSequence BufferSequence] + +A `BufferSequence` is a type meeting either of the following requirements: + +* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*`ConstBufferSequence`]] +* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*`MutableBufferSequence`]] + +[endsect] + + + +[section:stream Streams] + +Stream types represent objects capable of performing synchronous or +asynchronous I/O. They are based on concepts from `boost::asio`. + +[heading:Stream Stream] + +A type modeling [*`Stream`] meets either or both of the following requirements: + +* [link beast.types.stream.AsyncStream [*`AsyncStream`]] +* [link beast.types.stream.SyncStream [*`SyncStream`]] + +[heading:AsyncStream AsyncStream] + +A type modeling [*`AsyncStream`] meets the following requirements: + +* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*`AsyncReadStream`]] +* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*`AsyncWriteStream`]] + +[heading:SyncStream SyncStream] + +A type modeling [*`SyncStream`] meets the following requirements: + +* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*`SyncReadStream`]] +* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*`SyncWriteStream`]] + +[endsect] + + + +[section:Streambuf Streambuf] + +In the table below: + +* `X` denotes a class +* `a` denotes a value of type `X` +* `n` denotes a value convertible to `std::size_t` +* `U`, `T` denote unspecified types. + +[table Streambuf requirements +[[operation] [type] [semantics, pre/post-conditions]] +[ + [`X::const_buffers_type`] + [`T`] + [`T` meets the requirements for `ConstBufferSequence`.] +] +[ + [`X::mutable_buffers_type`] + [`U`] + [`U` meets the requirements for `MutableBufferSequence`.] +] +[ + [`a.commit(n)`] + [`void`] + [Moves bytes from the output sequence to the input sequence.] +] +[ + [`a.consume(n)`] + [`void`] + [Removes bytes from the input sequence.] +] +[ + [`a.data()`] + [`T`] + [Returns a list of buffers that represents the input sequence.] +] +[ + [`a.prepare(n)`] + [`U`] + [Returns a list of buffers that represents the output sequence, with + the given size.] +] +[ + [`a.size()`] + [`std::size_t`] + [Returns the size of the input sequence.] +] +[ + [`a.max_size()`] + [`std::size_t`] + [Returns the maximum size of the `Streambuf`.] +] +[ + [`read_size_helper(a, n)`] + [`std::size_t`] + [ + Returns the suggested number of bytes to read into the output + sequence where `n` is an upper limit on this value. One possible + implementation is to return the number of bytes that may be prepared + without causing a dynamic allocation or `n`, whichever is smaller. + Calls to `read_size_helper` will be made without namespace + qualification, to allow the rules for argument dependent lookup to + take effect. + ] +] +] + +[endsect] diff --git a/doc/design.qbk b/doc/design.qbk index 316b83b6..5e90dac8 100644 --- a/doc/design.qbk +++ b/doc/design.qbk @@ -8,7 +8,7 @@ [section:design Design choices] The implementations are driven by business needs of cryptocurrency server -applications ([link https://ripple.com Ripple] written in C++. These +applications ([@https://ripple.com Ripple] written in C++. These needs were not met by existing solutions so new code was written. The new code tries to avoid design flaws encountered in the already-existing software libraries: @@ -194,8 +194,8 @@ start. Other design goals: The WebSocket implementation [*does] provides support for shutting down the TLS connection through the use of the ADL compile-time virtual functions - [link beast.ref.wsproto__teardown `teardown`] and - [link beast.ref.wsproto__async_teardown `async_teardown`]. These will + [link beast.ref.websocket__teardown `teardown`] and + [link beast.ref.websocket__async_teardown `async_teardown`]. These will properly close the connection as per rfc6455 and overloads are available for TLS streams. Callers may provide their own overloads of these functions for user-defined next layer types. diff --git a/doc/http.qbk b/doc/http.qbk index 85f91b66..cbce909b 100644 --- a/doc/http.qbk +++ b/doc/http.qbk @@ -9,7 +9,7 @@ Beast.HTTP offers programmers simple and performant models of HTTP messages and their associated operations including synchronous and asynchronous reading and -writing using Boost.Asio. +writing of messages in the HTTP/1 wire format using Boost.Asio. The HTTP protocol is described fully in [@https://tools.ietf.org/html/rfc2616 rfc2616] @@ -25,20 +25,43 @@ compliant with the Hypertext Transfer Protocol and the supplements that follow. Unfortunately reliable implementations or industry standards do not exist in C++. -Beast.HTTP is built on Boost.Asio and uses HTTP parser from NodeJS, which is -extensively field tested and exceptionally robust. A proposal to add networking -functionality to the C++ standard library, based on Boost.Asio, is under -consideration by the standards committee. Since the final approved networking -interface for the C++ standard library will likely closely resemble the current -interface of Boost.Asio, it is logical for Beast.HTTP to use Boost.Asio as its -network transport. +Beast.HTTP is built on Boost.Asio and uses its own robust header-only HTTP/1 +message parser modeled after the nodejs http-parser (written in C). A proposal +to add networking functionality to the C++ standard library, based on +Boost.Asio, is under consideration by the standards committee. Since the final +approved networking interface for the C++ standard library will likely closely +resemble the current interface of Boost.Asio, it is logical for Beast.HTTP to +use Boost.Asio as its network transport. -[heading Scope] +[endsect] -The scope of this library is meant to include only the functionality of -modeling the HTTP message, serializing and deserializing the message, and -sending and receiving messages on sockets or streams. It is designed to -be a building block for creating higher level abstractions. + + +[section:scope Scope] + +This library is designed to be a building block for creating higher level +libraries. It is not designed to be end-user facing. There is no convenient +class that implements the core of a web server, nor is there a convenient +class to quickly perform common operations such as fetching a file or +connecting and retrieving a document from a secure connection. These +use-cases are important. But this library does not try to do that. Instead, +it offers primitives that can be used to build those user-facing algorithms. + +A HTTP message (referred to hereafter as "message") contains request or +response specific attributes, a series of zero or more name/value pairs +(collectively termed "headers"), and a series of octets called the message +body which may be zero in length. The HTTP protocol defines the client and +server roles: clients send messages called requests and servers send back +messages called responses. `http::message` models both requests and responses. +Beast aims to offer this functionality: + +* [*Model]: Provide a universal HTTP message class model. + +* [*Build]: Construct a new message and manipulate its contents. + +* [*Parse]: Deserialize a message from a network or memory stream in HTTP/1 wire format. + +* [*Serialize]: Serialize a message into a network or memory stream in HTTP/1 wire format. [note The documentation which follows assumes familiarity with both Boost.Asio and the HTTP protocol specification described in @@ -59,35 +82,17 @@ both Boost.Asio and the HTTP protocol specification described in ``` ] -A HTTP message (referred to hereafter as "message") contains a request or -response line, a series of zero or more name/value pairs (collectively -termed "headers"), and a series of octets called the message body which may -be zero in length. The HTTP protocol defines the client and server roles: -clients send messages called requests and servers send back messages called -responses. `http::message` models both requests and responses. The library -provides interfaces to perform these operations on messages: -* [*Parse] a new message from a series of octets. -* [*Assemble] a new message from scratch or from an existing message. - -* [*Serialize] a message into a series of octets. - -* [*Read] a message from a stream. This can be thought of as a compound -operation; a network read, followed by a [*parse]. - -* [*Write] a message to a stream. This can be thought of as a compound -operation: a [*serialize] followed by a network write. - -In the paragraphs that follow we describe simple interfaces that will serve -the majority of users looking merely to interact with a HTTP server, or -handle simple HTTP requests from clients. Subsequent sections cover the -message model in more depth, for advanced applications. +In the paragraphs that follow we describe the available interfaces for +performing typical operations such as interacting with a HTTP server +or handling simple requests. Subsequent sections cover the message model +and its customization points in more depth, for advanced applications. [heading Declarations] To do anything, a message must be declared. The message class template -requires at mininum, a bool indicating whether the message is a request +requires at mininum, a value indicating whether the message is a request (versus a response), and a `Body` type. The choice of `Body` determines the kind of container used to represent the message body. Here we will declare a request that has a `std::string` for the body container: diff --git a/doc/types.qbk b/doc/http_types.qbk similarity index 86% rename from doc/types.qbk rename to doc/http_types.qbk index d55d7c51..bf5f6a34 100644 --- a/doc/types.qbk +++ b/doc/http_types.qbk @@ -5,8 +5,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:types Type Requirements] - [section:Body Body] @@ -57,10 +55,10 @@ In this table: [section:BufferSequence BufferSequence] -A `BufferSequence` meets [*one of] the following requirements: +A `BufferSequence` is a type meeting either of the following requirements: -* `ConstBufferSequence` -* `MutableBufferSequence` +* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*`ConstBufferSequence`]] +* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*`MutableBufferSequence`]] [endsect] @@ -223,7 +221,7 @@ In this table: * `m` denotes a value of type `message const&` where `std::is_same:value == true`. -* `rc` is an object of type [link beast.reference.http__resume_context resume_context]. +* `rc` is an object of type [link beast.ref.http__resume_context resume_context]. * `ec` is a value of type `error_code&`. @@ -373,74 +371,3 @@ public: [endsect] - - -[section:Stream Stream] - -A `Stream` meets the following requirements: - -* `SyncReadStream` -* `SyncWriteStream` -* `AsyncReadStream` -* `AsyncWriteStream` - -[endsect] - - - -[section:Streambuf Streambuf] - -In the table below, `X` denotes a class, `a` denotes a value -of type `X`, `n` denotes a value convertible to `std::size_t`, -and `U` and `T` denote unspecified types. - -[table Streambuf requirements -[[operation] [type] [semantics, pre/post-conditions]] -[ - [`X::const_buffers_type`] - [`T`] - [`T` meets the requirements for `ConstBufferSequence`.] -] -[ - [`X::mutable_buffers_type`] - [`U`] - [`U` meets the requirements for `MutableBufferSequence`.] -] -[ - [`a.commit(n)`] - [`void`] - [Moves bytes from the output sequence to the input sequence.] -] -[ - [`a.consume(n)`] - [`void`] - [Removes bytes from the input sequence.] -] -[ - [`a.data()`] - [`T`] - [Returns a list of buffers that represents the input sequence.] -] -[ - [`a.prepare(n)`] - [`U`] - [Returns a list of buffers that represents the output sequence, with - the given size.] -] -[ - [`a.size()`] - [`std::size_t`] - [Returns the size of the input sequence.] -] -[ - [`a.max_size()`] - [`std::size_t`] - [Returns the maximum size of the `Streambuf`.] -] -] - -[endsect] - - - -[endsect] diff --git a/doc/quickref.xml b/doc/quickref.xml index b7110be2..8e9337bd 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -30,7 +30,7 @@ Classes basic_headers - basic_parser + basic_parser_v1 basic_streambuf_body empty_body error_code @@ -42,7 +42,7 @@ Type Traits - is_Body + is_Parser @@ -50,9 +50,14 @@ async_read async_write + prepare read write + Constants + + connection + Concepts Body @@ -66,7 +71,6 @@ Classes close_reason - static_string stream Options @@ -119,6 +123,7 @@ prepared_buffers static_streambuf static_streambuf_n + static_string streambuf streambuf_readstream @@ -128,20 +133,24 @@ bind_handler buffer_cat + consumed_buffers prepare_buffer prepare_buffers + to_string + write Type Traits + is_AsyncReadStream is_AsyncWriteStream is_AsyncStream is_BufferSequence + is_CompletionHandler is_ConstBufferSequence - is_Handler is_MutableBufferSequence is_Streambuf is_SyncReadStream @@ -153,8 +162,30 @@ Concepts BufferSequence - Stream + AsyncStream + Stream Streambuf + SyncStream + + + + + + + + + + + Diagnostic + + + + + + + + doc_debug + nested_doc_debug diff --git a/doc/reference.xsl b/doc/reference.xsl index 51d64ee2..cc0e9b5f 100644 --- a/doc/reference.xsl +++ b/doc/reference.xsl @@ -43,6 +43,7 @@ @@ -61,7 +62,6 @@ [endsect] - @@ -73,6 +73,9 @@ + + + @@ -108,6 +111,38 @@ + + + + + + + + + * + + + + & + + + + &... + + + + && + + + + &&... + + + + + + + @@ -124,20 +159,22 @@ - - - ``[link beast.ref.ConstBufferSequence ['ConstBufferSequence]]`` - - - ``['implementation-defined]`` - - - ``[link beast.ref.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]`` - - - - - + + + + ``['implementation-defined]`` + + + ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]`` + + + + + + + + + @@ -260,8 +297,9 @@ - - + + + @@ -391,6 +429,8 @@ + [heading See Also] + [heading Remarks] @@ -536,12 +576,13 @@ + - + @@ -554,6 +595,14 @@ + + [link beast.ref. ` @@ -561,89 +610,106 @@ `] - ` + [role red |1| - ` + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + [link beast.ref. + + + + + + + + + ` + + `] + + + [link beast.ref. + + ` + + `] + + + [role red + + ] + + + + + [role red + + ] + + + - - - - - - - - - - - - - - [link beast.ref. - - ` - - `] - - - ` - - ` - - + [role red |3| + + ] - - - - - - - - - - - - - - - - - - - [link beast.ref. - - ` - - `] - - - ` - - ` - - - - - + + + + + - + - + @@ -651,16 +717,49 @@ - [link beast.ref. + + + + + [link beast.ref. + + + + + + + + + ` + + `] + + + [link beast.ref. + + ` + + `] + + + [role red + + ] + + - ` - - ` + [role red + + ] @@ -1185,7 +1284,8 @@ - + + ``[link beast.ref. @@ -1412,21 +1512,62 @@ + template< > + + + + class ``[link beast.types.stream.AsyncStream [*AsyncStream]]`` + + + class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]`` + + + class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]`` + class ``[link beast.types.Body [*Body]]`` - + + class ``[link beast.types.BufferSequence [*BufferSequence]]`` + + + + ``[link beast.types.BufferSequence [*BufferSequence]]`` + + + class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]`` + + + class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]`` + + + class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]`` + + + class ``[link beast.types.stream.Stream [*Stream]]`` + + class ``[link beast.types.Streambuf [*Streambuf]]`` + + class ``[link beast.types.stream.SyncStream [*SyncStream]]`` + + + class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]`` + + + class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]`` + + @@ -1466,28 +1607,19 @@ - - - - && - - - - & - - - - * - - - - - - - + + + + + + + - = + + = + + , diff --git a/examples/file_body.hpp b/examples/file_body.hpp index b28371bb..dbcd34f8 100644 --- a/examples/file_body.hpp +++ b/examples/file_body.hpp @@ -20,7 +20,7 @@ #ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED #define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED -#include +#include #include #include #include diff --git a/include/beast/async_completion.hpp b/include/beast/async_completion.hpp index 121c037f..ab659326 100644 --- a/include/beast/async_completion.hpp +++ b/include/beast/async_completion.hpp @@ -8,7 +8,7 @@ #ifndef BEAST_ASYNC_COMPLETION_HPP #define BEAST_ASYNC_COMPLETION_HPP -#include +#include #include #include #include @@ -19,11 +19,11 @@ namespace beast { /** Helper for customizing the return type of asynchronous initiation functions. This class template is used to transform caller-provided completion - tokens in calls to asynchronous initiation functions. The transformation + handlers in calls to asynchronous initiation functions. The transformation allows customization of the return type of the initiating function, and the function signature of the final handler. - @tparam CompletionToken A CompletionHandler, or a user defined type + @tparam CompletionHandler A completion handler, or a user defined type with specializations for customizing the return type (for example, `boost::asio::use_future` or `boost::asio::yield_context`). @@ -32,22 +32,22 @@ namespace beast { Example: @code ... - template - typename async_completion + typename async_completion::result_type - async_initfn(..., CompletionToken&& token) + async_initfn(..., CompletionHandler&& handler) { - async_completion completion(token); + async_completion completion(handler); ... return completion.result.get(); } @endcode - See + @note See Library Foundations For Asynchronous Operations */ -template +template struct async_completion { /** The type of the final handler called by the asynchronous initiation function. @@ -56,7 +56,7 @@ struct async_completion */ using handler_type = typename boost::asio::handler_type< - CompletionToken, Signature>::type; + CompletionHandler, Signature>::type; /// The type of the value returned by the asynchronous initiation function. using result_type = typename @@ -64,14 +64,14 @@ struct async_completion /** Construct the helper. - @param token The completion token. Copies will be made as - required. If `CompletionToken` is movable, it may also be moved. + @param token The completion handler. Copies will be made as + required. If `CompletionHandler` is movable, it may also be moved. */ - async_completion(typename std::remove_reference::type& token) - : handler(std::forward(token)) + async_completion(typename std::remove_reference::type& token) + : handler(std::forward(token)) , result(handler) { - static_assert(is_Handler::value, + static_assert(is_CompletionHandler::value, "Handler requirements not met"); } diff --git a/include/beast/basic_streambuf.hpp b/include/beast/basic_streambuf.hpp index 9ff52af5..f81bdcc1 100644 --- a/include/beast/basic_streambuf.hpp +++ b/include/beast/basic_streambuf.hpp @@ -18,13 +18,15 @@ namespace beast { -/** A `Streambuf` that uses multiple buffers internally. +/** A @b `Streambuf` that uses multiple buffers internally. The implementation uses a sequence of one or more character arrays of varying sizes. Additional character array objects are appended to the sequence to accommodate changes in the size of the character sequence. + @note Meets the requirements of @b Streambuf. + @tparam Allocator The allocator to use for managing memory. */ template @@ -36,10 +38,14 @@ class basic_streambuf #endif { public: +#if GENERATING_DOCS /// The type of allocator used. + using allocator_type = Allocator; +#else using allocator_type = typename std::allocator_traits:: template rebind_alloc; +#endif private: // Storage for the list of buffers representing the input @@ -93,106 +99,104 @@ public: /** Move constructor. - The output sequence of this object will be empty. + The new object will have the input sequence of + the other stream buffer, and an empty output sequence. - After the move, the moved-from object will have an - empty input and output sequence, with no internal + @note After the move, the moved-from object will have + an empty input and output sequence, with no internal buffers allocated. - - @param other The stream buffer to move from. */ - basic_streambuf(basic_streambuf&& other); + basic_streambuf(basic_streambuf&&); /** Move constructor. - The output sequence of this object will be empty. + The new object will have the input sequence of + the other stream buffer, and an empty output sequence. - After the move, the moved-from object will have an - empty input and output sequence, with no internal + @note After the move, the moved-from object will have + an empty input and output sequence, with no internal buffers allocated. - @param other The stream buffer to move from. - @param alloc The allocator to associate with the stream buffer. */ - basic_streambuf(basic_streambuf&& other, + basic_streambuf(basic_streambuf&&, allocator_type const& alloc); /** Move assignment. - The output sequence of this object will be empty. + This object will have the input sequence of + the other stream buffer, and an empty output sequence. - After the move, the moved-from object will have an - empty input and output sequence, with no internal + @note After the move, the moved-from object will have + an empty input and output sequence, with no internal buffers allocated. - - @param other The stream buffer to move from. */ basic_streambuf& - operator=(basic_streambuf&& other); - - /// Copy constructor. - basic_streambuf(basic_streambuf const& other); + operator=(basic_streambuf&&); /** Copy constructor. - The output sequence of this object will be empty. + This object will have a copy of the other stream + buffer's input sequence, and an empty output sequence. + */ + basic_streambuf(basic_streambuf const&); - @param other The stream buffer to copy. + /** Copy constructor. + + This object will have a copy of the other stream + buffer's input sequence, and an empty output sequence. @param alloc The allocator to associate with the stream buffer. */ - basic_streambuf(basic_streambuf const& other, + basic_streambuf(basic_streambuf const&, allocator_type const& alloc); /** Copy assignment. - The output sequence of this object will be empty. - - @param other The stream buffer to copy. + This object will have a copy of the other stream + buffer's input sequence, and an empty output sequence. */ - basic_streambuf& operator=(basic_streambuf const& other); + basic_streambuf& operator=(basic_streambuf const&); /** Copy constructor. - The output sequence of this object will be empty. - - @param other The stream buffer to copy. + This object will have a copy of the other stream + buffer's input sequence, and an empty output sequence. */ template - basic_streambuf(basic_streambuf const& other); + basic_streambuf(basic_streambuf const&); /** Copy constructor. - The output sequence of this object will be empty. - - @param other The stream buffer to copy. + This object will have a copy of the other stream + buffer's input sequence, and an empty output sequence. @param alloc The allocator to associate with the stream buffer. */ template - basic_streambuf(basic_streambuf const& other, + basic_streambuf(basic_streambuf const&, allocator_type const& alloc); /** Copy assignment. - The output sequence of this object will be empty. - - @param other The stream buffer to copy. + This object will have a copy of the other stream + buffer's input sequence, and an empty output sequence. */ template - basic_streambuf& operator=(basic_streambuf const& other); + basic_streambuf& operator=(basic_streambuf const&); - /** Default constructor. + /** Construct a stream buffer. - @param alloc_size The size of buffer to allocate. This is a soft - limit, calls to prepare for buffers exceeding this size will allocate - the larger size. + @param alloc_size The size of buffer to allocate. This is a + soft limit, calls to prepare for buffers exceeding this size + will allocate the larger size. The default allocation size + is 1KB (1024 bytes). - @param alloc The allocator to use. + @param alloc The allocator to use. If this parameter is + unspecified, a default constructed allocator will be used. */ explicit basic_streambuf(std::size_t alloc_size = 1024, @@ -219,15 +223,26 @@ public: return in_size_; } - /// Get a list of buffers that represents the output sequence, with the given size. + /** Get a list of buffers that represents the output sequence, with the given size. + + @note Buffers representing the input sequence acquired prior to + this call remain valid. + */ mutable_buffers_type prepare(size_type n); - /// Move bytes from the output sequence to the input sequence. + /** Move bytes from the output sequence to the input sequence. + + @note Buffers representing the input sequence acquired prior to + this call remain valid. + */ void commit(size_type n); - /// Get a list of buffers that represents the input sequence. + /** Get a list of buffers that represents the input sequence. + + @note These buffers remain valid across subsequent calls to `prepare`. + */ const_buffers_type data() const; @@ -277,19 +292,9 @@ private: @return The stream buffer. */ -template -basic_streambuf& -operator<<(basic_streambuf& streambuf, T const& t); - -/** Convert the entire basic_streambuf to a string. - - @param streambuf The streambuf to convert. - - @return A string representing the contents of the input sequence. -*/ -template -std::string -to_string(basic_streambuf const& streambuf); +template +basic_streambuf& +operator<<(basic_streambuf& streambuf, T const& t); } // beast diff --git a/include/beast/bind_handler.hpp b/include/beast/bind_handler.hpp index cd40645c..103a3994 100644 --- a/include/beast/bind_handler.hpp +++ b/include/beast/bind_handler.hpp @@ -8,110 +8,19 @@ #ifndef BEAST_BIND_HANDLER_HPP #define BEAST_BIND_HANDLER_HPP -#include -#include -#include -#include -#include +#include +#include #include #include namespace beast { -namespace detail { - -/* Nullary handler that calls Handler with bound arguments. - - The bound handler provides the same io_service execution - guarantees as the original handler. -*/ -template -class bound_handler -{ -private: - using args_type = std::tuple::type...>; - - Handler h_; - args_type args_; - - template - static void invoke(Handler& h, Tuple& args, - index_sequence) - { - h(std::get(args)...); - } - -public: - using result_type = void; - - template - explicit - bound_handler(DeducedHandler&& handler, Args&&... args) - : h_(std::forward(handler)) - , args_(std::forward(args)...) - { - } - - void - operator()() - { - invoke(h_, args_, - index_sequence_for ()); - } - - void - operator()() const - { - invoke(h_, args_, - index_sequence_for ()); - } - - friend - void* - asio_handler_allocate( - std::size_t size, bound_handler* h) - { - return boost_asio_handler_alloc_helpers:: - allocate(size, h->h_); - } - - friend - void - asio_handler_deallocate( - void* p, std::size_t size, bound_handler* h) - { - boost_asio_handler_alloc_helpers:: - deallocate(p, size, h->h_); - } - - friend - bool - asio_handler_is_continuation(bound_handler* h) - { - return boost_asio_handler_cont_helpers:: - is_continuation (h->h_); - } - - template - friend - void - asio_handler_invoke(F&& f, bound_handler* h) - { - boost_asio_handler_invoke_helpers:: - invoke(f, h->h_); - } -}; - -} // detail - -//------------------------------------------------------------------------------ - /** Bind parameters to a completion handler, creating a wrapped handler. - This function creates a new handler which invoked with no parameters - calls the original handler with the list of bound arguments. The passed - handler and arguments are forwarded into the returned handler, which - provides the same `io_service` execution guarantees as the original + This function creates a new handler which, when invoked with no + parameters, calls the original handler with the list of bound arguments. + The passed handler and arguments are forwarded into the returned handler, + which provides the same `io_service` execution guarantees as the original handler. Unlike `io_service::wrap`, the returned handler can be used in a @@ -145,6 +54,9 @@ detail::bound_handler< #endif bind_handler(CompletionHandler&& handler, Args&&... args) { + static_assert(is_CompletionHandler< + CompletionHandler, void(Args...)>::value, + "CompletionHandler requirements not met"); return detail::bound_handler::type, Args...>(std::forward< CompletionHandler>(handler), @@ -153,10 +65,4 @@ bind_handler(CompletionHandler&& handler, Args&&... args) } // beast -namespace std { -template -void bind(beast::detail::bound_handler< - Handler, Args...>, ...) = delete; -} // std - #endif diff --git a/include/beast/buffer_cat.hpp b/include/beast/buffer_cat.hpp index bfbb2d2e..5c3fabb4 100644 --- a/include/beast/buffer_cat.hpp +++ b/include/beast/buffer_cat.hpp @@ -8,6 +8,7 @@ #ifndef BEAST_BUFFER_CAT_HPP #define BEAST_BUFFER_CAT_HPP +#include #include #include #include @@ -18,463 +19,9 @@ namespace beast { -namespace detail { - -template -class buffer_cat_helper -{ - std::tuple bs_; - -public: - using value_type = ValueType; - - class const_iterator; - - buffer_cat_helper(buffer_cat_helper&&) = default; - buffer_cat_helper(buffer_cat_helper const&) = default; - buffer_cat_helper& operator=(buffer_cat_helper&&) = default; - buffer_cat_helper& operator=(buffer_cat_helper const&) = default; - - explicit - buffer_cat_helper(Bs const&... bs) - : bs_(bs...) - { - } - - const_iterator - begin() const; - - const_iterator - end() const; -}; - -template -std::size_t constexpr -max_sizeof() -{ - return sizeof(U); -} - -template -std::size_t constexpr -max_sizeof() -{ - return - max_sizeof() > max_sizeof() ? - max_sizeof() : max_sizeof(); -} - -template -class buffer_cat_helper< - ValueType, Bs...>::const_iterator -{ - std::size_t n_; - std::tuple const* bs_; - std::array()> buf_; - - friend class buffer_cat_helper; - - template - using C = std::integral_constant; - - template - using iter_t = typename std::tuple_element< - I, std::tuple>::type::const_iterator; - - template - iter_t& - iter() - { - return *reinterpret_cast< - iter_t*>(buf_.data()); - } - - template - iter_t const& - iter() const - { - return *reinterpret_cast< - iter_t const*>(buf_.data()); - } - -public: - using value_type = ValueType; - using pointer = value_type const*; - using reference = value_type; - using difference_type = std::ptrdiff_t; - using iterator_category = - std::bidirectional_iterator_tag; - - ~const_iterator(); - const_iterator(); - const_iterator(const_iterator&& other); - const_iterator(const_iterator const& other); - const_iterator& operator=(const_iterator&& other); - const_iterator& operator=(const_iterator const& other); - - bool - operator==(const_iterator const& other) const; - - bool - operator!=(const_iterator const& other) const - { - return !(*this == other); - } - - reference - operator*() const; - - pointer - operator->() const = delete; - - const_iterator& - operator++(); - - const_iterator - operator++(int) - { - auto temp = *this; - ++(*this); - return temp; - } - - const_iterator& - operator--(); - - const_iterator - operator--(int) - { - auto temp = *this; - --(*this); - return temp; - } - -private: - const_iterator( - std::tuple const& bs, bool at_end); - - void - construct(C) - { - auto constexpr I = sizeof...(Bs); - n_ = I; - } - - template - void - construct(C) - { - if(std::get(*bs_).begin() != - std::get(*bs_).end()) - { - n_ = I; - new(buf_.data()) iter_t{ - std::get(*bs_).begin()}; - return; - } - construct(C{}); - } - - void - destroy(C) - { - return; - } - - template - void - destroy(C) - { - if(n_ == I) - { - using Iter = iter_t; - iter().~Iter(); - return; - } - destroy(C{}); - } - - void - move(C, const_iterator&&) - { - return; - } - - template - void - move(C, const_iterator&& other) - { - if(n_ == I) - { - new(buf_.data()) iter_t{ - std::move(other.iter())}; - return; - } - move(C{}, std::move(other)); - } - - void - copy(C, const_iterator const&) - { - return; - } - - template - void - copy(C, const_iterator const& other) - { - if(n_ == I) - { - new(buf_.data()) iter_t{ - other.iter()}; - return; - } - copy(C{}, other); - } - - bool - equal(C, - const_iterator const&) const - { - return true; - } - - template - bool - equal(C, const_iterator const& other) const - { - if(n_ == I) - return iter() == other.iter(); - return equal(C{}, other); - } - - [[noreturn]] - reference - dereference(C) const - { - throw std::logic_error("invalid iterator"); - } - - template - reference - dereference(C) const - { - if(n_ == I) - return *iter(); - return dereference(C{}); - } - - [[noreturn]] - void - increment(C) - { - throw std::logic_error("invalid iterator"); - } - - template - void - increment(C) - { - if(n_ == I) - { - if(++iter() != - std::get(*bs_).end()) - return; - using Iter = iter_t; - iter().~Iter(); - return construct(C{}); - } - increment(C{}); - } - - void - decrement(C) - { - auto constexpr I = sizeof...(Bs); - if(n_ == I) - { - --n_; - new(buf_.data()) iter_t{ - std::get(*bs_).end()}; - } - decrement(C{}); - } - - void - decrement(C<0>) - { - auto constexpr I = 0; - if(iter() != std::get(*bs_).begin()) - { - --iter(); - return; - } - throw std::logic_error("invalid iterator"); - } - - template - void - decrement(C) - { - if(n_ == I) - { - if(iter() != std::get(*bs_).begin()) - { - --iter(); - return; - } - --n_; - using Iter = iter_t; - iter().~Iter(); - new(buf_.data()) iter_t{ - std::get(*bs_).end()}; - } - decrement(C{}); - } -}; - -//------------------------------------------------------------------------------ - -template -buffer_cat_helper:: -const_iterator::~const_iterator() -{ - destroy(C<0>{}); -} - -template -buffer_cat_helper:: -const_iterator::const_iterator() - : n_(sizeof...(Bs)) - , bs_(nullptr) -{ -} - -template -buffer_cat_helper:: -const_iterator::const_iterator( - std::tuple const& bs, bool at_end) - : bs_(&bs) -{ - if(at_end) - n_ = sizeof...(Bs); - else - construct(C<0>{}); -} - -template -buffer_cat_helper:: -const_iterator::const_iterator(const_iterator&& other) - : n_(other.n_) - , bs_(other.bs_) -{ - move(C<0>{}, std::move(other)); -} - -template -buffer_cat_helper:: -const_iterator::const_iterator(const_iterator const& other) - : n_(other.n_) - , bs_(other.bs_) -{ - copy(C<0>{}, other); -} - -template -auto -buffer_cat_helper:: -const_iterator::operator=(const_iterator&& other) -> - const_iterator& -{ - if(&other == this) - return *this; - destroy(C<0>{}); - n_ = other.n_; - bs_ = other.bs_; - move(C<0>{}, std::move(other)); - return *this; -} - -template -auto -buffer_cat_helper:: -const_iterator::operator=(const_iterator const& other) -> -const_iterator& -{ - if(&other == this) - return *this; - destroy(C<0>{}); - n_ = other.n_; - bs_ = other.bs_; - copy(C<0>{}, other); - return *this; -} - -template -bool -buffer_cat_helper:: -const_iterator::operator==(const_iterator const& other) const -{ - if(bs_ != other.bs_) - return false; - if(n_ != other.n_) - return false; - return equal(C<0>{}, other); -} - -template -auto -buffer_cat_helper:: -const_iterator::operator*() const -> - reference -{ - return dereference(C<0>{}); -} - -template -auto -buffer_cat_helper:: -const_iterator::operator++() -> - const_iterator& -{ - increment(C<0>{}); - return *this; -} - -template -auto -buffer_cat_helper:: -const_iterator::operator--() -> - const_iterator& -{ - decrement(C{}); - return *this; -} - -template -auto -buffer_cat_helper::begin() const -> - const_iterator -{ - return const_iterator(bs_, false); -} - -template -auto -buffer_cat_helper::end() const -> - const_iterator -{ - return const_iterator(bs_, true); -} - -} // detail - -//------------------------------------------------------------------------------ - /** Concatenate 2 or more buffer sequences to form a `ConstBufferSequence`. - This function returns a `ConstBufferSequence` that when iterated, + This function returns a @b `ConstBufferSequence` that when iterated, efficiently concatenates the input buffer sequences. Copies of the arguments passed will be made; however, the returned object does not take ownership of the underlying memory. The application is still @@ -482,8 +29,8 @@ buffer_cat_helper::end() const -> @param buffers The list of buffer sequences to concatenate. - @return A new `ConstBufferSequence` that represents the concatenation - of the input buffer sequences. + @return A new @b `ConstBufferSequence` that represents the + concatenation of the input buffer sequences. */ #if GENERATING_DOCS template diff --git a/include/beast/buffer_concepts.hpp b/include/beast/buffer_concepts.hpp new file mode 100644 index 00000000..240834fa --- /dev/null +++ b/include/beast/buffer_concepts.hpp @@ -0,0 +1,61 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_BUFFER_CONCEPTS_HPP +#define BEAST_BUFFER_CONCEPTS_HPP + +#include +#include +#include + +namespace beast { + +/// Determine if `T` meets the requirements of @b `BufferSequence`. +template +#if GENERATING_DOCS +struct is_BufferSequence : std::integral_constant +#else +struct is_BufferSequence : detail::is_BufferSequence::type +#endif +{ +}; + +/// Determine if `T` meets the requirements of @b `ConstBufferSequence`. +template +#if GENERATING_DOCS +struct is_ConstBufferSequence : std::integral_constant +#else +struct is_ConstBufferSequence : + is_BufferSequence +#endif +{ +}; + +/// Determine if `T` meets the requirements of @b `MutableBufferSequence`. +template +#if GENERATING_DOCS +struct is_MutableBufferSequence : std::integral_constant +#else +struct is_MutableBufferSequence : + is_BufferSequence +#endif +{ +}; + +/// Determine if `T` meets the requirements of @b `Streambuf`. +template +#if GENERATING_DOCS +struct is_Streambuf : std::integral_constant +#else +struct is_Streambuf : detail::is_Streambuf::type +#endif +{ +}; + +} // beast + +#endif diff --git a/include/beast/buffers_adapter.hpp b/include/beast/buffers_adapter.hpp index 708b8144..b5c9965e 100644 --- a/include/beast/buffers_adapter.hpp +++ b/include/beast/buffers_adapter.hpp @@ -8,15 +8,16 @@ #ifndef BEAST_BUFFERS_ADAPTER_HPP #define BEAST_BUFFERS_ADAPTER_HPP +#include #include #include namespace beast { -/** Adapts a `MutableBufferSequence` into a `Streambuf`. +/** Adapts a @b `MutableBufferSequence` into a @b `Streambuf`. - This class wraps a `MutableBufferSequence` to meet the requirements - of `Streambuf`. Upon construction the input and output sequences are + This class wraps a @b `MutableBufferSequence` to meet the requirements + of @b `Streambuf`. Upon construction the input and output sequences are empty. A copy of the mutable buffer sequence object is stored; however, ownership of the underlying memory is not transferred. The caller is responsible for making sure that referenced memory remains valid @@ -25,20 +26,18 @@ namespace beast { The size of the mutable buffer sequence determines the maximum number of bytes which may be prepared and committed. - @tparam Buffers The type of mutable buffer sequence to wrap. + @tparam MutableBufferSequence The type of mutable buffer sequence to wrap. */ -template +template class buffers_adapter { private: - using buffers_type = typename std::decay::type; - using iter_type = typename buffers_type::const_iterator; + static_assert(is_MutableBufferSequence::value, + "MutableBufferSequence requirements not met"); - static auto constexpr is_mutable = - std::is_constructible::value_type>::value; + using iter_type = typename MutableBufferSequence::const_iterator; - Buffers bs_; + MutableBufferSequence bs_; iter_type begin_; iter_type out_; iter_type end_; @@ -98,7 +97,7 @@ public: transferred. */ explicit - buffers_adapter(Buffers const& buffers); + buffers_adapter(MutableBufferSequence const& buffers); /// Returns the largest size output sequence possible. std::size_t @@ -118,15 +117,25 @@ public: @throws std::length_error if the size would exceed the limit imposed by the underlying mutable buffer sequence. + + @note Buffers representing the input sequence acquired prior to + this call remain valid. */ mutable_buffers_type prepare(std::size_t n); - /// Move bytes from the output sequence to the input sequence. + /** Move bytes from the output sequence to the input sequence. + + @note Buffers representing the input sequence acquired prior to + this call remain valid. + */ void commit(std::size_t n); - /// Get a list of buffers that represents the input sequence. + /** Get a list of buffers that represents the input sequence. + + @note These buffers remain valid across subsequent calls to `prepare`. + */ const_buffers_type data() const; diff --git a/include/beast/consuming_buffers.hpp b/include/beast/consuming_buffers.hpp index 1c158606..32864d5e 100644 --- a/include/beast/consuming_buffers.hpp +++ b/include/beast/consuming_buffers.hpp @@ -8,6 +8,7 @@ #ifndef BEAST_CONSUMING_BUFFERS_HPP #define BEAST_CONSUMING_BUFFERS_HPP +#include #include #include #include @@ -28,26 +29,29 @@ namespace beast { Ownership of the underlying memory is not transferred, the application is still responsible for managing its lifetime. - @tparam Buffers The buffer sequence to wrap. + @tparam BufferSequence The buffer sequence to wrap. - @ptaram ValueType The type of buffer of the final buffer sequence. This + @tparam ValueType The type of buffer of the final buffer sequence. This can be different from the buffer type of the wrapped sequence. For example, a `MutableBufferSequence` can be transformed into a consumable `ConstBufferSequence`. Violations of buffer const safety are not permitted, and will result in a compile error. */ -template +template class consuming_buffers { using iter_type = - typename Buffers::const_iterator; + typename BufferSequence::const_iterator; + + static_assert(is_BufferSequence::value, + "BufferSequence requirements not met"); static_assert(std::is_constructible::value_type>::value, "ValueType requirements not met"); - Buffers bs_; + BufferSequence bs_; iter_type begin_; std::size_t skip_ = 0; @@ -90,7 +94,7 @@ public: underlying memory is not transferred or copied. */ explicit - consuming_buffers(Buffers const& buffers); + consuming_buffers(BufferSequence const& buffers); /// Get a bidirectional iterator to the first element. const_iterator diff --git a/include/beast/detail/bind_handler.hpp b/include/beast/detail/bind_handler.hpp new file mode 100644 index 00000000..4caba66d --- /dev/null +++ b/include/beast/detail/bind_handler.hpp @@ -0,0 +1,113 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_BIND_DETAIL_HANDLER_HPP +#define BEAST_BIND_DETAIL_HANDLER_HPP + +#include +#include +#include +#include +#include + +namespace beast { +namespace detail { + +/* Nullary handler that calls Handler with bound arguments. + + The bound handler provides the same io_service execution + guarantees as the original handler. +*/ +template +class bound_handler +{ +private: + using args_type = std::tuple< + typename std::decay::type...>; + + Handler h_; + args_type args_; + + template + static void invoke(Handler& h, Tuple& args, + index_sequence) + { + h(std::get(args)...); + } + +public: + using result_type = void; + + template + explicit + bound_handler(DeducedHandler&& handler, Args&&... args) + : h_(std::forward(handler)) + , args_(std::forward(args)...) + { + } + + void + operator()() + { + invoke(h_, args_, + index_sequence_for ()); + } + + void + operator()() const + { + invoke(h_, args_, + index_sequence_for ()); + } + + friend + void* + asio_handler_allocate( + std::size_t size, bound_handler* h) + { + return boost_asio_handler_alloc_helpers:: + allocate(size, h->h_); + } + + friend + void + asio_handler_deallocate( + void* p, std::size_t size, bound_handler* h) + { + boost_asio_handler_alloc_helpers:: + deallocate(p, size, h->h_); + } + + friend + bool + asio_handler_is_continuation(bound_handler* h) + { + return boost_asio_handler_cont_helpers:: + is_continuation (h->h_); + } + + template + friend + void + asio_handler_invoke(F&& f, bound_handler* h) + { + boost_asio_handler_invoke_helpers:: + invoke(f, h->h_); + } +}; + +} // detail +} // beast + +#include +namespace std { +template +void bind(beast::detail::bound_handler< + Handler, Args...>, ...) = delete; +} // std + +#endif diff --git a/include/beast/detail/buffer_cat.hpp b/include/beast/detail/buffer_cat.hpp new file mode 100644 index 00000000..388dd1ff --- /dev/null +++ b/include/beast/detail/buffer_cat.hpp @@ -0,0 +1,473 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_DETAIL_BUFFER_CAT_HPP +#define BEAST_DETAIL_BUFFER_CAT_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace detail { + +template +class buffer_cat_helper +{ + std::tuple bs_; + +public: + using value_type = ValueType; + + class const_iterator; + + buffer_cat_helper(buffer_cat_helper&&) = default; + buffer_cat_helper(buffer_cat_helper const&) = default; + buffer_cat_helper& operator=(buffer_cat_helper&&) = default; + buffer_cat_helper& operator=(buffer_cat_helper const&) = default; + + explicit + buffer_cat_helper(Bs const&... bs) + : bs_(bs...) + { + } + + const_iterator + begin() const; + + const_iterator + end() const; +}; + +template +std::size_t constexpr +max_sizeof() +{ + return sizeof(U); +} + +template +std::size_t constexpr +max_sizeof() +{ + return + max_sizeof() > max_sizeof() ? + max_sizeof() : max_sizeof(); +} + +template +class buffer_cat_helper< + ValueType, Bs...>::const_iterator +{ + std::size_t n_; + std::tuple const* bs_; + std::array()> buf_; + + friend class buffer_cat_helper; + + template + using C = std::integral_constant; + + template + using iter_t = typename std::tuple_element< + I, std::tuple>::type::const_iterator; + + template + iter_t& + iter() + { + return *reinterpret_cast< + iter_t*>(buf_.data()); + } + + template + iter_t const& + iter() const + { + return *reinterpret_cast< + iter_t const*>(buf_.data()); + } + +public: + using value_type = ValueType; + using pointer = value_type const*; + using reference = value_type; + using difference_type = std::ptrdiff_t; + using iterator_category = + std::bidirectional_iterator_tag; + + ~const_iterator(); + const_iterator(); + const_iterator(const_iterator&& other); + const_iterator(const_iterator const& other); + const_iterator& operator=(const_iterator&& other); + const_iterator& operator=(const_iterator const& other); + + bool + operator==(const_iterator const& other) const; + + bool + operator!=(const_iterator const& other) const + { + return !(*this == other); + } + + reference + operator*() const; + + pointer + operator->() const = delete; + + const_iterator& + operator++(); + + const_iterator + operator++(int) + { + auto temp = *this; + ++(*this); + return temp; + } + + const_iterator& + operator--(); + + const_iterator + operator--(int) + { + auto temp = *this; + --(*this); + return temp; + } + +private: + const_iterator( + std::tuple const& bs, bool at_end); + + void + construct(C) + { + auto constexpr I = sizeof...(Bs); + n_ = I; + } + + template + void + construct(C) + { + if(std::get(*bs_).begin() != + std::get(*bs_).end()) + { + n_ = I; + new(buf_.data()) iter_t{ + std::get(*bs_).begin()}; + return; + } + construct(C{}); + } + + void + destroy(C) + { + return; + } + + template + void + destroy(C) + { + if(n_ == I) + { + using Iter = iter_t; + iter().~Iter(); + return; + } + destroy(C{}); + } + + void + move(C, const_iterator&&) + { + return; + } + + template + void + move(C, const_iterator&& other) + { + if(n_ == I) + { + new(buf_.data()) iter_t{ + std::move(other.iter())}; + return; + } + move(C{}, std::move(other)); + } + + void + copy(C, const_iterator const&) + { + return; + } + + template + void + copy(C, const_iterator const& other) + { + if(n_ == I) + { + new(buf_.data()) iter_t{ + other.iter()}; + return; + } + copy(C{}, other); + } + + bool + equal(C, + const_iterator const&) const + { + return true; + } + + template + bool + equal(C, const_iterator const& other) const + { + if(n_ == I) + return iter() == other.iter(); + return equal(C{}, other); + } + + [[noreturn]] + reference + dereference(C) const + { + throw std::logic_error("invalid iterator"); + } + + template + reference + dereference(C) const + { + if(n_ == I) + return *iter(); + return dereference(C{}); + } + + [[noreturn]] + void + increment(C) + { + throw std::logic_error("invalid iterator"); + } + + template + void + increment(C) + { + if(n_ == I) + { + if(++iter() != + std::get(*bs_).end()) + return; + using Iter = iter_t; + iter().~Iter(); + return construct(C{}); + } + increment(C{}); + } + + void + decrement(C) + { + auto constexpr I = sizeof...(Bs); + if(n_ == I) + { + --n_; + new(buf_.data()) iter_t{ + std::get(*bs_).end()}; + } + decrement(C{}); + } + + void + decrement(C<0>) + { + auto constexpr I = 0; + if(iter() != std::get(*bs_).begin()) + { + --iter(); + return; + } + throw std::logic_error("invalid iterator"); + } + + template + void + decrement(C) + { + if(n_ == I) + { + if(iter() != std::get(*bs_).begin()) + { + --iter(); + return; + } + --n_; + using Iter = iter_t; + iter().~Iter(); + new(buf_.data()) iter_t{ + std::get(*bs_).end()}; + } + decrement(C{}); + } +}; + +//------------------------------------------------------------------------------ + +template +buffer_cat_helper:: +const_iterator::~const_iterator() +{ + destroy(C<0>{}); +} + +template +buffer_cat_helper:: +const_iterator::const_iterator() + : n_(sizeof...(Bs)) + , bs_(nullptr) +{ +} + +template +buffer_cat_helper:: +const_iterator::const_iterator( + std::tuple const& bs, bool at_end) + : bs_(&bs) +{ + if(at_end) + n_ = sizeof...(Bs); + else + construct(C<0>{}); +} + +template +buffer_cat_helper:: +const_iterator::const_iterator(const_iterator&& other) + : n_(other.n_) + , bs_(other.bs_) +{ + move(C<0>{}, std::move(other)); +} + +template +buffer_cat_helper:: +const_iterator::const_iterator(const_iterator const& other) + : n_(other.n_) + , bs_(other.bs_) +{ + copy(C<0>{}, other); +} + +template +auto +buffer_cat_helper:: +const_iterator::operator=(const_iterator&& other) -> + const_iterator& +{ + if(&other == this) + return *this; + destroy(C<0>{}); + n_ = other.n_; + bs_ = other.bs_; + move(C<0>{}, std::move(other)); + return *this; +} + +template +auto +buffer_cat_helper:: +const_iterator::operator=(const_iterator const& other) -> +const_iterator& +{ + if(&other == this) + return *this; + destroy(C<0>{}); + n_ = other.n_; + bs_ = other.bs_; + copy(C<0>{}, other); + return *this; +} + +template +bool +buffer_cat_helper:: +const_iterator::operator==(const_iterator const& other) const +{ + if(bs_ != other.bs_) + return false; + if(n_ != other.n_) + return false; + return equal(C<0>{}, other); +} + +template +auto +buffer_cat_helper:: +const_iterator::operator*() const -> + reference +{ + return dereference(C<0>{}); +} + +template +auto +buffer_cat_helper:: +const_iterator::operator++() -> + const_iterator& +{ + increment(C<0>{}); + return *this; +} + +template +auto +buffer_cat_helper:: +const_iterator::operator--() -> + const_iterator& +{ + decrement(C{}); + return *this; +} + +template +auto +buffer_cat_helper::begin() const -> + const_iterator +{ + return const_iterator(bs_, false); +} + +template +auto +buffer_cat_helper::end() const -> + const_iterator +{ + return const_iterator(bs_, true); +} + +} // detail +} // beast + +#endif diff --git a/include/beast/detail/buffer_concepts.hpp b/include/beast/detail/buffer_concepts.hpp new file mode 100644 index 00000000..ce1451fb --- /dev/null +++ b/include/beast/detail/buffer_concepts.hpp @@ -0,0 +1,140 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_DETAIL_BUFFER_CONCEPTS_HPP +#define BEAST_DETAIL_BUFFER_CONCEPTS_HPP + +#include +#include +#include + +namespace beast { +namespace detail { + +// Types that meet the requirements, +// for use with std::declval only. +template +struct BufferSequence +{ + using value_type = BufferType; + using const_iterator = BufferType const*; + ~BufferSequence(); + BufferSequence(BufferSequence const&) = default; + const_iterator begin() const noexcept; + const_iterator end() const noexcept; +}; +using ConstBufferSequence = + BufferSequence; +using MutableBufferSequence = + BufferSequence; + +template +class is_BufferSequence +{ + template > + static R check1(int); + template + static std::false_type check1(...); + using type1 = decltype(check1(0)); + + template::iterator_category>> + #else + // workaround: + // boost::asio::detail::consuming_buffers::const_iterator + // is not bidirectional + std::forward_iterator_tag, + typename std::iterator_traits< + typename U::const_iterator>::iterator_category>> + #endif + static R check2(int); + template + static std::false_type check2(...); + using type2 = decltype(check2(0)); + + template().begin()), + typename U::const_iterator>::type> + static R check3(int); + template + static std::false_type check3(...); + using type3 = decltype(check3(0)); + + template().end()), + typename U::const_iterator>::type> + static R check4(int); + template + static std::false_type check4(...); + using type4 = decltype(check4(0)); + +public: + using type = std::integral_constant::value && + std::is_destructible::value && + type1::value && type2::value && + type3::value && type4::value>; +}; + +template +class is_Streambuf +{ + template().prepare(1)), + boost::asio::mutable_buffer>::type::value>> + static R check1(int); + template + static std::false_type check1(...); + using type1 = decltype(check1(0)); + + template().data()), + boost::asio::const_buffer>::type::value>> + static R check2(int); + template + static std::false_type check2(...); + using type2 = decltype(check2(0)); + + template().commit(1), std::true_type{})> + static R check3(int); + template + static std::false_type check3(...); + using type3 = decltype(check3(0)); + + template().consume(1), std::true_type{})> + static R check4(int); + template + static std::false_type check4(...); + using type4 = decltype(check4(0)); + + template().size()), std::size_t>> + static R check5(int); + template + static std::false_type check5(...); + using type5 = decltype(check5(0)); + +public: + using type = std::integral_constant; +}; + +} // detail +} // beast + +#endif diff --git a/include/beast/detail/stream_concepts.hpp b/include/beast/detail/stream_concepts.hpp new file mode 100644 index 00000000..a329ac44 --- /dev/null +++ b/include/beast/detail/stream_concepts.hpp @@ -0,0 +1,140 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_DETAIL_STREAM_CONCEPTS_HPP +#define BEAST_DETAIL_STREAM_CONCEPTS_HPP + +#include +#include +#include +#include +#include + +namespace beast { +namespace detail { + +// Types that meet the requirements, +// for use with std::declval only. +struct StreamHandler +{ + StreamHandler(StreamHandler const&) = default; + void operator()(boost::system::error_code ec, std::size_t); +}; +using ReadHandler = StreamHandler; +using WriteHandler = StreamHandler; + +template +class has_get_io_service +{ + template().get_io_service()), + boost::asio::io_service&>> + static R check(int); + template + static std::false_type check(...); +public: + using type = decltype(check(0)); +}; + +template +class is_AsyncReadStream +{ + template().async_read_some( + std::declval(), + std::declval()), + std::true_type{})> + static R check(int); + template + static std::false_type check(...); + using type1 = decltype(check(0)); +public: + using type = std::integral_constant::type::value>; +}; + +template +class is_AsyncWriteStream +{ + template().async_write_some( + std::declval(), + std::declval()), + std::true_type{})> + static R check(int); + template + static std::false_type check(...); + using type1 = decltype(check(0)); +public: + using type = std::integral_constant::type::value>; +}; + +template +class is_SyncReadStream +{ + using error_code = + boost::system::error_code; + + template().read_some( + std::declval())), + std::size_t>> + static R check1(int); + template + static std::false_type check1(...); + using type1 = decltype(check1(0)); + + template().read_some( + std::declval(), + std::declval())), std::size_t>> + static R check2(int); + template + static std::false_type check2(...); + using type2 = decltype(check2(0)); + +public: + using type = std::integral_constant; +}; + +template +class is_SyncWriteStream +{ + using error_code = + boost::system::error_code; + + template().write_some( + std::declval())), + std::size_t>> + static R check1(int); + template + static std::false_type check1(...); + using type1 = decltype(check1(0)); + + template().write_some( + std::declval(), + std::declval())), std::size_t>> + static R check2(int); + template + static std::false_type check2(...); + using type2 = decltype(check2(0)); + +public: + using type = std::integral_constant; +}; + +} // detail +} // beast + +#endif diff --git a/include/beast/detail/write_streambuf.hpp b/include/beast/detail/write_streambuf.hpp index 710ebb06..06174242 100644 --- a/include/beast/detail/write_streambuf.hpp +++ b/include/beast/detail/write_streambuf.hpp @@ -8,6 +8,7 @@ #ifndef BEAST_DETAIL_WRITE_STREAMBUF_HPP #define BEAST_DETAIL_WRITE_STREAMBUF_HPP +#include #include #include #include diff --git a/include/beast/doc_debug.hpp b/include/beast/doc_debug.hpp new file mode 100644 index 00000000..61641496 --- /dev/null +++ b/include/beast/doc_debug.hpp @@ -0,0 +1,170 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_DOC_DEBUG_HPP +#define BEAST_DOC_DEBUG_HPP + +namespace beast { + +#if GENERATING_DOCS + +/// doc type (documentation debug helper) +using doc_type = int; + +/// doc enum (documentation debug helper) +enum doc_enum +{ + /// One (documentation debug helper) + one, + + /// Two (documentation debug helper) + two +}; + +/// doc enum class (documentation debug helper) +enum class doc_enum_class : unsigned +{ + /// one (documentation debug helper) + one, + + /// two (documentation debug helper) + two +}; + +/// doc func (documentation debug helper) +void doc_func(); + +/// doc class (documentation debug helper) +struct doc_class +{ + /// doc class member func (documentation debug helper) + void func(); +}; + +/// (documentation debug helper) +namespace nested { + +/// doc type (documentation debug helper) +using nested_doc_type = int; + +/// doc enum (documentation debug helper) +enum nested_doc_enum +{ + /// One (documentation debug helper) + one, + + /// Two (documentation debug helper) + two +}; + +/// doc enum class (documentation debug helper) +enum class nested_doc_enum_class : unsigned +{ + /// one (documentation debug helper) + one, + + /// two (documentation debug helper) + two +}; + +/// doc func (documentation debug helper) +void nested_doc_func(); + +/// doc class (documentation debug helper) +struct nested_doc_class +{ + /// doc class member func (documentation debug helper) + void func(); +}; + +} // nested + +/** This is here to help troubleshoot doc/reference.xsl problems + + Embedded references: + + @li type @ref doc_type + + @li enum @ref doc_enum + + @li enum item @ref doc_enum::one + + @li enum_class @ref doc_enum_class + + @li enum_class item @ref doc_enum_class::one + + @li func @ref doc_func + + @li class @ref doc_class + + @li class func @ref doc_class::func + + @li nested type @ref nested::nested_doc_type + + @li nested enum @ref nested::nested_doc_enum + + @li nested enum item @ref nested::nested_doc_enum::one + + @li nested enum_class @ref nested::nested_doc_enum_class + + @li nested enum_class item @ref nested::nested_doc_enum_class::one + + @li nested func @ref nested::nested_doc_func + + @li nested class @ref nested::nested_doc_class + + @li nested class func @ref nested::nested_doc_class::func +*/ +void doc_debug(); + +namespace nested { + +/** This is here to help troubleshoot doc/reference.xsl problems + + Embedded references: + + @li type @ref doc_type + + @li enum @ref doc_enum + + @li enum item @ref doc_enum::one + + @li enum_class @ref doc_enum_class + + @li enum_class item @ref doc_enum_class::one + + @li func @ref doc_func + + @li class @ref doc_class + + @li class func @ref doc_class::func + + @li nested type @ref nested_doc_type + + @li nested enum @ref nested_doc_enum + + @li nested enum item @ref nested_doc_enum::one + + @li nested enum_class @ref nested_doc_enum_class + + @li nested enum_class item @ref nested_doc_enum_class::one + + @li nested func @ref nested_doc_func + + @li nested class @ref nested_doc_class + + @li nested class func @ref nested_doc_class::func +*/ +void nested_doc_debug(); + +} // nested + +#endif + +} // beast + +#endif diff --git a/include/beast/handler_alloc.hpp b/include/beast/handler_alloc.hpp index 37ca25b1..cc12eace 100644 --- a/include/beast/handler_alloc.hpp +++ b/include/beast/handler_alloc.hpp @@ -28,28 +28,28 @@ namespace beast { @tparam T The type of objects allocated by the allocator. - @tparam Handler The type of handler. + @tparam CompletionHandler The type of handler. @note Allocated memory is only valid until the handler is called. The caller is still responsible for freeing memory. */ #if GENERATING_DOCS -template +template class handler_alloc; #else -template +template class handler_alloc { private: // We want a partial template specialization as a friend // but that isn't allowed so we friend all versions. This - // should produce a compile error if Handler is not + // should produce a compile error if CompletionHandler is not // constructible from H. // template friend class handler_alloc; - Handler h_; + CompletionHandler h_; public: using value_type = T; @@ -66,7 +66,7 @@ public: The handler is moved or copied into the allocator. */ explicit - handler_alloc(Handler&& h) + handler_alloc(CompletionHandler&& h) : h_(std::move(h)) { } @@ -76,21 +76,21 @@ public: A copy of the handler is made. */ explicit - handler_alloc(Handler const& h) + handler_alloc(CompletionHandler const& h) : h_(h) { } template handler_alloc( - handler_alloc&& other) + handler_alloc&& other) : h_(std::move(other.h_)) { } template handler_alloc( - handler_alloc const& other) + handler_alloc const& other) : h_(other.h_) { } @@ -127,7 +127,7 @@ public: friend bool operator==(handler_alloc const& lhs, - handler_alloc const& rhs) + handler_alloc const& rhs) { return true; } @@ -136,7 +136,7 @@ public: friend bool operator!=(handler_alloc const& lhs, - handler_alloc const& rhs) + handler_alloc const& rhs) { return !(lhs == rhs); } diff --git a/include/beast/handler_concepts.hpp b/include/beast/handler_concepts.hpp new file mode 100644 index 00000000..e0a4a89e --- /dev/null +++ b/include/beast/handler_concepts.hpp @@ -0,0 +1,27 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_HANDLER_CONCEPTS_HPP +#define BEAST_HANDLER_CONCEPTS_HPP + +#include +#include + +namespace beast { + +/// Determine if `T` meets the requirements of @b `CompletionHandler`. +template +#if GENERATING_DOCS +using is_CompletionHandler = std::integral_constant; +#else +using is_CompletionHandler = std::integral_constant::type>::value && + detail::is_call_possible::value>; +#endif +} // beast + +#endif diff --git a/include/beast/http.hpp b/include/beast/http.hpp index 7d6483a8..050b1493 100644 --- a/include/beast/http.hpp +++ b/include/beast/http.hpp @@ -5,12 +5,12 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_HPP_INCLUDED -#define BEAST_HTTP_HPP_INCLUDED +#ifndef BEAST_HTTP_HPP +#define BEAST_HTTP_HPP #include #include -#include +#include #include #include #include diff --git a/include/beast/http/basic_headers.hpp b/include/beast/http/basic_headers.hpp index 500d0b61..78e8b1e0 100644 --- a/include/beast/http/basic_headers.hpp +++ b/include/beast/http/basic_headers.hpp @@ -8,7 +8,6 @@ #ifndef BEAST_HTTP_BASIC_HEADERS_HPP #define BEAST_HTTP_BASIC_HEADERS_HPP -#include #include #include #include @@ -237,9 +236,20 @@ public: //------------------------------------------------------------------------------ -/** Container to store HTTP headers. +/** A container for storing HTTP headers. - Meets the requirements of `FieldSequence`. + This container is designed to store the field value pairs that make + up the headers and trailers in a HTTP message. Objects of this type + are iterable, which each element holding the field name and field + value. + + Field names are stored as-is, but comparison are case-insensitive. + The container preserves the order of insertion of fields with + different names. For fields with the same name, the implementation + concatenates values inserted with duplicate names as per the + rules in rfc2616 section 4.2. + + @note Meets the requirements of @b `FieldSequence`. */ template class basic_headers diff --git a/include/beast/http/basic_parser_v1.hpp b/include/beast/http/basic_parser_v1.hpp index c98d11ef..c9eb8e27 100644 --- a/include/beast/http/basic_parser_v1.hpp +++ b/include/beast/http/basic_parser_v1.hpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -43,49 +42,49 @@ enum values if those members are present (detected through SFINAE). The signatures which can be present in the derived class are:
- @li `void on_method(boost::string_ref const&, error_code& ec)` + @li `void on_method(boost::string_ref const&, error_code&)` Called for each piece of the Request-Method - @li `void on_uri(boost::string_ref const&, error_code& ec)` + @li `void on_uri(boost::string_ref const&, error_code&)` Called for each piece of the Request-URI - @li `void on_reason(boost::string_ref const&, error_code& ec)` + @li `void on_reason(boost::string_ref const&, error_code&)` Called for each piece of the reason-phrase - @li `void on_request(error_code& ec)` + @li `void on_request(error_code&)` Called after the entire Request-Line has been parsed successfully. - @li `void on_response(error_code& ec)` + @li `void on_response(error_code&)` Called after the entire Response-Line has been parsed successfully. - @li `void on_field(boost::string_ref const&, error_code& ec)` + @li `void on_field(boost::string_ref const&, error_code&)` Called for each piece of the current header field. - @li `void on_value(boost::string_ref const&, error_code& ec)` + @li `void on_value(boost::string_ref const&, error_code&)` Called for each piece of the current header value. - @li `int on_headers(error_code& ec)` + @li `int on_headers(error_code&)` Called when all the headers have been parsed successfully. - @li `void on_body(boost::string_ref const&, error_code& ec)` + @li `void on_body(boost::string_ref const&, error_code&)` Called for each piece of the body. If the headers indicated chunked encoding, the chunk encoding is removed from the buffer before being passed to the callback. - @li `void on_complete(error_code& ec)` + @li `void on_complete(error_code&)` Called when the entire message has been parsed successfully. - At this point, basic_parser_v1::complete() returns `true`, and - the parser is ready to parse another message if keep_alive() + At this point, @ref basic_parser_v1::complete returns `true`, and + the parser is ready to parse another message if keep_alive would return `true`. The return value of `on_headers` is special, it controls whether @@ -101,7 +100,7 @@ enum values The parser uses traits to determine if the callback is possible. If the Derived type omits one or more callbacks, they are simply - skipped with no compilation error. The default behavior of on_body + skipped with no compilation error. The default behavior of `on_body` when the derived class does not provide the member, is to specify that the body should not be skipped. @@ -354,12 +353,15 @@ public: @return The number of bytes consumed in the input sequence. */ - template::value>::type - > + template + #if GENERATING_DOCS std::size_t + #else + typename std::enable_if< + ! std::is_convertible::value, + std::size_t>::type + #endif write(ConstBufferSequence const& buffers, error_code& ec); /** Write a single buffer of data to the parser. @@ -380,8 +382,6 @@ public: Callbacks and errors will still be processed as usual. @note This is typically called when a socket read returns eof. - - @throws boost::system::system_error Thrown on failure. */ void write_eof(error_code& ec); diff --git a/include/beast/http/body_writer.hpp b/include/beast/http/body_type.hpp similarity index 67% rename from include/beast/http/body_writer.hpp rename to include/beast/http/body_type.hpp index a976bea5..2b88d57b 100644 --- a/include/beast/http/body_writer.hpp +++ b/include/beast/http/body_type.hpp @@ -5,11 +5,11 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_BODY_WRITER_HPP -#define BEAST_HTTP_BODY_WRITER_HPP +#ifndef BEAST_HTTP_BODY_TYPE_HPP +#define BEAST_HTTP_BODY_TYPE_HPP -// Convenience header to include everything necessary for -// declaring an object meeting the BodyWriter requirements. +// Convenience header to include everything +// needed when declarating a user defined Body type. #include #include diff --git a/include/beast/http/empty_body.hpp b/include/beast/http/empty_body.hpp index defe548b..7ac6d06a 100644 --- a/include/beast/http/empty_body.hpp +++ b/include/beast/http/empty_body.hpp @@ -8,7 +8,7 @@ #ifndef BEAST_HTTP_EMPTY_BODY_HPP #define BEAST_HTTP_EMPTY_BODY_HPP -#include +#include #include #include #include @@ -18,6 +18,8 @@ namespace beast { namespace http { /** An empty content-body. + + Meets the requirements of @b `Body`. */ struct empty_body { diff --git a/include/beast/http/error.hpp b/include/beast/http/error.hpp index d82d45bd..cf2aba23 100644 --- a/include/beast/http/error.hpp +++ b/include/beast/http/error.hpp @@ -9,6 +9,7 @@ #define BEAST_HTTP_ERROR_HPP #include +#include namespace beast { namespace http { diff --git a/include/beast/http/impl/basic_headers.ipp b/include/beast/http/impl/basic_headers.ipp index 27d52966..f1eb2f0b 100644 --- a/include/beast/http/impl/basic_headers.ipp +++ b/include/beast/http/impl/basic_headers.ipp @@ -8,8 +8,6 @@ #ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP #define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP -#include - namespace beast { namespace http { diff --git a/include/beast/http/impl/basic_parser_v1.ipp b/include/beast/http/impl/basic_parser_v1.ipp index 4a17e780..1050c22a 100644 --- a/include/beast/http/impl/basic_parser_v1.ipp +++ b/include/beast/http/impl/basic_parser_v1.ipp @@ -8,6 +8,8 @@ #ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP #define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP +#include + namespace beast { namespace http { @@ -32,8 +34,11 @@ keep_alive() const // Implementation inspired by nodejs/http-parser template -template -std::size_t +template +typename std::enable_if< + ! std::is_convertible::value, + std::size_t>::type basic_parser_v1:: write(ConstBufferSequence const& buffers, error_code& ec) { diff --git a/include/beast/http/impl/message_v1.ipp b/include/beast/http/impl/message_v1.ipp index 8a939592..153b6f4d 100644 --- a/include/beast/http/impl/message_v1.ipp +++ b/include/beast/http/impl/message_v1.ipp @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/include/beast/http/impl/read.ipp b/include/beast/http/impl/read.ipp index ff036712..7bd07cfe 100644 --- a/include/beast/http/impl/read.ipp +++ b/include/beast/http/impl/read.ipp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace beast { diff --git a/include/beast/http/impl/write.ipp b/include/beast/http/impl/write.ipp index 57fe6a12..b8364157 100644 --- a/include/beast/http/impl/write.ipp +++ b/include/beast/http/impl/write.ipp @@ -13,9 +13,10 @@ #include #include #include +#include #include +#include #include -#include #include #include #include diff --git a/include/beast/http/message.hpp b/include/beast/http/message.hpp index bb0ab957..1f417d95 100644 --- a/include/beast/http/message.hpp +++ b/include/beast/http/message.hpp @@ -9,7 +9,6 @@ #define BEAST_HTTP_MESSAGE_HPP #include -#include #include #include diff --git a/include/beast/http/message_v1.hpp b/include/beast/http/message_v1.hpp index 3f33ddfa..b5b4fe17 100644 --- a/include/beast/http/message_v1.hpp +++ b/include/beast/http/message_v1.hpp @@ -9,7 +9,6 @@ #define BEAST_HTTP_MESSAGE_V1_HPP #include -#include #include #include @@ -92,7 +91,7 @@ is_upgrade(message_v1 const& msg); /** HTTP/1 connection prepare options. - @note These values are used with `prepare`. + @note These values are used with @ref prepare. */ enum class connection { diff --git a/include/beast/http/read.hpp b/include/beast/http/read.hpp index e792961a..040d3371 100644 --- a/include/beast/http/read.hpp +++ b/include/beast/http/read.hpp @@ -19,17 +19,29 @@ namespace http { /** Read a HTTP/1 message from a stream. - @param stream The stream to read the message from. + This function is used to synchronously read a message from + the stream. The call blocks until one of the following conditions + is true: - @param streambuf A Streambuf used to hold unread bytes. The - implementation may read past the end of the message. The extra - bytes are stored here, to be presented in a subsequent call to - read. + @li A complete message is read in. - @param msg An object used to store the read message. Any + @li An error occurs on the stream. + + This function is implemented in terms of one or more calls to the + stream's `read_some` function. + + @param stream The stream to which the data is to be written. + The type must support the @b `SyncReadStream` concept. + + @param streambuf An object meeting the @b `Streambuf` type requirements + used to hold unread bytes. The implementation may read past the end of + the message. The extra bytes are stored here, to be presented in a + subsequent call to @ref read. + + @param msg An object used to store the message. Any contents will be overwritten. - @throws boost::system::system_error on failure. + @throws boost::system::system_error Thrown on failure. */ template @@ -43,17 +55,29 @@ read(SyncReadStream& stream, Streambuf& streambuf, throw boost::system::system_error{ec}; } -/** Read a HTTP message from a stream. +/** Read a HTTP/1 message from a stream. - @param stream The stream to read the message from. + This function is used to synchronously read a message from + the stream. The call blocks until one of the following conditions + is true: - @param streambuf A Streambuf used to hold unread bytes. The - implementation may read past the end of the message. The extra - bytes are stored here, to be presented in a subsequent call to - read. + @li A complete message is read in. - @param msg An object used to store the read message. Any - contents will be overwritten. + @li An error occurs on the stream. + + This function is implemented in terms of one or more calls to the + stream's `read_some` function. + + @param stream The stream to which the data is to be written. + The type must support the @b `SyncReadStream` concept. + + @param streambuf An object meeting the @b `Streambuf` type requirements + used to hold unread bytes. The implementation may read past the end of + the message. The extra bytes are stored here, to be presented in a + subsequent call to @ref read. + + @param msg An object used to store the message. Any contents + will be overwritten. @param ec Set to the error, if any occurred. */ @@ -64,17 +88,31 @@ read(SyncReadStream& stream, Streambuf& streambuf, message_v1& msg, error_code& ec); -/** Start reading a HTTP message from a stream asynchronously. +/** Start an asynchronous operation to read a HTTP/1 message from a stream. + + This function is used to asynchronously read a message from the + stream. The function call always returns immediately. The asynchronous + operation will continue until one of the following conditions is true: + + @li A complete message is read in. + + @li An error occurs on the stream. + + This operation is implemented in terms of one or more calls to the + next layer's `async_read_some` function, and is known as a + composed operation. The program must ensure that the stream + performs no other operations until this operation completes. @param stream The stream to read the message from. + The type must support the @b `AsyncReadStream` concept. @param streambuf A Streambuf used to hold unread bytes. The implementation may read past the end of the message. The extra bytes are stored here, to be presented in a subsequent call to - async_read. + @ref async_read. - @param msg An object used to store the read message. Any - contents will be overwritten. + @param msg An object used to store the message. Any contents + will be overwritten. @param handler The handler to be called when the request completes. Copies will be made of the handler as required. The equivalent @@ -85,7 +123,7 @@ read(SyncReadStream& stream, Streambuf& streambuf, Regardless of whether the asynchronous operation completes immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a - manner equivalent to using boost::asio::io_service::post(). + manner equivalent to using `boost::asio::io_service::post`. */ template +#include #include #include #include @@ -17,7 +17,9 @@ namespace beast { namespace http { -/** A Body represented by a Streambuf +/** A message body represented by a Streambuf + + Meets the requirements of @b `Body`. */ template struct basic_streambuf_body @@ -34,10 +36,10 @@ private: value_type& sb_; public: - template + template explicit reader(message& m) noexcept + basic_streambuf_body, Headers>& m) noexcept : sb_(m.body) { } diff --git a/include/beast/http/string_body.hpp b/include/beast/http/string_body.hpp index f852bbd0..fa5ec654 100644 --- a/include/beast/http/string_body.hpp +++ b/include/beast/http/string_body.hpp @@ -8,7 +8,7 @@ #ifndef BEAST_HTTP_STRING_BODY_HPP #define BEAST_HTTP_STRING_BODY_HPP -#include +#include #include #include #include @@ -18,6 +18,8 @@ namespace beast { namespace http { /** A Body represented by a std::string. + + Meets the requirements of @b `Body`. */ struct string_body { @@ -33,10 +35,10 @@ private: value_type& s_; public: - template + template explicit reader(message& m) noexcept + string_body, Headers>& m) noexcept : s_(m.body) { } diff --git a/include/beast/http/write.hpp b/include/beast/http/write.hpp index 22aa2e76..617919b8 100644 --- a/include/beast/http/write.hpp +++ b/include/beast/http/write.hpp @@ -18,13 +18,30 @@ namespace beast { namespace http { -/** Write a HTTP/1 message to a stream. +/** Write a HTTP/1 message on a stream. - @param stream The stream to send the message on. + This function is used to write a message to a stream. The call + will block until one of the following conditions is true: - @param msg The message to send. + @li The entire message is sent. - @throws boost::system::error code on failure. + @li An error occurs. + + This operation is implemented in terms of one or more calls + to the stream's `write_some` function. + + The implementation will automatically perform chunk encoding if + the contents of the message indicate that chunk encoding is required. + If the semantics of the message indicate that the connection should + be closed after the message is sent, the error returns from this + function will be `boost::asio::error::eof`. + + @param stream The stream to which the data is to be written. + The type must support the @b `SyncWriteStream` concept. + + @param msg The message to write. + + @throws boost::system::error Thrown on failure. */ template @@ -32,11 +49,28 @@ void write(SyncWriteStream& stream, message_v1 const& msg); -/** Write a HTTP/1 message to a stream. +/** Write a HTTP/1 message on a stream. - @param stream The stream to send the message on. + This function is used to write a message to a stream. The call + will block until one of the following conditions is true: - @param msg The message to send. + @li The entire message is sent. + + @li An error occurs. + + This operation is implemented in terms of one or more calls + to the stream's `write_some` function. + + The implementation will automatically perform chunk encoding if + the contents of the message indicate that chunk encoding is required. + If the semantics of the message indicate that the connection should + be closed after the message is sent, the error returns from this + function will be `boost::asio::error::eof`. + + @param stream The stream to which the data is to be written. + The type must support the @b `SyncWriteStream` concept. + + @param msg The message to write. @param ec Set to the error, if any occurred. */ @@ -47,13 +81,35 @@ write(SyncWriteStream& stream, message_v1 const& msg, error_code& ec); -/** Start writing a HTTP/1 message to a stream asynchronously. +/** Start an asynchronous operation to write a HTTP/1 message to a stream. - @param stream The stream to send the message on. + This function is used to asynchronously write a message to a stream. + The function call always returns immediately. The asynchronous + operation will continue until one of the following conditions is true: + + @li The entire message is sent. + + @li An error occurs. + + This operation is implemented in terms of one or more calls to the + stream's `async_write_some` functions, and is known as a composed + operation. The program must ensure that the stream performs no + other write operations (such as @ref async_write, the stream's + `async_write_some` function, or any other composed operations that + perform writes) until this operation completes. + + The implementation will automatically perform chunk encoding if + the contents of the message indicate that chunk encoding is required. + If the semantics of the message indicate that the connection should + be closed after the message is sent, the operation will complete with + the error set to `boost::asio::error::eof`. + + @param stream The stream to which the data is to be written. + The type must support the @b `AsyncWriteStream` concept. @param msg The message to send. - @param token The handler to be called when the request completes. + @param handler The handler to be called when the request completes. Copies will be made of the handler as required. The equivalent function signature of the handler must be: @code void handler( @@ -62,9 +118,9 @@ write(SyncWriteStream& stream, Regardless of whether the asynchronous operation completes immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a - manner equivalent to using boost::asio::io_service::post(). + manner equivalent to using `boost::asio::io_service::post`. - @note The message must remain valid at least until the + @note The message object must remain valid at least until the completion handler is called, no copies are made. */ template #include #include #include @@ -849,22 +850,6 @@ basic_streambuf::debug_check() const #endif } -template -basic_streambuf& -operator<<(basic_streambuf& streambuf, T const& t) -{ - using boost::asio::buffer; - using boost::asio::buffer_copy; - std::stringstream ss; - ss << t; - auto const& s = ss.str(); - streambuf.commit(buffer_copy( - streambuf.prepare(s.size()), buffer(s))); - return streambuf; -} - -//------------------------------------------------------------------------------ - template std::size_t read_size_helper(basic_streambuf< @@ -874,17 +859,12 @@ read_size_helper(basic_streambuf< std::max(512, streambuf.prepare_size())); } -template -std::string -to_string(basic_streambuf const& streambuf) +template +basic_streambuf& +operator<<(basic_streambuf& streambuf, T const& t) { - using boost::asio::buffer; - using boost::asio::buffer_copy; - std::string s; - s.resize(streambuf.size()); - buffer_copy( - buffer(&s[0], s.size()), streambuf.data()); - return s; + detail::write_streambuf(streambuf, t); + return streambuf; } } // beast diff --git a/include/beast/impl/buffers_adapter.ipp b/include/beast/impl/buffers_adapter.ipp index d0b22c6a..ec2fc614 100644 --- a/include/beast/impl/buffers_adapter.ipp +++ b/include/beast/impl/buffers_adapter.ipp @@ -17,8 +17,9 @@ namespace beast { -template -class buffers_adapter::const_buffers_type +template +class buffers_adapter:: + const_buffers_type { buffers_adapter const* ba_; @@ -48,8 +49,9 @@ private: } }; -template -class buffers_adapter::const_buffers_type::const_iterator +template +class buffers_adapter:: + const_buffers_type::const_iterator { iter_type it_; buffers_adapter const* ba_ = nullptr; @@ -136,19 +138,19 @@ private: } }; -template +template inline auto -buffers_adapter::const_buffers_type::begin() const -> +buffers_adapter::const_buffers_type::begin() const -> const_iterator { return const_iterator{*ba_, ba_->begin_}; } -template +template inline auto -buffers_adapter::const_buffers_type::end() const -> +buffers_adapter::const_buffers_type::end() const -> const_iterator { return const_iterator{*ba_, ba_->out_ == @@ -157,8 +159,9 @@ buffers_adapter::const_buffers_type::end() const -> //------------------------------------------------------------------------------ -template -class buffers_adapter::mutable_buffers_type +template +class buffers_adapter:: +mutable_buffers_type { buffers_adapter const* ba_; @@ -189,8 +192,9 @@ private: } }; -template -class buffers_adapter::mutable_buffers_type::const_iterator +template +class buffers_adapter:: +mutable_buffers_type::const_iterator { iter_type it_; buffers_adapter const* ba_ = nullptr; @@ -277,19 +281,19 @@ private: } }; -template +template inline auto -buffers_adapter::mutable_buffers_type::begin() const -> +buffers_adapter::mutable_buffers_type::begin() const -> const_iterator { return const_iterator{*ba_, ba_->out_}; } -template +template inline auto -buffers_adapter::mutable_buffers_type::end() const -> +buffers_adapter::mutable_buffers_type::end() const -> const_iterator { return const_iterator{*ba_, ba_->end_}; @@ -297,8 +301,8 @@ buffers_adapter::mutable_buffers_type::end() const -> //------------------------------------------------------------------------------ -template -buffers_adapter::buffers_adapter( +template +buffers_adapter::buffers_adapter( buffers_adapter&& other) : buffers_adapter(std::move(other), std::distance(other.bs_.begin(), other.begin_), @@ -307,8 +311,8 @@ buffers_adapter::buffers_adapter( { } -template -buffers_adapter::buffers_adapter( +template +buffers_adapter::buffers_adapter( buffers_adapter const& other) : buffers_adapter(other, std::distance(other.bs_.begin(), other.begin_), @@ -317,9 +321,9 @@ buffers_adapter::buffers_adapter( { } -template +template auto -buffers_adapter::operator=( +buffers_adapter::operator=( buffers_adapter&& other) -> buffers_adapter& { auto const nbegin = std::distance( @@ -340,9 +344,9 @@ buffers_adapter::operator=( return *this; } -template +template auto -buffers_adapter::operator=( +buffers_adapter::operator=( buffers_adapter const& other) -> buffers_adapter& { auto const nbegin = std::distance( @@ -363,9 +367,9 @@ buffers_adapter::operator=( return *this; } -template -buffers_adapter::buffers_adapter( - Buffers const& bs) +template +buffers_adapter::buffers_adapter( + MutableBufferSequence const& bs) : bs_(bs) , begin_(bs_.begin()) , out_(bs_.begin()) @@ -374,14 +378,12 @@ buffers_adapter::buffers_adapter( { } -template +template auto -buffers_adapter::prepare(std::size_t n) -> +buffers_adapter::prepare(std::size_t n) -> mutable_buffers_type { using boost::asio::buffer_size; - static_assert(is_mutable, - "Operation not valid for ConstBufferSequence"); end_ = out_; if(end_ != bs_.end()) { @@ -416,13 +418,11 @@ buffers_adapter::prepare(std::size_t n) -> return mutable_buffers_type{*this}; } -template +template void -buffers_adapter::commit(std::size_t n) +buffers_adapter::commit(std::size_t n) { using boost::asio::buffer_size; - static_assert(is_mutable, - "Operation not valid for ConstBufferSequence"); if(out_ == end_) return; auto const last = std::prev(end_); @@ -456,18 +456,18 @@ buffers_adapter::commit(std::size_t n) } } -template +template inline auto -buffers_adapter::data() const -> +buffers_adapter::data() const -> const_buffers_type { return const_buffers_type{*this}; } -template +template void -buffers_adapter::consume(std::size_t n) +buffers_adapter::consume(std::size_t n) { for(;;) { diff --git a/include/beast/impl/consuming_buffers.ipp b/include/beast/impl/consuming_buffers.ipp index 864bde3a..748892e2 100644 --- a/include/beast/impl/consuming_buffers.ipp +++ b/include/beast/impl/consuming_buffers.ipp @@ -8,7 +8,7 @@ #ifndef BEAST_IMPL_CONSUMING_BUFFERS_IPP #define BEAST_IMPL_CONSUMING_BUFFERS_IPP -#include +#include #include #include #include @@ -18,13 +18,13 @@ namespace beast { -template -class consuming_buffers::const_iterator +template +class consuming_buffers::const_iterator { - friend class consuming_buffers; + friend class consuming_buffers; using iter_type = - typename Buffers::const_iterator; + typename BufferSequence::const_iterator; iter_type it_; consuming_buffers const* b_ = nullptr; @@ -105,8 +105,8 @@ private: } }; -template -consuming_buffers:: +template +consuming_buffers:: consuming_buffers(consuming_buffers&& other) : consuming_buffers(std::move(other), std::distance( @@ -114,8 +114,8 @@ consuming_buffers(consuming_buffers&& other) { } -template -consuming_buffers:: +template +consuming_buffers:: consuming_buffers(consuming_buffers const& other) : consuming_buffers(other, std::distance( @@ -123,9 +123,9 @@ consuming_buffers(consuming_buffers const& other) { } -template +template auto -consuming_buffers:: +consuming_buffers:: operator=(consuming_buffers&& other) -> consuming_buffers& { @@ -137,9 +137,9 @@ operator=(consuming_buffers&& other) -> return *this; } -template +template auto -consuming_buffers:: +consuming_buffers:: operator=(consuming_buffers const& other) -> consuming_buffers& { @@ -151,35 +151,35 @@ operator=(consuming_buffers const& other) -> return *this; } -template -consuming_buffers:: -consuming_buffers(Buffers const& bs) +template +consuming_buffers:: +consuming_buffers(BufferSequence const& bs) : bs_(bs) , begin_(bs_.begin()) { - static_assert(is_BufferSequence::value, + static_assert(is_BufferSequence::value, "BufferSequence requirements not met"); } -template +template auto -consuming_buffers::begin() const -> +consuming_buffers::begin() const -> const_iterator { return const_iterator{*this, begin_}; } -template +template auto -consuming_buffers::end() const -> +consuming_buffers::end() const -> const_iterator { return const_iterator{*this, bs_.end()}; } -template +template void -consuming_buffers::consume(std::size_t n) +consuming_buffers::consume(std::size_t n) { using boost::asio::buffer_size; for(;n > 0 && begin_ != bs_.end(); ++begin_) @@ -196,11 +196,11 @@ consuming_buffers::consume(std::size_t n) } } -template -consuming_buffers -consumed_buffers(Buffers const& bs, std::size_t n) +template +consuming_buffers +consumed_buffers(BufferSequence const& bs, std::size_t n) { - consuming_buffers cb(bs); + consuming_buffers cb(bs); cb.consume(n); return cb; } diff --git a/include/beast/impl/streambuf_readstream.ipp b/include/beast/impl/streambuf_readstream.ipp index ec1744c9..6de6d212 100644 --- a/include/beast/impl/streambuf_readstream.ipp +++ b/include/beast/impl/streambuf_readstream.ipp @@ -9,7 +9,10 @@ #define BEAST_IMPL_STREAMBUF_READSTREAM_IPP #include +#include #include +#include +#include namespace beast { @@ -157,8 +160,6 @@ streambuf_readstream:: streambuf_readstream(Args&&... args) : next_layer_(std::forward(args)...) { - static_assert(is_Streambuf::value, - "Streambuf requirements not met"); } template @@ -175,7 +176,7 @@ async_write_some(ConstBufferSequence const& buffers, static_assert(is_ConstBufferSequence< ConstBufferSequence>::value, "ConstBufferSequence requirements not met"); - static_assert(is_Handler::value, "WriteHandler requirements not met"); return next_layer_.async_write_some(buffers, diff --git a/include/beast/static_streambuf.hpp b/include/beast/static_streambuf.hpp index 36c298d6..add19212 100644 --- a/include/beast/static_streambuf.hpp +++ b/include/beast/static_streambuf.hpp @@ -15,15 +15,15 @@ namespace beast { -/** A `Streambuf` with a fixed size internal buffer. +/** A @b `Streambuf` with a fixed size internal buffer. Ownership of the underlying storage belongs to the derived class. @note Variables are usually declared using the template class - `static_streambuf_n`; however, to reduce the number of instantiations + @ref static_streambuf_n; however, to reduce the number of instantiations of template functions receiving static stream buffer arguments in a deduced context, the signature of the receiving function should use - `static_streambuf`. + @ref static_streambuf. */ class static_streambuf { @@ -75,18 +75,28 @@ public: @throws std::length_error if the size would exceed the limit imposed by the underlying mutable buffer sequence. + + @note Buffers representing the input sequence acquired prior to + this call remain valid. */ mutable_buffers_type prepare(std::size_t n); - /// Move bytes from the output sequence to the input sequence. + /** Move bytes from the output sequence to the input sequence. + + @note Buffers representing the input sequence acquired prior to + this call remain valid. + */ void commit(std::size_t n) { out_ += std::min(n, last_ - out_); } - /// Get a list of buffers that represents the input sequence. + /** Get a list of buffers that represents the input sequence. + + @note These buffers remain valid across subsequent calls to `prepare`. + */ const_buffers_type data() const; @@ -129,9 +139,11 @@ protected: */ template class static_streambuf_n - : private boost::base_from_member< + : public static_streambuf +#if ! GENERATING_DOCS + , private boost::base_from_member< std::array> - , public static_streambuf +#endif { using member_type = boost::base_from_member< std::array>; diff --git a/include/beast/static_string.hpp b/include/beast/static_string.hpp index 3bf1fb8f..47584f7a 100644 --- a/include/beast/static_string.hpp +++ b/include/beast/static_string.hpp @@ -20,7 +20,6 @@ #ifndef BEAST_WEBSOCKET_STATIC_STRING_HPP #define BEAST_WEBSOCKET_STATIC_STRING_HPP -#include #include #include #include @@ -28,13 +27,11 @@ #include namespace beast { -namespace websocket { /** A string with a fixed-size storage area. - `static_string` objects behave like `std::string` except that - the storage is not dynamically allocated but rather fixed in - size. + These objects behave like `std::string` except that the storage + is not dynamically allocated but rather fixed in size. These strings offer performance advantages when a protocol imposes a natural small upper limit on the size of a value. @@ -281,7 +278,7 @@ public: { return N; } - + /// Reduces memory usage by freeing unused memory. void shrink_to_fit() @@ -401,7 +398,7 @@ operator=(const CharT (&s)[M]) -> static_assert(M-1 <= N, "static_string overflow"); n_ = M-1; - std::copy(&s[0], &s[M], &s_[0]); + Traits::copy(&s_[0], &s[0], M); return *this; } @@ -690,7 +687,6 @@ bool operator>=( #endif -} // websocket } // beast #endif diff --git a/include/beast/stream_concepts.hpp b/include/beast/stream_concepts.hpp new file mode 100644 index 00000000..ec07f0f3 --- /dev/null +++ b/include/beast/stream_concepts.hpp @@ -0,0 +1,76 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_STREAM_CONCEPTS_HPP +#define BEAST_STREAM_CONCEPTS_HPP + +#include +#include + +namespace beast { + +/// Determine if `T` has the `get_io_service` member. +template +#if GENERATING_DOCS +struct has_get_io_service : std::integral_constant{}; +#else +using has_get_io_service = typename detail::has_get_io_service::type; +#endif + +/// Determine if `T` meets the requirements of @b `AsyncReadStream`. +template +#if GENERATING_DOCS +struct is_AsyncReadStream : std::integral_constant{}; +#else +using is_AsyncReadStream = typename detail::is_AsyncReadStream::type; +#endif + +/// Determine if `T` meets the requirements of @b `AsyncWriteStream`. +template +#if GENERATING_DOCS +struct is_AsyncWriteStream : std::integral_constant{}; +#else +using is_AsyncWriteStream = typename detail::is_AsyncWriteStream::type; +#endif + +/// Determine if `T` meets the requirements of @b `SyncReadStream`. +template +#if GENERATING_DOCS +struct is_SyncReadStream : std::integral_constant{}; +#else +using is_SyncReadStream = typename detail::is_SyncReadStream::type; +#endif + +/// Determine if `T` meets the requirements of @b `SyncWriterStream`. +template +#if GENERATING_DOCS +struct is_SyncWriteStream : std::integral_constant{}; +#else +using is_SyncWriteStream = typename detail::is_SyncWriteStream::type; +#endif + +/// Determine if `T` meets the requirements of @b `AsyncStream`. +template +#if GENERATING_DOCS +struct is_AsyncStream : std::integral_constant{}; +#else +using is_AsyncStream = std::integral_constant::value && is_AsyncWriteStream::value>; +#endif + +/// Determine if `T` meets the requirements of @b `SyncStream`. +template +#if GENERATING_DOCS +struct is_SyncStream : std::integral_constant{}; +#else +using is_SyncStream = std::integral_constant::value && is_SyncWriteStream::value>; +#endif + +} // beast + +#endif diff --git a/include/beast/streambuf.hpp b/include/beast/streambuf.hpp index 04ab4b3e..cc30b817 100644 --- a/include/beast/streambuf.hpp +++ b/include/beast/streambuf.hpp @@ -12,6 +12,15 @@ namespace beast { +/** A @b `Streambuf` that uses multiple buffers internally. + + The implementation uses a sequence of one or more character arrays + of varying sizes. Additional character array objects are appended to + the sequence to accommodate changes in the size of the character + sequence. + + @note Meets the requirements of @b `Streambuf`. +*/ using streambuf = basic_streambuf>; } // beast diff --git a/include/beast/streambuf_readstream.hpp b/include/beast/streambuf_readstream.hpp index 869f1784..75c0d5bc 100644 --- a/include/beast/streambuf_readstream.hpp +++ b/include/beast/streambuf_readstream.hpp @@ -9,8 +9,9 @@ #define BEAST_STREAMBUF_READSTREAM_HPP #include +#include +#include #include -#include #include #include #include @@ -20,11 +21,11 @@ namespace beast { -/** A `Stream` with attached `Streambuf` to buffer reads. +/** A @b `Stream` with attached @b `Streambuf` to buffer reads. - This wraps a `Stream` implementation so that calls to write are + This wraps a @b `Stream` implementation so that calls to write are passed through to the underlying stream, while calls to read will - first consume the input sequence stored in a `Streambuf` which + first consume the input sequence stored in a @b `Streambuf` which is part of the object. The use-case for this class is different than that of the @@ -37,10 +38,10 @@ namespace beast { Uses: - * Transparently leave untouched input acquired in calls + @li Transparently leave untouched input acquired in calls to `boost::asio::read_until` behind for subsequent callers. - * "Preload" a stream with handshake input data acquired + @li "Preload" a stream with handshake input data acquired from other sources. Example: @@ -88,6 +89,9 @@ namespace beast { template class streambuf_readstream { + static_assert(is_Streambuf::value, + "Streambuf requirements not met"); + using error_code = boost::system::error_code; template @@ -107,8 +111,12 @@ public: /// The type of the lowest layer. using lowest_layer_type = +#if GENERATING_DOCS + implementation_defined; +#else typename detail::get_lowest_layer< next_layer_type>::type; +#endif /** Move constructor. @@ -233,8 +241,11 @@ public: /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. template - typename async_completion< - WriteHandler, void(error_code)>::result_type +#if GENERATING_DOCS + void_or_deduced +#else + typename async_completion::result_type +#endif async_write_some(ConstBufferSequence const& buffers, WriteHandler&& handler); @@ -254,8 +265,11 @@ public: /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. template - typename async_completion< - ReadHandler, void(error_code)>::result_type +#if GENERATING_DOCS + void_or_deduced +#else + typename async_completion::result_type +#endif async_read_some(MutableBufferSequence const& buffers, ReadHandler&& handler); }; diff --git a/include/beast/to_string.hpp b/include/beast/to_string.hpp index a21c7e09..711483cd 100644 --- a/include/beast/to_string.hpp +++ b/include/beast/to_string.hpp @@ -8,24 +8,24 @@ #ifndef BEAST_TO_STRING_HPP #define BEAST_TO_STRING_HPP -#include +#include #include #include namespace beast { -/** Convert a `ConstBufferSequence` to a `std::string`. +/** Convert a @b `ConstBufferSequence` to a `std::string`. This function will convert the octets in a buffer sequence to a string. All octets will be inserted into the resulting string, including null or unprintable characters. @param buffers The buffer sequence to convert. - - @returns A string representing the contents of the input area. + + @return A string representing the contents of the input area. @note This function participates in overload resolution only if - the streambuf parameter meets the requirements of Streambuf. + the streambuf parameter meets the requirements of @b `Streambuf`. */ template -#include -#include -#include -#include -#include -#include - -namespace beast { - -//------------------------------------------------------------------------------ - -// Types that meet the requirements, -// for use with std::declval only. -// - -#if GENERATING_DOCS -namespace detail { -#else -namespace concept { -#endif - -template -struct BufferSequence -{ - using value_type = BufferType; - using const_iterator = BufferType const*; - ~BufferSequence(); - BufferSequence(BufferSequence const&) = default; - const_iterator - begin() const noexcept; - const_iterator - end() const noexcept; -}; - -using ConstBufferSequence = - BufferSequence; - -using MutableBufferSequence = - BufferSequence; - -struct StreamHandler -{ - StreamHandler(StreamHandler const&) = default; - void - operator()(boost::system::error_code ec, - std::size_t); -}; - -using ReadHandler = StreamHandler; -using WriteHandler = StreamHandler; - -} // concept - -// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html -// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html -// -/// Determine if `T` meets the requirements of `BufferSequence`. -template -class is_BufferSequence -{ - template > - static R check1(int); - template - static std::false_type check1(...); - using type1 = decltype(check1(0)); - - template::iterator_category>> - #else - // workaround: - // boost::asio::detail::consuming_buffers::const_iterator - // is not bidirectional - std::forward_iterator_tag, - typename std::iterator_traits< - typename U::const_iterator>::iterator_category>> - #endif - static R check2(int); - template - static std::false_type check2(...); - using type2 = decltype(check2(0)); - - template().begin()), - typename U::const_iterator>::type> - static R check3(int); - template - static std::false_type check3(...); - using type3 = decltype(check3(0)); - - template().end()), - typename U::const_iterator>::type> - static R check4(int); - template - static std::false_type check4(...); - using type4 = decltype(check4(0)); - -public: - /// `true` if `T` meets the requirements. - static bool const value = - std::is_copy_constructible::value && - std::is_destructible::value && - type1::value && type2::value && - type3::value && type4::value; -}; - -#if ! GENERATING_DOCS - -/// Determine if `T` meets the requirements of `ConstBufferSequence`. -template -using is_ConstBufferSequence = - is_BufferSequence; -static_assert(is_ConstBufferSequence::value, ""); -static_assert(! is_ConstBufferSequence::value, ""); - -/// Determine if `T` meets the requirements of `MutableBufferSequence`. -template -using is_MutableBufferSequence = - is_BufferSequence; -static_assert(is_MutableBufferSequence::value, ""); -static_assert(! is_MutableBufferSequence::value, ""); - -#endif - -//------------------------------------------------------------------------------ - -/// Determine if `T` has the `get_io_service` member. -template -class has_get_io_service -{ - template().get_io_service()), - boost::asio::io_service&>> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - -public: - /// `true` if `T` meets the requirements. - static bool const value = type::value; -}; -static_assert(! has_get_io_service::value, ""); - -// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html -// -/// Determine if `T` meets the requirements of `AsyncReadStream`. -template -class is_AsyncReadStream -{ - template().async_read_some( - std::declval(), - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - -public: - /// `true` if `T` meets the requirements. - static bool const value = - has_get_io_service::value && type::value; -}; -static_assert(! is_AsyncReadStream::value, ""); - -// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html -// -/// Determine if `T` meets the requirements of `AsyncWriteStream`. -template -class is_AsyncWriteStream -{ - template().async_write_some( - std::declval(), - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - -public: - /// `true` if `T` meets the requirements. - static bool const value = - has_get_io_service::value && type::value; -}; -static_assert(! is_AsyncWriteStream::value, ""); - -// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html -// -/// Determine if `T` meets the requirements of `SyncReadStream`. -template -class is_SyncReadStream -{ - using error_code = - boost::system::error_code; - - template().read_some( - std::declval())), - std::size_t>> - static R check1(int); - template - static std::false_type check1(...); - using type1 = decltype(check1(0)); - - template().read_some( - std::declval(), - std::declval())), std::size_t>> - static R check2(int); - template - static std::false_type check2(...); - using type2 = decltype(check2(0)); - -public: - /// `true` if `T` meets the requirements. - static bool const value = - type1::value && type2::value; -}; -static_assert(! is_SyncReadStream::value, ""); - -// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html -// -/// Determine if `T` meets the requirements of `SyncWriterStream`. -template -class is_SyncWriteStream -{ - using error_code = - boost::system::error_code; - - template().write_some( - std::declval())), - std::size_t>> - static R check1(int); - template - static std::false_type check1(...); - using type1 = decltype(check1(0)); - - template().write_some( - std::declval(), - std::declval())), std::size_t>> - static R check2(int); - template - static std::false_type check2(...); - using type2 = decltype(check2(0)); - -public: - /// `true` if `T` meets the requirements. - static bool const value = - type1::value && type2::value; -}; -static_assert(! is_SyncWriteStream::value, ""); - -/// Determine if `T` meets the requirements of `SyncStream`. -template -struct is_SyncStream -{ - /// `true` if `T` meets the requirements. - static bool const value = - is_SyncReadStream::value && - is_SyncWriteStream::value; -}; - -/// Determine if `T` meets the requirements of `SyncStream`. -template -struct is_AsyncStream -{ - /// `true` if `T` meets the requirements. - static bool const value = - is_AsyncReadStream::value && - is_AsyncWriteStream::value; -}; - -/// Determine if `T` meets the requirements of `Streambuf`. -template -class is_Streambuf -{ - template().prepare(1))>::value>> - static R check1(int); - template - static std::false_type check1(...); - using type1 = decltype(check1(0)); - - template().data())>::value>> - static R check2(int); - template - static std::false_type check2(...); - using type2 = decltype(check2(0)); - - template().commit(1), std::true_type{})> - static R check3(int); - template - static std::false_type check3(...); - using type3 = decltype(check3(0)); - - template().consume(1), std::true_type{})> - static R check4(int); - template - static std::false_type check4(...); - using type4 = decltype(check4(0)); - - template().size()), std::size_t>> - static R check5(int); - template - static std::false_type check5(...); - using type5 = decltype(check5(0)); - -public: - /// `true` if `T` meets the requirements. - static bool const value = - type1::value && type2::value && - type3::value && type4::value && - type5::value; -}; - -#if ! GENERATING_DOCS - -/// Determine if `T` meets the requirements of `CompletionHandler`. -template -using is_Handler = std::integral_constant::type>::value && - detail::is_call_possible::value>; - -#endif - -} // beast - -#endif diff --git a/include/beast/websocket/detail/debug.hpp b/include/beast/websocket/detail/debug.hpp index 91de367b..e86e2e59 100644 --- a/include/beast/websocket/detail/debug.hpp +++ b/include/beast/websocket/detail/debug.hpp @@ -17,10 +17,9 @@ */ //============================================================================== -#ifndef BEAST_WSPROTO_DEBUG_H_INCLUDED -#define BEAST_WSPROTO_DEBUG_H_INCLUDED +#ifndef BEAST_WEBSOCKET_DETAIL_DEBUG_HPP +#define BEAST_WEBSOCKET_DETAIL_DEBUG_HPP -#include #include #include #include @@ -82,7 +81,7 @@ format(std::string s) } } // detail -} // wsproto +} // websocket } // beast #endif diff --git a/include/beast/websocket/detail/error.hpp b/include/beast/websocket/detail/error.hpp index 0495a9ae..5aa1cf74 100644 --- a/include/beast/websocket/detail/error.hpp +++ b/include/beast/websocket/detail/error.hpp @@ -30,7 +30,7 @@ public: const char* name() const noexcept override { - return "wsproto"; + return "websocket"; } std::string @@ -50,7 +50,7 @@ public: case error::request_invalid: return "upgrade request invalid"; case error::request_denied: return "upgrade request denied"; default: - return "wsproto.error"; + return "websocket error"; } } diff --git a/include/beast/websocket/error.hpp b/include/beast/websocket/error.hpp index 09cbdcc1..fa00cef2 100644 --- a/include/beast/websocket/error.hpp +++ b/include/beast/websocket/error.hpp @@ -9,6 +9,7 @@ #define BEAST_WEBSOCKET_ERROR_HPP #include +#include namespace beast { namespace websocket { @@ -16,7 +17,7 @@ namespace websocket { /// The type of error used by functions and completion handlers. using error_code = boost::system::error_code; -/// Error values +/// Error codes returned from @ref stream operations. enum class error { /// Both sides performed a WebSocket close @@ -50,8 +51,10 @@ enum class error request_denied }; +#if ! GENERATING_DOCS error_code make_error_code(error e); +#endif } // websocket } // beast diff --git a/include/beast/websocket/impl/read_frame_op.ipp b/include/beast/websocket/impl/read_frame_op.ipp index 46613690..c4dbd225 100644 --- a/include/beast/websocket/impl/read_frame_op.ipp +++ b/include/beast/websocket/impl/read_frame_op.ipp @@ -396,7 +396,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) // teardown case 11: d.state = 12; - wsproto_helpers::call_async_teardown( + websocket_helpers::call_async_teardown( d.ws.next_layer(), std::move(*this)); return; @@ -482,7 +482,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) // teardown case 19: d.state = 20; - wsproto_helpers::call_async_teardown( + websocket_helpers::call_async_teardown( d.ws.next_layer(), std::move(*this)); return; diff --git a/include/beast/websocket/impl/ssl.ipp b/include/beast/websocket/impl/ssl.ipp index 5f054f28..54951b85 100644 --- a/include/beast/websocket/impl/ssl.ipp +++ b/include/beast/websocket/impl/ssl.ipp @@ -9,7 +9,7 @@ #define BEAST_WEBSOCKET_IMPL_SSL_IPP_INCLUDED #include -#include +#include namespace beast { namespace websocket { @@ -144,7 +144,7 @@ async_teardown( boost::asio::ssl::stream& stream, TeardownHandler&& handler) { - static_assert(beast::is_Handler< + static_assert(beast::is_CompletionHandler< TeardownHandler, void(error_code)>::value, "TeardownHandler requirements not met"); detail::teardown_ssl_op #include #include -#include -#include -#include -#include -#include -#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -613,7 +614,7 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec) if(error_) return; } - wsproto_helpers::call_teardown(next_layer(), ec); + websocket_helpers::call_teardown(next_layer(), ec); error_ = ec != 0; if(error_) return; @@ -622,7 +623,7 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec) return; } if(! ec) - wsproto_helpers::call_teardown(next_layer(), ec); + websocket_helpers::call_teardown(next_layer(), ec); if(! ec) ec = error::closed; error_ = ec != 0; diff --git a/include/beast/websocket/impl/teardown.ipp b/include/beast/websocket/impl/teardown.ipp index 689f647e..61c700f9 100644 --- a/include/beast/websocket/impl/teardown.ipp +++ b/include/beast/websocket/impl/teardown.ipp @@ -9,7 +9,7 @@ #define BEAST_WEBSOCKET_IMPL_TEARDOWN_IPP #include -#include +#include #include namespace beast { @@ -157,7 +157,7 @@ async_teardown( boost::asio::ip::tcp::socket& socket, TeardownHandler&& handler) { - static_assert(beast::is_Handler< + static_assert(beast::is_CompletionHandler< TeardownHandler, void(error_code)>::value, "TeardownHandler requirements not met"); detail::teardown_tcp_opRFC 6455 7.4.1 Defined Status Codes + */ +#if GENERATING_DOCS +enum close_code +#else namespace close_code { using value = std::uint16_t; enum +#endif { - // used internally to mean "no error" + /// used internally to mean "no error" none = 0, normal = 1000, going_away = 1001, protocol_error = 1002, + unknown_data = 1003, bad_payload = 1007, policy_error = 1008, @@ -71,17 +76,15 @@ enum last = 5000 // satisfy warnings }; +#if ! GENERATING_DOCS } // close_code +#endif #if ! GENERATING_DOCS - using reason_string_type = static_string<123, char>; - -/// Payload type for pings and pongs using ping_payload_type = static_string<125, char>; - #endif /** Description of the close reason. diff --git a/include/beast/websocket/ssl.hpp b/include/beast/websocket/ssl.hpp index 8d7606b3..5ed57222 100644 --- a/include/beast/websocket/ssl.hpp +++ b/include/beast/websocket/ssl.hpp @@ -25,14 +25,14 @@ namespace websocket { `boost::asio::ssl::stream`, callers are responsible for providing a suitable overload of this function. - @param socket The stream to tear down. + @param stream The stream to tear down. @param ec Set to the error if any occurred. */ -template +template void teardown( - boost::asio::ssl::stream& stream, + boost::asio::ssl::stream& stream, error_code& ec); /** Start tearing down a `boost::asio::ssl::stream`. diff --git a/include/beast/websocket/stream.hpp b/include/beast/websocket/stream.hpp index 0f98ae93..45c53057 100644 --- a/include/beast/websocket/stream.hpp +++ b/include/beast/websocket/stream.hpp @@ -42,7 +42,7 @@ struct frame_info /** Provides message-oriented functionality using WebSocket. - The stream class template provides asynchronous and blocking + The @ref stream class template provides asynchronous and blocking message-oriented functionality necessary for clients and servers to utilize the WebSocket protocol. @@ -54,8 +54,8 @@ struct frame_info @par Example - To use the WebSocket stream template with an - ip::tcp::socket, you would write: + To use the @ref stream template with an `ip::tcp::socket`, + you would write: @code websocket::stream ws(io_service); @@ -66,15 +66,20 @@ struct frame_info websocket::stream ws(sock); @endcode - @tparam NextLayer An object meeting the requirements of ReadStream, - WriteStream, AsyncReadStream, and AsyncWriteStream. + @tparam NextLayer The type representing the next layer, to which + data will be read and written during operations. For synchronous + operations, the type must support the @b `SyncStream` concept. + For asynchronous operations, the type must support the @b `AsyncStream` + concept. @note A stream object must not be destroyed while there are pending asynchronous operations associated with it. @par Concepts - AsyncReadStream, AsyncWriteStream, - Decorator, Streambuf, SyncReadStream, SyncWriteStream. + @b `AsyncStream`, + @b `Decorator`, + @b `Streambuf`, + @b `SyncStream` */ template class stream : public detail::stream_base @@ -90,8 +95,12 @@ public: /// The type of the lowest layer. using lowest_layer_type = +#if GENERATING_DOCS + implementation_defined; +#else typename beast::detail::get_lowest_layer< next_layer_type>::type; +#endif /** Move-construct a stream. @@ -105,7 +114,7 @@ public: /** Move assignment. - If @c NextLayer is move constructible, this function + If `NextLayer` is move constructible, this function will move-construct a new stream from the existing stream. @note The behavior of move assignment on or from streams @@ -130,8 +139,8 @@ public: /** Destructor. - A stream object must not be destroyed while there are - pending asynchronous operations associated with it. + @note A stream object must not be destroyed while there + are pending asynchronous operations associated with it. */ ~stream() = default; @@ -157,6 +166,7 @@ public: std::forward(an)...); } + /// Set the automatic fragment size option void set_option(auto_fragment_size const& o) { @@ -167,36 +177,42 @@ public: wr_frag_size_ = o.value; } + /// Set the decorator used for HTTP messages void set_option(detail::decorator_type o) { d_ = std::move(o); } + /// Set the keep-alive option void set_option(keep_alive const& o) { keep_alive_ = o.value; } + /// Set the outgoing message type void set_option(message_type const& o) { wr_opcode_ = o.value; } + /// Set the read buffer size void set_option(read_buffer_size const& o) { stream_.reserve(o.value); } + /// Set the maximum incoming message size allowed void set_option(read_message_max const& o) { rd_msg_max_ = o.value; } + /// Set the size of the write buffer void set_option(write_buffer_size const& o) { @@ -289,22 +305,25 @@ public: /** Read and respond to a WebSocket HTTP Upgrade request. This function is used to synchronously read a HTTP WebSocket - Upgrade request and send the HTTP response. + Upgrade request and send the HTTP response. The call blocks until + one of the following conditions is true: - If the contents of the request are valid, the HTTP response - indicates a successful upgrade and the stream is then ready - to send and receive WebSocket protocol frames and messages. - - If the WebSocket HTTP Upgrade request cannot be satisfied, - a HTTP response is sent indicating the reason and status - code (typically 400, "Bad Request"), and an appropriate - exception will be thrown. - - The call blocks until one of the following conditions is true: + @li A HTTP request finishes receiving, and a HTTP response finishes + sending. @li An error occurs on the stream. - @li The entire HTTP response has been sent. + This function is implemented in terms of one or more calls to the + next layer's `read_some` and `write_some` functions. + + If the stream receives a valid HTTP WebSocket Upgrade request, a + HTTP response is sent back indicating a successful upgrade. When this + call returns, the stream is then ready to send and receive WebSocket + protocol frames and messages. + + If the HTTP Upgrade request is invalid or cannot be satisfied, a + HTTP response is sent indicating the reason and status code + (typically 400, "Bad Request"). This counts as a failure. @throws boost::system::system_error Thrown on failure. */ @@ -314,21 +333,25 @@ public: /** Read and respond to a WebSocket HTTP Upgrade request. This function is used to synchronously read a HTTP WebSocket - Upgrade request and send the HTTP response. + Upgrade request and send the HTTP response. The call blocks until + one of the following conditions is true: - If the contents of the request are valid, the HTTP response - indicates a successful upgrade and the stream is then ready - to send and receive WebSocket protocol frames and messages. - - If the WebSocket HTTP Upgrade request cannot be satisfied, - a HTTP response is sent indicating the reason and status - code (typically 400, "Bad Request"). - - The call blocks until one of the following conditions is true: + @li A HTTP request finishes receiving, and a HTTP response finishes + sending. @li An error occurs on the stream. - @li The entire HTTP response has been sent. + This function is implemented in terms of one or more calls to the + next layer's `read_some` and `write_some` functions. + + If the stream receives a valid HTTP WebSocket Upgrade request, a + HTTP response is sent back indicating a successful upgrade. When this + call returns, the stream is then ready to send and receive WebSocket + protocol frames and messages. + + If the HTTP Upgrade request is invalid or cannot be satisfied, a + HTTP response is sent indicating the reason and status code + (typically 400, "Bad Request"). This counts as a failure. @param ec Set to indicate what error occurred, if any. */ @@ -339,15 +362,28 @@ public: This function is used to asynchronously read a HTTP WebSocket Upgrade request and send the HTTP response. The function call - always returns immediately. + always returns immediately. The asynchronous operation will + continue until one of the following conditions is true: - If the contents of the request are valid, the HTTP response - indicates a successful upgrade and the stream is then ready - to send and receive WebSocket protocol frames and messages. + @li A HTTP request finishes receiving, and a HTTP response finishes + sending. - If the WebSocket HTTP Upgrade request cannot be satisfied, - a HTTP response is sent indicating the reason and status - code (typically 400, "Bad Request"). + @li An error occurs on the stream. + + This operation is implemented in terms of one or more calls to the + next layer's `async_read_some` and `async_write_some` functions, and + is known as a composed operation. The program must ensure + that the stream performs no other operations until this operation + completes. + + If the stream receives a valid HTTP WebSocket Upgrade request, a + HTTP response is sent back indicating a successful upgrade. When + this call returns, the stream is then ready to send and receive + WebSocket protocol frames and messages. + + If the HTTP Upgrade request is invalid or cannot be satisfied, a + HTTP response is sent indicating the reason and status code + (typically 400, "Bad Request"). This counts as a failure. @param handler The handler to be called when the request completes. Copies will be made of the handler as required. The equivalent @@ -358,33 +394,41 @@ public: Regardless of whether the asynchronous operation completes immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a - manner equivalent to using boost::asio::io_service::post(). + manner equivalent to using `boost::asio::io_service::post`. */ template + #if GENERATING_DOCS + void_or_deduced + #else typename async_completion< AcceptHandler, void(error_code)>::result_type + #endif async_accept(AcceptHandler&& handler); /** Read and respond to a WebSocket HTTP Upgrade request. This function is used to synchronously read a HTTP WebSocket - Upgrade request and send the HTTP response. + Upgrade request and send the HTTP response. The call blocks until + one of the following conditions is true: - If the contents of the request are valid, the HTTP response - indicates a successful upgrade and the stream is then ready - to send and receive WebSocket protocol frames and messages. - - If the WebSocket HTTP Upgrade request cannot be satisfied, - a HTTP response is sent indicating the reason and status - code (typically 400, "Bad Request"). - - The call blocks until one of the following conditions is true: + @li A HTTP request finishes receiving, and a HTTP response finishes + sending. @li An error occurs on the stream. - @li The entire HTTP response has been sent. + This function is implemented in terms of one or more calls to the + next layer's `read_some` and `write_some` functions. - @param buffers Caller provide data that has already been + If the stream receives a valid HTTP WebSocket Upgrade request, a + HTTP response is sent back indicating a successful upgrade. When + this call returns, the stream is then ready to send and receive + WebSocket protocol frames and messages. + + If the HTTP Upgrade request is invalid or cannot be satisfied, a + HTTP response is sent indicating the reason and status code + (typically 400, "Bad Request"). This counts as a failure. + + @param buffers Caller provided data that has already been received on the stream. This may be used for implementations allowing multiple protocols on the same stream. The buffered data will first be applied to the handshake, and @@ -400,23 +444,27 @@ public: /** Read and respond to a WebSocket HTTP Upgrade request. This function is used to synchronously read a HTTP WebSocket - Upgrade request and send the HTTP response. + Upgrade request and send the HTTP response. The call blocks until + one of the following conditions is true: - If the contents of the request are valid, the HTTP response - indicates a successful upgrade and the stream is then ready - to send and receive WebSocket protocol frames and messages. - - If the WebSocket HTTP Upgrade request cannot be satisfied, - a HTTP response is sent indicating the reason and status - code (typically 400, "Bad Request"). - - The call blocks until one of the following conditions is true: + @li A HTTP request finishes receiving, and a HTTP response finishes + sending. @li An error occurs on the stream. - @li The entire HTTP response has been sent. + This function is implemented in terms of one or more calls to the + next layer's `read_some` and `write_some` functions. - @param buffers Caller provide data that has already been + If the stream receives a valid HTTP WebSocket Upgrade request, a + HTTP response is sent back indicating a successful upgrade. When + this call returns, the stream is then ready to send and receive + WebSocket protocol frames and messages. + + If the HTTP Upgrade request is invalid or cannot be satisfied, a + HTTP response is sent indicating the reason and status code + (typically 400, "Bad Request"). This counts as a failure. + + @param buffers Caller provided data that has already been received on the stream. This may be used for implementations allowing multiple protocols on the same stream. The buffered data will first be applied to the handshake, and @@ -433,17 +481,30 @@ public: This function is used to asynchronously read a HTTP WebSocket Upgrade request and send the HTTP response. The function call - always returns immediately. + always returns immediately. The asynchronous operation will + continue until one of the following conditions is true: - If the contents of the request are valid, the HTTP response - indicates a successful upgrade and the stream is then ready - to send and receive WebSocket protocol frames and messages. + @li A HTTP request finishes receiving, and a HTTP response finishes + sending. - If the WebSocket HTTP Upgrade request cannot be satisfied, - a HTTP response is sent indicating the reason and status - code (typically 400, "Bad Request"). + @li An error occurs on the stream. - @param buffers Caller provide data that has already been + This operation is implemented in terms of one or more calls to the + next layer's `async_read_some` and `async_write_some` functions, and + is known as a composed operation. The program must ensure + that the stream performs no other operations until this operation + completes. + + If the stream receives a valid HTTP WebSocket Upgrade request, a + HTTP response is sent back indicating a successful upgrade. When + this call returns, the stream is then ready to send and receive + WebSocket protocol frames and messages. + + If the HTTP Upgrade request is invalid or cannot be satisfied, a + HTTP response is sent indicating the reason and status code + (typically 400, "Bad Request"). This counts as a failure. + + @param buffers Caller provided data that has already been received on the stream. This may be used for implementations allowing multiple protocols on the same stream. The buffered data will first be applied to the handshake, and @@ -459,36 +520,43 @@ public: Regardless of whether the asynchronous operation completes immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a - manner equivalent to using boost::asio::io_service::post(). + manner equivalent to using `boost::asio::io_service::post`. */ template + #if GENERATING_DOCS + void_or_deduced + #else typename async_completion< AcceptHandler, void(error_code)>::result_type + #endif async_accept(ConstBufferSequence const& buffers, AcceptHandler&& handler); /** Respond to a WebSocket HTTP Upgrade request - This function is used to synchronously send the HTTP response - to a HTTP WebSocket Upgrade request. - - If the contents of the request are valid, the HTTP response - indicates a successful upgrade and the stream is then ready - to send and receive WebSocket protocol frames and messages. - - If the WebSocket HTTP Upgrade request cannot be satisfied, - a HTTP response is sent indicating the reason and status - code (typically 400, "Bad Request"). - + This function is used to synchronously send the HTTP response to + a HTTP request possibly containing a WebSocket Upgrade request. The call blocks until one of the following conditions is true: + @li A HTTP response finishes sending. + @li An error occurs on the stream. - @li The entire HTTP response has been sent. + This function is implemented in terms of one or more calls to the + next layer's `write_some` functions. - @param request An object containing the HTTP Upgrade request. The - implementation will make copies as necessary before this - function call returns. + If the passed HTTP request is a valid HTTP WebSocket Upgrade + request, a HTTP response is sent back indicating a successful + upgrade. When this call returns, the stream is then ready to send + and receive WebSocket protocol frames and messages. + + If the HTTP request is invalid or cannot be satisfied, a HTTP + response is sent indicating the reason and status code (typically + 400, "Bad Request"). This counts as a failure. + + @param request An object containing the HTTP Upgrade request. + Ownership is not transferred, the implementation will not access + this object from other threads. @throws boost::system::system_error Thrown on failure. */ @@ -499,26 +567,29 @@ public: /** Respond to a WebSocket HTTP Upgrade request - This function is used to synchronously send the HTTP response - to a HTTP WebSocket Upgrade request. - - If the contents of the request are valid, the HTTP response - indicates a successful upgrade and the stream is then ready - to send and receive WebSocket protocol frames and messages. - - If the WebSocket HTTP Upgrade request cannot be satisfied, - a HTTP response is sent indicating the reason and status - code (typically 400, "Bad Request"). - + This function is used to synchronously send the HTTP response to + a HTTP request possibly containing a WebSocket Upgrade request. The call blocks until one of the following conditions is true: + @li A HTTP response finishes sending. + @li An error occurs on the stream. - @li The entire HTTP response has been sent. + This function is implemented in terms of one or more calls to the + next layer's `write_some` functions. - @param request An object containing the HTTP Upgrade request. The - implementation will make copies as necessary before this - function call returns. + If the passed HTTP request is a valid HTTP WebSocket Upgrade + request, a HTTP response is sent back indicating a successful + upgrade. When this call returns, the stream is then ready to send + and receive WebSocket protocol frames and messages. + + If the HTTP request is invalid or cannot be satisfied, a HTTP + response is sent indicating the reason and status code (typically + 400, "Bad Request"). This counts as a failure. + + @param request An object containing the HTTP Upgrade request. + Ownership is not transferred, the implementation will not access + this object from other threads. @param ec Set to indicate what error occurred, if any. */ @@ -527,23 +598,35 @@ public: accept(http::request_v1 const& request, error_code& ec); - /** Start reading and responding to a WebSocket HTTP Upgrade request. + /** Start responding to a WebSocket HTTP Upgrade request. - This function is used to asynchronously read a HTTP WebSocket - Upgrade request and send the HTTP response. The function call - always returns immediately. + This function is used to asynchronously send the HTTP response + to a HTTP request possibly containing a WebSocket Upgrade request. + The function call always returns immediately. The asynchronous + operation will continue until one of the following conditions is + true: - If the contents of the request are valid, the HTTP response - indicates a successful upgrade and the stream is then ready - to send and receive WebSocket protocol frames and messages. + @li A HTTP response finishes sending. - If the WebSocket HTTP Upgrade request cannot be satisfied, - a HTTP response is sent indicating the reason and status - code (typically 400, "Bad Request"). + @li An error occurs on the stream. - @param request An object containing the HTTP Upgrade request. The - implementation will make copies as necessary before this - function call returns. + This operation is implemented in terms of one or more calls to the + next layer's `async_write_some` functions, and is known as a + composed operation. The program must ensure that the + stream performs no other operations until this operation completes. + + If the passed HTTP request is a valid HTTP WebSocket Upgrade + request, a HTTP response is sent back indicating a successful + upgrade. When this asynchronous operaiton completes, the stream is + then ready to send and receive WebSocket protocol frames and messages. + + If the HTTP request is invalid or cannot be satisfied, a HTTP + response is sent indicating the reason and status code (typically + 400, "Bad Request"). This counts as a failure. + + @param request An object containing the HTTP Upgrade request. + Ownership is not transferred, the implementation will not access + this object from other threads. @param handler The handler to be called when the request completes. Copies will be made of the handler as required. The equivalent @@ -554,33 +637,44 @@ public: Regardless of whether the asynchronous operation completes immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a - manner equivalent to using boost::asio::io_service::post(). + manner equivalent to using `boost::asio::io_service::post`. */ template + #if GENERATING_DOCS + void_or_deduced + #else typename async_completion< AcceptHandler, void(error_code)>::result_type + #endif async_accept(http::request_v1 const& request, AcceptHandler&& handler); - /** Send a WebSocket Upgrade request. + /** Send a HTTP WebSocket Upgrade request and receive the response. This function is used to synchronously send the WebSocket upgrade HTTP request. The call blocks until one of the following conditions is true: + @li A HTTP request finishes sending and a HTTP response finishes + receiving. + @li An error occurs on the stream - @li A complete HTTP response with the result of the upgrade - request is received. + This function is implemented in terms of one or more calls to the + next layer's `read_some` and `write_some` functions. - @throws boost::system::system_error Thrown on failure. + The operation is successful if the received HTTP response indicates + a successful HTTP Upgrade (represented by a Status-Code of 101, + "switching protocols"). - @param host The name of the remote host, required by - the HTTP protocol. + @param host The name of the remote host, + required by the HTTP protocol. @param resource The requesting URI, which may not be empty, required by the HTTP protocol. + @throws boost::system::system_error Thrown on failure. + @par Example @code websocket::stream ws(io_service); @@ -599,19 +693,26 @@ public: handshake(boost::string_ref const& host, boost::string_ref const& resource); - /** Send a WebSocket Upgrade request. + /** Send a HTTP WebSocket Upgrade request and receive the response. This function is used to synchronously send the WebSocket upgrade HTTP request. The call blocks until one of the following conditions is true: - @li An error occurs on the stream. + @li A HTTP request finishes sending and a HTTP response finishes + receiving. - @li A complete HTTP response with the result of the upgrade - request is received. + @li An error occurs on the stream - @param host The name of the remote host, required by - the HTTP protocol. + This function is implemented in terms of one or more calls to the + next layer's `read_some` and `write_some` functions. + + The operation is successful if the received HTTP response indicates + a successful HTTP Upgrade (represented by a Status-Code of 101, + "switching protocols"). + + @param host The name of the remote host, + required by the HTTP protocol. @param resource The requesting URI, which may not be empty, required by the HTTP protocol. @@ -634,11 +735,28 @@ public: handshake(boost::string_ref const& host, boost::string_ref const& resource, error_code& ec); - /** Asynchronously send a WebSocket Upgrade request. + /** Start an asynchronous operation to send an upgrade request and receive the response. - This function is used to asynchronously send the WebSocket - upgrade HTTP request. This function call always returns - immediately. + This function is used to asynchronously send the HTTP WebSocket + upgrade request and receive the HTTP WebSocket Upgrade response. + This function call always returns immediately. The asynchronous + operation will continue until one of the following conditions is + true: + + @li A HTTP request finishes sending and a HTTP response finishes + receiving. + + @li An error occurs on the stream. + + This operation is implemented in terms of one or more calls to the + next layer's `async_read_some` and `async_write_some` functions, and + is known as a composed operation. The program must ensure + that the stream performs no other operations until this operation + completes. + + The operation is successful if the received HTTP response indicates + a successful HTTP Upgrade (represented by a Status-Code of 101, + "switching protocols"). @param host The name of the remote host, required by the HTTP protocol. Copies may be made as needed. @@ -656,45 +774,67 @@ public: Regardless of whether the asynchronous operation completes immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a - manner equivalent to using boost::asio::io_service::post(). + manner equivalent to using `boost::asio::io_service::post`. */ template + #if GENERATING_DOCS + void_or_deduced + #else typename async_completion< HandshakeHandler, void(error_code)>::result_type + #endif async_handshake(boost::string_ref const& host, boost::string_ref const& resource, HandshakeHandler&& h); - /** Perform a WebSocket close. + /** Send a WebSocket close frame. - This function initiates the WebSocket close procedure. + This function is used to sycnhronously send a close frame on + the stream. The call blocks until one of the following is true: + + @li The close frame finishes sending. + + @li An error occurs on the stream. + + This function is implemented in terms of one or more calls to the + next layer's `write_some` functions. If the close reason specifies a close code other than - close_code::none, the close frame is sent with the close code - and optional reason string. Otherwise, the close frame + @ref close_code::none, the close frame is sent with the close + code and optional reason string. Otherwise, the close frame is sent with no payload. Callers should not attempt to write WebSocket data after initiating the close. Instead, callers should continue - reading until an error occurs. A read returning error::closed + reading until an error occurs. A read returning @ref error::closed indicates a successful connection closure. @param cr The reason for the close. + + @throws boost::system::system_error Thrown on failure. */ void close(close_reason const& cr); - /** Perform a WebSocket close. + /** Send a WebSocket close frame. - This function initiates the WebSocket close procedure. + This function is used to sycnhronously send a close frame on + the stream. The call blocks until one of the following is true: + + @li The close frame finishes sending. + + @li An error occurs on the stream. + + This function is implemented in terms of one or more calls to the + next layer's `write_some` functions. If the close reason specifies a close code other than - close_code::none, the close frame is sent with the close code - and optional reason string. Otherwise, the close frame + @ref close_code::none, the close frame is sent with the close + code and optional reason string. Otherwise, the close frame is sent with no payload. Callers should not attempt to write WebSocket data after initiating the close. Instead, callers should continue - reading until an error occurs. A read returning error::closed + reading until an error occurs. A read returning @ref error::closed indicates a successful connection closure. @param cr The reason for the close. @@ -704,18 +844,32 @@ public: void close(close_reason const& cr, error_code& ec); - /** Start an asychronous WebSocket close operation. + /** Start an asycnhronous operation to send a WebSocket close frame. - This function initiates the WebSocket close procedure. + This function is used to asynchronously send a close frame on + the stream. This function call always returns immediately. The + asynchronous operation will continue until one of the following + conditions is true: + + @li The close frame finishes sending. + + @li An error occurs on the stream. + + This operation is implemented in terms of one or more calls to the + next layer's `async_write_some` functions, and is known as a + composed operation. The program must ensure that the + stream performs no other write operations (such as + @ref stream::async_write, @ref stream::async_write_frame, or + @ref stream::async_close) until this operation completes. If the close reason specifies a close code other than - close_code::none, the close frame is sent with the close code - and optional reason string. Otherwise, the close frame + @ref close_code::none, the close frame is sent with the close + code and optional reason string. Otherwise, the close frame is sent with no payload. Callers should not attempt to write WebSocket data after initiating the close. Instead, callers should continue - reading until an error occurs. A read returning error::closed + reading until an error occurs. A read returning @ref error::closed indicates a successful connection closure. @param cr The reason for the close. @@ -731,21 +885,39 @@ public: Regardless of whether the asynchronous operation completes immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a - manner equivalent to using boost::asio::io_service::post(). + manner equivalent to using `boost::asio::io_service::post`. */ template + #if GENERATING_DOCS + void_or_deduced + #else typename async_completion< CloseHandler, void(error_code)>::result_type + #endif async_close(close_reason const& cr, CloseHandler&& handler); - /** Read a message. + /** Read a message from the stream. - This function is used to read a message from the - websocket. The function call will block until the message - has been read successfully, or until an error occurs. + This function is used to synchronously read a message from + the stream. The call blocks until one of the following is true: - On success op is set to reflect the message type, binary - or text. + @li A complete message is received. + + @li An error occurs on the stream. + + This call is implemented in terms of one or more calls to the + stream's `read_some` and `write_some` operations. + + Upon a success, op is set to either binary or text depending on + the message type, and the input area of the stream buffer will + hold all the message payload bytes (which may be zero in length). + + Control frames encountered while reading frame or message data + are handled automatically. Pings are replied to, pongs are noted, + and close frames initiate the WebSocket close procedure. When a + close frame is received, this call will eventually return + @ref error::closed. Because of the need to handle control frames, + read operations can cause writes to take place. @param op A value to receive the message type. This object must remain valid until the handler is called. @@ -759,14 +931,28 @@ public: void read(opcode& op, Streambuf& streambuf); - /** Read a message. + /** Read a message from the stream. - This function is used to read a message from the - websocket. The function call will block until the message - has been read successfully, or until an error occurs. + This function is used to synchronously read a message from + the stream. The call blocks until one of the following is true: - On success op is set to reflect the message type, binary - or text. + @li A complete message is received. + + @li An error occurs on the stream. + + This call is implemented in terms of one or more calls to the + stream's `read_some` and `write_some` operations. + + Upon a success, op is set to either binary or text depending on + the message type, and the input area of the stream buffer will + hold all the message payload bytes (which may be zero in length). + + Control frames encountered while reading frame or message data + are handled automatically. Pings are replied to, pongs are noted, + and close frames initiate the WebSocket close procedure. When a + close frame is received, this call will eventually return + @ref error::closed. Because of the need to handle control frames, + read operations can cause writes to take place. @param op A value to receive the message type. This object must remain valid until the handler is called. @@ -781,15 +967,37 @@ public: read(opcode& op, Streambuf& streambuf, error_code& ec); - /** Start reading a message asynchronously. + /** Start an asynchronous operation to read a message from the stream. This function is used to asychronously read a message from - the websocket. The function call always returns immediately. + the stream. The function call always returns immediately. The + asynchronous operation will continue until one of the following + is true: - Upon a successful completion, op is set to either binary or - text depending on the message type, and the input area of the - streambuf will hold all the message payload bytes (which may - be zero in length). + @li A complete message is received. + + @li An error occurs on the stream. + + This operation is implemented in terms of one or more calls to the + next layer's `async_read_some` and `async_write_some` functions, + and is known as a composed operation. The program must + ensure that the stream performs no other until this operation + completes. + + Upon a success, op is set to either binary or text depending on + the message type, and the input area of the stream buffer will + hold all the message payload bytes (which may be zero in length). + + Control frames encountered while reading frame or message data + are handled automatically. Pings are replied to, pongs are noted, + and close frames initiate the WebSocket close procedure. When a + close frame is received, this call will eventually return + @ref error::closed. Because of the need to handle control frames, + read operations can cause writes to take place. These writes are + managed transparently; callers can still have one active + asynchronous read and asynchronous write operation pending + simultaneously (a user initiated call to @ref async_close + counts as a write). @param op A value to receive the message type. This object must remain valid until the handler is called. @@ -808,7 +1016,7 @@ public: Regardless of whether the asynchronous operation completes immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a - manner equivalent to using boost::asio::io_service::post(). + manner equivalent to using `boost::asio::io_service::post`. */ template #if GENERATING_DOCS @@ -820,24 +1028,32 @@ public: async_read(opcode& op, Streambuf& streambuf, ReadHandler&& handler); - /** Read a message frame. + /** Read a message frame from the stream. - This function is used to read a single message frame from - the websocket. The function call will block until one message - frame has been read successfully, or an error occurs. + This function is used to synchronously read a single message + frame from the stream. The call blocks until one of the following + is true: - On success, fi is filled out to reflect the message payload + @li A complete frame is received. + + @li An error occurs on the stream. + + This call is implemented in terms of one or more calls to the + stream's `read_some` and `write_some` operations. + + Upon success, fi is filled out to reflect the message payload contents. op is set to binary or text, and the fin flag indicates if all the message data has been read in. To read the entire message, callers should repeat the read_frame operation until fi.fin is true. A message with no payload will have fi.fin == true, and zero bytes placed into the stream buffer. - If a control frame is received while attempting to read a - message frame, the control frame is handled automatically. - If a ping control frame is received, a pong is sent immediately. - If a close control frame is received, a close is sent in - response and the read operation will return with `error::closed`. + Control frames encountered while reading frame or message data + are handled automatically. Pings are replied to, pongs are noted, + and close frames initiate the WebSocket close procedure. When a + close frame is received, this call will eventually return + @ref error::closed. Because of the need to handle control frames, + read operations can cause writes to take place. @param fi An object to store metadata about the message. @@ -849,24 +1065,32 @@ public: void read_frame(frame_info& fi, Streambuf& streambuf); - /** Read a message frame. + /** Read a message frame from the stream. - This function is used to read a single message frame from - the websocket. The function call will block until one message - frame has been read successfully, or an error occurs. + This function is used to synchronously read a single message + frame from the stream. The call blocks until one of the following + is true: - On success, fi is filled out to reflect the message payload + @li A complete frame is received. + + @li An error occurs on the stream. + + This call is implemented in terms of one or more calls to the + stream's `read_some` and `write_some` operations. + + Upon success, fi is filled out to reflect the message payload contents. op is set to binary or text, and the fin flag indicates if all the message data has been read in. To read the entire message, callers should repeat the read_frame operation until fi.fin is true. A message with no payload will have fi.fin == true, and zero bytes placed into the stream buffer. - If a control frame is received while attempting to read a - message frame, the control frame is handled automatically. - If a ping control frame is received, a pong is sent immediately. - If a close control frame is received, a close is sent in - response and the read operation will return with `error::closed`. + Control frames encountered while reading frame or message data + are handled automatically. Pings are replied to, pongs are noted, + and close frames initiate the WebSocket close procedure. When a + close frame is received, this call will eventually return + @ref error::closed. Because of the need to handle control frames, + read operations can cause writes to take place. @param fi An object to store metadata about the message. @@ -878,11 +1102,22 @@ public: void read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec); - /** Start reading a message frame asynchronously. + /** Start an asynchronous operation to read a message frame from the stream. This function is used to asychronously read a single message frame from the websocket. The function call always returns - immediately. + immediately. The asynchronous operation will continue until + one of the following conditions is true: + + @li A complete frame is received. + + @li An error occurs on the stream. + + This operation is implemented in terms of one or more calls to the + next layer's `async_read_some` and `async_write_some` functions, + and is known as a composed operation. The program must + ensure that the stream performs no other until this operation + completes. Upon a successful completion, fi is filled out to reflect the message payload contents. op is set to binary or text, and the @@ -892,11 +1127,16 @@ public: payload will have fi.fin == true, and zero bytes placed into the stream buffer. - If a control frame is received while attempting to read a - message frame, the control frame is handled automatically. - If a ping control frame is received, a pong is sent immediately. - If a close control frame is received, a close is sent in - response and the read operation will return with `error::closed`. + Control frames encountered while reading frame or message data + are handled automatically. Pings are replied to, pongs are noted, + and close frames initiate the WebSocket close procedure. When a + close frame is received, this call will eventually return + @ref error::closed. Because of the need to handle control frames, + read operations can cause writes to take place. These writes are + managed transparently; callers can still have one active + asynchronous read and asynchronous write operation pending + simultaneously (a user initiated call to @ref async_close + counts as a write). @param fi An object to store metadata about the message. This object must remain valid until the handler is called. @@ -919,24 +1159,33 @@ public: manner equivalent to using boost::asio::io_service::post(). */ template + #if GENERATING_DOCS + void_or_deduced + #else typename async_completion< ReadHandler, void(error_code)>::result_type + #endif async_read_frame(frame_info& fi, Streambuf& streambuf, ReadHandler&& handler); - /** Send a message. + /** Write a message to the stream. - This function is used to write a message to the websocket. - The call blocks until one of the following conditions is met: + This function is used to synchronously write a message to + the stream. The call blocks until one of the following conditions + is met: @li The entire message is sent. @li An error occurs. - The message opcode will be set to text or binary as - per the current setting of the `message_type` option. - If automatic fragmenting is enabled, the message will be - split into one or more frames as necessary. + This operation is implemented in terms of one or more calls to the + next layer's `write_some` function. + + The current setting of the @ref message_type option controls + whether the message opcode is set to text or binary. If the + @ref auto_fragment_size option is set, the message will be split + into one or more frames as necessary. The actual payload contents + sent may be transformed as per the WebSocket protocol settings. @param buffers The buffers containing the entire message payload. The implementation will make copies of this object @@ -948,27 +1197,30 @@ public: @throws boost::system::system_error Thrown on failure. @note This function always sends an entire message. To - send a message in fragments, use `write_frame`. + send a message in fragments, use @ref write_frame. */ template void write(ConstBufferSequence const& buffers); - /** Send a message. + /** Write a message to the stream. - This function is used to write a message to the websocket. - The call blocks until one of the following conditions is met: + This function is used to synchronously write a message to + the stream. The call blocks until one of the following conditions + is met: @li The entire message is sent. @li An error occurs. - The message opcode will be set to text or binary as - per the current setting of the `message_type` option. - If automatic fragmenting is enabled, the message will be - split into one or more frames as necessary. + This operation is implemented in terms of one or more calls to the + next layer's `write_some` function. - @param ec Set to indicate what error occurred, if any. + The current setting of the @ref message_type option controls + whether the message opcode is set to text or binary. If the + @ref auto_fragment_size option is set, the message will be split + into one or more frames as necessary. The actual payload contents + sent may be transformed as per the WebSocket protocol settings. @param buffers The buffers containing the entire message payload. The implementation will make copies of this object @@ -977,22 +1229,40 @@ public: the memory locations pointed to by buffers remains valid until the completion handler is called. + @param ec Set to indicate what error occurred, if any. + + @throws boost::system::system_error Thrown on failure. + @note This function always sends an entire message. To - send a message in fragments, use `write_frame`. + send a message in fragments, use @ref write_frame. */ template void write(ConstBufferSequence const& buffers, error_code& ec); - /** Start writing a complete message asynchronously. + /** Start an asynchronous operation to write a message to the stream. This function is used to asychronously write a message to - the websocket. The function call always returns immediately. + the stream. The function call always returns immediately. + The asynchronous operation will continue until one of the + following conditions is true: - The message opcode will be set to text or binary as - per the current setting of the `message_type` option. - If automatic fragmenting is enabled, the message will be - split into one or more frames as necessary. + @li The entire message is sent. + + @li An error occurs. + + This operation is implemented in terms of one or more calls + to the next layer's `async_write_some` functions, and is known + as a composed operation. The program must ensure that + the stream performs no other write operations (such as + stream::async_write, stream::async_write_frame, or + stream::async_close). + + The current setting of the @ref message_type option controls + whether the message opcode is set to text or binary. If the + @ref auto_fragment_size option is set, the message will be split + into one or more frames as necessary. The actual payload contents + sent may be transformed as per the WebSocket protocol settings. @param buffers The buffers containing the entire message payload. The implementation will make copies of this object @@ -1012,7 +1282,7 @@ public: Regardless of whether the asynchronous operation completes immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a - manner equivalent to using boost::asio::io_service::post(). + manner equivalent to using `boost::asio::io_service::post`. */ template #if GENERATING_DOCS @@ -1024,50 +1294,51 @@ public: async_write(ConstBufferSequence const& buffers, WriteHandler&& handler); - /** Send a frame. + /** Send a message frame on the stream. - This function is used to write a frame to a stream. The + This function is used to write a frame to the stream. The call will block until one of the following conditions is true: - @li All of the data in the supplied buffers has been written. + @li The entire frame is sent. @li An error occurs. This operation is implemented in terms of one or more calls - to the stream's write_some function. The actual payload sent - may be transformed as per the WebSocket protocol settings. + to the stream's `write_some` function. If this is the beginning of a new message, the message opcode will be set to text or binary as per the current setting of - the `message_type` option. - - @throws boost::system::system_error Thrown on failure. + the @ref message_type option. The actual payload sent + may be transformed as per the WebSocket protocol settings. @param fin `true` if this is the last frame in the message. @param buffers One or more buffers containing the frame's payload data. + + @throws boost::system::system_error Thrown on failure. */ template void write_frame(bool fin, ConstBufferSequence const& buffers); - /** Send a frame. + /** Send a message frame on the stream. - This function is used to write a frame to a stream. The + This function is used to write a frame to the stream. The call will block until one of the following conditions is true: - @li All of the data in the supplied buffers has been written. + @li The entire frame is sent. @li An error occurs. This operation is implemented in terms of one or more calls - to the stream's write_some function. The actual payload sent + to the stream's `write_some` function. The actual payload sent may be transformed as per the WebSocket protocol settings. If this is the beginning of a new message, the message opcode will be set to text or binary as per the current setting of - the `message_type` option. + the @ref message_type option. The actual payload sent + may be transformed as per the WebSocket protocol settings. @param fin `true` if this is the last frame in the message. @@ -1081,19 +1352,29 @@ public: write_frame(bool fin, ConstBufferSequence const& buffers, error_code& ec); - /** Start sending a frame asynchronously. + /** Start an asynchronous operation to send a message frame on the stream. - This function is used to asynchronously write a WebSocket - frame on the stream. This function call always returns - immediately. + This function is used to asynchronously write a message frame + on the stream. This function call always returns immediately. + The asynchronous operation will continue until one of the following + conditions is true: + + @li The entire frame is sent. + + @li An error occurs. + + This operation is implemented in terms of one or more calls + to the next layer's `async_write_some` functions, and is known + as a composed operation. The actual payload sent + may be transformed as per the WebSocket protocol settings. The + program must ensure that the stream performs no other write + operations (such as stream::async_write, stream::async_write_frame, + or stream::async_close). If this is the beginning of a new message, the message opcode will be set to text or binary as per the current setting of - the `message_type` option. - - This operation is implemented in terms of one or more calls - to the stream's async_write_some function. The actual payload - sent may be transformed as per the WebSocket protocol settings. + the @ref message_type option. The actual payload sent + may be transformed as per the WebSocket protocol settings. @param fin A bool indicating whether or not the frame is the last frame in the corresponding WebSockets message. @@ -1113,8 +1394,12 @@ public: ); @endcode */ template + #if GENERATING_DOCS + void_or_deduced + #else typename async_completion< WriteHandler, void(error_code)>::result_type + #endif async_write_frame(bool fin, ConstBufferSequence const& buffers, WriteHandler&& handler); diff --git a/include/beast/websocket/teardown.hpp b/include/beast/websocket/teardown.hpp index 2bbc6e24..6c59d2f1 100644 --- a/include/beast/websocket/teardown.hpp +++ b/include/beast/websocket/teardown.hpp @@ -30,8 +30,8 @@ namespace websocket { /** Tear down a connection. This tears down a connection. The implementation will call - the overload of this function based on the `Stream` parameter - used to consruct the socket. When `Stream` is a user defined + the overload of this function based on the `Socket` parameter + used to consruct the socket. When `Socket` is a user defined type, and not a `boost::asio::ip::tcp::socket` or any `boost::asio::ssl::stream`, callers are responsible for providing a suitable overload of this function. @@ -48,7 +48,7 @@ teardown(Socket& socket, error_code& ec) = delete; This begins tearing down a connection asynchronously. The implementation will call the overload of this function - based on the `Stream` parameter used to consruct the socket. + based on the `Socket` parameter used to consruct the socket. When `Stream` is a user defined type, and not a `boost::asio::ip::tcp::socket` or any `boost::asio::ssl::stream`, callers are responsible for providing a suitable overload @@ -68,9 +68,9 @@ teardown(Socket& socket, error_code& ec) = delete; manner equivalent to using boost::asio::io_service::post(). */ -template +template void -async_teardown(AsyncSocket& socket, TeardownHandler&& handler) = delete; +async_teardown(Socket& socket, TeardownHandler&& handler) = delete; //------------------------------------------------------------------------------ @@ -126,11 +126,11 @@ async_teardown( //------------------------------------------------------------------------------ -namespace wsproto_helpers { +namespace websocket_helpers { // Calls to teardown and async_teardown must be made from // a namespace that does not contain any overloads of these -// functions. The wsproto_helpers namespace is defined here +// functions. The websocket_helpers namespace is defined here // for that purpose. template diff --git a/include/beast/write_streambuf.hpp b/include/beast/write_streambuf.hpp index 9a5fca6f..24dc61a0 100644 --- a/include/beast/write_streambuf.hpp +++ b/include/beast/write_streambuf.hpp @@ -8,7 +8,7 @@ #ifndef BEAST_WRITE_STREAMBUF_HPP #define BEAST_WRITE_STREAMBUF_HPP -#include +#include #include #include #include @@ -21,15 +21,15 @@ namespace beast { argument into the stream buffer. It is capable of converting the following types of arguments: - @li `boost::asio::const_buffer` + @li `boost::asio::const_buffer` @li `boost::asio::mutable_buffer` - @li A type for which the call to `boost::asio::buffer()` is defined + @li A type meeting the requirements of @b `ConvertibleToConstBuffer` - @li A type meeting the requirements of `ConstBufferSequence` + @li A type meeting the requirements of @b `ConstBufferSequence` - @li A type meeting the requirements of `MutableBufferSequence` + @li A type meeting the requirements of @b `MutableBufferSequence` For all types not listed above, the function will invoke `boost::lexical_cast` on the argument in an attempt to convert to @@ -45,7 +45,7 @@ namespace beast { @throws unspecified Any exceptions thrown by `boost::lexical_cast`. @note This function participates in overload resolution only if - the `streambuf` parameter meets the requirements of Streambuf. + the `streambuf` parameter meets the requirements of @b `Streambuf`. */ template #if GENERATING_DOCS diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 796a890a..84d6df20 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,17 +10,23 @@ add_executable (core-tests basic_streambuf.cpp bind_handler.cpp buffer_cat.cpp + buffer_concepts.cpp buffers_adapter.cpp consuming_buffers.cpp handler_alloc.cpp + handler_concepts.cpp + http.cpp placeholders.cpp prepare_buffers.cpp static_streambuf.cpp static_string.cpp + stream_concepts.cpp streambuf.cpp streambuf_readstream.cpp to_string.cpp - type_check.cpp + version.cpp + websocket.cpp + write_streambuf.cpp detail/base64.cpp detail/empty_base_optimization.cpp ) @@ -34,13 +40,14 @@ add_executable (http-tests main.cpp http/basic_headers.cpp http/basic_parser_v1.cpp + http/body_type.cpp http/empty_body.cpp http/error.cpp http/headers.cpp http/message.cpp http/message_v1.cpp http/parse_error.cpp - http/parser.cpp + http/parser_v1.cpp http/read.cpp http/reason.cpp http/resume_context.cpp @@ -49,6 +56,7 @@ add_executable (http-tests http/status.cpp http/streambuf_body.cpp http/string_body.cpp + http/type_check.cpp http/write.cpp ) diff --git a/test/Jamfile b/test/Jamfile index fe441cd2..9cc87f2f 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -13,17 +13,23 @@ unit-test core-tests : basic_streambuf.cpp bind_handler.cpp buffer_cat.cpp + buffer_concepts.cpp buffers_adapter.cpp consuming_buffers.cpp handler_alloc.cpp + handler_concepts.cpp + http.cpp placeholders.cpp prepare_buffers.cpp static_streambuf.cpp static_string.cpp + stream_concepts.cpp streambuf.cpp streambuf_readstream.cpp to_string.cpp - type_check.cpp + version.cpp + websocket.cpp + write_streambuf.cpp detail/base64.cpp detail/empty_base_optimization.cpp ; @@ -32,13 +38,14 @@ unit-test http-tests : main.cpp http/basic_headers.cpp http/basic_parser_v1.cpp + http/body_type.cpp http/empty_body.cpp http/error.cpp http/headers.cpp http/message.cpp http/message_v1.cpp http/parse_error.cpp - http/parser.cpp + http/parser_v1.cpp http/read.cpp http/reason.cpp http/resume_context.cpp @@ -47,6 +54,7 @@ unit-test http-tests : http/status.cpp http/streambuf_body.cpp http/string_body.cpp + http/type_check.cpp http/write.cpp ; diff --git a/test/basic_streambuf.cpp b/test/basic_streambuf.cpp index 5a43e777..88cb42db 100644 --- a/test/basic_streambuf.cpp +++ b/test/basic_streambuf.cpp @@ -16,7 +16,6 @@ #include namespace beast { -namespace test { struct test_allocator_info { @@ -327,16 +326,22 @@ public: } } + void testStream() + { + streambuf sb; + sb << "x"; + } + void run() override { testPrepare(); testStreambuf(); testSpecial(); testAllocator(); + testStream(); } }; BEAST_DEFINE_TESTSUITE(basic_streambuf,core,beast); -} // test } // beast diff --git a/test/bind_handler.cpp b/test/bind_handler.cpp index 1d478b8e..2a643567 100644 --- a/test/bind_handler.cpp +++ b/test/bind_handler.cpp @@ -12,7 +12,6 @@ #include namespace beast { -namespace test { class bind_handler_test : public detail::unit_test::suite { @@ -33,5 +32,4 @@ public: BEAST_DEFINE_TESTSUITE(bind_handler,core,beast); -} // test } // beast diff --git a/test/buffer_cat.cpp b/test/buffer_cat.cpp index be44f0eb..2ad517d5 100644 --- a/test/buffer_cat.cpp +++ b/test/buffer_cat.cpp @@ -16,7 +16,6 @@ #include namespace beast { -namespace test { class buffer_cat_test : public detail::unit_test::suite { @@ -77,5 +76,4 @@ public: BEAST_DEFINE_TESTSUITE(buffer_cat,core,beast); -} // test } // beast diff --git a/test/buffer_concepts.cpp b/test/buffer_concepts.cpp new file mode 100644 index 00000000..ac53a476 --- /dev/null +++ b/test/buffer_concepts.cpp @@ -0,0 +1,25 @@ +// +// Copyright (c) 2013-2016 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) +// + +// Test that header file is self-contained. +#include + +namespace beast { + +namespace { +struct T +{ +}; +} + +static_assert(is_ConstBufferSequence::value, ""); +static_assert(! is_ConstBufferSequence::value, ""); + +static_assert(is_MutableBufferSequence::value, ""); +static_assert(! is_MutableBufferSequence::value, ""); + +} // beast diff --git a/test/buffers_adapter.cpp b/test/buffers_adapter.cpp index 08588135..f8eaf9a1 100644 --- a/test/buffers_adapter.cpp +++ b/test/buffers_adapter.cpp @@ -14,7 +14,6 @@ #include namespace beast { -namespace test { class buffers_adapter_test : public detail::unit_test::suite { @@ -158,5 +157,4 @@ public: BEAST_DEFINE_TESTSUITE(buffers_adapter,core,beast); -} // test } // beast diff --git a/test/consuming_buffers.cpp b/test/consuming_buffers.cpp index 9b3ce353..2c2061dd 100644 --- a/test/consuming_buffers.cpp +++ b/test/consuming_buffers.cpp @@ -13,7 +13,6 @@ #include namespace beast { -namespace test { class consuming_buffers_test : public beast::detail::unit_test::suite { @@ -89,7 +88,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(consuming_buffers,asio,beast); +BEAST_DEFINE_TESTSUITE(consuming_buffers,core,beast); -} // test } // beast diff --git a/test/detail/base64.cpp b/test/detail/base64.cpp index 7125d9d0..6180aeb2 100644 --- a/test/detail/base64.cpp +++ b/test/detail/base64.cpp @@ -47,7 +47,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(base64,detail,beast); +BEAST_DEFINE_TESTSUITE(base64,core,beast); } // test } // beast diff --git a/test/detail/empty_base_optimization.cpp b/test/detail/empty_base_optimization.cpp index d6bf972d..cd29072d 100644 --- a/test/detail/empty_base_optimization.cpp +++ b/test/detail/empty_base_optimization.cpp @@ -103,7 +103,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(empty_base_optimization,detail,beast); +BEAST_DEFINE_TESTSUITE(empty_base_optimization,core,beast); } // test } // beast diff --git a/test/handler_alloc.cpp b/test/handler_alloc.cpp index f27a1943..e1ca1300 100644 --- a/test/handler_alloc.cpp +++ b/test/handler_alloc.cpp @@ -6,4 +6,23 @@ // // Test that header file is self-contained. -#include +#include + +#include +#include + +namespace beast { + +class to_string_test : public beast::detail::unit_test::suite +{ +public: + void run() + { + expect(to_string(boost::asio::const_buffers_1("x", 1)) == "x"); + } +}; + +BEAST_DEFINE_TESTSUITE(to_string,core,beast); + +} // beast + diff --git a/test/handler_concepts.cpp b/test/handler_concepts.cpp new file mode 100644 index 00000000..c75c7381 --- /dev/null +++ b/test/handler_concepts.cpp @@ -0,0 +1,23 @@ +// +// Copyright (c) 2013-2016 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) +// + +// Test that header file is self-contained. +#include + +namespace beast { + +namespace { +struct T +{ + void operator()(int); +}; +} + +static_assert(is_CompletionHandler::value, ""); +static_assert(! is_CompletionHandler::value, ""); + +} // beast diff --git a/test/type_check.cpp b/test/http.cpp similarity index 89% rename from test/type_check.cpp rename to test/http.cpp index 2bdde9a9..a3811b4a 100644 --- a/test/type_check.cpp +++ b/test/http.cpp @@ -6,4 +6,4 @@ // // Test that header file is self-contained. -#include +#include diff --git a/test/http/body_type.cpp b/test/http/body_type.cpp new file mode 100644 index 00000000..cfddca65 --- /dev/null +++ b/test/http/body_type.cpp @@ -0,0 +1,9 @@ +// +// Copyright (c) 2013-2016 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) +// + +// Test that header file is self-contained. +#include diff --git a/test/http/body_writer.cpp b/test/http/body_writer.cpp new file mode 100644 index 00000000..cfddca65 --- /dev/null +++ b/test/http/body_writer.cpp @@ -0,0 +1,9 @@ +// +// Copyright (c) 2013-2016 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) +// + +// Test that header file is self-contained. +#include diff --git a/test/http/nodejs_parser.hpp b/test/http/nodejs_parser.hpp index 65419850..f4ab9290 100644 --- a/test/http/nodejs_parser.hpp +++ b/test/http/nodejs_parser.hpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/test/http/parser.cpp b/test/http/parser_v1.cpp similarity index 94% rename from test/http/parser.cpp rename to test/http/parser_v1.cpp index 7e090a8e..0514227a 100644 --- a/test/http/parser.cpp +++ b/test/http/parser_v1.cpp @@ -15,7 +15,7 @@ namespace beast { namespace http { -class parser_test : public beast::detail::unit_test::suite +class parser_v1_test : public beast::detail::unit_test::suite { public: void run() override @@ -64,7 +64,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(parser,http,beast); +BEAST_DEFINE_TESTSUITE(parser_v1,http,beast); } // http } // beast diff --git a/test/prepare_buffers.cpp b/test/prepare_buffers.cpp index 8ec75ccf..90a3a387 100644 --- a/test/prepare_buffers.cpp +++ b/test/prepare_buffers.cpp @@ -14,7 +14,6 @@ #include namespace beast { -namespace test { class prepare_buffers_test : public beast::detail::unit_test::suite { @@ -95,7 +94,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(prepare_buffers,asio,beast); +BEAST_DEFINE_TESTSUITE(prepare_buffers,core,beast); -} // test } // beast diff --git a/test/sig_wait.hpp b/test/sig_wait.hpp index 34ff1efd..a687b712 100644 --- a/test/sig_wait.hpp +++ b/test/sig_wait.hpp @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_EXAMPLE_SIG_WAIT_H_INCLUDED -#define BEAST_EXAMPLE_SIG_WAIT_H_INCLUDED +#ifndef BEAST_TEST_SIG_WAIT_H_INCLUDED +#define BEAST_TEST_SIG_WAIT_H_INCLUDED #include #include diff --git a/test/static_streambuf.cpp b/test/static_streambuf.cpp index 46e68aa8..0c07c995 100644 --- a/test/static_streambuf.cpp +++ b/test/static_streambuf.cpp @@ -13,7 +13,6 @@ #include namespace beast { -namespace test { class static_streambuf_test : public beast::detail::unit_test::suite { @@ -146,7 +145,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(static_streambuf,asio,beast); +BEAST_DEFINE_TESTSUITE(static_streambuf,core,beast); -} // test } // beastp diff --git a/test/static_string.cpp b/test/static_string.cpp index 10051661..5a389e4b 100644 --- a/test/static_string.cpp +++ b/test/static_string.cpp @@ -11,7 +11,6 @@ #include namespace beast { -namespace websocket { class static_string_test : public beast::detail::unit_test::suite { @@ -185,7 +184,6 @@ public: } }; -BEAST_DEFINE_TESTSUITE(static_string,websocket,beast); +BEAST_DEFINE_TESTSUITE(static_string,core,beast); -} // websocket } // beast diff --git a/test/stream_concepts.cpp b/test/stream_concepts.cpp new file mode 100644 index 00000000..3c1fdac3 --- /dev/null +++ b/test/stream_concepts.cpp @@ -0,0 +1,30 @@ +// +// Copyright (c) 2013-2016 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) +// + +// Test that header file is self-contained. +#include +#include + +namespace beast { + +using stream_type = boost::asio::ip::tcp::socket; + +static_assert(has_get_io_service::value, ""); +static_assert(is_AsyncReadStream::value, ""); +static_assert(is_AsyncWriteStream::value, ""); +static_assert(is_AsyncStream::value, ""); +static_assert(is_SyncReadStream::value, ""); +static_assert(is_SyncWriteStream::value, ""); +static_assert(is_SyncStream::value, ""); + +static_assert(! has_get_io_service::value, ""); +static_assert(! is_AsyncReadStream::value, ""); +static_assert(! is_AsyncWriteStream::value, ""); +static_assert(! is_SyncReadStream::value, ""); +static_assert(! is_SyncWriteStream::value, ""); + +} // beast diff --git a/test/to_string.cpp b/test/to_string.cpp index 7e0981fb..610a5adb 100644 --- a/test/to_string.cpp +++ b/test/to_string.cpp @@ -7,3 +7,4 @@ // Test that header file is self-contained. #include + diff --git a/test/version.cpp b/test/version.cpp new file mode 100644 index 00000000..b6909085 --- /dev/null +++ b/test/version.cpp @@ -0,0 +1,9 @@ +// +// Copyright (c) 2013-2016 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) +// + +// Test that header file is self-contained. +#include diff --git a/test/websocket.cpp b/test/websocket.cpp new file mode 100644 index 00000000..f14aed1c --- /dev/null +++ b/test/websocket.cpp @@ -0,0 +1,9 @@ +// +// Copyright (c) 2013-2016 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) +// + +// Test that header file is self-contained. +#include diff --git a/test/websocket/stream.cpp b/test/websocket/stream.cpp index 3bbe0b4d..002cd53f 100644 --- a/test/websocket/stream.cpp +++ b/test/websocket/stream.cpp @@ -85,7 +85,7 @@ public: template typename async_completion::result_type + void(error_code, std::size_t)>::result_type async_read_some(MutableBufferSequence const& buffers, ReadHandler&& handler) { @@ -120,7 +120,7 @@ public: template typename async_completion::result_type + void(error_code, std::size_t)>::result_type async_write_some(ConstBuffeSequence const& buffers, WriteHandler&& handler) {