Beast documentation work

This commit is contained in:
Vinnie Falco
2016-04-22 19:02:07 -04:00
parent 010444d77a
commit 7cfdab936c
33 changed files with 1723 additions and 1562 deletions

View File

@@ -17,3 +17,8 @@
* Remove or change http::headers alias
* Do something about the methods.hpp and fields.hpp type headers
* Fix index in docs
* Fix integer warning in file_body.hpp
* Use make_error_code in websocket to set the category right
* Figure out why namespace rfc2616 is included in docs
(currently disabled via GENERATING_DOCS macro)
* Include Example program listings in the docs

View File

@@ -51,13 +51,13 @@ LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_PACKAGE = YES
EXTRACT_STATIC = YES
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = NO
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = YES
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO

View File

@@ -41,64 +41,24 @@ both Boost.Asio and the HTTP protocol specification described in
[section:example Example]
[section:usage Usage]
All examples and identifiers mentioned in this document are written as
if the following declarations are in effect:
```
#include <boost/asio.hpp>
#include <beast/http.hpp>
using namespace beast;
using namespace boost::asio;
```
Create a HTTP request:
```
http::request<http::empty_body> req({http::method_t::http_get, "/", 11});
req.headers.insert("Host", "127.0.0.1:80");
req.headers.insert("User-Agent", "Beast.HTTP");
```
When sending a message, the Content-Length and Transfer-Encoding are set
automatically based on the properties of the body. Depending on the HTTP
version of the message and properties of the message body, the implementation
will automaticaly chunk-encode the data sent on the wire:
```
ip::tcp::socket sock(ios);
...
http::response<http::string_body> resp({200, "OK", 11});
resp.headers.insert("Server", "Beast.HTTP");
resp.body = "The command was successful";
write(sock, resp);
}
```
Receiving a message is simple, declare a value of type message and call `read`.
This example reads a message, builds a response, and sends it.
```
void handle_connection(ip::tcp::socket& sock)
{
request<string_body> req;
read(sock, req);
response<string_body> resp;
...
write(sock, resp);
}
```
[endsect]
[section:message Message model]
[note
Sample code and identifiers mentioned in this section are written
as if the following declarations are in effect:
```
#include <beast/http.hpp>
using namespace beast;
```
]
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. Applications using HTTP often perform these operations
on messages:
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.
@@ -112,6 +72,205 @@ 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.
[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
(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:
```
http::message<true, http::string_body> req;
```
Two type aliases are provided for notational convenience when declaring
messages. These two statements declare a request and a response respectively:
```
http::request<http::string_body> req;
http::response<http::string_body> resp;
```
[heading Members]
Message objects are default constructible, with public access to data members.
Request and response objects have some common members, and some members unique
to the message type. These statements set all the members in each message:
```
http::request<http::string_body> req;
req.method = http::method_t::http_get;
req.url = "/index.html";
req.version = 11; // HTTP/1.1
req.headers.insert("User-Agent", "hello_world");
req.body = "";
http::response<http::string_body> resp;
resp.status = 404;
resp.reason = "Not Found";
resp.version = 10; // HTTP/1.0
resp.headers.insert("Server", "Beast.HTTP");
resp.body = "The requested resource was not found.";
```
The following statements achieve the same effects as the statements above:
```
http::request<http::string_body> req({http::method_t::http_get, "/index.html", 11});
req.headers.insert("User-Agent", "hello_world");
req.body = "";
http::response<http::string_body> resp({404, "Not Found", 10});
resp.headers.insert("Server", "Beast.HTTP");
resp.body = "The requested resource was not found.";
```
[heading Headers]
The `message::headers` member is a container for setting the field/value
pairs in the message. These statements change the values of the headers
in the message passed:
```
template<class Body>
void set_fields(http::request<Body>& req)
{
if(! req.exists("User-Agent"))
req.insert("User-Agent", "myWebClient");
if(req.exists("Accept-Charset"))
req.erase("Accept-Charset");
req.replace("Accept", "text/plain");
}
```
[heading Body]
The `message::body` member represents the message body. Depending on the
`Body` template argument type, this could be a writable container. The
following types, provided by the library, are suitable choices for the
`Body` type:
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
Used in GET requests where there is no message body. Example:
```
http::request<http::empty_body> req({http::method_t::http_get, "/index.html", 11});
```
* [link beast.ref.http__string_body [*`string_body`:]] A body with a
`value_type` as `std::string`. Useful for quickly putting together a request
or response with simple text in the message body (such as an error message).
Has the same insertion complexity of `std::string`. This is the type of body
used in the examples:
```
http::response<http::string_body> resp;
static_assert(std::is_same<decltype(resp.body), std::string>::value);
resp.body = "Here is the data you requested";
```
* [link beast.ref.http__basic_streambuf_body [*`basic_streambuf_body`:]] A body with a
`value_type` of `streambuf`. A streambuf is an efficient storage object which
uses multiple octet arrays of varying lengths to represent data. Here is
a body that uses a `boost::asio::streambuf` as its container:
```
template<class ConstBufferSequence>
http::response<http::basic_streambuf_body<boost::asio::streambuf>>
make_response(ConstBufferSequence const& buffers)
{
http::response<http::streambuf_body<boost::asio::streambuf>> resp;
resp.body.commit(boost::asio::buffer_copy(resp.body.prepare(
boost::asio::buffer_size(buffers)), buffers));
return resp;
}
```
[heading Sockets]
The library provides simple free functions modeled after Boost.Asio to
send and receive messages on TCP/IP sockets, SSL streams, or any object
which meets the Boost.Asio type requirements (SyncReadStream, SyncWriteStream,
AsyncReadStream, and AsyncWriteStream depending on the types of operations
performed). To send messages synchronously, use one of the `http:write`
functions:
```
void send_request(boost::asio::ip::tcp::socket& sock)
{
http::request<http::empty_body> req({http::method_t::http_get, "/index.html", 11});
...
http::write(sock, req); // Throws exception on error
...
// Alternatively
boost::system::error:code ec;
http::write(sock, req, ec);
if(ec)
std::cerr << "error writing http message: " << ec.message();
}
```
An asynchronous interface is available:
```
void handle_write(boost::system::error_code);
...
http::request<http::empty_body> req;
...
http::async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
```
When the implementation reads messages from a socket, it can read bytes lying
after the end of the message if they are present (the alternative is to read
a single byte at a time which is unsuitable for performance reasons). To
store and re-use these extra bytes on subsequent messages, the read interface
requires an additional paramter: a [link beast.types.Streambuf [*`Streambuf`]]
object. This example reads a message from the socket, with the extra bytes
stored in the streambuf parameter for use in a subsequent call to read:
```
boost::asio::streambuf sb;
...
http::response<http::string_body> resp;
http::read(sock, sb, resp); // Throws exception on error
...
// Alternatively
boost::system::error:code ec;
http::read(sock, sb, resp, ec);
if(ec)
std::cerr << "error reading http message: " << ec.message();
```
As with the write function, an asynchronous interface is available. The
stream buffer parameter must remain valid until the completion handler is
called:
```
void handle_read(boost::system::error_code);
...
boost::asio::streambuf sb;
http::response<http::string_body> resp;
...
http::async_read(sock, resp, std::bind(&handle_read, std::placeholders::_1));
```
An alternative to using a `boost::asio::streambuf` is to use a
[link beast.ref.streambuf `beast::streambuf`], which meets the requirements of
[*`Streambuf`] and is optimized for performance:
```
void handle_read(boost::system::error_code);
...
beast::streambuf sb;
http::response<http::string_body> resp;
http::read(sock, sb, resp);
```
The `read` implementation can use any object meeting the requirements of
[link beast.types.Streambuf [*`Streambuf`]], allowing callers to define custom
memory management strategies used by the implementation.
[endsect]
[section:advanced Advanced]
The spectrum of hardware and software platforms which perform these typical
HTTP operations is vast, ranging from powerful servers in large datacenters
to tiny resource-limited embedded devices. No single concrete implementation
@@ -122,10 +281,15 @@ message body as a disk file may support sending but not parsing. Many efficient
and correct models of messages exist, supporting some or all of the
operations listed above.
To support a variety of implementation strategies, we introduce customization
points for the header and body via class template arguments. This illustration
shows the message class template (boilerplate present in the actual
declaration has been removed for clarity):
[heading Message model]
The message class template and provided Body types are suitable for casual
library users. This section explains the message model for advanced users
who wish to take control over aspects of the implementation. We introduce
customization points for the header and body via class template arguments.
This illustration shows more detail about the
[link beast.ref.http__message [*`message`]] class template (boilerplate
present in the actual declaration has been removed for clarity):
[$images/message.png [width 580px] [height 225px]]
@@ -143,45 +307,7 @@ overloaded on the type of message.
[section:body Body parameter]
The `Body` template argument in the `message` class must meet the
[link beast.types.Body [*`Body`] requirements]. It provides customization
of the data member in the message, the algorithm for parsing, and the
algorithm for serialization:
[$images/body.png [width 510px] [height 210px]]
The following types, provided by the library, meet the `Body` requirements:
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
Used in GET requests where there is no message body.
* [link beast.ref.http__string_body [*`string_body`:]] A body with a
`value_type` of `std::string`. Useful for quickly putting together a request
or response with simple text in the message body (such as an error message).
Subject to the performance limit of strings if large amounts of data are
inserted.
* [link beast.ref.http__basic_streambuf_body [*`basic_streambuf_body`:]] A body with a
`value_type` of `streambuf`. A streambuf is an efficient storage object which
uses multiple octet arrays of varying lengths to represent data.
Instances of the optional nested types `writer` and `reader` perform
serialization and deserialization of the message body. If either or
both of these types are present, the message becomes serializable, parsable,
or both. They model [link beast.types.Reader [*`Reader`]] and
[link beast.types.Writer [*`Writer`]] respectively.
For specialized applications, users may implement their own types which
meet the requirements. The examples included with this library provide a
Body implementation used to serve files in a HTTP server.
[endsect]
[section:headers Headers container]
[section:headers Headers Type]
The `Headers` type represents the field/value pairs present in every HTTP
message. These types implement the
@@ -208,5 +334,27 @@ has_connect(FieldSequence const& fs)
[section:body Body Type]
The `Body` template argument in the `message` class must meet the
[link beast.types.Body [*`Body`] requirements]. It provides customization
of the data member in the message, the algorithm for parsing, and the
algorithm for serialization:
[$images/body.png [width 510px] [height 210px]]
Instances of the optional nested types `writer` and `reader` perform
serialization and deserialization of the message body. If either or
both of these types are present, the message becomes serializable, parsable,
or both. They model [link beast.types.Reader [*`Reader`]] and
[link beast.types.Writer [*`Writer`]] respectively.
For specialized applications, users may implement their own types which
meet the requirements. The examples included with this library provide a
Body implementation used to serve files in a HTTP server.
[endsect]
[endsect]

View File

@@ -40,31 +40,22 @@
<xsl:sort select="concat((. | ancestor::*)/compoundname, '::', name, ':x')"/>
<xsl:sort select="name"/>
<xsl:choose>
<xsl:when test="@kind='class' or @kind='struct'">
<xsl:call-template name="class"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="namespace-memberdef"/>
</xsl:otherwise>
<!--
<xsl:when test="@kind='class' or @kind='struct'">
<xsl:if test="
contains(compoundname, 'beast::') and
not(contains(compoundname, '::detail'))">
not(contains(compoundname, '::detail')) and
not(contains(compoundname, 'rfc2616')) and
not(contains(@prot, 'private'))">
<xsl:call-template name="class"/>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:if test="
not(contains(ancestor::*/compoundname, '::detail')) and
not(contains(ancestor::*/compoundname, '::service::key')) and
not(contains(ancestor::*/compoundname, '_helper')) and
not(contains(name, '_helper')) and
not(contains(name, 'io_service_impl'))">
not(contains(compoundname, 'rfc2616'))">
<xsl:call-template name="namespace-memberdef"/>
</xsl:if>
</xsl:otherwise>
-->
</xsl:choose>
</xsl:for-each>
<xsl:text>&#xd;[endsect]</xsl:text>
@@ -288,6 +279,14 @@
</xsl:if>
</xsl:template>
<xsl:template match="ulink" mode="markup">
<xsl:text>[@</xsl:text>
<xsl:value-of select="@url"/>
<xsl:text> </xsl:text>
<xsl:value-of select="."/>
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match="programlisting" mode="markup">
<xsl:value-of select="$newline"/>
<xsl:value-of select="$newline"/>
@@ -673,18 +672,16 @@
<xsl:value-of select="$newline"/>
<xsl:text>[heading Requirements]&#xd;</xsl:text>
<xsl:text>['Header: ][^</xsl:text>
<xsl:value-of select="substring-after($file, 'beast/')"/>
<xsl:value-of select="substring-after($file, 'include/')"/>
<xsl:text>] &#xd;&#xd;</xsl:text>
<xsl:text>['Convenience header: ]</xsl:text>
<xsl:choose>
<xsl:when test="contains($file, 'beast/asio')">
<xsl:text>[^beast/asio.h]</xsl:text>
</xsl:when>
<xsl:when test="contains($file, 'beast/http')">
<xsl:text>[^beast/http.h]</xsl:text>
<xsl:text>['Convenience header: ][^beast/http.hpp]</xsl:text>
</xsl:when>
<xsl:when test="contains($file, 'beast/wsproto')">
<xsl:text>[^beast/wsproto.h]</xsl:text>
<xsl:when test="contains($file, 'beast/websocket')">
<xsl:text>['Convenience header: ][^beast/websocket.hpp]</xsl:text>
</xsl:when>
<xsl:when test="contains($file, 'beast/')">
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$file"/>
@@ -911,7 +908,7 @@
</xsl:for-each>
<xsl:text>]&#xd;</xsl:text>
</xsl:if>
<xsl:if test="count(sectiondef[@kind='private-func' or @kind='protected-private-func']) > 0">
<xsl:if test="count(sectiondef[@kind='private-func' or @kind='protected-private-func']) &lt; 0">
<xsl:text>[heading Private Member Functions]&#xd;</xsl:text>
<xsl:text>[table&#xd; [[Name][Description]]&#xd;</xsl:text>
<xsl:for-each select="sectiondef[@kind='private-func']/memberdef" mode="class-table">
@@ -988,7 +985,7 @@
</xsl:for-each>
<xsl:text>]&#xd;</xsl:text>
</xsl:if>
<xsl:if test="count(sectiondef[@kind='private-attrib' or @kind='private-static-attrib']) > 0">
<xsl:if test="count(sectiondef[@kind='private-attrib' or @kind='private-static-attrib']) &lt; 0">
<xsl:text>[heading Private Data Members]&#xd;</xsl:text>
<xsl:text>[table&#xd; [[Name][Description]]&#xd;</xsl:text>
<xsl:for-each select="sectiondef[@kind='private-attrib' or @kind='private-static-attrib']/memberdef" mode="class-table">
@@ -1274,7 +1271,7 @@
<xsl:text>```&#xd;</xsl:text>
</xsl:when>
</xsl:choose>
<xsl:apply-templates select="detaileddescription"/>
<xsl:apply-templates select="detaileddescription" mode="markup"/>
<xsl:if test="@kind='typedef' or @kind='friend'">
<xsl:call-template name="header-requirements">
<xsl:with-param name="file" select="$class-file"/>
@@ -1423,91 +1420,12 @@
<xsl:template match="param" mode="class-detail-template">
<xsl:text> </xsl:text>
<xsl:value-of select="type"/>
<xsl:choose>
<xsl:when test="declname = 'Allocator'">
<xsl:value-of select="declname"/>
<xsl:when test="type = 'class Body'">
<xsl:text>class ``[link beast.types.Body [*Body]]``</xsl:text>
</xsl:when>
<xsl:when test="declname = 'Arg'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'BufferSequence'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'ByteType'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'Clock'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'CompletionCondition'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'ConnectCondition'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'Context_Service'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'DatagramSocketService1'">
<xsl:value-of select="concat('``[link beast.ref.DatagramSocketService ', declname, ']``')"/>
</xsl:when>
<xsl:when test="declname = 'EndpointIterator'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'Elem'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'ErrorEnum'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'Function'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'Iterator'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'MatchCondition'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'N'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'OtherAllocator'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'PasswordCallback'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'PodType'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'PointerToPodType'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'Protocol1'">
<xsl:value-of select="concat('``[link beast.ref.Protocol ', declname, ']``')"/>
</xsl:when>
<xsl:when test="declname = 'RawSocketService1'">
<xsl:value-of select="concat('``[link beast.ref.RawSocketService ', declname, ']``')"/>
</xsl:when>
<xsl:when test="declname = 'SeqPacketSocketService1'">
<xsl:value-of select="concat('``[link beast.ref.SeqPacketSocketService ', declname, ']``')"/>
</xsl:when>
<xsl:when test="declname = 'Signature'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'SocketAcceptorService1' or declname = 'SocketAcceptorService2'">
<xsl:value-of select="concat('``[link beast.ref.SocketAcceptorService ', declname, ']``')"/>
</xsl:when>
<xsl:when test="declname = 'SocketService1' or declname = 'SocketService2'">
<xsl:value-of select="concat('``[link beast.ref.SocketService ', declname, ']``')"/>
</xsl:when>
<xsl:when test="declname = 'Stream'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'StreamSocketService1'">
<xsl:value-of select="concat('``[link beast.ref.StreamSocketService ', declname, ']``')"/>
<xsl:when test="type = 'class Streambuf'">
<xsl:text>class ``[link beast.types.Streambuf [*Streambuf]]``</xsl:text>
</xsl:when>
<xsl:when test="declname = 'T'">
<xsl:value-of select="declname"/>
@@ -1518,22 +1436,14 @@
<xsl:when test="declname = 'TN'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'Time'">
<xsl:when test="count(declname) > 0">
<xsl:value-of select="type"/>
<xsl:text> </xsl:text>
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'TimeType'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'Traits'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="declname = 'VerifyCallback'">
<xsl:value-of select="declname"/>
</xsl:when>
<xsl:when test="count(declname) = 0">
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(' ``[link beast.ref.', declname, ' ', declname, ']``')"/>
<xsl:value-of select="type"/>
<!--<xsl:value-of select="concat(' ``[link beast.ref.', declname, ' ', declname, ']``')"/>-->
</xsl:otherwise>
</xsl:choose>
<xsl:if test="count(defval) > 0">
@@ -1557,6 +1467,10 @@
</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>

View File

@@ -23,7 +23,6 @@
#include <beast/bind_handler.hpp>
#include <beast/handler_alloc.hpp>
#include <beast/http/read.hpp>
#include <beast/http/type_check.hpp>
#include <beast/http/write.hpp>
#include <cassert>

View File

@@ -16,13 +16,12 @@
namespace beast {
/** Completion helper for implementing the extensible asynchronous model.
/** 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 allows customization of
the return type of the initiating function, and the type
of the final handler.
This class template is used to transform caller-provided completion
tokens 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
with specializations for customizing the return type (for example,
@@ -30,14 +29,16 @@ namespace beast {
@tparam Signature The callable signature of the final completion handler.
Usage:
Example:
@code
...
template<class CompletionToken>
typename async_completion<CompletionToken, Signature>::result_type
typename async_completion<CompletionToken,
void(boost::system::error_code)>::result_type
async_initfn(..., CompletionToken&& token)
{
async_completion<CompletionToken, Signature> completion(token);
async_completion<CompletionToken,
void(boost::system::error_code)> completion(token);
...
return completion.result.get();
}
@@ -49,19 +50,19 @@ namespace beast {
template <class CompletionToken, class Signature>
struct async_completion
{
/** The type of the final handler.
/** The type of the final handler called by the asynchronous initiation function.
Objects of this type will be callable with the
specified signature.
Objects of this type will be callable with the specified signature.
*/
using handler_type =
typename boost::asio::handler_type<
CompletionToken, Signature>::type;
/// The type of the value returned by the asynchronous initiation function.
using result_type = typename
boost::asio::async_result<handler_type>::type;
/** Construct the completion helper.
/** Construct the helper.
@param token The completion token. Copies will be made as
required. If `CompletionToken` is movable, it may also be moved.
@@ -74,10 +75,10 @@ struct async_completion
"Handler requirements not met");
}
/** The final completion handler, callable with the specified signature. */
/// The final completion handler, callable with the specified signature.
handler_type handler;
/** The return value of the asynchronous initiation function. */
/// The return value of the asynchronous initiation function.
boost::asio::async_result<handler_type> result;
};

View File

@@ -36,6 +36,7 @@ class basic_streambuf
#endif
{
public:
/// The type of allocator used.
using allocator_type = typename
std::allocator_traits<Allocator>::
template rebind_alloc<std::uint8_t>;
@@ -73,10 +74,20 @@ private:
size_type out_end_ = 0; // output end offset in list_.back()
public:
#if GENERATING_DOCS
/// The type used to represent the input sequence as a list of buffers.
using const_buffers_type = implementation_defined;
/// The type used to represent the output sequence as a list of buffers.
using mutable_buffers_type = implementation_defined;
#else
class const_buffers_type;
class mutable_buffers_type;
#endif
/// Destructor.
~basic_streambuf();
@@ -175,7 +186,7 @@ public:
template<class OtherAlloc>
basic_streambuf& operator=(basic_streambuf<OtherAlloc> const& other);
/** Construct a stream buffer.
/** Default constructor.
@param alloc_size The size of buffer to allocate. This is a soft
limit, calls to prepare for buffers exceeding this size will allocate
@@ -258,60 +269,6 @@ private:
debug_check() const;
};
/// The type used to represent the input sequence as a list of buffers.
template<class Allocator>
class basic_streambuf<Allocator>::const_buffers_type
{
basic_streambuf const* sb_ = nullptr;
friend class basic_streambuf;
explicit
const_buffers_type(basic_streambuf const& sb);
public:
using value_type = boost::asio::const_buffer;
class const_iterator;
const_buffers_type() = default;
const_buffers_type(const_buffers_type const&) = default;
const_buffers_type& operator=(const_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
};
/// The type used to represent the output sequence as a list of buffers.
template<class Allocator>
class basic_streambuf<Allocator>::mutable_buffers_type
{
basic_streambuf const* sb_;
friend class basic_streambuf;
explicit
mutable_buffers_type(basic_streambuf const& sb);
public:
using value_type = mutable_buffer;
class const_iterator;
mutable_buffers_type() = default;
mutable_buffers_type(mutable_buffers_type const&) = default;
mutable_buffers_type& operator=(mutable_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
};
/** Format output to a stream buffer.
@param streambuf The streambuf to write to.
@@ -322,7 +279,7 @@ public:
*/
template<class Alloc, class T>
basic_streambuf<Alloc>&
operator<<(basic_streambuf<Alloc>& buf, T const& t);
operator<<(basic_streambuf<Alloc>& streambuf, T const& t);
/** Convert the entire basic_streambuf to a string.

View File

@@ -121,7 +121,7 @@ public:
Example:
@code
template<class AsyncReadStream, ReadHandler>
template<class AsyncReadStream, class ReadHandler>
void
do_cancel(AsyncReadStream& stream, ReadHandler&& handler)
{

View File

@@ -9,11 +9,6 @@
#define BEAST_BUFFERS_ADAPTER_HPP
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <array>
#include <cstring>
#include <iterator>
#include <stdexcept>
#include <type_traits>
namespace beast {
@@ -70,19 +65,30 @@ private:
}
public:
#if GENERATING_DOCS
/// The type used to represent the input sequence as a list of buffers.
using const_buffers_type = implementation_defined;
/// The type used to represent the output sequence as a list of buffers.
using mutable_buffers_type = implementation_defined;
#else
class const_buffers_type;
class mutable_buffers_type;
// Move constructor.
#endif
/// Move constructor.
buffers_adapter(buffers_adapter&& other);
// Copy constructor.
/// Copy constructor.
buffers_adapter(buffers_adapter const& other);
// Move assignment.
/// Move assignment.
buffers_adapter& operator=(buffers_adapter&& other);
// Copy assignment.
/// Copy assignment.
buffers_adapter& operator=(buffers_adapter const&);
/** Construct a buffers adapter.
@@ -129,508 +135,8 @@ public:
consume(std::size_t n);
};
//------------------------------------------------------------------------------
/// The type used to represent the input sequence as a list of buffers.
template<class Buffers>
class buffers_adapter<Buffers>::const_buffers_type
{
buffers_adapter const* ba_;
public:
using value_type = boost::asio::const_buffer;
class const_iterator;
const_buffers_type() = default;
const_buffers_type(
const_buffers_type const&) = default;
const_buffers_type& operator=(
const_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class buffers_adapter;
const_buffers_type(buffers_adapter const& ba)
: ba_(&ba)
{
}
};
template<class Buffers>
class buffers_adapter<Buffers>::const_buffers_type::const_iterator
{
iter_type it_;
buffers_adapter const* ba_;
public:
using value_type = boost::asio::const_buffer;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return ba_ == other.ba_ &&
it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
return value_type{buffer_cast<void const*>(*it_),
(ba_->out_ == ba_->bs_.end() ||
it_ != ba_->out_) ? buffer_size(*it_) : ba_->out_pos_} +
(it_ == ba_->begin_ ? ba_->in_pos_ : 0);
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
--it_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class const_buffers_type;
const_iterator(buffers_adapter const& ba,
iter_type iter)
: it_(iter)
, ba_(&ba)
{
}
};
template<class Buffers>
inline
auto
buffers_adapter<Buffers>::const_buffers_type::begin() const ->
const_iterator
{
return const_iterator{*ba_, ba_->begin_};
}
template<class Buffers>
inline
auto
buffers_adapter<Buffers>::const_buffers_type::end() const ->
const_iterator
{
return const_iterator{*ba_, ba_->out_ ==
ba_->end_ ? ba_->end_ : std::next(ba_->out_)};
}
//------------------------------------------------------------------------------
/// The type used to represent the output sequence as a list of buffers.
template<class Buffers>
class buffers_adapter<Buffers>::mutable_buffers_type
{
buffers_adapter const* ba_;
public:
using value_type = boost::asio::mutable_buffer;
class const_iterator;
mutable_buffers_type() = default;
mutable_buffers_type(
mutable_buffers_type const&) = default;
mutable_buffers_type& operator=(
mutable_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class buffers_adapter;
mutable_buffers_type(
buffers_adapter const& ba)
: ba_(&ba)
{
}
};
template<class Buffers>
class buffers_adapter<Buffers>::mutable_buffers_type::const_iterator
{
iter_type it_;
buffers_adapter const* ba_;
public:
using value_type = boost::asio::mutable_buffer;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return ba_ == other.ba_ &&
it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
return value_type{buffer_cast<void*>(*it_),
it_ == std::prev(ba_->end_) ?
ba_->out_end_ : buffer_size(*it_)} +
(it_ == ba_->out_ ? ba_->out_pos_ : 0);
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
--it_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class mutable_buffers_type;
const_iterator(buffers_adapter const& ba,
iter_type iter)
: it_(iter)
, ba_(&ba)
{
}
};
template<class Buffers>
inline
auto
buffers_adapter<Buffers>::mutable_buffers_type::begin() const ->
const_iterator
{
return const_iterator{*ba_, ba_->out_};
}
template<class Buffers>
inline
auto
buffers_adapter<Buffers>::mutable_buffers_type::end() const ->
const_iterator
{
return const_iterator{*ba_, ba_->end_};
}
//------------------------------------------------------------------------------
template<class Buffers>
buffers_adapter<Buffers>::buffers_adapter(
buffers_adapter&& other)
: buffers_adapter(std::move(other),
std::distance<iter_type>(other.bs_.begin(), other.begin_),
std::distance<iter_type>(other.bs_.begin(), other.out_),
std::distance<iter_type>(other.bs_.begin(), other.end_))
{
}
template<class Buffers>
buffers_adapter<Buffers>::buffers_adapter(
buffers_adapter const& other)
: buffers_adapter(other,
std::distance<iter_type>(other.bs_.begin(), other.begin_),
std::distance<iter_type>(other.bs_.begin(), other.out_),
std::distance<iter_type>(other.bs_.begin(), other.end_))
{
}
template<class Buffers>
auto
buffers_adapter<Buffers>::operator=(
buffers_adapter&& other) -> buffers_adapter&
{
auto const nbegin = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
auto const nout = std::distance<iter_type>(
other.bs_.begin(), other.out_);
auto const nend = std::distance<iter_type>(
other.bs_.begin(), other.end_);
bs_ = std::move(other.bs_);
begin_ = std::next(bs_.begin(), nbegin);
out_ = std::next(bs_.begin(), nout);
end_ = std::next(bs_.begin(), nend);
max_size_ = other.max_size_;
in_pos_ = other.in_pos_;
in_size_ = other.in_size_;
out_pos_ = other.out_pos_;
out_end_ = other.out_end_;
return *this;
}
template<class Buffers>
auto
buffers_adapter<Buffers>::operator=(
buffers_adapter const& other) -> buffers_adapter&
{
auto const nbegin = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
auto const nout = std::distance<iter_type>(
other.bs_.begin(), other.out_);
auto const nend = std::distance<iter_type>(
other.bs_.begin(), other.end_);
bs_ = other.bs_;
begin_ = std::next(bs_.begin(), nbegin);
out_ = std::next(bs_.begin(), nout);
end_ = std::next(bs_.begin(), nend);
max_size_ = other.max_size_;
in_pos_ = other.in_pos_;
in_size_ = other.in_size_;
out_pos_ = other.out_pos_;
out_end_ = other.out_end_;
return *this;
}
template<class Buffers>
buffers_adapter<Buffers>::buffers_adapter(
Buffers const& bs)
: bs_(bs)
, begin_(bs_.begin())
, out_(bs_.begin())
, end_(bs_.begin())
, max_size_(boost::asio::buffer_size(bs_))
{
}
template<class Buffers>
auto
buffers_adapter<Buffers>::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())
{
auto size = buffer_size(*end_) - out_pos_;
if(n > size)
{
n -= size;
while(++end_ != bs_.end())
{
size = buffer_size(*end_);
if(n < size)
{
out_end_ = n;
n = 0;
++end_;
break;
}
n -= size;
out_end_ = size;
}
}
else
{
++end_;
out_end_ = out_pos_ + n;
n = 0;
}
}
if(n > 0)
throw std::length_error(
"no space in buffers_adapter");
return mutable_buffers_type{*this};
}
template<class Buffers>
void
buffers_adapter<Buffers>::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_);
while(out_ != last)
{
auto const avail =
buffer_size(*out_) - out_pos_;
if(n < avail)
{
out_pos_ += n;
in_size_ += n;
max_size_ -= n;
return;
}
++out_;
n -= avail;
out_pos_ = 0;
in_size_ += avail;
max_size_ -= avail;
}
n = std::min(n, out_end_ - out_pos_);
out_pos_ += n;
in_size_ += n;
max_size_ -= n;
if(out_pos_ == buffer_size(*out_))
{
++out_;
out_pos_ = 0;
out_end_ = 0;
}
}
template<class Buffers>
inline
auto
buffers_adapter<Buffers>::data() const ->
const_buffers_type
{
return const_buffers_type{*this};
}
template<class Buffers>
void
buffers_adapter<Buffers>::consume(std::size_t n)
{
for(;;)
{
if(begin_ != out_)
{
auto const avail =
buffer_size(*begin_) - in_pos_;
if(n < avail)
{
in_size_ -= n;
in_pos_ += n;
break;
}
n -= avail;
in_size_ -= avail;
in_pos_ = 0;
++begin_;
}
else
{
auto const avail = out_pos_ - in_pos_;
if(n < avail)
{
in_size_ -= n;
in_pos_ += n;
}
else
{
in_size_ -= avail;
if(out_pos_ != out_end_||
out_ != std::prev(bs_.end()))
{
in_pos_ = out_pos_;
}
else
{
// Use the whole buffer now.
in_pos_ = 0;
out_pos_ = 0;
out_end_ = 0;
}
}
break;
}
}
}
} // beast
#include <beast/impl/buffers_adapter.ipp>
#endif

View File

@@ -14,6 +14,11 @@
namespace beast {
namespace debug {
/** Diagnostic utility to convert a `ConstBufferSequence` to a string.
@note Carriage returns and linefeeds will have additional escape
representations printed for visibility.
*/
template<class Buffers>
std::string
buffers_to_string(Buffers const& bs)

View File

@@ -8,7 +8,6 @@
#ifndef BEAST_CONSUMING_BUFFERS_HPP
#define BEAST_CONSUMING_BUFFERS_HPP
#include <beast/type_check.hpp>
#include <boost/asio/buffer.hpp>
#include <cstdint>
#include <iterator>
@@ -64,8 +63,15 @@ public:
/// The type for each element in the list of buffers.
using value_type = ValueType;
#if GENERATING_DOCS
/// A bidirectional iterator type that may be used to read elements.
using const_iterator = implementation_defined;
#else
class const_iterator;
#endif
/// Move constructor.
consuming_buffers(consuming_buffers&&);
@@ -104,194 +110,13 @@ public:
consume(std::size_t n);
};
/// A bidirectional iterator type that may be used to read elements.
template<class Buffers, class ValueType>
class consuming_buffers<Buffers, ValueType>::const_iterator
{
friend class consuming_buffers<Buffers, ValueType>;
using iter_type =
typename Buffers::const_iterator;
iter_type it_;
consuming_buffers const* b_;
public:
using value_type =
typename std::iterator_traits<iter_type>::value_type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return b_ == other.b_ && it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
if(it_ == b_->begin_)
return *it_ + b_->skip_;
return *it_;
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
--it_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
const_iterator(consuming_buffers const& b,
iter_type it)
: it_(it)
, b_(&b)
{
}
};
template<class Buffers, class ValueType>
consuming_buffers<Buffers, ValueType>::
consuming_buffers(consuming_buffers&& other)
: consuming_buffers(std::move(other),
std::distance<iter_type>(
other.bs_.begin(), other.begin_))
{
}
template<class Buffers, class ValueType>
consuming_buffers<Buffers, ValueType>::
consuming_buffers(consuming_buffers const& other)
: consuming_buffers(other,
std::distance<iter_type>(
other.bs_.begin(), other.begin_))
{
}
template<class Buffers, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::
operator=(consuming_buffers&& other) ->
consuming_buffers&
{
auto const nbegin = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
bs_ = std::move(other.bs_);
begin_ = std::next(bs_.begin(), nbegin);
skip_ = other.skip_;
return *this;
}
template<class Buffers, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::
operator=(consuming_buffers const& other) ->
consuming_buffers&
{
auto const nbegin = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
bs_ = other.bs_;
begin_ = std::next(bs_.begin(), nbegin);
skip_ = other.skip_;
return *this;
}
template<class Buffers, class ValueType>
consuming_buffers<Buffers, ValueType>::
consuming_buffers(Buffers const& bs)
: bs_(bs)
, begin_(bs_.begin())
{
}
template<class Buffers, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::begin() const ->
const_iterator
{
return const_iterator{*this, begin_};
}
template<class Buffers, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::end() const ->
const_iterator
{
return const_iterator{*this, bs_.end()};
}
template<class Buffers, class ValueType>
void
consuming_buffers<Buffers, ValueType>::consume(std::size_t n)
{
using boost::asio::buffer_size;
for(;n > 0 && begin_ != bs_.end(); ++begin_)
{
auto const len =
buffer_size(*begin_) - skip_;
if(n < len)
{
skip_ += n;
break;
}
n -= len;
skip_ = 0;
}
}
/// Returns a consumed buffer
template<class Buffers>
consuming_buffers<Buffers, typename Buffers::value_type>
consumed_buffers(Buffers const& bs, std::size_t n)
{
consuming_buffers<Buffers> cb(bs);
cb.consume(n);
return cb;
}
consumed_buffers(Buffers const& bs, std::size_t n);
} // beast
#include <beast/impl/consuming_buffers.ipp>
#endif

View File

@@ -22,12 +22,21 @@ namespace beast {
/** An allocator that uses handler customizations.
This allocator uses the handler customizations `asio_handler_allocate`
and `asio_handler_deallocate` to manage memory.
and `asio_handler_deallocate` to manage memory. It meets the requirements
of `Allocator` and can be used anywhere a `std::allocator` is
accepted.
@tparam T The type of object
@tparam T The type of objects allocated by the allocator.
@tparam Handler 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>
class handler_alloc;
#else
template <class T, class Handler>
class handler_alloc
{
@@ -132,6 +141,7 @@ public:
return !(lhs == rhs);
}
};
#endif
} // beast

View File

@@ -22,7 +22,6 @@
#include <beast/http/rfc2616.hpp>
#include <beast/http/streambuf_body.hpp>
#include <beast/http/string_body.hpp>
#include <beast/http/type_check.hpp>
#include <beast/http/write.hpp>
#endif

View File

@@ -22,9 +22,16 @@ namespace http {
*/
struct empty_body
{
struct value_type
{
};
#if GENERATING_DOCS
/// The type of the `message::body` member
using value_type = void;
#else
struct value_type {};
#endif
#if GENERATING_DOCS
private:
#endif
struct reader
{

View File

@@ -9,7 +9,6 @@
#define BEAST_HTTP_IMPL_MESSAGE_IPP
#include <beast/http/chunk_encode.hpp>
#include <beast/http/type_check.hpp>
#include <beast/http/detail/writes.hpp>
#include <beast/http/detail/write_preparation.hpp>
#include <beast/http/resume_context.hpp>
@@ -26,16 +25,12 @@ template<bool isRequest, class Body, class Headers>
message<isRequest, Body, Headers>::
message()
{
static_assert(is_Body<Body>::value,
"Body requirements not met");
}
template<bool isRequest, class Body, class Headers>
message<isRequest, Body, Headers>::
message(request_params params)
{
static_assert(is_Body<Body>::value,
"Body requirements not met");
static_assert(isRequest, "message is not a request");
this->method = params.method;
this->url = std::move(params.url);
@@ -46,8 +41,6 @@ template<bool isRequest, class Body, class Headers>
message<isRequest, Body, Headers>::
message(response_params params)
{
static_assert(is_Body<Body>::value,
"Body requirements not met");
static_assert(! isRequest, "message is not a response");
this->status = params.status;
this->reason = std::move(params.reason);
@@ -160,8 +153,6 @@ std::ostream&
operator<<(std::ostream& os,
message<isRequest, Body, Headers> const& msg)
{
static_assert(is_WritableBody<Body>::value,
"WritableBody requirements not met");
error_code ec;
detail::write_preparation<isRequest, Body, Headers> wp(msg);
wp.init(ec);

View File

@@ -8,7 +8,6 @@
#ifndef BEAST_HTTP_IMPL_READ_IPP_HPP
#define BEAST_HTTP_IMPL_READ_IPP_HPP
#include <beast/http/type_check.hpp>
#include <beast/bind_handler.hpp>
#include <beast/handler_alloc.hpp>
#include <cassert>
@@ -219,8 +218,6 @@ read(SyncReadStream& stream, Streambuf& streambuf,
"SyncReadStream requirements not met");
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(is_ReadableBody<Body>::value,
"ReadableBody requirements not met");
parser<isRequest, Body, Headers> p;
for(;;)
{
@@ -268,8 +265,6 @@ async_read(AsyncReadStream& stream, Streambuf& streambuf,
"AsyncReadStream requirements not met");
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(is_ReadableBody<Body>::value,
"ReadableBody requirements not met");
beast::async_completion<ReadHandler,
void(error_code)> completion(handler);
detail::read_op<AsyncReadStream, Streambuf,

View File

@@ -10,7 +10,6 @@
#include <beast/http/chunk_encode.hpp>
#include <beast/http/resume_context.hpp>
#include <beast/http/type_check.hpp>
#include <beast/http/detail/writes.hpp>
#include <beast/http/detail/write_preparation.hpp>
#include <beast/buffer_cat.hpp>
@@ -265,9 +264,9 @@ operator()(error_code ec, std::size_t, bool again)
case 4:
// VFALCO Unfortunately the current interface to the
// Writer concept prevents us from using coalescing the
// Writer concept prevents us from coalescing the
// final body chunk with the final chunk delimiter.
//
//
// write final chunk
d.state = 5;
boost::asio::async_write(d.s,
@@ -359,8 +358,6 @@ write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg,
boost::system::error_code& ec)
{
static_assert(is_WritableBody<Body>::value,
"WritableBody requirements not met");
detail::write_preparation<isRequest, Body, Headers> wp(msg);
wp.init(ec);
if(ec)
@@ -447,8 +444,6 @@ async_write(AsyncWriteStream& stream,
static_assert(
is_AsyncWriteStream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met");
static_assert(is_WritableBody<Body>::value,
"WritableBody requirements not met");
beast::async_completion<WriteHandler,
void(error_code)> completion(handler);
detail::write_op<AsyncWriteStream, decltype(completion.handler),

View File

@@ -35,6 +35,8 @@ struct response_fields
} // detail
#if ! GENERATING_DOCS
struct request_params
{
http::method_t method;
@@ -49,6 +51,8 @@ struct response_params
int version;
};
#endif
/** A HTTP message.
A message can be a request or response, depending on the `isRequest`
@@ -110,7 +114,7 @@ struct message
/// Diagnostics only
template<bool, class, class>
friend
friend
std::ostream&
operator<<(std::ostream& os,
message const& m);

View File

@@ -11,7 +11,6 @@
#include <beast/async_completion.hpp>
#include <beast/http/error.hpp>
#include <beast/http/parser.hpp>
#include <beast/http/type_check.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/system/error_code.hpp>

View File

@@ -21,6 +21,8 @@
namespace beast {
#if ! GENERATING_DOCS
/** Routines for performing RFC2616 compliance.
RFC2616:
Hypertext Transfer Protocol -- HTTP/1.1
@@ -454,6 +456,8 @@ token_in_list(boost::string_ref const& value,
} // rfc2616
#endif
} // beast
#endif

View File

@@ -23,8 +23,13 @@ namespace http {
template<class Streambuf>
struct basic_streambuf_body
{
/// The type of the `message::body` member
using value_type = Streambuf;
#if GENERATING_DOCS
private:
#endif
class reader
{
value_type& sb_;

View File

@@ -23,8 +23,13 @@ namespace http {
*/
struct string_body
{
/// The type of the `message::body` member
using value_type = std::string;
#if GENERATING_DOCS
private:
#endif
class reader
{
value_type& s_;

View File

@@ -1,49 +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_HTTP_TYPE_CHECK_HPP
#define BEAST_HTTP_TYPE_CHECK_HPP
#include <type_traits>
namespace beast {
namespace http {
/// Evaluates to std::true_type if `T` models Body
template<class T>
struct is_Body : std::true_type
{
};
/// Evalulates to std::true_type if Body has a reader
template<class T>
struct is_ReadableBody : std::true_type
{
};
/// Evalulates to std::true_type if Body has a writer
template<class T>
struct is_WritableBody : std::true_type
{
};
/// Evaluates to std::true_type if `T` models HTTPMessage
template<class T>
struct is_HTTPMessage : std::false_type
{
};
/// Evaluates to std::true_type if `HTTPMessage` is a request
template<class HTTPMessage>
struct is_HTTPRequest : std::true_type
{
};
} // http
} // beast
#endif

View File

@@ -115,6 +115,59 @@ public:
}
};
template<class Allocator>
class basic_streambuf<Allocator>::const_buffers_type
{
basic_streambuf const* sb_ = nullptr;
friend class basic_streambuf;
explicit
const_buffers_type(basic_streambuf const& sb);
public:
/// Why?
using value_type = boost::asio::const_buffer;
class const_iterator;
const_buffers_type() = default;
const_buffers_type(const_buffers_type const&) = default;
const_buffers_type& operator=(const_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
};
template<class Allocator>
class basic_streambuf<Allocator>::mutable_buffers_type
{
basic_streambuf const* sb_;
friend class basic_streambuf;
explicit
mutable_buffers_type(basic_streambuf const& sb);
public:
using value_type = mutable_buffer;
class const_iterator;
mutable_buffers_type() = default;
mutable_buffers_type(mutable_buffers_type const&) = default;
mutable_buffers_type& operator=(mutable_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
};
//------------------------------------------------------------------------------
template<class Allocator>
@@ -798,16 +851,16 @@ basic_streambuf<Allocator>::debug_check() const
template<class Alloc, class T>
basic_streambuf<Alloc>&
operator<<(basic_streambuf<Alloc>& buf, T const& t)
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();
buf.commit(buffer_copy(buf.prepare(s.size()),
boost::asio::buffer(s)));
return buf;
streambuf.commit(buffer_copy(
streambuf.prepare(s.size()), buffer(s)));
return streambuf;
}
//------------------------------------------------------------------------------

View File

@@ -0,0 +1,520 @@
//
// 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_IMPL_BUFFERS_ADAPTER_IPP
#define BEAST_IMPL_BUFFERS_ADAPTER_IPP
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
#include <type_traits>
namespace beast {
template<class Buffers>
class buffers_adapter<Buffers>::const_buffers_type
{
buffers_adapter const* ba_;
public:
using value_type = boost::asio::const_buffer;
class const_iterator;
const_buffers_type() = default;
const_buffers_type(
const_buffers_type const&) = default;
const_buffers_type& operator=(
const_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class buffers_adapter;
const_buffers_type(buffers_adapter const& ba)
: ba_(&ba)
{
}
};
template<class Buffers>
class buffers_adapter<Buffers>::const_buffers_type::const_iterator
{
iter_type it_;
buffers_adapter const* ba_;
public:
using value_type = boost::asio::const_buffer;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return ba_ == other.ba_ &&
it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
return value_type{buffer_cast<void const*>(*it_),
(ba_->out_ == ba_->bs_.end() ||
it_ != ba_->out_) ? buffer_size(*it_) : ba_->out_pos_} +
(it_ == ba_->begin_ ? ba_->in_pos_ : 0);
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
--it_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class const_buffers_type;
const_iterator(buffers_adapter const& ba,
iter_type iter)
: it_(iter)
, ba_(&ba)
{
}
};
template<class Buffers>
inline
auto
buffers_adapter<Buffers>::const_buffers_type::begin() const ->
const_iterator
{
return const_iterator{*ba_, ba_->begin_};
}
template<class Buffers>
inline
auto
buffers_adapter<Buffers>::const_buffers_type::end() const ->
const_iterator
{
return const_iterator{*ba_, ba_->out_ ==
ba_->end_ ? ba_->end_ : std::next(ba_->out_)};
}
//------------------------------------------------------------------------------
template<class Buffers>
class buffers_adapter<Buffers>::mutable_buffers_type
{
buffers_adapter const* ba_;
public:
using value_type = boost::asio::mutable_buffer;
class const_iterator;
mutable_buffers_type() = default;
mutable_buffers_type(
mutable_buffers_type const&) = default;
mutable_buffers_type& operator=(
mutable_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class buffers_adapter;
mutable_buffers_type(
buffers_adapter const& ba)
: ba_(&ba)
{
}
};
template<class Buffers>
class buffers_adapter<Buffers>::mutable_buffers_type::const_iterator
{
iter_type it_;
buffers_adapter const* ba_;
public:
using value_type = boost::asio::mutable_buffer;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return ba_ == other.ba_ &&
it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
return value_type{buffer_cast<void*>(*it_),
it_ == std::prev(ba_->end_) ?
ba_->out_end_ : buffer_size(*it_)} +
(it_ == ba_->out_ ? ba_->out_pos_ : 0);
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
--it_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class mutable_buffers_type;
const_iterator(buffers_adapter const& ba,
iter_type iter)
: it_(iter)
, ba_(&ba)
{
}
};
template<class Buffers>
inline
auto
buffers_adapter<Buffers>::mutable_buffers_type::begin() const ->
const_iterator
{
return const_iterator{*ba_, ba_->out_};
}
template<class Buffers>
inline
auto
buffers_adapter<Buffers>::mutable_buffers_type::end() const ->
const_iterator
{
return const_iterator{*ba_, ba_->end_};
}
//------------------------------------------------------------------------------
template<class Buffers>
buffers_adapter<Buffers>::buffers_adapter(
buffers_adapter&& other)
: buffers_adapter(std::move(other),
std::distance<iter_type>(other.bs_.begin(), other.begin_),
std::distance<iter_type>(other.bs_.begin(), other.out_),
std::distance<iter_type>(other.bs_.begin(), other.end_))
{
}
template<class Buffers>
buffers_adapter<Buffers>::buffers_adapter(
buffers_adapter const& other)
: buffers_adapter(other,
std::distance<iter_type>(other.bs_.begin(), other.begin_),
std::distance<iter_type>(other.bs_.begin(), other.out_),
std::distance<iter_type>(other.bs_.begin(), other.end_))
{
}
template<class Buffers>
auto
buffers_adapter<Buffers>::operator=(
buffers_adapter&& other) -> buffers_adapter&
{
auto const nbegin = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
auto const nout = std::distance<iter_type>(
other.bs_.begin(), other.out_);
auto const nend = std::distance<iter_type>(
other.bs_.begin(), other.end_);
bs_ = std::move(other.bs_);
begin_ = std::next(bs_.begin(), nbegin);
out_ = std::next(bs_.begin(), nout);
end_ = std::next(bs_.begin(), nend);
max_size_ = other.max_size_;
in_pos_ = other.in_pos_;
in_size_ = other.in_size_;
out_pos_ = other.out_pos_;
out_end_ = other.out_end_;
return *this;
}
template<class Buffers>
auto
buffers_adapter<Buffers>::operator=(
buffers_adapter const& other) -> buffers_adapter&
{
auto const nbegin = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
auto const nout = std::distance<iter_type>(
other.bs_.begin(), other.out_);
auto const nend = std::distance<iter_type>(
other.bs_.begin(), other.end_);
bs_ = other.bs_;
begin_ = std::next(bs_.begin(), nbegin);
out_ = std::next(bs_.begin(), nout);
end_ = std::next(bs_.begin(), nend);
max_size_ = other.max_size_;
in_pos_ = other.in_pos_;
in_size_ = other.in_size_;
out_pos_ = other.out_pos_;
out_end_ = other.out_end_;
return *this;
}
template<class Buffers>
buffers_adapter<Buffers>::buffers_adapter(
Buffers const& bs)
: bs_(bs)
, begin_(bs_.begin())
, out_(bs_.begin())
, end_(bs_.begin())
, max_size_(boost::asio::buffer_size(bs_))
{
}
template<class Buffers>
auto
buffers_adapter<Buffers>::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())
{
auto size = buffer_size(*end_) - out_pos_;
if(n > size)
{
n -= size;
while(++end_ != bs_.end())
{
size = buffer_size(*end_);
if(n < size)
{
out_end_ = n;
n = 0;
++end_;
break;
}
n -= size;
out_end_ = size;
}
}
else
{
++end_;
out_end_ = out_pos_ + n;
n = 0;
}
}
if(n > 0)
throw std::length_error(
"no space in buffers_adapter");
return mutable_buffers_type{*this};
}
template<class Buffers>
void
buffers_adapter<Buffers>::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_);
while(out_ != last)
{
auto const avail =
buffer_size(*out_) - out_pos_;
if(n < avail)
{
out_pos_ += n;
in_size_ += n;
max_size_ -= n;
return;
}
++out_;
n -= avail;
out_pos_ = 0;
in_size_ += avail;
max_size_ -= avail;
}
n = std::min(n, out_end_ - out_pos_);
out_pos_ += n;
in_size_ += n;
max_size_ -= n;
if(out_pos_ == buffer_size(*out_))
{
++out_;
out_pos_ = 0;
out_end_ = 0;
}
}
template<class Buffers>
inline
auto
buffers_adapter<Buffers>::data() const ->
const_buffers_type
{
return const_buffers_type{*this};
}
template<class Buffers>
void
buffers_adapter<Buffers>::consume(std::size_t n)
{
for(;;)
{
if(begin_ != out_)
{
auto const avail =
buffer_size(*begin_) - in_pos_;
if(n < avail)
{
in_size_ -= n;
in_pos_ += n;
break;
}
n -= avail;
in_size_ -= avail;
in_pos_ = 0;
++begin_;
}
else
{
auto const avail = out_pos_ - in_pos_;
if(n < avail)
{
in_size_ -= n;
in_pos_ += n;
}
else
{
in_size_ -= avail;
if(out_pos_ != out_end_||
out_ != std::prev(bs_.end()))
{
in_pos_ = out_pos_;
}
else
{
// Use the whole buffer now.
in_pos_ = 0;
out_pos_ = 0;
out_end_ = 0;
}
}
break;
}
}
}
} // beast
#endif

View File

@@ -0,0 +1,211 @@
//
// 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_IMPL_CONSUMING_BUFFERS_IPP
#define BEAST_IMPL_CONSUMING_BUFFERS_IPP
#include <beast/type_check.hpp>
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <type_traits>
#include <utility>
namespace beast {
template<class Buffers, class ValueType>
class consuming_buffers<Buffers, ValueType>::const_iterator
{
friend class consuming_buffers<Buffers, ValueType>;
using iter_type =
typename Buffers::const_iterator;
iter_type it_;
consuming_buffers const* b_;
public:
using value_type =
typename std::iterator_traits<iter_type>::value_type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return b_ == other.b_ && it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
if(it_ == b_->begin_)
return *it_ + b_->skip_;
return *it_;
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
--it_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
const_iterator(consuming_buffers const& b,
iter_type it)
: it_(it)
, b_(&b)
{
}
};
template<class Buffers, class ValueType>
consuming_buffers<Buffers, ValueType>::
consuming_buffers(consuming_buffers&& other)
: consuming_buffers(std::move(other),
std::distance<iter_type>(
other.bs_.begin(), other.begin_))
{
}
template<class Buffers, class ValueType>
consuming_buffers<Buffers, ValueType>::
consuming_buffers(consuming_buffers const& other)
: consuming_buffers(other,
std::distance<iter_type>(
other.bs_.begin(), other.begin_))
{
}
template<class Buffers, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::
operator=(consuming_buffers&& other) ->
consuming_buffers&
{
auto const nbegin = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
bs_ = std::move(other.bs_);
begin_ = std::next(bs_.begin(), nbegin);
skip_ = other.skip_;
return *this;
}
template<class Buffers, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::
operator=(consuming_buffers const& other) ->
consuming_buffers&
{
auto const nbegin = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
bs_ = other.bs_;
begin_ = std::next(bs_.begin(), nbegin);
skip_ = other.skip_;
return *this;
}
template<class Buffers, class ValueType>
consuming_buffers<Buffers, ValueType>::
consuming_buffers(Buffers const& bs)
: bs_(bs)
, begin_(bs_.begin())
{
static_assert(is_BufferSequence<Buffers, ValueType>::value,
"BufferSequence requirements not met");
}
template<class Buffers, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::begin() const ->
const_iterator
{
return const_iterator{*this, begin_};
}
template<class Buffers, class ValueType>
auto
consuming_buffers<Buffers, ValueType>::end() const ->
const_iterator
{
return const_iterator{*this, bs_.end()};
}
template<class Buffers, class ValueType>
void
consuming_buffers<Buffers, ValueType>::consume(std::size_t n)
{
using boost::asio::buffer_size;
for(;n > 0 && begin_ != bs_.end(); ++begin_)
{
auto const len =
buffer_size(*begin_) - skip_;
if(n < len)
{
skip_ += n;
break;
}
n -= len;
skip_ = 0;
}
}
template<class Buffers>
consuming_buffers<Buffers, typename Buffers::value_type>
consumed_buffers(Buffers const& bs, std::size_t n)
{
consuming_buffers<Buffers> cb(bs);
cb.consume(n);
return cb;
}
} // beast
#endif

View File

@@ -0,0 +1,215 @@
//
// 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_IMPL_PREPARE_BUFFERS_IPP
#define BEAST_IMPL_PREPARE_BUFFERS_IPP
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <stdexcept>
#include <utility>
namespace beast {
template<class BufferSequence>
void
prepared_buffers<BufferSequence>::
setup(std::size_t n)
{
for(end_ = bs_.begin(); end_ != bs_.end(); ++end_)
{
auto const len =
boost::asio::buffer_size(*end_);
if(n <= len)
{
size_ = n;
back_ = end_++;
return;
}
n -= len;
}
size_ = 0;
back_ = end_;
}
template<class BufferSequence>
class prepared_buffers<BufferSequence>::const_iterator
{
friend class prepared_buffers<BufferSequence>;
using iter_type =
typename BufferSequence::const_iterator;
prepared_buffers const* b_;
typename BufferSequence::const_iterator it_;
public:
using value_type =
typename std::iterator_traits<iter_type>::value_type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return b_ == other.b_ && it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
if(it_ == b_->back_)
return prepare_buffer(b_->size_, *it_);
return *it_;
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
--it_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
const_iterator(prepared_buffers const& b,
bool at_end)
: b_(&b)
, it_(at_end ? b.end_ : b.bs_.begin())
{
}
};
template<class BufferSequence>
prepared_buffers<BufferSequence>::
prepared_buffers(prepared_buffers&& other)
: prepared_buffers(std::move(other),
std::distance<iter_type>(other.bs_.begin(), other.back_),
std::distance<iter_type>(other.bs_.begin(), other.end_))
{
}
template<class BufferSequence>
prepared_buffers<BufferSequence>::
prepared_buffers(prepared_buffers const& other)
: prepared_buffers(other,
std::distance<iter_type>(other.bs_.begin(), other.back_),
std::distance<iter_type>(other.bs_.begin(), other.end_))
{
}
template<class BufferSequence>
auto
prepared_buffers<BufferSequence>::
operator=(prepared_buffers&& other) ->
prepared_buffers&
{
auto const nback = std::distance<iter_type>(
other.bs_.begin(), other.back_);
auto const nend = std::distance<iter_type>(
other.bs_.begin(), other.end_);
bs_ = std::move(other.bs_);
back_ = std::next(bs_.begin(), nback);
end_ = std::next(bs_.begin(), nend);
size_ = other.size_;
return *this;
}
template<class BufferSequence>
auto
prepared_buffers<BufferSequence>::
operator=(prepared_buffers const& other) ->
prepared_buffers&
{
auto const nback = std::distance<iter_type>(
other.bs_.begin(), other.back_);
auto const nend = std::distance<iter_type>(
other.bs_.begin(), other.end_);
bs_ = other.bs_;
back_ = std::next(bs_.begin(), nback);
end_ = std::next(bs_.begin(), nend);
size_ = other.size_;
return *this;
}
template<class BufferSequence>
prepared_buffers<BufferSequence>::
prepared_buffers(std::size_t n, BufferSequence const& bs)
: bs_(bs)
{
setup(n);
}
template<class BufferSequence>
auto
prepared_buffers<BufferSequence>::begin() const ->
const_iterator
{
return const_iterator{*this, false};
}
template<class BufferSequence>
auto
prepared_buffers<BufferSequence>::end() const ->
const_iterator
{
return const_iterator{*this, true};
}
template<class BufferSequence>
inline
prepared_buffers<BufferSequence>
prepare_buffers(std::size_t n, BufferSequence const& buffers)
{
return prepared_buffers<BufferSequence>(n, buffers);
}
} // beast
#endif

View File

@@ -0,0 +1,304 @@
//
// 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_IMPL_STATIC_STREAMBUF_IPP
#define BEAST_IMPL_STATIC_STREAMBUF_IPP
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <cstring>
#include <iterator>
#include <stdexcept>
namespace beast {
class static_streambuf::const_buffers_type
{
std::size_t n_;
std::uint8_t const* p_;
public:
using value_type = boost::asio::const_buffer;
class const_iterator;
const_buffers_type() = default;
const_buffers_type(
const_buffers_type const&) = default;
const_buffers_type& operator=(
const_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class static_streambuf;
const_buffers_type(
std::uint8_t const* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
class static_streambuf::const_buffers_type::const_iterator
{
std::size_t n_;
std::uint8_t const* p_;
public:
using value_type = boost::asio::const_buffer;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return p_ == other.p_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return value_type{p_, n_};
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
p_ += n_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
p_ -= n_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class const_buffers_type;
const_iterator(
std::uint8_t const* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
inline
auto
static_streambuf::const_buffers_type::begin() const ->
const_iterator
{
return const_iterator{p_, n_};
}
inline
auto
static_streambuf::const_buffers_type::end() const ->
const_iterator
{
return const_iterator{p_ + n_, n_};
}
//------------------------------------------------------------------------------
class static_streambuf::mutable_buffers_type
{
std::size_t n_;
std::uint8_t* p_;
public:
using value_type = boost::asio::mutable_buffer;
class const_iterator;
mutable_buffers_type() = default;
mutable_buffers_type(
mutable_buffers_type const&) = default;
mutable_buffers_type& operator=(
mutable_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class static_streambuf;
mutable_buffers_type(
std::uint8_t* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
class static_streambuf::mutable_buffers_type::const_iterator
{
std::size_t n_;
std::uint8_t* p_;
public:
using value_type = boost::asio::mutable_buffer;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return p_ == other.p_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return value_type{p_, n_};
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
p_ += n_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
p_ -= n_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class mutable_buffers_type;
const_iterator(std::uint8_t* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
inline
auto
static_streambuf::mutable_buffers_type::begin() const ->
const_iterator
{
return const_iterator{p_, n_};
}
inline
auto
static_streambuf::mutable_buffers_type::end() const ->
const_iterator
{
return const_iterator{p_ + n_, n_};
}
//------------------------------------------------------------------------------
inline
auto
static_streambuf::prepare(std::size_t n) ->
mutable_buffers_type
{
if(n > static_cast<std::size_t>(end_ - out_))
throw std::length_error("no space in streambuf");
last_ = out_ + n;
return mutable_buffers_type{out_, n};
}
inline
auto
static_streambuf::data() const ->
const_buffers_type
{
return const_buffers_type{in_,
static_cast<std::size_t>(out_ - in_)};
}
} // beast
#endif

View File

@@ -85,8 +85,15 @@ public:
using value_type =
typename std::iterator_traits<iter_type>::value_type;
#if GENERATING_DOCS
/// A bidirectional iterator type that may be used to read elements.
using const_iterator = implementation_defined;
#else
class const_iterator;
#endif
/// Move constructor.
prepared_buffers(prepared_buffers&&);
@@ -120,190 +127,9 @@ public:
private:
void
setup(std::size_t n)
{
for(end_ = bs_.begin(); end_ != bs_.end(); ++end_)
{
auto const len =
boost::asio::buffer_size(*end_);
if(n <= len)
{
size_ = n;
back_ = end_++;
return;
}
n -= len;
}
size_ = 0;
back_ = end_;
}
setup(std::size_t n);
};
/// A bidirectional iterator type that may be used to read elements.
template<class BufferSequence>
class prepared_buffers<BufferSequence>::const_iterator
{
friend class prepared_buffers<BufferSequence>;
using iter_type =
typename BufferSequence::const_iterator;
prepared_buffers const* b_;
typename BufferSequence::const_iterator it_;
public:
using value_type =
typename std::iterator_traits<iter_type>::value_type;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return b_ == other.b_ && it_ == other.it_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
if(it_ == b_->back_)
return prepare_buffer(b_->size_, *it_);
return *it_;
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
++it_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
--it_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
const_iterator(prepared_buffers const& b,
bool at_end)
: b_(&b)
, it_(at_end ? b.end_ : b.bs_.begin())
{
}
};
template<class BufferSequence>
prepared_buffers<BufferSequence>::
prepared_buffers(prepared_buffers&& other)
: prepared_buffers(std::move(other),
std::distance<iter_type>(other.bs_.begin(), other.back_),
std::distance<iter_type>(other.bs_.begin(), other.end_))
{
}
template<class BufferSequence>
prepared_buffers<BufferSequence>::
prepared_buffers(prepared_buffers const& other)
: prepared_buffers(other,
std::distance<iter_type>(other.bs_.begin(), other.back_),
std::distance<iter_type>(other.bs_.begin(), other.end_))
{
}
template<class BufferSequence>
auto
prepared_buffers<BufferSequence>::
operator=(prepared_buffers&& other) ->
prepared_buffers&
{
auto const nback = std::distance<iter_type>(
other.bs_.begin(), other.back_);
auto const nend = std::distance<iter_type>(
other.bs_.begin(), other.end_);
bs_ = std::move(other.bs_);
back_ = std::next(bs_.begin(), nback);
end_ = std::next(bs_.begin(), nend);
size_ = other.size_;
return *this;
}
template<class BufferSequence>
auto
prepared_buffers<BufferSequence>::
operator=(prepared_buffers const& other) ->
prepared_buffers&
{
auto const nback = std::distance<iter_type>(
other.bs_.begin(), other.back_);
auto const nend = std::distance<iter_type>(
other.bs_.begin(), other.end_);
bs_ = other.bs_;
back_ = std::next(bs_.begin(), nback);
end_ = std::next(bs_.begin(), nend);
size_ = other.size_;
return *this;
}
template<class BufferSequence>
prepared_buffers<BufferSequence>::
prepared_buffers(std::size_t n, BufferSequence const& bs)
: bs_(bs)
{
setup(n);
}
template<class BufferSequence>
auto
prepared_buffers<BufferSequence>::begin() const ->
const_iterator
{
return const_iterator{*this, false};
}
template<class BufferSequence>
auto
prepared_buffers<BufferSequence>::end() const ->
const_iterator
{
return const_iterator{*this, true};
}
//------------------------------------------------------------------------------
/** Return a trimmed, wrapped buffer sequence.
@@ -321,13 +147,11 @@ prepared_buffers<BufferSequence>::end() const ->
will be made, but ownership of the underlying memory is not transferred.
*/
template<class BufferSequence>
inline
prepared_buffers<BufferSequence>
prepare_buffers(std::size_t n, BufferSequence const& buffers)
{
return prepared_buffers<BufferSequence>(n, buffers);
}
prepare_buffers(std::size_t n, BufferSequence const& buffers);
} // beast
#include <beast/impl/prepare_buffers.ipp>
#endif

View File

@@ -8,12 +8,10 @@
#ifndef BEAST_STATIC_STREAMBUF_HPP
#define BEAST_STATIC_STREAMBUF_HPP
#include <boost/asio/buffer.hpp>
#include <boost/utility/base_from_member.hpp>
#include <algorithm>
#include <array>
#include <cstring>
#include <iterator>
#include <stdexcept>
namespace beast {
@@ -40,18 +38,23 @@ protected:
std::uint8_t* end_;
public:
#if GENERATING_DOCS
/// The type used to represent the input sequence as a list of buffers.
using const_buffers_type = implementation_defined;
/// The type used to represent the output sequence as a list of buffers.
using mutable_buffers_type = implementation_defined;
#else
class const_buffers_type;
class mutable_buffers_type;
#if GENERATING_DOCS
private:
#endif
static_streambuf(
static_streambuf const& other) noexcept = delete;
static_streambuf& operator=(
static_streambuf const&) noexcept = delete;
#if GENERATING_DOCS
public:
#endif
/// Returns the largest size output sequence possible.
@@ -116,293 +119,6 @@ protected:
//------------------------------------------------------------------------------
/// The type used to represent the input sequence as a list of buffers.
class static_streambuf::const_buffers_type
{
std::size_t n_;
std::uint8_t const* p_;
public:
using value_type = boost::asio::const_buffer;
class const_iterator;
const_buffers_type() = default;
const_buffers_type(
const_buffers_type const&) = default;
const_buffers_type& operator=(
const_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class static_streambuf;
const_buffers_type(
std::uint8_t const* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
class static_streambuf::const_buffers_type::const_iterator
{
std::size_t n_;
std::uint8_t const* p_;
public:
using value_type = boost::asio::const_buffer;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return p_ == other.p_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return value_type{p_, n_};
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
p_ += n_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
p_ -= n_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class const_buffers_type;
const_iterator(
std::uint8_t const* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
inline
auto
static_streambuf::const_buffers_type::begin() const ->
const_iterator
{
return const_iterator{p_, n_};
}
inline
auto
static_streambuf::const_buffers_type::end() const ->
const_iterator
{
return const_iterator{p_ + n_, n_};
}
//------------------------------------------------------------------------------
/// The type used to represent the output sequence as a list of buffers.
class static_streambuf::mutable_buffers_type
{
std::size_t n_;
std::uint8_t* p_;
public:
using value_type = boost::asio::mutable_buffer;
class const_iterator;
mutable_buffers_type() = default;
mutable_buffers_type(
mutable_buffers_type const&) = default;
mutable_buffers_type& operator=(
mutable_buffers_type const&) = default;
const_iterator
begin() const;
const_iterator
end() const;
private:
friend class static_streambuf;
mutable_buffers_type(
std::uint8_t* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
class static_streambuf::mutable_buffers_type::const_iterator
{
std::size_t n_;
std::uint8_t* p_;
public:
using value_type = boost::asio::mutable_buffer;
using pointer = value_type const*;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(const_iterator&& other) = default;
const_iterator(const_iterator const& other) = default;
const_iterator& operator=(const_iterator&& other) = default;
const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const
{
return p_ == other.p_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return value_type{p_, n_};
}
pointer
operator->() const = delete;
const_iterator&
operator++()
{
p_ += n_;
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
const_iterator&
operator--()
{
p_ -= n_;
return *this;
}
const_iterator
operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
private:
friend class mutable_buffers_type;
const_iterator(std::uint8_t* p, std::size_t n)
: n_(n)
, p_(p)
{
}
};
inline
auto
static_streambuf::mutable_buffers_type::begin() const ->
const_iterator
{
return const_iterator{p_, n_};
}
inline
auto
static_streambuf::mutable_buffers_type::end() const ->
const_iterator
{
return const_iterator{p_ + n_, n_};
}
//------------------------------------------------------------------------------
inline
auto
static_streambuf::prepare(std::size_t n) ->
mutable_buffers_type
{
if(n > static_cast<std::size_t>(end_ - out_))
throw std::length_error("no space in streambuf");
last_ = out_ + n;
return mutable_buffers_type{out_, n};
}
inline
auto
static_streambuf::data() const ->
const_buffers_type
{
return const_buffers_type{in_,
static_cast<std::size_t>(out_ - in_)};
}
//------------------------------------------------------------------------------
/** A `Streambuf` with a fixed size internal buffer.
@tparam N The number of bytes in the internal buffer.
@@ -456,4 +172,6 @@ public:
} // beast
#include <beast/impl/static_streambuf.ipp>
#endif

View File

@@ -13,6 +13,7 @@
namespace beast {
namespace websocket {
/// The type of error used by functions and completion handlers.
using error_code = boost::system::error_code;
/// Error values

View File

@@ -45,7 +45,6 @@ unit-test http_tests :
http/rfc2616.cpp
http/streambuf_body.cpp
http/string_body.cpp
http/type_check.cpp
http/write.cpp
;

View File

@@ -1,9 +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)
//
// Test that header file is self-contained.
#include <beast/http/type_check.hpp>