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
This commit is contained in:
Vinnie Falco
2016-05-01 12:33:35 -04:00
parent c309f53ed2
commit 313620ce7e
92 changed files with 2915 additions and 1808 deletions

View File

@@ -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

View File

@@ -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 \

View File

@@ -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]

118
doc/core_types.qbk Normal file
View File

@@ -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]

View File

@@ -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.

View File

@@ -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:

View File

@@ -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<decltype(m.body), Body::value_type>: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]

View File

@@ -30,7 +30,7 @@
<bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__basic_headers">basic_headers</link></member>
<member><link linkend="beast.ref.http__basic_parser">basic_parser</link></member>
<member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member>
<member><link linkend="beast.ref.http__basic_streambuf_body">basic_streambuf_body</link></member>
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
<member><link linkend="beast.ref.http__error_code">error_code</link></member>
@@ -42,7 +42,7 @@
</simplelist>
<bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
<member><link linkend="beast.ref.http__is_Parser">is_Parser</link></member>
</simplelist>
</entry>
<entry valign="top">
@@ -50,9 +50,14 @@
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__async_read">async_read</link></member>
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
<member><link linkend="beast.ref.http__prepare">prepare</link></member>
<member><link linkend="beast.ref.http__read">read</link></member>
<member><link linkend="beast.ref.http__write">write</link></member>
</simplelist>
<bridgehead renderas="sect3">Constants</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__connection">connection</link></member>
</simplelist>
<bridgehead renderas="sect3">Concepts</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.types.Body">Body</link></member>
@@ -66,7 +71,6 @@
<bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.websocket__close_reason">close_reason</link></member>
<member><link linkend="beast.ref.websocket__static_string">static_string</link></member>
<member><link linkend="beast.ref.websocket__stream">stream</link></member>
</simplelist>
<bridgehead renderas="sect3">Options</bridgehead>
@@ -119,6 +123,7 @@
<member><link linkend="beast.ref.prepared_buffers">prepared_buffers</link></member>
<member><link linkend="beast.ref.static_streambuf">static_streambuf</link></member>
<member><link linkend="beast.ref.static_streambuf_n">static_streambuf_n</link></member>
<member><link linkend="beast.ref.static_string">static_string</link></member>
<member><link linkend="beast.ref.streambuf">streambuf</link></member>
<member><link linkend="beast.ref.streambuf_readstream">streambuf_readstream</link></member>
</simplelist>
@@ -128,20 +133,24 @@
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.bind_handler">bind_handler</link></member>
<member><link linkend="beast.ref.buffer_cat">buffer_cat</link></member>
<member><link linkend="beast.ref.consumed_buffers">consumed_buffers</link></member>
<member><link linkend="beast.ref.prepare_buffer">prepare_buffer</link></member>
<member><link linkend="beast.ref.prepare_buffers">prepare_buffers</link></member>
<member><link linkend="beast.ref.to_string">to_string</link></member>
<member><link linkend="beast.ref.write">write</link></member>
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
<member><link linkend="beast.ref.is_AsyncStream">is_AsyncStream</link></member>
<member><link linkend="beast.ref.is_BufferSequence">is_BufferSequence</link></member>
<member><link linkend="beast.ref.is_CompletionHandler">is_CompletionHandler</link></member>
<member><link linkend="beast.ref.is_ConstBufferSequence">is_ConstBufferSequence</link></member>
<member><link linkend="beast.ref.is_Handler">is_Handler</link></member>
<member><link linkend="beast.ref.is_MutableBufferSequence">is_MutableBufferSequence</link></member>
<member><link linkend="beast.ref.is_Streambuf">is_Streambuf</link></member>
<member><link linkend="beast.ref.is_SyncReadStream">is_SyncReadStream</link></member>
@@ -153,8 +162,30 @@
<bridgehead renderas="sect3">Concepts</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.types.BufferSequence">BufferSequence</link></member>
<member><link linkend="beast.types.Stream">Stream</link></member>
<member><link linkend="beast.types.stream.AsyncStream">AsyncStream</link></member>
<member><link linkend="beast.types.stream.Stream">Stream</link></member>
<member><link linkend="beast.types.Streambuf">Streambuf</link></member>
<member><link linkend="beast.types.stream.SyncStream">SyncStream</link></member>
</simplelist>
</entry>
</row>
</tbody>
</tgroup>
<tgroup cols="1">
<colspec colname="a"/>
<thead>
<row>
<entry valign="center" namest="a" nameend="a">
<bridgehead renderas="sect2">Diagnostic</bridgehead>
</entry>
</row>
</thead>
<tbody>
<row>
<entry valign="top">
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.doc_debug">doc_debug</link></member>
<member><link linkend="beast.ref.nested__nested_doc_debug">nested_doc_debug</link></member>
</simplelist>
</entry>
</row>

View File

@@ -43,6 +43,7 @@
<xsl:when test="@kind='class' or @kind='struct'">
<xsl:if test="
contains(compoundname, 'beast::') and
not(contains(compoundname, 'boost::')) and
not(contains(compoundname, '::detail')) and
not(contains(compoundname, 'rfc2616')) and
not(contains(@prot, 'private'))">
@@ -61,7 +62,6 @@
<xsl:text>&#xd;[endsect]</xsl:text>
</xsl:template>
<!--========== Utilities ==========-->
<xsl:template name="strip-beast-ns">
@@ -73,6 +73,9 @@
<xsl:when test="contains($name, 'beast::')">
<xsl:value-of select="substring-after($name, 'beast::')"/>
</xsl:when>
<xsl:when test="$name = 'beast'">
<xsl:text></xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$name"/>
</xsl:otherwise>
@@ -108,6 +111,38 @@
</xsl:choose>
</xsl:template>
<xsl:template name="cleanup-param">
<xsl:param name="name"/>
<xsl:variable name="clean">
<xsl:value-of select="$name"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="' *' = substring($clean, string-length($clean) - 1)">
<xsl:value-of select="substring($clean, 1, string-length($clean) - 2)"/>
<xsl:text>*</xsl:text>
</xsl:when>
<xsl:when test="' &amp;' = substring($clean, string-length($clean) - 1)">
<xsl:value-of select="substring($clean, 1, string-length($clean) - 2)"/>
<xsl:text>&amp;</xsl:text>
</xsl:when>
<xsl:when test="' &amp;...' = substring($clean, string-length($clean) - 4)">
<xsl:value-of select="substring($clean, 1, string-length($clean) - 5)"/>
<xsl:text>&amp;...</xsl:text>
</xsl:when>
<xsl:when test="' &amp;&amp;' = substring($clean, string-length($clean) - 2)">
<xsl:value-of select="substring($clean, 1, string-length($clean) - 3)"/>
<xsl:text>&amp;&amp;</xsl:text>
</xsl:when>
<xsl:when test="' &amp;&amp;...' = substring($clean, string-length($clean) - 5)">
<xsl:value-of select="substring($clean, 1, string-length($clean) - 6)"/>
<xsl:text>&amp;&amp;...</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$clean"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="cleanup-type">
<xsl:param name="name"/>
<xsl:variable name="type">
@@ -124,20 +159,22 @@
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$type='ConstBufferSequence'">
<xsl:text>``[link beast.ref.ConstBufferSequence ['ConstBufferSequence]]``</xsl:text>
</xsl:when>
<xsl:when test="$type='implementation_defined'">
<xsl:text>``['implementation-defined]``</xsl:text>
</xsl:when>
<xsl:when test="$type='void_or_deduced'">
<xsl:text>``[link beast.ref.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]``</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$type"/>
</xsl:otherwise>
</xsl:choose>
<xsl:variable name="cleaned">
<xsl:choose>
<xsl:when test="$type='implementation_defined'">
<xsl:text>``['implementation-defined]``</xsl:text>
</xsl:when>
<xsl:when test="$type='void_or_deduced'">
<xsl:text>``[@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]]``</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$type"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:call-template name="cleanup-param">
<xsl:with-param name="name" select="$cleaned"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="make-id">
@@ -260,8 +297,9 @@
<!--========== Markup ==========-->
<xsl:template match="para" mode="markup">
<xsl:apply-templates mode="markup"/>
<xsl:text>&#xd;</xsl:text>
<xsl:value-of select="$newline"/>
<xsl:apply-templates mode="markup"/>
<xsl:value-of select="$newline"/>
</xsl:template>
<xsl:template match="para" mode="markup-nested">
@@ -391,6 +429,8 @@
<xsl:apply-templates mode="markup"/>
</xsl:when>
<xsl:when test="@kind='see'">
<xsl:text>[heading See Also]&#xd;</xsl:text>
<xsl:apply-templates mode="markup"/>
</xsl:when>
<xsl:when test="@kind='note'">
<xsl:text>[heading Remarks]&#xd;</xsl:text>
@@ -536,12 +576,13 @@
</xsl:template>
<xsl:template match="ref[@kindref='compound']" mode="markup">
<xsl:variable name="name">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains(@refid, 'asio') or contains($name, 'asio::')">
<xsl:when test="contains(@refid, 'beast')">
<xsl:variable name="dox-ref-id" select="@refid"/>
<xsl:variable name="ref-name">
<xsl:call-template name="strip-beast-ns">
@@ -554,6 +595,14 @@
<xsl:with-param name="name" select="$ref-name"/>
</xsl:call-template>
</xsl:variable>
<!--<xsl:text>|1|</xsl:text>-->
<!--
<xsl:text>[role red ref-name='</xsl:text>
<xsl:value-of select="$ref-name"/>
<xsl:text>'|ref-id='</xsl:text>
<xsl:value-of select="$ref-id"/>
<xsl:text>']|</xsl:text>
-->
<xsl:text>[link beast.ref.</xsl:text>
<xsl:value-of select="$ref-id"/>
<xsl:text> `</xsl:text>
@@ -561,89 +610,106 @@
<xsl:text>`]</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>`</xsl:text>
<xsl:text>[role red |1|</xsl:text>
<xsl:value-of select="."/>
<xsl:text>`</xsl:text>
<xsl:text>]</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ref[@kindref='member']" mode="markup">
<xsl:variable name="name">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:variable name="dox-ref-id" select="@refid"/>
<xsl:variable name="memberdefs" select="/doxygen//compounddef/sectiondef/memberdef[@id=$dox-ref-id]"/>
<xsl:variable name="def-kind" select="($memberdefs)/../../@kind"/>
<xsl:variable name="sec-kind" select="($memberdefs)/../@kind"/>
<xsl:choose>
<xsl:when test="contains(@refid, 'beast') and count($memberdefs) &gt; 0">
<xsl:variable name="dox-compound-name" select="($memberdefs)[1]/../../compoundname"/>
<xsl:variable name="dox-name" select="($memberdefs)[1]/name"/>
<xsl:variable name="ref-name">
<xsl:call-template name="strip-beast-ns">
<xsl:with-param name="name" select="$dox-compound-name"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ref-id">
<xsl:call-template name="make-id">
<xsl:with-param name="name" select="$ref-name"/>
</xsl:call-template>
</xsl:variable>
<!--<xsl:text>|2|</xsl:text>-->
<!--
<xsl:text>[role red def-kind='</xsl:text>
<xsl:value-of select="$def-kind"/>
<xsl:text>', sec-kind='</xsl:text>
<xsl:value-of select="$sec-kind"/>
<xsl:text>', ref-id='</xsl:text>
<xsl:value-of select="$ref-id"/>
<xsl:text>'] </xsl:text>
-->
<xsl:choose>
<xsl:when test="$def-kind = 'namespace'">
<xsl:text>[link beast.ref.</xsl:text>
<xsl:choose>
<xsl:when test="string-length($ref-id) &gt; 0">
<xsl:value-of select="concat($ref-id,'__',$dox-name)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$dox-name"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text> `</xsl:text>
<xsl:value-of name="text" select="$dox-name"/>
<xsl:text>`]</xsl:text>
</xsl:when>
<xsl:when test="$def-kind = 'class' or $def-kind = 'struct'">
<xsl:text>[link beast.ref.</xsl:text>
<xsl:value-of select="concat($ref-id,'.',$dox-name)"/>
<xsl:text> `</xsl:text>
<xsl:value-of name="text" select="$name"/>
<xsl:text>`]</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>[role red </xsl:text>
<xsl:value-of select="$name"/>
<xsl:text>]</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:text>[role red </xsl:text>
<xsl:value-of select="$name"/>
<xsl:text>]</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ref[@kindref='compound']" mode="markup-nested">
<xsl:variable name="name">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains(@refid, 'asio') or contains($name, 'asio::')">
<xsl:variable name="dox-ref-id" select="@refid"/>
<xsl:variable name="ref-name">
<xsl:call-template name="strip-beast-ns">
<xsl:with-param name="name"
select="(/doxygen//compounddef[@id=$dox-ref-id])[1]/compoundname"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ref-id">
<xsl:call-template name="make-id">
<xsl:with-param name="name" select="$ref-name"/>
</xsl:call-template>
</xsl:variable>
<xsl:text>[link beast.ref.</xsl:text>
<xsl:value-of select="$ref-id"/>
<xsl:text> `</xsl:text>
<xsl:value-of name="text" select="$ref-name"/>
<xsl:text>`]</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>`</xsl:text>
<xsl:value-of select="."/>
<xsl:text>`</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>[role red |3|</xsl:text>
<xsl:value-of select="."/>
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match="ref[@kindref='member']" mode="markup">
<xsl:variable name="dox-ref-id" select="@refid"/>
<xsl:variable name="memberdefs" select="/doxygen//compounddef/sectiondef/memberdef[@id=$dox-ref-id]"/>
<xsl:choose>
<xsl:when test="contains(@refid, 'namespaceboost_1_1asio') and count($memberdefs) &gt; 0">
<xsl:variable name="dox-compound-name" select="($memberdefs)[1]/../../compoundname"/>
<xsl:variable name="dox-name" select="($memberdefs)[1]/name"/>
<xsl:variable name="ref-name">
<xsl:call-template name="strip-beast-ns">
<xsl:with-param name="name" select="concat($dox-compound-name,'::',$dox-name)"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ref-id">
<xsl:call-template name="make-id">
<xsl:with-param name="name" select="$ref-name"/>
</xsl:call-template>
</xsl:variable>
<xsl:text>[link beast.ref.</xsl:text>
<xsl:value-of select="$ref-id"/>
<xsl:text> `</xsl:text>
<xsl:value-of name="text" select="$ref-name"/>
<xsl:text>`]</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>`</xsl:text>
<xsl:value-of select="."/>
<xsl:text>`</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ref[@kindref='member']" mode="markup-nested">
<xsl:variable name="name">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:variable name="dox-ref-id" select="@refid"/>
<xsl:variable name="memberdefs" select="/doxygen//compounddef/sectiondef/memberdef[@id=$dox-ref-id]"/>
<xsl:variable name="def-kind" select="($memberdefs)/../../@kind"/>
<xsl:variable name="sec-kind" select="($memberdefs)/../@kind"/>
<xsl:choose>
<xsl:when test="contains(@refid, 'namespaceboost_1_1asio') and count($memberdefs) &gt; 0">
<xsl:when test="contains(@refid, 'beast') and count($memberdefs) &gt; 0">
<xsl:variable name="dox-compound-name" select="($memberdefs)[1]/../../compoundname"/>
<xsl:variable name="dox-name" select="($memberdefs)[1]/name"/>
<xsl:variable name="ref-name">
<xsl:call-template name="strip-beast-ns">
<xsl:with-param name="name" select="concat($dox-compound-name,'::',$dox-name)"/>
<xsl:with-param name="name" select="$dox-compound-name"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ref-id">
@@ -651,16 +717,49 @@
<xsl:with-param name="name" select="$ref-name"/>
</xsl:call-template>
</xsl:variable>
<xsl:text>[link beast.ref.</xsl:text>
<!--<xsl:text>|2|</xsl:text>-->
<!--
<xsl:text>[role red def-kind='</xsl:text>
<xsl:value-of select="$def-kind"/>
<xsl:text>', sec-kind='</xsl:text>
<xsl:value-of select="$sec-kind"/>
<xsl:text>', ref-id='</xsl:text>
<xsl:value-of select="$ref-id"/>
<xsl:text> `</xsl:text>
<xsl:value-of name="text" select="$ref-name"/>
<xsl:text>`]</xsl:text>
<xsl:text>'] </xsl:text>
-->
<xsl:choose>
<xsl:when test="$def-kind = 'namespace'">
<xsl:text>[link beast.ref.</xsl:text>
<xsl:choose>
<xsl:when test="string-length($ref-id) &gt; 0">
<xsl:value-of select="concat($ref-id,'__',$dox-name)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$dox-name"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text> `</xsl:text>
<xsl:value-of name="text" select="$dox-name"/>
<xsl:text>`]</xsl:text>
</xsl:when>
<xsl:when test="$def-kind = 'class' or $def-kind = 'struct'">
<xsl:text>[link beast.ref.</xsl:text>
<xsl:value-of select="concat($ref-id,'.',$dox-name)"/>
<xsl:text> `</xsl:text>
<xsl:value-of name="text" select="$name"/>
<xsl:text>`]</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>[role red </xsl:text>
<xsl:value-of select="$name"/>
<xsl:text>]</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:text>`</xsl:text>
<xsl:value-of select="."/>
<xsl:text>`</xsl:text>
<xsl:text>[role red </xsl:text>
<xsl:value-of select="$name"/>
<xsl:text>]</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
@@ -1185,7 +1284,8 @@
</xsl:call-template>
</xsl:variable>
<xsl:if test="string-length($stripped-type) &gt; 0">
<xsl:value-of select="$stripped-type"/><xsl:text> </xsl:text>
<xsl:value-of select="$stripped-type"/>
<xsl:text>&#xd;</xsl:text>
</xsl:if>
<xsl:text>``[link beast.ref.</xsl:text>
<xsl:value-of select="$class-id"/>
@@ -1412,21 +1512,62 @@
</xsl:template>
<xsl:template match="templateparamlist" mode="class-detail">
<xsl:text>template&lt;&#xd;</xsl:text>
<xsl:apply-templates select="param" mode="class-detail-template"/>
<xsl:text>&gt;&#xd;</xsl:text>
</xsl:template>
<xsl:template match="param" mode="class-detail-template">
<xsl:text> </xsl:text>
<xsl:choose>
<xsl:when test="type = 'class AsyncStream'">
<xsl:text>class ``[link beast.types.stream.AsyncStream [*AsyncStream]]``</xsl:text>
</xsl:when>
<xsl:when test="type = 'class AsyncReadStream'">
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]``</xsl:text>
</xsl:when>
<xsl:when test="type = 'class AsyncWriteStream'">
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]``</xsl:text>
</xsl:when>
<xsl:when test="type = 'class Body'">
<xsl:text>class ``[link beast.types.Body [*Body]]``</xsl:text>
</xsl:when>
<xsl:when test="type = 'class Streambuf'">
<xsl:when test="type = 'class BufferSequence'">
<xsl:text>class ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
</xsl:when>
<xsl:when test="(type = 'class' or type = 'class...') and declname = 'BufferSequence'">
<xsl:value-of select="type"/>
<xsl:text> ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
</xsl:when>
<xsl:when test="declname = 'CompletionHandler' or type = 'class CompletionHandler'">
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]``</xsl:text>
</xsl:when>
<xsl:when test="declname = 'ConstBufferSequence' or type = 'class ConstBufferSequence'">
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]``</xsl:text>
</xsl:when>
<xsl:when test="declname = 'MutableBufferSequence' or type = 'class MutableBufferSequence'">
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]``</xsl:text>
</xsl:when>
<xsl:when test="declname = 'Stream' or type = 'class Stream'">
<xsl:text>class ``[link beast.types.stream.Stream [*Stream]]``</xsl:text>
</xsl:when>
<xsl:when test="declname = 'Streambuf' or type = 'class Streambuf'">
<xsl:text>class ``[link beast.types.Streambuf [*Streambuf]]``</xsl:text>
</xsl:when>
<xsl:when test="type = 'class SyncStream'">
<xsl:text>class ``[link beast.types.stream.SyncStream [*SyncStream]]``</xsl:text>
</xsl:when>
<xsl:when test="declname = 'SyncReadStream' or type = 'class SyncReadStream'">
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]``</xsl:text>
</xsl:when>
<xsl:when test="declname = 'SyncWriteStream' or type = 'class SyncWriteStream'">
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]``</xsl:text>
</xsl:when>
<xsl:when test="declname = 'T'">
<xsl:value-of select="declname"/>
</xsl:when>
@@ -1466,28 +1607,19 @@
<xsl:value-of select="array"/>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="' &amp;&amp;' = substring(type, string-length(type) - 2)">
<xsl:value-of select="substring(type, 1, string-length(type) - 3)"/>
<xsl:text>&amp;&amp;</xsl:text>
</xsl:when>
<xsl:when test="' &amp;' = substring(type, string-length(type) - 1)">
<xsl:value-of select="substring(type, 1, string-length(type) - 2)"/>
<xsl:text>&amp;</xsl:text>
</xsl:when>
<xsl:when test="' *' = substring(type, string-length(type) - 1)">
<xsl:value-of select="substring(type, 1, string-length(type) - 2)"/>
<xsl:text>*</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="type"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text>
<xsl:value-of select="declname"/>
<xsl:call-template name="cleanup-param">
<xsl:with-param name="name" select="type"/>
</xsl:call-template>
<xsl:if test="count(declname) > 0">
<xsl:text> </xsl:text>
<xsl:value-of select="declname"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="count(defval) > 0"> = <xsl:value-of select="defval"/></xsl:if>
<xsl:if test="count(defval) > 0">
<xsl:text> = </xsl:text>
<xsl:value-of select="defval"/>
</xsl:if>
<xsl:if test="not(position() = last())">
<xsl:text>,</xsl:text>
</xsl:if>

View File

@@ -20,7 +20,7 @@
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
#include <beast/http/body_writer.hpp>
#include <beast/http/body_type.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/filesystem.hpp>
#include <cstdio>

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_ASYNC_COMPLETION_HPP
#define BEAST_ASYNC_COMPLETION_HPP
#include <beast/type_check.hpp>
#include <beast/handler_concepts.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/handler_type.hpp>
#include <type_traits>
@@ -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<class CompletionToken>
typename async_completion<CompletionToken,
template<class CompletionHandler>
typename async_completion<CompletionHandler,
void(boost::system::error_code)>::result_type
async_initfn(..., CompletionToken&& token)
async_initfn(..., CompletionHandler&& handler)
{
async_completion<CompletionToken,
void(boost::system::error_code)> completion(token);
async_completion<CompletionHandler,
void(boost::system::error_code)> completion(handler);
...
return completion.result.get();
}
@endcode
See <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf">
@note See <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf">
Library Foundations For Asynchronous Operations</a>
*/
template <class CompletionToken, class Signature>
template <class CompletionHandler, class Signature>
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<CompletionToken>::type& token)
: handler(std::forward<CompletionToken>(token))
async_completion(typename std::remove_reference<CompletionHandler>::type& token)
: handler(std::forward<CompletionHandler>(token))
, result(handler)
{
static_assert(is_Handler<handler_type, Signature>::value,
static_assert(is_CompletionHandler<handler_type, Signature>::value,
"Handler requirements not met");
}

View File

@@ -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<class Allocator>
@@ -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<Allocator>::
template rebind_alloc<std::uint8_t>;
#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<class OtherAlloc>
basic_streambuf(basic_streambuf<OtherAlloc> const& other);
basic_streambuf(basic_streambuf<OtherAlloc> 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<class OtherAlloc>
basic_streambuf(basic_streambuf<OtherAlloc> const& other,
basic_streambuf(basic_streambuf<OtherAlloc> 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<class OtherAlloc>
basic_streambuf& operator=(basic_streambuf<OtherAlloc> const& other);
basic_streambuf& operator=(basic_streambuf<OtherAlloc> 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<class Alloc, class T>
basic_streambuf<Alloc>&
operator<<(basic_streambuf<Alloc>& 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<class Allocator>
std::string
to_string(basic_streambuf<Allocator> const& streambuf);
template<class Allocator, class T>
basic_streambuf<Allocator>&
operator<<(basic_streambuf<Allocator>& streambuf, T const& t);
} // beast

View File

@@ -8,110 +8,19 @@
#ifndef BEAST_BIND_HANDLER_HPP
#define BEAST_BIND_HANDLER_HPP
#include <beast/detail/integer_sequence.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <functional>
#include <beast/handler_concepts.hpp>
#include <beast/detail/bind_handler.hpp>
#include <type_traits>
#include <utility>
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 Handler, class... Args>
class bound_handler
{
private:
using args_type = std::tuple<typename std::decay<Args>::type...>;
Handler h_;
args_type args_;
template<class Tuple, std::size_t... S>
static void invoke(Handler& h, Tuple& args,
index_sequence<S...>)
{
h(std::get<S>(args)...);
}
public:
using result_type = void;
template<class DeducedHandler>
explicit
bound_handler(DeducedHandler&& handler, Args&&... args)
: h_(std::forward<DeducedHandler>(handler))
, args_(std::forward<Args>(args)...)
{
}
void
operator()()
{
invoke(h_, args_,
index_sequence_for<Args...> ());
}
void
operator()() const
{
invoke(h_, args_,
index_sequence_for<Args...> ());
}
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<class F>
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<typename std::decay<
CompletionHandler>::type, Args...>(std::forward<
CompletionHandler>(handler),
@@ -153,10 +65,4 @@ bind_handler(CompletionHandler&& handler, Args&&... args)
} // beast
namespace std {
template<class Handler, class... Args>
void bind(beast::detail::bound_handler<
Handler, Args...>, ...) = delete;
} // std
#endif

View File

@@ -8,6 +8,7 @@
#ifndef BEAST_BUFFER_CAT_HPP
#define BEAST_BUFFER_CAT_HPP
#include <beast/detail/buffer_cat.hpp>
#include <boost/asio/buffer.hpp>
#include <cstdint>
#include <iterator>
@@ -18,463 +19,9 @@
namespace beast {
namespace detail {
template<class ValueType, class... Bs>
class buffer_cat_helper
{
std::tuple<Bs...> 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<class U>
std::size_t constexpr
max_sizeof()
{
return sizeof(U);
}
template<class U0, class U1, class... Us>
std::size_t constexpr
max_sizeof()
{
return
max_sizeof<U0>() > max_sizeof<U1, Us...>() ?
max_sizeof<U0>() : max_sizeof<U1, Us...>();
}
template<class ValueType, class... Bs>
class buffer_cat_helper<
ValueType, Bs...>::const_iterator
{
std::size_t n_;
std::tuple<Bs...> const* bs_;
std::array<std::uint8_t,
max_sizeof<typename Bs::const_iterator...>()> buf_;
friend class buffer_cat_helper<ValueType, Bs...>;
template<std::size_t I>
using C = std::integral_constant<std::size_t, I>;
template<std::size_t I>
using iter_t = typename std::tuple_element<
I, std::tuple<Bs...>>::type::const_iterator;
template<std::size_t I>
iter_t<I>&
iter()
{
return *reinterpret_cast<
iter_t<I>*>(buf_.data());
}
template<std::size_t I>
iter_t<I> const&
iter() const
{
return *reinterpret_cast<
iter_t<I> 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<Bs...> const& bs, bool at_end);
void
construct(C<sizeof...(Bs)>)
{
auto constexpr I = sizeof...(Bs);
n_ = I;
}
template<std::size_t I>
void
construct(C<I>)
{
if(std::get<I>(*bs_).begin() !=
std::get<I>(*bs_).end())
{
n_ = I;
new(buf_.data()) iter_t<I>{
std::get<I>(*bs_).begin()};
return;
}
construct(C<I+1>{});
}
void
destroy(C<sizeof...(Bs)>)
{
return;
}
template<std::size_t I>
void
destroy(C<I>)
{
if(n_ == I)
{
using Iter = iter_t<I>;
iter<I>().~Iter();
return;
}
destroy(C<I+1>{});
}
void
move(C<sizeof...(Bs)>, const_iterator&&)
{
return;
}
template<std::size_t I>
void
move(C<I>, const_iterator&& other)
{
if(n_ == I)
{
new(buf_.data()) iter_t<I>{
std::move(other.iter<I>())};
return;
}
move(C<I+1>{}, std::move(other));
}
void
copy(C<sizeof...(Bs)>, const_iterator const&)
{
return;
}
template<std::size_t I>
void
copy(C<I>, const_iterator const& other)
{
if(n_ == I)
{
new(buf_.data()) iter_t<I>{
other.iter<I>()};
return;
}
copy(C<I+1>{}, other);
}
bool
equal(C<sizeof...(Bs)>,
const_iterator const&) const
{
return true;
}
template<std::size_t I>
bool
equal(C<I>, const_iterator const& other) const
{
if(n_ == I)
return iter<I>() == other.iter<I>();
return equal(C<I+1>{}, other);
}
[[noreturn]]
reference
dereference(C<sizeof...(Bs)>) const
{
throw std::logic_error("invalid iterator");
}
template<std::size_t I>
reference
dereference(C<I>) const
{
if(n_ == I)
return *iter<I>();
return dereference(C<I+1>{});
}
[[noreturn]]
void
increment(C<sizeof...(Bs)>)
{
throw std::logic_error("invalid iterator");
}
template<std::size_t I>
void
increment(C<I>)
{
if(n_ == I)
{
if(++iter<I>() !=
std::get<I>(*bs_).end())
return;
using Iter = iter_t<I>;
iter<I>().~Iter();
return construct(C<I+1>{});
}
increment(C<I+1>{});
}
void
decrement(C<sizeof...(Bs)>)
{
auto constexpr I = sizeof...(Bs);
if(n_ == I)
{
--n_;
new(buf_.data()) iter_t<I-1>{
std::get<I-1>(*bs_).end()};
}
decrement(C<I-1>{});
}
void
decrement(C<0>)
{
auto constexpr I = 0;
if(iter<I>() != std::get<I>(*bs_).begin())
{
--iter<I>();
return;
}
throw std::logic_error("invalid iterator");
}
template<std::size_t I>
void
decrement(C<I>)
{
if(n_ == I)
{
if(iter<I>() != std::get<I>(*bs_).begin())
{
--iter<I>();
return;
}
--n_;
using Iter = iter_t<I>;
iter<I>().~Iter();
new(buf_.data()) iter_t<I-1>{
std::get<I-1>(*bs_).end()};
}
decrement(C<I-1>{});
}
};
//------------------------------------------------------------------------------
template<class ValueType, class... Bs>
buffer_cat_helper<ValueType, Bs...>::
const_iterator::~const_iterator()
{
destroy(C<0>{});
}
template<class ValueType, class... Bs>
buffer_cat_helper<ValueType, Bs...>::
const_iterator::const_iterator()
: n_(sizeof...(Bs))
, bs_(nullptr)
{
}
template<class ValueType, class... Bs>
buffer_cat_helper<ValueType, Bs...>::
const_iterator::const_iterator(
std::tuple<Bs...> const& bs, bool at_end)
: bs_(&bs)
{
if(at_end)
n_ = sizeof...(Bs);
else
construct(C<0>{});
}
template<class ValueType, class... Bs>
buffer_cat_helper<ValueType, Bs...>::
const_iterator::const_iterator(const_iterator&& other)
: n_(other.n_)
, bs_(other.bs_)
{
move(C<0>{}, std::move(other));
}
template<class ValueType, class... Bs>
buffer_cat_helper<ValueType, Bs...>::
const_iterator::const_iterator(const_iterator const& other)
: n_(other.n_)
, bs_(other.bs_)
{
copy(C<0>{}, other);
}
template<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::
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<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::
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<class ValueType, class... Bs>
bool
buffer_cat_helper<ValueType, Bs...>::
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<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::
const_iterator::operator*() const ->
reference
{
return dereference(C<0>{});
}
template<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::
const_iterator::operator++() ->
const_iterator&
{
increment(C<0>{});
return *this;
}
template<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::
const_iterator::operator--() ->
const_iterator&
{
decrement(C<sizeof...(Bs)>{});
return *this;
}
template<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::begin() const ->
const_iterator
{
return const_iterator(bs_, false);
}
template<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::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<ValueType, Bs...>::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<class... BufferSequence>

View File

@@ -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 <beast/detail/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
#include <type_traits>
namespace beast {
/// Determine if `T` meets the requirements of @b `BufferSequence`.
template<class T, class BufferType>
#if GENERATING_DOCS
struct is_BufferSequence : std::integral_constant<bool, ...>
#else
struct is_BufferSequence : detail::is_BufferSequence<T, BufferType>::type
#endif
{
};
/// Determine if `T` meets the requirements of @b `ConstBufferSequence`.
template<class T>
#if GENERATING_DOCS
struct is_ConstBufferSequence : std::integral_constant<bool, ...>
#else
struct is_ConstBufferSequence :
is_BufferSequence<T, boost::asio::const_buffer>
#endif
{
};
/// Determine if `T` meets the requirements of @b `MutableBufferSequence`.
template<class T>
#if GENERATING_DOCS
struct is_MutableBufferSequence : std::integral_constant<bool, ...>
#else
struct is_MutableBufferSequence :
is_BufferSequence<T, boost::asio::mutable_buffer>
#endif
{
};
/// Determine if `T` meets the requirements of @b `Streambuf`.
template<class T>
#if GENERATING_DOCS
struct is_Streambuf : std::integral_constant<bool, ...>
#else
struct is_Streambuf : detail::is_Streambuf<T>::type
#endif
{
};
} // beast
#endif

View File

@@ -8,15 +8,16 @@
#ifndef BEAST_BUFFERS_ADAPTER_HPP
#define BEAST_BUFFERS_ADAPTER_HPP
#include <beast/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
#include <type_traits>
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<class Buffers>
template<class MutableBufferSequence>
class buffers_adapter
{
private:
using buffers_type = typename std::decay<Buffers>::type;
using iter_type = typename buffers_type::const_iterator;
static_assert(is_MutableBufferSequence<MutableBufferSequence>::value,
"MutableBufferSequence requirements not met");
static auto constexpr is_mutable =
std::is_constructible<boost::asio::mutable_buffer,
typename std::iterator_traits<iter_type>::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;

View File

@@ -8,6 +8,7 @@
#ifndef BEAST_CONSUMING_BUFFERS_HPP
#define BEAST_CONSUMING_BUFFERS_HPP
#include <beast/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
#include <cstdint>
#include <iterator>
@@ -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<class Buffers,
class ValueType = typename Buffers::value_type>
template<class BufferSequence,
class ValueType = typename BufferSequence::value_type>
class consuming_buffers
{
using iter_type =
typename Buffers::const_iterator;
typename BufferSequence::const_iterator;
static_assert(is_BufferSequence<BufferSequence, ValueType>::value,
"BufferSequence requirements not met");
static_assert(std::is_constructible<ValueType,
typename std::iterator_traits<iter_type>::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

View File

@@ -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 <beast/detail/integer_sequence.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <utility>
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 Handler, class... Args>
class bound_handler
{
private:
using args_type = std::tuple<
typename std::decay<Args>::type...>;
Handler h_;
args_type args_;
template<class Tuple, std::size_t... S>
static void invoke(Handler& h, Tuple& args,
index_sequence<S...>)
{
h(std::get<S>(args)...);
}
public:
using result_type = void;
template<class DeducedHandler>
explicit
bound_handler(DeducedHandler&& handler, Args&&... args)
: h_(std::forward<DeducedHandler>(handler))
, args_(std::forward<Args>(args)...)
{
}
void
operator()()
{
invoke(h_, args_,
index_sequence_for<Args...> ());
}
void
operator()() const
{
invoke(h_, args_,
index_sequence_for<Args...> ());
}
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<class F>
friend
void
asio_handler_invoke(F&& f, bound_handler* h)
{
boost_asio_handler_invoke_helpers::
invoke(f, h->h_);
}
};
} // detail
} // beast
#include <functional>
namespace std {
template<class Handler, class... Args>
void bind(beast::detail::bound_handler<
Handler, Args...>, ...) = delete;
} // std
#endif

View File

@@ -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 <boost/asio/buffer.hpp>
#include <cstdint>
#include <iterator>
#include <new>
#include <stdexcept>
#include <tuple>
#include <utility>
namespace beast {
namespace detail {
template<class ValueType, class... Bs>
class buffer_cat_helper
{
std::tuple<Bs...> 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<class U>
std::size_t constexpr
max_sizeof()
{
return sizeof(U);
}
template<class U0, class U1, class... Us>
std::size_t constexpr
max_sizeof()
{
return
max_sizeof<U0>() > max_sizeof<U1, Us...>() ?
max_sizeof<U0>() : max_sizeof<U1, Us...>();
}
template<class ValueType, class... Bs>
class buffer_cat_helper<
ValueType, Bs...>::const_iterator
{
std::size_t n_;
std::tuple<Bs...> const* bs_;
std::array<std::uint8_t,
max_sizeof<typename Bs::const_iterator...>()> buf_;
friend class buffer_cat_helper<ValueType, Bs...>;
template<std::size_t I>
using C = std::integral_constant<std::size_t, I>;
template<std::size_t I>
using iter_t = typename std::tuple_element<
I, std::tuple<Bs...>>::type::const_iterator;
template<std::size_t I>
iter_t<I>&
iter()
{
return *reinterpret_cast<
iter_t<I>*>(buf_.data());
}
template<std::size_t I>
iter_t<I> const&
iter() const
{
return *reinterpret_cast<
iter_t<I> 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<Bs...> const& bs, bool at_end);
void
construct(C<sizeof...(Bs)>)
{
auto constexpr I = sizeof...(Bs);
n_ = I;
}
template<std::size_t I>
void
construct(C<I>)
{
if(std::get<I>(*bs_).begin() !=
std::get<I>(*bs_).end())
{
n_ = I;
new(buf_.data()) iter_t<I>{
std::get<I>(*bs_).begin()};
return;
}
construct(C<I+1>{});
}
void
destroy(C<sizeof...(Bs)>)
{
return;
}
template<std::size_t I>
void
destroy(C<I>)
{
if(n_ == I)
{
using Iter = iter_t<I>;
iter<I>().~Iter();
return;
}
destroy(C<I+1>{});
}
void
move(C<sizeof...(Bs)>, const_iterator&&)
{
return;
}
template<std::size_t I>
void
move(C<I>, const_iterator&& other)
{
if(n_ == I)
{
new(buf_.data()) iter_t<I>{
std::move(other.iter<I>())};
return;
}
move(C<I+1>{}, std::move(other));
}
void
copy(C<sizeof...(Bs)>, const_iterator const&)
{
return;
}
template<std::size_t I>
void
copy(C<I>, const_iterator const& other)
{
if(n_ == I)
{
new(buf_.data()) iter_t<I>{
other.iter<I>()};
return;
}
copy(C<I+1>{}, other);
}
bool
equal(C<sizeof...(Bs)>,
const_iterator const&) const
{
return true;
}
template<std::size_t I>
bool
equal(C<I>, const_iterator const& other) const
{
if(n_ == I)
return iter<I>() == other.iter<I>();
return equal(C<I+1>{}, other);
}
[[noreturn]]
reference
dereference(C<sizeof...(Bs)>) const
{
throw std::logic_error("invalid iterator");
}
template<std::size_t I>
reference
dereference(C<I>) const
{
if(n_ == I)
return *iter<I>();
return dereference(C<I+1>{});
}
[[noreturn]]
void
increment(C<sizeof...(Bs)>)
{
throw std::logic_error("invalid iterator");
}
template<std::size_t I>
void
increment(C<I>)
{
if(n_ == I)
{
if(++iter<I>() !=
std::get<I>(*bs_).end())
return;
using Iter = iter_t<I>;
iter<I>().~Iter();
return construct(C<I+1>{});
}
increment(C<I+1>{});
}
void
decrement(C<sizeof...(Bs)>)
{
auto constexpr I = sizeof...(Bs);
if(n_ == I)
{
--n_;
new(buf_.data()) iter_t<I-1>{
std::get<I-1>(*bs_).end()};
}
decrement(C<I-1>{});
}
void
decrement(C<0>)
{
auto constexpr I = 0;
if(iter<I>() != std::get<I>(*bs_).begin())
{
--iter<I>();
return;
}
throw std::logic_error("invalid iterator");
}
template<std::size_t I>
void
decrement(C<I>)
{
if(n_ == I)
{
if(iter<I>() != std::get<I>(*bs_).begin())
{
--iter<I>();
return;
}
--n_;
using Iter = iter_t<I>;
iter<I>().~Iter();
new(buf_.data()) iter_t<I-1>{
std::get<I-1>(*bs_).end()};
}
decrement(C<I-1>{});
}
};
//------------------------------------------------------------------------------
template<class ValueType, class... Bs>
buffer_cat_helper<ValueType, Bs...>::
const_iterator::~const_iterator()
{
destroy(C<0>{});
}
template<class ValueType, class... Bs>
buffer_cat_helper<ValueType, Bs...>::
const_iterator::const_iterator()
: n_(sizeof...(Bs))
, bs_(nullptr)
{
}
template<class ValueType, class... Bs>
buffer_cat_helper<ValueType, Bs...>::
const_iterator::const_iterator(
std::tuple<Bs...> const& bs, bool at_end)
: bs_(&bs)
{
if(at_end)
n_ = sizeof...(Bs);
else
construct(C<0>{});
}
template<class ValueType, class... Bs>
buffer_cat_helper<ValueType, Bs...>::
const_iterator::const_iterator(const_iterator&& other)
: n_(other.n_)
, bs_(other.bs_)
{
move(C<0>{}, std::move(other));
}
template<class ValueType, class... Bs>
buffer_cat_helper<ValueType, Bs...>::
const_iterator::const_iterator(const_iterator const& other)
: n_(other.n_)
, bs_(other.bs_)
{
copy(C<0>{}, other);
}
template<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::
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<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::
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<class ValueType, class... Bs>
bool
buffer_cat_helper<ValueType, Bs...>::
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<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::
const_iterator::operator*() const ->
reference
{
return dereference(C<0>{});
}
template<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::
const_iterator::operator++() ->
const_iterator&
{
increment(C<0>{});
return *this;
}
template<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::
const_iterator::operator--() ->
const_iterator&
{
decrement(C<sizeof...(Bs)>{});
return *this;
}
template<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::begin() const ->
const_iterator
{
return const_iterator(bs_, false);
}
template<class ValueType, class... Bs>
auto
buffer_cat_helper<ValueType, Bs...>::end() const ->
const_iterator
{
return const_iterator(bs_, true);
}
} // detail
} // beast
#endif

View File

@@ -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 <boost/asio/buffer.hpp>
#include <iterator>
#include <type_traits>
namespace beast {
namespace detail {
// Types that meet the requirements,
// for use with std::declval only.
template<class BufferType>
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<boost::asio::const_buffer>;
using MutableBufferSequence =
BufferSequence<boost::asio::mutable_buffer>;
template<class T, class BufferType>
class is_BufferSequence
{
template<class U, class R = std::is_convertible<
typename U::value_type, BufferType> >
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_base_of<
#if 0
std::bidirectional_iterator_tag,
typename std::iterator_traits<
typename U::const_iterator>::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<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
template<class U, class R = typename
std::is_convertible<decltype(
std::declval<U>().begin()),
typename U::const_iterator>::type>
static R check3(int);
template<class>
static std::false_type check3(...);
using type3 = decltype(check3<T>(0));
template<class U, class R = typename std::is_convertible<decltype(
std::declval<U>().end()),
typename U::const_iterator>::type>
static R check4(int);
template<class>
static std::false_type check4(...);
using type4 = decltype(check4<T>(0));
public:
using type = std::integral_constant<bool,
std::is_copy_constructible<T>::value &&
std::is_destructible<T>::value &&
type1::value && type2::value &&
type3::value && type4::value>;
};
template<class T>
class is_Streambuf
{
template<class U, class R = std::integral_constant<
bool, is_BufferSequence<decltype(
std::declval<U>().prepare(1)),
boost::asio::mutable_buffer>::type::value>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::integral_constant<
bool, is_BufferSequence<decltype(
std::declval<U>().data()),
boost::asio::const_buffer>::type::value>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
template<class U, class R = decltype(
std::declval<U>().commit(1), std::true_type{})>
static R check3(int);
template<class>
static std::false_type check3(...);
using type3 = decltype(check3<T>(0));
template<class U, class R = decltype(
std::declval<U>().consume(1), std::true_type{})>
static R check4(int);
template<class>
static std::false_type check4(...);
using type4 = decltype(check4<T>(0));
template<class U, class R = std::is_same<decltype(
std::declval<U>().size()), std::size_t>>
static R check5(int);
template<class>
static std::false_type check5(...);
using type5 = decltype(check5<T>(0));
public:
using type = std::integral_constant<bool,
type1::value && type2::value &&
type3::value && type4::value &&
type5::value>;
};
} // detail
} // beast
#endif

View File

@@ -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 <beast/buffer_concepts.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/system/error_code.hpp>
#include <type_traits>
#include <utility>
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 T>
class has_get_io_service
{
template<class U, class R = typename std::is_same<
decltype(std::declval<U>().get_io_service()),
boost::asio::io_service&>>
static R check(int);
template <class>
static std::false_type check(...);
public:
using type = decltype(check<T>(0));
};
template<class T>
class is_AsyncReadStream
{
template<class U, class R = decltype(
std::declval<U>().async_read_some(
std::declval<MutableBufferSequence>(),
std::declval<ReadHandler>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type1 = decltype(check<T>(0));
public:
using type = std::integral_constant<bool,
type1::value &&
has_get_io_service<T>::type::value>;
};
template<class T>
class is_AsyncWriteStream
{
template<class U, class R = decltype(
std::declval<U>().async_write_some(
std::declval<ConstBufferSequence>(),
std::declval<WriteHandler>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type1 = decltype(check<T>(0));
public:
using type = std::integral_constant<bool,
type1::value &&
has_get_io_service<T>::type::value>;
};
template<class T>
class is_SyncReadStream
{
using error_code =
boost::system::error_code;
template<class U, class R = std::is_same<decltype(
std::declval<U>().read_some(
std::declval<MutableBufferSequence>())),
std::size_t>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_same<decltype(
std::declval<U>().read_some(
std::declval<MutableBufferSequence>(),
std::declval<error_code&>())), std::size_t>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
public:
using type = std::integral_constant<bool,
type1::value && type2::value>;
};
template<class T>
class is_SyncWriteStream
{
using error_code =
boost::system::error_code;
template<class U, class R = std::is_same<decltype(
std::declval<U>().write_some(
std::declval<ConstBufferSequence>())),
std::size_t>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_same<decltype(
std::declval<U>().write_some(
std::declval<ConstBufferSequence>(),
std::declval<error_code&>())), std::size_t>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
public:
using type = std::integral_constant<bool,
type1::value && type2::value>;
};
} // detail
} // beast
#endif

View File

@@ -8,6 +8,7 @@
#ifndef BEAST_DETAIL_WRITE_STREAMBUF_HPP
#define BEAST_DETAIL_WRITE_STREAMBUF_HPP
#include <beast/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/lexical_cast.hpp>
#include <utility>

170
include/beast/doc_debug.hpp Normal file
View File

@@ -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

View File

@@ -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 <class T, class Handler>
template <class T, class CompletionHandler>
class handler_alloc;
#else
template <class T, class Handler>
template <class T, class CompletionHandler>
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 <class U, class H>
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<class U>
handler_alloc(
handler_alloc<U, Handler>&& other)
handler_alloc<U, CompletionHandler>&& other)
: h_(std::move(other.h_))
{
}
template<class U>
handler_alloc(
handler_alloc<U, Handler> const& other)
handler_alloc<U, CompletionHandler> const& other)
: h_(other.h_)
{
}
@@ -127,7 +127,7 @@ public:
friend
bool
operator==(handler_alloc const& lhs,
handler_alloc<U, Handler> const& rhs)
handler_alloc<U, CompletionHandler> const& rhs)
{
return true;
}
@@ -136,7 +136,7 @@ public:
friend
bool
operator!=(handler_alloc const& lhs,
handler_alloc<U, Handler> const& rhs)
handler_alloc<U, CompletionHandler> const& rhs)
{
return !(lhs == rhs);
}

View File

@@ -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 <beast/detail/is_call_possible.hpp>
#include <type_traits>
namespace beast {
/// Determine if `T` meets the requirements of @b `CompletionHandler`.
template<class T, class Signature>
#if GENERATING_DOCS
using is_CompletionHandler = std::integral_constant<bool, ...>;
#else
using is_CompletionHandler = std::integral_constant<bool,
std::is_copy_constructible<typename std::decay<T>::type>::value &&
detail::is_call_possible<T, Signature>::value>;
#endif
} // beast
#endif

View File

@@ -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 <beast/http/basic_headers.hpp>
#include <beast/http/basic_parser_v1.hpp>
#include <beast/http/body_writer.hpp>
#include <beast/http/body_type.hpp>
#include <beast/http/empty_body.hpp>
#include <beast/http/error.hpp>
#include <beast/http/headers.hpp>

View File

@@ -8,7 +8,6 @@
#ifndef BEAST_HTTP_BASIC_HEADERS_HPP
#define BEAST_HTTP_BASIC_HEADERS_HPP
#include <beast/type_check.hpp>
#include <beast/detail/ci_char_traits.hpp>
#include <beast/detail/empty_base_optimization.hpp>
#include <boost/intrusive/list.hpp>
@@ -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 Allocator>
class basic_headers

View File

@@ -12,7 +12,6 @@
#include <beast/http/parse_error.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/http/detail/basic_parser_v1.hpp>
#include <beast/type_check.hpp>
#include <boost/asio/buffer.hpp>
#include <array>
#include <cassert>
@@ -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:<br>
@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<class ConstBufferSequence,
class = typename std::enable_if<
! std::is_convertible<ConstBufferSequence,
boost::asio::const_buffer>::value>::type
>
template<class ConstBufferSequence>
#if GENERATING_DOCS
std::size_t
#else
typename std::enable_if<
! std::is_convertible<ConstBufferSequence,
boost::asio::const_buffer>::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);

View File

@@ -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 <beast/http/error.hpp>
#include <beast/http/message.hpp>

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_EMPTY_BODY_HPP
#define BEAST_HTTP_EMPTY_BODY_HPP
#include <beast/http/body_writer.hpp>
#include <beast/http/body_type.hpp>
#include <beast/streambuf.hpp>
#include <boost/asio/buffer.hpp>
#include <memory>
@@ -18,6 +18,8 @@ namespace beast {
namespace http {
/** An empty content-body.
Meets the requirements of @b `Body`.
*/
struct empty_body
{

View File

@@ -9,6 +9,7 @@
#define BEAST_HTTP_ERROR_HPP
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
namespace beast {
namespace http {

View File

@@ -8,8 +8,6 @@
#ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
#include <beast/type_check.hpp>
namespace beast {
namespace http {

View File

@@ -8,6 +8,8 @@
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
#include <beast/buffer_concepts.hpp>
namespace beast {
namespace http {
@@ -32,8 +34,11 @@ keep_alive() const
// Implementation inspired by nodejs/http-parser
template<bool isRequest, class Derived>
template<class ConstBufferSequence, class>
std::size_t
template<class ConstBufferSequence>
typename std::enable_if<
! std::is_convertible<ConstBufferSequence,
boost::asio::const_buffer>::value,
std::size_t>::type
basic_parser_v1<isRequest, Derived>::
write(ConstBufferSequence const& buffers, error_code& ec)
{

View File

@@ -10,7 +10,6 @@
#include <beast/http/rfc2616.hpp>
#include <beast/http/detail/has_content_length.hpp>
#include <beast/type_check.hpp>
#include <boost/optional.hpp>
#include <stdexcept>

View File

@@ -11,6 +11,7 @@
#include <beast/http/parser_v1.hpp>
#include <beast/bind_handler.hpp>
#include <beast/handler_alloc.hpp>
#include <beast/stream_concepts.hpp>
#include <cassert>
namespace beast {

View File

@@ -13,9 +13,10 @@
#include <beast/http/detail/has_content_length.hpp>
#include <beast/buffer_cat.hpp>
#include <beast/bind_handler.hpp>
#include <beast/buffer_concepts.hpp>
#include <beast/handler_alloc.hpp>
#include <beast/stream_concepts.hpp>
#include <beast/streambuf.hpp>
#include <beast/type_check.hpp>
#include <beast/write_streambuf.hpp>
#include <boost/asio/write.hpp>
#include <boost/logic/tribool.hpp>

View File

@@ -9,7 +9,6 @@
#define BEAST_HTTP_MESSAGE_HPP
#include <beast/http/basic_headers.hpp>
#include <beast/type_check.hpp>
#include <memory>
#include <string>

View File

@@ -9,7 +9,6 @@
#define BEAST_HTTP_MESSAGE_V1_HPP
#include <beast/http/message.hpp>
#include <beast/type_check.hpp>
#include <memory>
#include <string>
@@ -92,7 +91,7 @@ is_upgrade(message_v1<isRequest, Body, Headers> 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
{

View File

@@ -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<class SyncReadStream, class Streambuf,
bool isRequest, class Body, class Headers>
@@ -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<isRequest, Body, Headers>& 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
<em>composed operation</em>. 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<class AsyncReadStream, class Streambuf,
bool isRequest, class Body, class Headers,

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_STREAMBUF_BODY_HPP
#define BEAST_HTTP_STREAMBUF_BODY_HPP
#include <beast/http/body_writer.hpp>
#include <beast/http/body_type.hpp>
#include <beast/buffer_cat.hpp>
#include <beast/streambuf.hpp>
#include <memory>
@@ -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<class Streambuf>
struct basic_streambuf_body
@@ -34,10 +36,10 @@ private:
value_type& sb_;
public:
template<bool isRequest, class Allocator>
template<bool isRequest, class Headers>
explicit
reader(message<isRequest,
basic_streambuf_body, Allocator>& m) noexcept
basic_streambuf_body, Headers>& m) noexcept
: sb_(m.body)
{
}

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_STRING_BODY_HPP
#define BEAST_HTTP_STRING_BODY_HPP
#include <beast/http/body_writer.hpp>
#include <beast/http/body_type.hpp>
#include <beast/buffer_cat.hpp>
#include <beast/streambuf.hpp>
#include <memory>
@@ -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<bool isRequest, class Allocator>
template<bool isRequest, class Headers>
explicit
reader(message<isRequest,
string_body, Allocator>& m) noexcept
string_body, Headers>& m) noexcept
: s_(m.body)
{
}

View File

@@ -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<class SyncWriteStream,
bool isRequest, class Body, class Headers>
@@ -32,11 +49,28 @@ void
write(SyncWriteStream& stream,
message_v1<isRequest, Body, Headers> 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<isRequest, Body, Headers> 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 <em>composed
operation</em>. 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<class AsyncWriteStream,
@@ -85,6 +141,9 @@ async_write(AsyncWriteStream& stream,
The function converts the message to its HTTP/1 serialized
representation and stores the result in the output stream.
The implementation will automatically perform chunk encoding if
the contents of the message indicate that chunk encoding is required.
@param os The ostream to write to.
@param msg The message to write.

View File

@@ -8,6 +8,7 @@
#ifndef BEAST_IMPL_BASIC_STREAMBUF_IPP
#define BEAST_IMPL_BASIC_STREAMBUF_IPP
#include <beast/detail/write_streambuf.hpp>
#include <algorithm>
#include <cassert>
#include <exception>
@@ -849,22 +850,6 @@ basic_streambuf<Allocator>::debug_check() const
#endif
}
template<class Alloc, class T>
basic_streambuf<Alloc>&
operator<<(basic_streambuf<Alloc>& 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<class Allocator>
std::size_t
read_size_helper(basic_streambuf<
@@ -874,17 +859,12 @@ read_size_helper(basic_streambuf<
std::max<std::size_t>(512, streambuf.prepare_size()));
}
template<class Allocator>
std::string
to_string(basic_streambuf<Allocator> const& streambuf)
template<class Alloc, class T>
basic_streambuf<Alloc>&
operator<<(basic_streambuf<Alloc>& 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

View File

@@ -17,8 +17,9 @@
namespace beast {
template<class Buffers>
class buffers_adapter<Buffers>::const_buffers_type
template<class MutableBufferSequence>
class buffers_adapter<MutableBufferSequence>::
const_buffers_type
{
buffers_adapter const* ba_;
@@ -48,8 +49,9 @@ private:
}
};
template<class Buffers>
class buffers_adapter<Buffers>::const_buffers_type::const_iterator
template<class MutableBufferSequence>
class buffers_adapter<MutableBufferSequence>::
const_buffers_type::const_iterator
{
iter_type it_;
buffers_adapter const* ba_ = nullptr;
@@ -136,19 +138,19 @@ private:
}
};
template<class Buffers>
template<class MutableBufferSequence>
inline
auto
buffers_adapter<Buffers>::const_buffers_type::begin() const ->
buffers_adapter<MutableBufferSequence>::const_buffers_type::begin() const ->
const_iterator
{
return const_iterator{*ba_, ba_->begin_};
}
template<class Buffers>
template<class MutableBufferSequence>
inline
auto
buffers_adapter<Buffers>::const_buffers_type::end() const ->
buffers_adapter<MutableBufferSequence>::const_buffers_type::end() const ->
const_iterator
{
return const_iterator{*ba_, ba_->out_ ==
@@ -157,8 +159,9 @@ buffers_adapter<Buffers>::const_buffers_type::end() const ->
//------------------------------------------------------------------------------
template<class Buffers>
class buffers_adapter<Buffers>::mutable_buffers_type
template<class MutableBufferSequence>
class buffers_adapter<MutableBufferSequence>::
mutable_buffers_type
{
buffers_adapter const* ba_;
@@ -189,8 +192,9 @@ private:
}
};
template<class Buffers>
class buffers_adapter<Buffers>::mutable_buffers_type::const_iterator
template<class MutableBufferSequence>
class buffers_adapter<MutableBufferSequence>::
mutable_buffers_type::const_iterator
{
iter_type it_;
buffers_adapter const* ba_ = nullptr;
@@ -277,19 +281,19 @@ private:
}
};
template<class Buffers>
template<class MutableBufferSequence>
inline
auto
buffers_adapter<Buffers>::mutable_buffers_type::begin() const ->
buffers_adapter<MutableBufferSequence>::mutable_buffers_type::begin() const ->
const_iterator
{
return const_iterator{*ba_, ba_->out_};
}
template<class Buffers>
template<class MutableBufferSequence>
inline
auto
buffers_adapter<Buffers>::mutable_buffers_type::end() const ->
buffers_adapter<MutableBufferSequence>::mutable_buffers_type::end() const ->
const_iterator
{
return const_iterator{*ba_, ba_->end_};
@@ -297,8 +301,8 @@ buffers_adapter<Buffers>::mutable_buffers_type::end() const ->
//------------------------------------------------------------------------------
template<class Buffers>
buffers_adapter<Buffers>::buffers_adapter(
template<class MutableBufferSequence>
buffers_adapter<MutableBufferSequence>::buffers_adapter(
buffers_adapter&& other)
: buffers_adapter(std::move(other),
std::distance<iter_type>(other.bs_.begin(), other.begin_),
@@ -307,8 +311,8 @@ buffers_adapter<Buffers>::buffers_adapter(
{
}
template<class Buffers>
buffers_adapter<Buffers>::buffers_adapter(
template<class MutableBufferSequence>
buffers_adapter<MutableBufferSequence>::buffers_adapter(
buffers_adapter const& other)
: buffers_adapter(other,
std::distance<iter_type>(other.bs_.begin(), other.begin_),
@@ -317,9 +321,9 @@ buffers_adapter<Buffers>::buffers_adapter(
{
}
template<class Buffers>
template<class MutableBufferSequence>
auto
buffers_adapter<Buffers>::operator=(
buffers_adapter<MutableBufferSequence>::operator=(
buffers_adapter&& other) -> buffers_adapter&
{
auto const nbegin = std::distance<iter_type>(
@@ -340,9 +344,9 @@ buffers_adapter<Buffers>::operator=(
return *this;
}
template<class Buffers>
template<class MutableBufferSequence>
auto
buffers_adapter<Buffers>::operator=(
buffers_adapter<MutableBufferSequence>::operator=(
buffers_adapter const& other) -> buffers_adapter&
{
auto const nbegin = std::distance<iter_type>(
@@ -363,9 +367,9 @@ buffers_adapter<Buffers>::operator=(
return *this;
}
template<class Buffers>
buffers_adapter<Buffers>::buffers_adapter(
Buffers const& bs)
template<class MutableBufferSequence>
buffers_adapter<MutableBufferSequence>::buffers_adapter(
MutableBufferSequence const& bs)
: bs_(bs)
, begin_(bs_.begin())
, out_(bs_.begin())
@@ -374,14 +378,12 @@ buffers_adapter<Buffers>::buffers_adapter(
{
}
template<class Buffers>
template<class MutableBufferSequence>
auto
buffers_adapter<Buffers>::prepare(std::size_t n) ->
buffers_adapter<MutableBufferSequence>::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<Buffers>::prepare(std::size_t n) ->
return mutable_buffers_type{*this};
}
template<class Buffers>
template<class MutableBufferSequence>
void
buffers_adapter<Buffers>::commit(std::size_t n)
buffers_adapter<MutableBufferSequence>::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<Buffers>::commit(std::size_t n)
}
}
template<class Buffers>
template<class MutableBufferSequence>
inline
auto
buffers_adapter<Buffers>::data() const ->
buffers_adapter<MutableBufferSequence>::data() const ->
const_buffers_type
{
return const_buffers_type{*this};
}
template<class Buffers>
template<class MutableBufferSequence>
void
buffers_adapter<Buffers>::consume(std::size_t n)
buffers_adapter<MutableBufferSequence>::consume(std::size_t n)
{
for(;;)
{

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_IMPL_CONSUMING_BUFFERS_IPP
#define BEAST_IMPL_CONSUMING_BUFFERS_IPP
#include <beast/type_check.hpp>
#include <beast/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <cstdint>
@@ -18,13 +18,13 @@
namespace beast {
template<class Buffers, class ValueType>
class consuming_buffers<Buffers, ValueType>::const_iterator
template<class BufferSequence, class ValueType>
class consuming_buffers<BufferSequence, ValueType>::const_iterator
{
friend class consuming_buffers<Buffers, ValueType>;
friend class consuming_buffers<BufferSequence, ValueType>;
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<class Buffers, class ValueType>
consuming_buffers<Buffers, ValueType>::
template<class BufferSequence, class ValueType>
consuming_buffers<BufferSequence, ValueType>::
consuming_buffers(consuming_buffers&& other)
: consuming_buffers(std::move(other),
std::distance<iter_type>(
@@ -114,8 +114,8 @@ consuming_buffers(consuming_buffers&& other)
{
}
template<class Buffers, class ValueType>
consuming_buffers<Buffers, ValueType>::
template<class BufferSequence, class ValueType>
consuming_buffers<BufferSequence, ValueType>::
consuming_buffers(consuming_buffers const& other)
: consuming_buffers(other,
std::distance<iter_type>(
@@ -123,9 +123,9 @@ consuming_buffers(consuming_buffers const& other)
{
}
template<class Buffers, class ValueType>
template<class BufferSequence, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::
consuming_buffers<BufferSequence, ValueType>::
operator=(consuming_buffers&& other) ->
consuming_buffers&
{
@@ -137,9 +137,9 @@ operator=(consuming_buffers&& other) ->
return *this;
}
template<class Buffers, class ValueType>
template<class BufferSequence, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::
consuming_buffers<BufferSequence, ValueType>::
operator=(consuming_buffers const& other) ->
consuming_buffers&
{
@@ -151,35 +151,35 @@ operator=(consuming_buffers const& other) ->
return *this;
}
template<class Buffers, class ValueType>
consuming_buffers<Buffers, ValueType>::
consuming_buffers(Buffers const& bs)
template<class BufferSequence, class ValueType>
consuming_buffers<BufferSequence, ValueType>::
consuming_buffers(BufferSequence const& bs)
: bs_(bs)
, begin_(bs_.begin())
{
static_assert(is_BufferSequence<Buffers, ValueType>::value,
static_assert(is_BufferSequence<BufferSequence, ValueType>::value,
"BufferSequence requirements not met");
}
template<class Buffers, class ValueType>
template<class BufferSequence, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::begin() const ->
consuming_buffers<BufferSequence, ValueType>::begin() const ->
const_iterator
{
return const_iterator{*this, begin_};
}
template<class Buffers, class ValueType>
template<class BufferSequence, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::end() const ->
consuming_buffers<BufferSequence, ValueType>::end() const ->
const_iterator
{
return const_iterator{*this, bs_.end()};
}
template<class Buffers, class ValueType>
template<class BufferSequence, class ValueType>
void
consuming_buffers<Buffers, ValueType>::consume(std::size_t n)
consuming_buffers<BufferSequence, ValueType>::consume(std::size_t n)
{
using boost::asio::buffer_size;
for(;n > 0 && begin_ != bs_.end(); ++begin_)
@@ -196,11 +196,11 @@ consuming_buffers<Buffers, ValueType>::consume(std::size_t n)
}
}
template<class Buffers>
consuming_buffers<Buffers, typename Buffers::value_type>
consumed_buffers(Buffers const& bs, std::size_t n)
template<class BufferSequence>
consuming_buffers<BufferSequence, typename BufferSequence::value_type>
consumed_buffers(BufferSequence const& bs, std::size_t n)
{
consuming_buffers<Buffers> cb(bs);
consuming_buffers<BufferSequence> cb(bs);
cb.consume(n);
return cb;
}

View File

@@ -9,7 +9,10 @@
#define BEAST_IMPL_STREAMBUF_READSTREAM_IPP
#include <beast/bind_handler.hpp>
#include <beast/handler_concepts.hpp>
#include <beast/handler_alloc.hpp>
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
namespace beast {
@@ -157,8 +160,6 @@ streambuf_readstream<Stream, Streambuf>::
streambuf_readstream(Args&&... args)
: next_layer_(std::forward<Args>(args)...)
{
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
}
template<class Stream, class Streambuf>
@@ -175,7 +176,7 @@ async_write_some(ConstBufferSequence const& buffers,
static_assert(is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
static_assert(is_Handler<WriteHandler,
static_assert(is_CompletionHandler<WriteHandler,
void(error_code, std::size_t)>::value,
"WriteHandler requirements not met");
return next_layer_.async_write_some(buffers,

View File

@@ -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<std::size_t>(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<std::size_t N>
class static_streambuf_n
: private boost::base_from_member<
: public static_streambuf
#if ! GENERATING_DOCS
, private boost::base_from_member<
std::array<std::uint8_t, N>>
, public static_streambuf
#endif
{
using member_type = boost::base_from_member<
std::array<std::uint8_t, N>>;

View File

@@ -20,7 +20,6 @@
#ifndef BEAST_WEBSOCKET_STATIC_STRING_HPP
#define BEAST_WEBSOCKET_STATIC_STRING_HPP
#include <algorithm>
#include <array>
#include <cstdint>
#include <iterator>
@@ -28,13 +27,11 @@
#include <string>
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

View File

@@ -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 <beast/detail/stream_concepts.hpp>
#include <type_traits>
namespace beast {
/// Determine if `T` has the `get_io_service` member.
template<class T>
#if GENERATING_DOCS
struct has_get_io_service : std::integral_constant<bool, ...>{};
#else
using has_get_io_service = typename detail::has_get_io_service<T>::type;
#endif
/// Determine if `T` meets the requirements of @b `AsyncReadStream`.
template<class T>
#if GENERATING_DOCS
struct is_AsyncReadStream : std::integral_constant<bool, ...>{};
#else
using is_AsyncReadStream = typename detail::is_AsyncReadStream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b `AsyncWriteStream`.
template<class T>
#if GENERATING_DOCS
struct is_AsyncWriteStream : std::integral_constant<bool, ...>{};
#else
using is_AsyncWriteStream = typename detail::is_AsyncWriteStream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b `SyncReadStream`.
template<class T>
#if GENERATING_DOCS
struct is_SyncReadStream : std::integral_constant<bool, ...>{};
#else
using is_SyncReadStream = typename detail::is_SyncReadStream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b `SyncWriterStream`.
template<class T>
#if GENERATING_DOCS
struct is_SyncWriteStream : std::integral_constant<bool, ...>{};
#else
using is_SyncWriteStream = typename detail::is_SyncWriteStream<T>::type;
#endif
/// Determine if `T` meets the requirements of @b `AsyncStream`.
template<class T>
#if GENERATING_DOCS
struct is_AsyncStream : std::integral_constant<bool, ...>{};
#else
using is_AsyncStream = std::integral_constant<bool,
is_AsyncReadStream<T>::value && is_AsyncWriteStream<T>::value>;
#endif
/// Determine if `T` meets the requirements of @b `SyncStream`.
template<class T>
#if GENERATING_DOCS
struct is_SyncStream : std::integral_constant<bool, ...>{};
#else
using is_SyncStream = std::integral_constant<bool,
is_SyncReadStream<T>::value && is_SyncWriteStream<T>::value>;
#endif
} // beast
#endif

View File

@@ -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<std::allocator<char>>;
} // beast

View File

@@ -9,8 +9,9 @@
#define BEAST_STREAMBUF_READSTREAM_HPP
#include <beast/async_completion.hpp>
#include <beast/buffer_concepts.hpp>
#include <beast/stream_concepts.hpp>
#include <beast/streambuf.hpp>
#include <beast/type_check.hpp>
#include <beast/detail/get_lowest_layer.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_service.hpp>
@@ -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 Stream, class Streambuf>
class streambuf_readstream
{
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
using error_code = boost::system::error_code;
template<class Buffers, class Handler>
@@ -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<class ConstBufferSequence, class WriteHandler>
typename async_completion<
WriteHandler, void(error_code)>::result_type
#if GENERATING_DOCS
void_or_deduced
#else
typename async_completion<WriteHandler, void(error_code)>::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<class MutableBufferSequence, class ReadHandler>
typename async_completion<
ReadHandler, void(error_code)>::result_type
#if GENERATING_DOCS
void_or_deduced
#else
typename async_completion<ReadHandler, void(error_code)>::result_type
#endif
async_read_some(MutableBufferSequence const& buffers,
ReadHandler&& handler);
};

View File

@@ -8,24 +8,24 @@
#ifndef BEAST_TO_STRING_HPP
#define BEAST_TO_STRING_HPP
#include <beast/type_check.hpp>
#include <beast/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
#include <string>
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<class ConstBufferSequence
#if ! GENERATING_DOCS

View File

@@ -1,356 +0,0 @@
//
// 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_TYPE_CHECK_HPP
#define BEAST_TYPE_CHECK_HPP
#include <beast/detail/is_call_possible.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
#include <iterator>
#include <type_traits>
#include <utility>
namespace beast {
//------------------------------------------------------------------------------
// Types that meet the requirements,
// for use with std::declval only.
//
#if GENERATING_DOCS
namespace detail {
#else
namespace concept {
#endif
template<class BufferType>
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<boost::asio::const_buffer>;
using MutableBufferSequence =
BufferSequence<boost::asio::mutable_buffer>;
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 T, class BufferType>
class is_BufferSequence
{
template<class U, class R = std::is_convertible<
typename U::value_type, BufferType> >
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_base_of<
#if 0
std::bidirectional_iterator_tag,
typename std::iterator_traits<
typename U::const_iterator>::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<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
template<class U, class R = typename
std::is_convertible<decltype(
std::declval<U>().begin()),
typename U::const_iterator>::type>
static R check3(int);
template<class>
static std::false_type check3(...);
using type3 = decltype(check3<T>(0));
template<class U, class R = typename std::is_convertible<decltype(
std::declval<U>().end()),
typename U::const_iterator>::type>
static R check4(int);
template<class>
static std::false_type check4(...);
using type4 = decltype(check4<T>(0));
public:
/// `true` if `T` meets the requirements.
static bool const value =
std::is_copy_constructible<T>::value &&
std::is_destructible<T>::value &&
type1::value && type2::value &&
type3::value && type4::value;
};
#if ! GENERATING_DOCS
/// Determine if `T` meets the requirements of `ConstBufferSequence`.
template<class T>
using is_ConstBufferSequence =
is_BufferSequence<T, boost::asio::const_buffer>;
static_assert(is_ConstBufferSequence<concept::ConstBufferSequence>::value, "");
static_assert(! is_ConstBufferSequence<int>::value, "");
/// Determine if `T` meets the requirements of `MutableBufferSequence`.
template<class C>
using is_MutableBufferSequence =
is_BufferSequence<C, boost::asio::mutable_buffer>;
static_assert(is_MutableBufferSequence<concept::MutableBufferSequence>::value, "");
static_assert(! is_MutableBufferSequence<int>::value, "");
#endif
//------------------------------------------------------------------------------
/// Determine if `T` has the `get_io_service` member.
template<class T>
class has_get_io_service
{
template<class U, class R = typename std::is_same<
decltype(std::declval<U>().get_io_service()),
boost::asio::io_service&>>
static R check(int);
template <class>
static std::false_type check(...);
using type = decltype(check<T>(0));
public:
/// `true` if `T` meets the requirements.
static bool const value = type::value;
};
static_assert(! has_get_io_service<int>::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 T>
class is_AsyncReadStream
{
template<class U, class R = decltype(
std::declval<U>().async_read_some(
std::declval<concept::MutableBufferSequence>(),
std::declval<concept::ReadHandler>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type = decltype(check<T>(0));
public:
/// `true` if `T` meets the requirements.
static bool const value =
has_get_io_service<T>::value && type::value;
};
static_assert(! is_AsyncReadStream<int>::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 T>
class is_AsyncWriteStream
{
template<class U, class R = decltype(
std::declval<U>().async_write_some(
std::declval<concept::ConstBufferSequence>(),
std::declval<concept::WriteHandler>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type = decltype(check<T>(0));
public:
/// `true` if `T` meets the requirements.
static bool const value =
has_get_io_service<T>::value && type::value;
};
static_assert(! is_AsyncWriteStream<int>::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 T>
class is_SyncReadStream
{
using error_code =
boost::system::error_code;
template<class U, class R = std::is_same<decltype(
std::declval<U>().read_some(
std::declval<concept::MutableBufferSequence>())),
std::size_t>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_same<decltype(
std::declval<U>().read_some(
std::declval<concept::MutableBufferSequence>(),
std::declval<error_code&>())), std::size_t>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
public:
/// `true` if `T` meets the requirements.
static bool const value =
type1::value && type2::value;
};
static_assert(! is_SyncReadStream<int>::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 T>
class is_SyncWriteStream
{
using error_code =
boost::system::error_code;
template<class U, class R = std::is_same<decltype(
std::declval<U>().write_some(
std::declval<concept::ConstBufferSequence>())),
std::size_t>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::is_same<decltype(
std::declval<U>().write_some(
std::declval<concept::ConstBufferSequence>(),
std::declval<error_code&>())), std::size_t>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
public:
/// `true` if `T` meets the requirements.
static bool const value =
type1::value && type2::value;
};
static_assert(! is_SyncWriteStream<int>::value, "");
/// Determine if `T` meets the requirements of `SyncStream`.
template<class T>
struct is_SyncStream
{
/// `true` if `T` meets the requirements.
static bool const value =
is_SyncReadStream<T>::value &&
is_SyncWriteStream<T>::value;
};
/// Determine if `T` meets the requirements of `SyncStream`.
template<class T>
struct is_AsyncStream
{
/// `true` if `T` meets the requirements.
static bool const value =
is_AsyncReadStream<T>::value &&
is_AsyncWriteStream<T>::value;
};
/// Determine if `T` meets the requirements of `Streambuf`.
template<class T>
class is_Streambuf
{
template<class U, class R = std::integral_constant<
bool, is_MutableBufferSequence<decltype(
std::declval<U>().prepare(1))>::value>>
static R check1(int);
template<class>
static std::false_type check1(...);
using type1 = decltype(check1<T>(0));
template<class U, class R = std::integral_constant<
bool, is_ConstBufferSequence<decltype(
std::declval<U>().data())>::value>>
static R check2(int);
template<class>
static std::false_type check2(...);
using type2 = decltype(check2<T>(0));
template<class U, class R = decltype(
std::declval<U>().commit(1), std::true_type{})>
static R check3(int);
template<class>
static std::false_type check3(...);
using type3 = decltype(check3<T>(0));
template<class U, class R = decltype(
std::declval<U>().consume(1), std::true_type{})>
static R check4(int);
template<class>
static std::false_type check4(...);
using type4 = decltype(check4<T>(0));
template<class U, class R = std::is_same<decltype(
std::declval<U>().size()), std::size_t>>
static R check5(int);
template<class>
static std::false_type check5(...);
using type5 = decltype(check5<T>(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<class T, class Signature>
using is_Handler = std::integral_constant<bool,
std::is_copy_constructible<typename std::decay<T>::type>::value &&
detail::is_call_possible<T, Signature>::value>;
#endif
} // beast
#endif

View File

@@ -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 <beast/unit_test/suite.h>
#include <boost/asio/buffer.hpp>
#include <iomanip>
#include <sstream>
@@ -82,7 +81,7 @@ format(std::string s)
}
} // detail
} // wsproto
} // websocket
} // beast
#endif

View File

@@ -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";
}
}

View File

@@ -9,6 +9,7 @@
#define BEAST_WEBSOCKET_ERROR_HPP
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
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

View File

@@ -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;

View File

@@ -9,7 +9,7 @@
#define BEAST_WEBSOCKET_IMPL_SSL_IPP_INCLUDED
#include <beast/async_completion.hpp>
#include <beast/type_check.hpp>
#include <beast/handler_concepts.hpp>
namespace beast {
namespace websocket {
@@ -144,7 +144,7 @@ async_teardown(
boost::asio::ssl::stream<AsyncStream>& 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<AsyncStream, typename std::decay<

View File

@@ -18,16 +18,17 @@
#include <beast/websocket/impl/response_op.ipp>
#include <beast/websocket/impl/write_op.ipp>
#include <beast/websocket/impl/write_frame_op.ipp>
#include <beast/buffer_cat.hpp>
#include <beast/consuming_buffers.hpp>
#include <beast/prepare_buffers.hpp>
#include <beast/static_streambuf.hpp>
#include <beast/streambuf.hpp>
#include <beast/type_check.hpp>
#include <beast/http/read.hpp>
#include <beast/http/write.hpp>
#include <beast/http/reason.hpp>
#include <beast/http/rfc2616.hpp>
#include <beast/buffer_cat.hpp>
#include <beast/buffer_concepts.hpp>
#include <beast/consuming_buffers.hpp>
#include <beast/prepare_buffers.hpp>
#include <beast/static_streambuf.hpp>
#include <beast/stream_concepts.hpp>
#include <beast/streambuf.hpp>
#include <boost/endian/buffers.hpp>
#include <algorithm>
#include <cassert>
@@ -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;

View File

@@ -9,7 +9,7 @@
#define BEAST_WEBSOCKET_IMPL_TEARDOWN_IPP
#include <beast/async_completion.hpp>
#include <beast/type_check.hpp>
#include <beast/handler_concepts.hpp>
#include <memory>
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_op<typename std::decay<

View File

@@ -19,17 +19,17 @@ namespace websocket {
/** Automatic fragmentation size option.
Sets the maximum size of fragments generated when sending
messages on a WebSocket socket.
Sets the maximum size of fragments generated when sending messages
on a WebSocket stream.
When the automatic fragmentation size is non-zero, messages
exceeding the size will be split into multiple frames no
larger than the size. This setting does not affect frames
send explicitly using `write_frame` or `async_write_frame`.
When the automatic fragmentation size is non-zero, messages exceeding
the size will be split into multiple frames no larger than the size.
This setting does not affect frames sent explicitly using
@ref stream::write_frame or @ref stream::async_write_frame.
The default setting is to fragment messages into 16KB frames.
@note Objects of this type are passed to socket::set_option.
@note Objects of this type are passed to @ref stream::set_option.
@par Example
Setting the automatic fragmentation size option:
@@ -61,18 +61,20 @@ struct auto_fragment_size
Server or User-Agent fields. The default setting applies no
transformation to the HTTP message.
For synchronous operations, the implementation will call the
decorator before the function call to perform the operation
returns.
The context in which the decorator is called depends on the
type of operation performed:
For asynchronous operations, the implementation guarantees that
calls to the decorator will be made from the same implicit or
explicit strand used to call the asynchronous initiation
@li For synchronous operations, the implementation will call the
decorator before the operation unblocks.
@li For asynchronous operations, the implementation guarantees
that calls to the decorator will be made from the same implicit
or explicit strand used to call the asynchronous initiation
function.
The default setting is no decorator.
@note Objects of this type are passed to socket::set_option.
@note Objects of this type are passed to @ref stream::set_option.
@par Example
Setting the decorator.
@@ -121,7 +123,7 @@ decorate(Decorator&& d)
The default setting is to close connections after a failed
upgrade request.
@note Objects of this type are passed to socket::set_option.
@note Objects of this type are passed to @ref stream::set_option.
@par Example
Setting the keep alive option.
@@ -155,7 +157,7 @@ struct keep_alive
The default setting is opcode::text.
@note Objects of this type are passed to socket::set_option.
@note Objects of this type are passed to @ref stream::set_option.
@par Example
Setting the message type to binary.
@@ -191,7 +193,7 @@ struct message_type
The default is no buffering.
@note Objects of this type are passed to socket::set_option.
@note Objects of this type are passed to @ref stream::set_option.
@par Example
Setting the read buffer size.
@@ -224,7 +226,7 @@ struct read_buffer_size
The default setting is 16 megabytes.
@note Objects of this type are passed to socket::set_option.
@note Objects of this type are passed to @ref stream::set_option.
@par Example
Setting the maximum read message size.
@@ -262,7 +264,7 @@ struct read_message_max
The default setting is 4096. The minimum value is 1024.
@note Objects of this type are passed to socket::set_option.
@note Objects of this type are passed to @ref stream::set_option.
@par Example
Setting the write buffer size.

View File

@@ -41,19 +41,24 @@ enum class opcode : std::uint8_t
These codes accompany close frames.
@see RFC 6455 7.4.1 Defined Status Codes
https://tools.ietf.org/html/rfc6455#section-7.4.1
@see <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455 7.4.1 Defined Status Codes</a>
*/
#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.

View File

@@ -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<class AsyncStream>
template<class SyncStream>
void
teardown(
boost::asio::ssl::stream<AsyncStream>& stream,
boost::asio::ssl::stream<SyncStream>& stream,
error_code& ec);
/** Start tearing down a `boost::asio::ssl::stream`.

File diff suppressed because it is too large Load Diff

View File

@@ -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<class AsyncSocket, class TeardownHandler>
template<class Socket, class TeardownHandler>
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<class Socket>

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_WRITE_STREAMBUF_HPP
#define BEAST_WRITE_STREAMBUF_HPP
#include <beast/type_check.hpp>
#include <beast/buffer_concepts.hpp>
#include <beast/detail/write_streambuf.hpp>
#include <type_traits>
#include <utility>
@@ -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<class Streambuf, class... Args>
#if GENERATING_DOCS

View File

@@ -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
)

View File

@@ -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
;

View File

@@ -16,7 +16,6 @@
#include <string>
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

View File

@@ -12,7 +12,6 @@
#include <functional>
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

View File

@@ -16,7 +16,6 @@
#include <vector>
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

25
test/buffer_concepts.cpp Normal file
View File

@@ -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 <beast/buffer_concepts.hpp>
namespace beast {
namespace {
struct T
{
};
}
static_assert(is_ConstBufferSequence<detail::ConstBufferSequence>::value, "");
static_assert(! is_ConstBufferSequence<T>::value, "");
static_assert(is_MutableBufferSequence<detail::MutableBufferSequence>::value, "");
static_assert(! is_MutableBufferSequence<T>::value, "");
} // beast

View File

@@ -14,7 +14,6 @@
#include <iterator>
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

View File

@@ -13,7 +13,6 @@
#include <string>
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

View File

@@ -47,7 +47,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(base64,detail,beast);
BEAST_DEFINE_TESTSUITE(base64,core,beast);
} // test
} // beast

View File

@@ -103,7 +103,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(empty_base_optimization,detail,beast);
BEAST_DEFINE_TESTSUITE(empty_base_optimization,core,beast);
} // test
} // beast

View File

@@ -6,4 +6,23 @@
//
// Test that header file is self-contained.
#include <beast/handler_alloc.hpp>
#include <beast/to_string.hpp>
#include <beast/detail/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp>
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

23
test/handler_concepts.cpp Normal file
View File

@@ -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 <beast/handler_concepts.hpp>
namespace beast {
namespace {
struct T
{
void operator()(int);
};
}
static_assert(is_CompletionHandler<T, void(int)>::value, "");
static_assert(! is_CompletionHandler<T, void(void)>::value, "");
} // beast

View File

@@ -6,4 +6,4 @@
//
// Test that header file is self-contained.
#include <beast/type_check.hpp>
#include <beast/http.hpp>

9
test/http/body_type.cpp Normal file
View File

@@ -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 <beast/http/body_type.hpp>

View File

@@ -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 <beast/http/body_type.hpp>

View File

@@ -13,7 +13,7 @@
#include <beast/http/error.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/rfc2616.hpp>
#include <beast/type_check.hpp>
#include <beast/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/system/error_code.hpp>
#include <cstdint>

View File

@@ -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

View File

@@ -14,7 +14,6 @@
#include <string>
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

View File

@@ -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 <boost/asio.hpp>
#include <condition_variable>

View File

@@ -13,7 +13,6 @@
#include <string>
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

View File

@@ -11,7 +11,6 @@
#include <beast/detail/unit_test/suite.hpp>
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

30
test/stream_concepts.cpp Normal file
View File

@@ -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 <beast/stream_concepts.hpp>
#include <boost/asio/ip/tcp.hpp>
namespace beast {
using stream_type = boost::asio::ip::tcp::socket;
static_assert(has_get_io_service<stream_type>::value, "");
static_assert(is_AsyncReadStream<stream_type>::value, "");
static_assert(is_AsyncWriteStream<stream_type>::value, "");
static_assert(is_AsyncStream<stream_type>::value, "");
static_assert(is_SyncReadStream<stream_type>::value, "");
static_assert(is_SyncWriteStream<stream_type>::value, "");
static_assert(is_SyncStream<stream_type>::value, "");
static_assert(! has_get_io_service<int>::value, "");
static_assert(! is_AsyncReadStream<int>::value, "");
static_assert(! is_AsyncWriteStream<int>::value, "");
static_assert(! is_SyncReadStream<int>::value, "");
static_assert(! is_SyncWriteStream<int>::value, "");
} // beast

View File

@@ -7,3 +7,4 @@
// Test that header file is self-contained.
#include <beast/to_string.hpp>

9
test/version.cpp Normal file
View File

@@ -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 <beast/version.hpp>

9
test/websocket.cpp Normal file
View File

@@ -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 <beast/websocket.hpp>

View File

@@ -85,7 +85,7 @@ public:
template<class MutableBufferSequence, class ReadHandler>
typename async_completion<ReadHandler,
void(std::size_t, error_code)>::result_type
void(error_code, std::size_t)>::result_type
async_read_some(MutableBufferSequence const& buffers,
ReadHandler&& handler)
{
@@ -120,7 +120,7 @@ public:
template<class ConstBuffeSequence, class WriteHandler>
typename async_completion<WriteHandler,
void(std::size_t, error_code)>::result_type
void(error_code, std::size_t)>::result_type
async_write_some(ConstBuffeSequence const& buffers,
WriteHandler&& handler)
{