Refactor HTTP identifier names (API Change):

fix #171

Several names and  HTTP identifiers are renamed to be
more consistent, self-explanatory, and concise:

* "Fields" is a collection of HTTP header fields (rfc7230 section 3.2)
* "Header" is the Start Line plus Fields. Another way to look at it is,
  the HTTP message minus the body.
* `basic_fields` replaces `basic_headers`
* `fields` replaces `headers`
* `Fields` replaces `Headers` in template parameter lists
* `header` replaces `message_headers`
* `header::fields` replaces `message_headers::fields`

The changes are cosmetic and do not affect run-time behavior.
This commit is contained in:
Vinnie Falco
2016-11-10 05:34:49 -05:00
parent 879262abb1
commit e3848e7281
63 changed files with 1220 additions and 1125 deletions

View File

@@ -1,3 +1,12 @@
1.0.0-b20
API Changes:
* Rename HTTP identifiers
--------------------------------------------------------------------------------
>>>>>>> b152207... .
1.0.0-b19 1.0.0-b19
* Boost library min/max guidance * Boost library min/max guidance

View File

@@ -447,17 +447,16 @@ start. Other design goals:
or frame data, which is of any type meeting the requirements of or frame data, which is of any type meeting the requirements of
__DynamicBuffer__ (modeled after `boost::asio::streambuf`). __DynamicBuffer__ (modeled after `boost::asio::streambuf`).
Beast comes with the class `beast::basic_streambuf`, an efficient Beast comes with the class __basic_streambuf__, an efficient
implementation of the [*DynamicBuffer] concept which makes use of multiple implementation of the __DynamicBuffer__ concept which makes use of multiple
allocated octet arrays. If an incoming message is broken up into allocated octet arrays. If an incoming message is broken up into
multiple pieces, no reallocation occurs. Instead, new allocations are multiple pieces, no reallocation occurs. Instead, new allocations are
appended to the sequence when existing allocations are filled. Beast appended to the sequence when existing allocations are filled. Beast
does not impose any particular memory management model on callers. The does not impose any particular memory management model on callers. The
`basic_streambuf` provided by beast supports standard allocators through __basic_streambuf__ provided by beast supports standard allocators through
a template argument. Use the [*DynamicBuffer] that comes with beast, a template argument. Use the __DynamicBuffer__ that comes with beast,
customize the allocator if you desire, or provide your own type that customize the allocator if you desire, or provide your own type that
meets the meets the requirements.
[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/basic_streambuf.hpp#L21 concept requirements].
[table [table
[ [

View File

@@ -5,30 +5,62 @@
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
] ]
[/
ideas:
- complete send request walkthrough (client)
- complete receive response walkthrough (client)
- complete receive request walkthrough (server)
- complete send response walkthrough (server)
- Introduce concepts from simple to complex
- Smooth progression of new ideas building on the previous ideas
- do we show a simplified message with collapsed fields?
- do we introduce `header` or `message` first?
contents:
Message (and header, fields)
Create request
Create response
Algorithms
Write
Read
Parse
Examples
Send Request
Receive Response
Receive Request
Send Response
Advanced
Responding to HEAD
Expect: 100-continue
Body (user defined)
section beast.http.examples Examples
note
In the example code which follows, `socket` refers to an object of type
`boost::asio::ip::tcp::socket` which is currently connected to a remote peer.
]
[section:http Using HTTP] [section:http Using HTTP]
[block ''' [block '''
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist> <informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
<member><link linkend="beast.http.message">Messages</link></member> <member><link linkend="beast.http.message">Message</link></member>
<member><link linkend="beast.http.headers">Headers</link></member> <member><link linkend="beast.http.fields">Fields</link></member>
<member><link linkend="beast.http.body">Body</link></member> <member><link linkend="beast.http.body">Body</link></member>
<member><link linkend="beast.http.algorithms">Algorithms</link></member> <member><link linkend="beast.http.algorithms">Algorithms</link></member>
<member><link linkend="beast.http.sockets">Sockets</link></member>
</simplelist></entry></row></tbody></tgroup></informaltable> </simplelist></entry></row></tbody></tgroup></informaltable>
'''] ''']
Beast.HTTP offers programmers simple and performant models of HTTP messages and Beast offers programmers simple and performant models of HTTP messages and
their associated operations including synchronous and asynchronous reading and their associated operations including synchronous and asynchronous reading and
writing of messages in the HTTP/1 wire format using Boost.Asio. writing of messages and headers in the HTTP/1 wire format using Boost.Asio.
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.
[note [note
The following documentation assumes familiarity with both Boost.Asio The following documentation assumes familiarity with both Boost.Asio
@@ -36,6 +68,7 @@ messages called responses.
and identifiers mentioned in this section are written as if the following and identifiers mentioned in this section are written as if the following
declarations are in effect: declarations are in effect:
``` ```
#include <beast/core.hpp>
#include <beast/http.hpp> #include <beast/http.hpp>
using namespace beast; using namespace beast;
using namespace beast::http; using namespace beast::http;
@@ -44,101 +77,124 @@ messages called responses.
[section:message Messages]
The __message__ class template models HTTP/1 and HTTP/2 requests and responses.
These class templates are complete: they contain all the information needed
by the algorithms. Objects of this type are first class: They may be returned
from functions, moved, copied, passed as arguments, and stored in containers.
Request and response messages are distinct types; functions may be overloaded
on just one or the other if desired. Because this class template supports
HTTP/1 and HTTP/2, it is sometimes referred to as the universal message model.
There are three important template parameters in the message class: [section:message Message]
The HTTP protocol defines the client and server roles: clients send messages
called requests and servers send back messages called responses. A HTTP message
(referred to hereafter as "message") contains request or response specific
attributes (contained in the "Start Line"), a series of zero or more name/value
pairs (collectively termed "Fields"), and an optional series of octets called
the message body which may be zero in length. The start line for a HTTP request
includes a string called the method, a string called the URL, and a version
number indicating HTTP/1.0 or HTTP/1.1. For a response, the start line contains
an integer status code and a string called the reason phrase. Alternatively, a
HTTP message can be viewed as two parts: a header, followed by a body.
[note
The Reason-Phrase is obsolete as of rfc7230.
]
The __header__ class template models the header for HTTP/1 and HTTP/2 messages.
This class template is a family of specializations, one for requests and one
for responses, depending on the [*`isRequest`] template value.
The [*`Fields`] template type determines the type of associative container
used to store the field values. The provided __basic_fields__ class template
and __fields__ type alias are typical choices for the [*`Fields`] type, but
advanced applications may supply user defined types which meet the requirements.
The __message__ class template models the header and optional body for HTTP/1
and HTTP/2 requests and responses. It is derived from the __header__ class
template with the same shared template parameters, and adds the `body` data
member. The message class template requires an additional template argument
type [*`Body`]. This type controls the container used to represent the body,
if any, as well as the algorithms needed to serialize and parse bodies of
that type.
This illustration shows the declarations and members of the __header__ and
__message__ class templates, as well as the inheritance relationship:
[$images/message.png [width 650px] [height 390px]]
For notational convenience, these template type aliases are provided which
supply typical choices for the [*`Fields`] type:
``` ```
template< using request_header = header<true, fields>;
bool isRequest, using response_header = header<false, fields>;
class Body,
class Headers
>
class message;
template<class Body, class Fields = fields>
using request = message<true, Body, Fields>;
template<class Body, class Fields = fields>
using response = message<false, Body, Fields>;
``` ```
* [*`isRequest`]: Controls whether or not the message is a request or response. The code examples below show how to create and fill in a request and response
Depending on the value, different data members will be present in the resulting object:
type.
* [*`Body`]: determines both the kind of container used to represent the [table Create Message
message body and the algorithms used to parse and serialize it. [[HTTP Request] [HTTP Response]]
[[
* [*`Headers`]: determines the container used to represent the HTTP headers. ```
request<empty_body> req;
For notational convenience, the following template type aliases are provided: req.version = 11; // HTTP/1.1
```
template<
class Body,
class Headers = basic_headers<std::allocator<char>>>
using request = message<true, Body, Headers>;
template<
class Body,
class Headers = basic_headers<std::allocator<char>>>
using response = message<false, Body, Headers>;
```
The message class template has different data members depending on whether
it represents a request or response. These simplified declarations
notionally illustrate the members of HTTP/1 messages:
```
template<class Body, class Headers>
struct request
{
int version; // 10 for HTTP/1.0, 11 for HTTP/1.1
std::string method;
std::string url;
Headers headers;
typename Body::value_type body;
};
template<class Body, class Headers>
struct response
{
int version; // 10 for HTTP/1.0, 11 for HTTP/1.1
int status;
std::string reason;
Headers headers;
typename Body::value_type body;
};
```
These statements set fields in request and response message objects:
```
request<string_body> req;
req.version = 11; // HTTP/1.1
req.method = "GET"; req.method = "GET";
req.url = "/index.html"; req.url = "/index.htm"
req.headers.insert("User-Agent", "Beast.HTTP"); req.fields.insert("Accept", "text/html");
req.body = ""; req.fields.insert("Connection", "keep-alive");
req.fields.insert("User-Agent", "Beast");
```
][
```
response<string_body> res; response<string_body> res;
res.version = 10; // HTTP/1.0 res.version = 11; // HTTP/1.1
res.status = 404; res.status = 200;
res.reason = "Not Found"; res.reason = "OK";
res.headers.insert("Server", "Beast.HTTP"); res.fields.insert("Sever", "Beast");
res.body = "The requested resource was not found."; res.fields.insert("Content-Length", 4);
``` res.body = "****";
```
]]]
In the serialized format of a HTTP message, the header is represented as a
series of text lines ending in CRLF (`"\r\n"`). The end of the header is
indicated by a line containing only CRLF. Here are examples of serialized HTTP
request and response objects. The objects created above will produce these
results when serialized. Note that only the response has a body:
[table Serialized HTTP Request and Response
[[HTTP Request] [HTTP Response]]
[[
```
GET /index.htm HTTP/1.1\r\n
Accept: text/html\r\n
Connection: keep-alive\r\n
User-Agent: Beast\r\n
\r\n
```
][
```
200 OK HTTP/1.1\r\n
Server: Beast\r\n
Content-Length: 4\r\n
\r\n
****
```
]]]
[endsect] [endsect]
[section:headers Headers]
The [*`Headers`] type represents a container that can set or retrieve the [section:fields Fields]
headers in a message. Beast provides the
[link beast.ref.http__basic_headers `basic_headers`] class which serves The [*`Fields`] type represents a container that can set or retrieve the
fields in a message. Beast provides the
[link beast.ref.http__basic_fields `basic_fields`] class which serves
the needs for most users. It supports modification and inspection of values. the needs for most users. It supports modification and inspection of values.
The field names are not case-sensitive. The field names are not case-sensitive.
@@ -157,15 +213,7 @@ These statements change the values of the headers in the message passed:
} }
``` ```
[heading Advanced] User defined [*`Fields`] types are possible. To support serialization, the
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]]
User defined [*`Headers`] types are possible. To support serialization, the
type must meet the requirements of __FieldSequence__. To support parsing using type must meet the requirements of __FieldSequence__. To support parsing using
the provided parser, the type must provide the `insert` member function. the provided parser, the type must provide the `insert` member function.
@@ -233,30 +281,24 @@ serializing message bodies that come from a file.
[section:algorithms Algorithms] [section:algorithms Algorithms]
In addition to the universal message model, Beast provides synchronous Algorithms are provided to serialize and deserialize HTTP/1 messages on
algorithms which operate on HTTP/1 messages: streams.
* [link beast.ref.http__read [*read]]: Parse a message from a stream * [link beast.ref.http__read [*read]]: Deserialize a HTTP/1 __header__ or __message__ from a stream.
* [link beast.ref.http__write [*write]]: Serialize a HTTP/1 __header__ or __message__ to a stream.
* [link beast.ref.http__write [*write]]: Serialize a message into its wire format on a stream
Asynchronous versions of these algorithms are also available: Asynchronous versions of these algorithms are also available:
* [link beast.ref.http__async_read [*async_read]]: Parse a message from a stream * [link beast.ref.http__async_read [*async_read]]: Deserialize a HTTP/1 __header__ or __message__ asynchronously from a stream.
* [link beast.ref.http__async_write [*async_write]]: Serialize a HTTP/1 __header__ or __message__ asynchronously to a stream.
* [link beast.ref.http__async_write [*async_write]]: Serialize a message into its wire format on a stream [heading Using Sockets]
[endsect] The free function algorithms are modeled after Boost.Asio to send and receive
messages on TCP/IP sockets, SSL streams, or any object which meets the
Boost.Asio type requirements (__SyncReadStream__, __SyncWriteStream__,
__AsyncReadStream__, and __AsyncWriteStream__ depending on the types of
[section:sockets Using Sockets] operations performed). To send messages synchronously, use one of the
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
[link beast.ref.http__write `write`] functions: [link beast.ref.http__write `write`] functions:
``` ```
void send_request(boost::asio::ip::tcp::socket& sock) void send_request(boost::asio::ip::tcp::socket& sock)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -23,25 +23,33 @@
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>'''] [template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>'''] [template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
[def __asio_handler_invoke__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]]
[def __asio_handler_allocate__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]]
[def __AsyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]]
[def __AsyncWriteStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]]
[def __Body__ [link beast.ref.Body [*`Body`]]]
[def __CompletionHandler__ [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]]
[def __ConstBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]]
[def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]]
[def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]]
[def __message__ [link beast.ref.http__message `message`]]
[def __message_v1__ [link beast.ref.http__message_v1 `message_v1`]]
[def __MutableBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]]
[def __N4588__ [@http://cplusplus.github.io/networking-ts/draft.pdf [*N4588]]] [def __N4588__ [@http://cplusplus.github.io/networking-ts/draft.pdf [*N4588]]]
[def __rfc6455__ [@https://tools.ietf.org/html/rfc6455 rfc6455]] [def __rfc6455__ [@https://tools.ietf.org/html/rfc6455 rfc6455]]
[def __rfc7230__ [@https://tools.ietf.org/html/rfc7230 rfc7230]] [def __rfc7230__ [@https://tools.ietf.org/html/rfc7230 rfc7230]]
[def __streambuf__ [link beast.ref.streambuf `streambuf`]]
[def __asio_handler_invoke__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]]
[def __asio_handler_allocate__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]]
[def __void_or_deduced__ [@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]]]
[def __AsyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]]
[def __AsyncWriteStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]]
[def __CompletionHandler__ [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]]
[def __ConstBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]]
[def __MutableBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]]
[def __SyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]] [def __SyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]]
[def __SyncWriteStream__ [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]] [def __SyncWriteStream__ [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]]
[def __void_or_deduced__ [@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]]]
[def __Body__ [link beast.ref.Body [*`Body`]]]
[def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]]
[def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]]
[def __Parser__ [link beast.ref.Parser [*`Parser`]]]
[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]]
[def __fields__ [link beast.ref.http__fields `fields`]]
[def __header__ [link beast.ref.http__header `header`]]
[def __message__ [link beast.ref.http__message `message`]]
[def __streambuf__ [link beast.ref.streambuf `streambuf`]]
[def __basic_streambuf__ [link beast.ref.basic_streambuf `basic_streambuf`]]
Beast is a cross-platform, header-only C++ library built on Boost.Asio that Beast is a cross-platform, header-only C++ library built on Boost.Asio that
provides implementations of the HTTP and WebSocket protocols. provides implementations of the HTTP and WebSocket protocols.

View File

@@ -30,24 +30,25 @@
<bridgehead renderas="sect3">Classes</bridgehead> <bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__basic_dynabuf_body">basic_dynabuf_body</link></member> <member><link linkend="beast.ref.http__basic_dynabuf_body">basic_dynabuf_body</link></member>
<member><link linkend="beast.ref.http__basic_headers">basic_headers</link></member> <member><link linkend="beast.ref.http__basic_fields">basic_fields</link></member>
<member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member> <member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member>
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member> <member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
<member><link linkend="beast.ref.http__headers">headers</link></member> <member><link linkend="beast.ref.http__fields">fields</link></member>
<member><link linkend="beast.ref.http__headers_parser_v1">headers_parser_v1</link></member> <member><link linkend="beast.ref.http__header">header</link></member>
<member><link linkend="beast.ref.http__header_parser_v1">header_parser_v1</link></member>
<member><link linkend="beast.ref.http__message">message</link></member> <member><link linkend="beast.ref.http__message">message</link></member>
<member><link linkend="beast.ref.http__message_headers">message_headers</link></member>
<member><link linkend="beast.ref.http__parser_v1">parser_v1</link></member> <member><link linkend="beast.ref.http__parser_v1">parser_v1</link></member>
<member><link linkend="beast.ref.http__request">request</link></member> <member><link linkend="beast.ref.http__request">request</link></member>
<member><link linkend="beast.ref.http__request_headers">request_headers</link></member> <member><link linkend="beast.ref.http__request_header">request_header</link></member>
<member><link linkend="beast.ref.http__response">response</link></member> <member><link linkend="beast.ref.http__response">response</link></member>
<member><link linkend="beast.ref.http__response_headers">response_headers</link></member> <member><link linkend="beast.ref.http__response_header">response_header</link></member>
<member><link linkend="beast.ref.http__resume_context">resume_context</link></member> <member><link linkend="beast.ref.http__resume_context">resume_context</link></member>
<member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member> <member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member>
<member><link linkend="beast.ref.http__string_body">string_body</link></member> <member><link linkend="beast.ref.http__string_body">string_body</link></member>
</simplelist> </simplelist>
<bridgehead renderas="sect3">rfc7230</bridgehead> <bridgehead renderas="sect3">rfc7230</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__ext_list">ext_list</link></member> <member><link linkend="beast.ref.http__ext_list">ext_list</link></member>
<member><link linkend="beast.ref.http__param_list">param_list</link></member> <member><link linkend="beast.ref.http__param_list">param_list</link></member>
<member><link linkend="beast.ref.http__token_list">token_list</link></member> <member><link linkend="beast.ref.http__token_list">token_list</link></member>
@@ -56,20 +57,21 @@
<entry valign="top"> <entry valign="top">
<bridgehead renderas="sect3">Functions</bridgehead> <bridgehead renderas="sect3">Functions</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
<member><link linkend="beast.ref.http__async_read">async_read</link></member> <member><link linkend="beast.ref.http__async_read">async_read</link></member>
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
<member><link linkend="beast.ref.http__async_write">async_write</link></member> <member><link linkend="beast.ref.http__async_write">async_write</link></member>
<member><link linkend="beast.ref.http__chunk_encode">chunk_encode</link></member> <member><link linkend="beast.ref.http__chunk_encode">chunk_encode</link></member>
<member><link linkend="beast.ref.http__chunk_encode_final">chunk_encode_final</link></member> <member><link linkend="beast.ref.http__chunk_encode_final">chunk_encode_final</link></member>
<member><link linkend="beast.ref.http__swap">swap</link></member>
<member><link linkend="beast.ref.http__is_keep_alive">is_keep_alive</link></member> <member><link linkend="beast.ref.http__is_keep_alive">is_keep_alive</link></member>
<member><link linkend="beast.ref.http__is_upgrade">is_upgrade</link></member> <member><link linkend="beast.ref.http__is_upgrade">is_upgrade</link></member>
<member><link linkend="beast.ref.http__operator_ls_">operator&lt;&lt;</link></member>
<member><link linkend="beast.ref.http__parse">parse</link></member> <member><link linkend="beast.ref.http__parse">parse</link></member>
<member><link linkend="beast.ref.http__prepare">prepare</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__read">read</link></member>
<member><link linkend="beast.ref.http__swap">swap</link></member> <member><link linkend="beast.ref.http__reason_string">reason_string</link></member>
<member><link linkend="beast.ref.http__with_body">with_body</link></member> <member><link linkend="beast.ref.http__with_body">with_body</link></member>
<member><link linkend="beast.ref.http__write">write</link></member> <member><link linkend="beast.ref.http__write">write</link></member>
<member><link linkend="beast.ref.http__operator_ls_">operator&lt;&lt;</link></member>
</simplelist> </simplelist>
<bridgehead renderas="sect3">Type Traits</bridgehead> <bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">
@@ -84,14 +86,17 @@
<entry valign="top"> <entry valign="top">
<bridgehead renderas="sect3">Options</bridgehead> <bridgehead renderas="sect3">Options</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__header_max_size">header_max_size</link></member>
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member> <member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
<member><link linkend="beast.ref.http__headers_max_size">headers_max_size</link></member>
<member><link linkend="beast.ref.http__skip_body">skip_body</link></member> <member><link linkend="beast.ref.http__skip_body">skip_body</link></member>
</simplelist> </simplelist>
<bridgehead renderas="sect3">Constants</bridgehead> <bridgehead renderas="sect3">Constants</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__body_what">body_what</link></member> <member><link linkend="beast.ref.http__body_what">body_what</link></member>
<member><link linkend="beast.ref.http__connection">connection</link></member> <member><link linkend="beast.ref.http__connection">connection</link></member>
<member><link linkend="beast.ref.http__no_content_length">no_content_length</link></member>
<member><link linkend="beast.ref.http__parse_error">parse_error</link></member>
<member><link linkend="beast.ref.http__parse_flag">parse_flag</link></member>
</simplelist> </simplelist>
<bridgehead renderas="sect3">Concepts</bridgehead> <bridgehead renderas="sect3">Concepts</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">

View File

@@ -8,9 +8,12 @@
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED #ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED #define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
#include <beast/http/body_type.hpp> #include <beast/core/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/resume_context.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/logic/tribool.hpp>
#include <cstdio> #include <cstdio>
#include <cstdint> #include <cstdint>
@@ -34,8 +37,8 @@ struct file_body
writer(writer const&) = delete; writer(writer const&) = delete;
writer& operator=(writer const&) = delete; writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
writer(message<isRequest, file_body, Headers> const& m) noexcept writer(message<isRequest, file_body, Fields> const& m) noexcept
: path_(m.body) : path_(m.body)
{ {
} }

View File

@@ -85,7 +85,7 @@ public:
private: private:
template<class Stream, class Handler, template<class Stream, class Handler,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
class write_op class write_op
{ {
using alloc_type = using alloc_type =
@@ -94,13 +94,13 @@ private:
struct data struct data
{ {
Stream& s; Stream& s;
message<isRequest, Body, Headers> m; message<isRequest, Body, Fields> m;
Handler h; Handler h;
bool cont; bool cont;
template<class DeducedHandler> template<class DeducedHandler>
data(DeducedHandler&& h_, Stream& s_, data(DeducedHandler&& h_, Stream& s_,
message<isRequest, Body, Headers>&& m_) message<isRequest, Body, Fields>&& m_)
: s(s_) : s(s_)
, m(std::move(m_)) , m(std::move(m_))
, h(std::forward<DeducedHandler>(h_)) , h(std::forward<DeducedHandler>(h_))
@@ -170,16 +170,16 @@ private:
}; };
template<class Stream, template<class Stream,
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class DeducedHandler> class DeducedHandler>
static static
void void
async_write(Stream& stream, message< async_write(Stream& stream, message<
isRequest, Body, Headers>&& msg, isRequest, Body, Fields>&& msg,
DeducedHandler&& handler) DeducedHandler&& handler)
{ {
write_op<Stream, typename std::decay<DeducedHandler>::type, write_op<Stream, typename std::decay<DeducedHandler>::type,
isRequest, Body, Headers>{std::forward<DeducedHandler>( isRequest, Body, Fields>{std::forward<DeducedHandler>(
handler), stream, std::move(msg)}; handler), stream, std::move(msg)};
} }
@@ -240,8 +240,8 @@ private:
res.status = 404; res.status = 404;
res.reason = "Not Found"; res.reason = "Not Found";
res.version = req_.version; res.version = req_.version;
res.headers.insert("Server", "http_async_server"); res.fields.insert("Server", "http_async_server");
res.headers.insert("Content-Type", "text/html"); res.fields.insert("Content-Type", "text/html");
res.body = "The file '" + path + "' was not found"; res.body = "The file '" + path + "' was not found";
prepare(res); prepare(res);
async_write(sock_, std::move(res), async_write(sock_, std::move(res),
@@ -255,8 +255,8 @@ private:
res.status = 200; res.status = 200;
res.reason = "OK"; res.reason = "OK";
res.version = req_.version; res.version = req_.version;
res.headers.insert("Server", "http_async_server"); res.fields.insert("Server", "http_async_server");
res.headers.insert("Content-Type", mime_type(path)); res.fields.insert("Content-Type", mime_type(path));
res.body = path; res.body = path;
prepare(res); prepare(res);
async_write(sock_, std::move(res), async_write(sock_, std::move(res),
@@ -269,8 +269,8 @@ private:
res.status = 500; res.status = 500;
res.reason = "Internal Error"; res.reason = "Internal Error";
res.version = req_.version; res.version = req_.version;
res.headers.insert("Server", "http_async_server"); res.fields.insert("Server", "http_async_server");
res.headers.insert("Content-Type", "text/html"); res.fields.insert("Content-Type", "text/html");
res.body = res.body =
std::string{"An internal error occurred"} + e.what(); std::string{"An internal error occurred"} + e.what();
prepare(res); prepare(res);

View File

@@ -40,9 +40,9 @@ int main(int, char const*[])
req.method = "GET"; req.method = "GET";
req.url = "/"; req.url = "/";
req.version = 11; req.version = 11;
req.headers.insert("Host", host + std::string(":") + req.fields.insert("Host", host + std::string(":") +
boost::lexical_cast<std::string>(ep.port())); boost::lexical_cast<std::string>(ep.port()));
req.headers.insert("User-Agent", "beast/http"); req.fields.insert("User-Agent", "beast/http");
prepare(req); prepare(req);
write(sock, req); write(sock, req);
response<string_body> res; response<string_body> res;

View File

@@ -26,9 +26,9 @@ int main()
req.method = "GET"; req.method = "GET";
req.url = "/"; req.url = "/";
req.version = 11; req.version = 11;
req.headers.replace("Host", host + ":" + req.fields.replace("Host", host + ":" +
boost::lexical_cast<std::string>(sock.remote_endpoint().port())); boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
req.headers.replace("User-Agent", "Beast"); req.fields.replace("User-Agent", "Beast");
beast::http::prepare(req); beast::http::prepare(req);
beast::http::write(sock, req); beast::http::write(sock, req);

View File

@@ -168,8 +168,8 @@ private:
res.status = 404; res.status = 404;
res.reason = "Not Found"; res.reason = "Not Found";
res.version = req.version; res.version = req.version;
res.headers.insert("Server", "http_sync_server"); res.fields.insert("Server", "http_sync_server");
res.headers.insert("Content-Type", "text/html"); res.fields.insert("Content-Type", "text/html");
res.body = "The file '" + path + "' was not found"; res.body = "The file '" + path + "' was not found";
prepare(res); prepare(res);
write(sock, res, ec); write(sock, res, ec);
@@ -183,8 +183,8 @@ private:
res.status = 200; res.status = 200;
res.reason = "OK"; res.reason = "OK";
res.version = req.version; res.version = req.version;
res.headers.insert("Server", "http_sync_server"); res.fields.insert("Server", "http_sync_server");
res.headers.insert("Content-Type", mime_type(path)); res.fields.insert("Content-Type", mime_type(path));
res.body = path; res.body = path;
prepare(res); prepare(res);
write(sock, res, ec); write(sock, res, ec);
@@ -197,8 +197,8 @@ private:
res.status = 500; res.status = 500;
res.reason = "Internal Error"; res.reason = "Internal Error";
res.version = req.version; res.version = req.version;
res.headers.insert("Server", "http_sync_server"); res.fields.insert("Server", "http_sync_server");
res.headers.insert("Content-Type", "text/html"); res.fields.insert("Content-Type", "text/html");
res.body = res.body =
std::string{"An internal error occurred: "} + e.what(); std::string{"An internal error occurred: "} + e.what();
prepare(res); prepare(res);

View File

@@ -38,9 +38,9 @@ int main()
req.method = "GET"; req.method = "GET";
req.url = "/"; req.url = "/";
req.version = 11; req.version = 11;
req.headers.insert("Host", host + ":" + req.fields.insert("Host", host + ":" +
boost::lexical_cast<std::string>(sock.remote_endpoint().port())); boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
req.headers.insert("User-Agent", "Beast"); req.fields.insert("User-Agent", "Beast");
beast::http::prepare(req); beast::http::prepare(req);
beast::http::write(stream, req); beast::http::write(stream, req);

View File

@@ -46,7 +46,7 @@ namespace beast {
Example: Example:
@code @code
// Process the next HTTP headers on the stream, // Process the next HTTP header on the stream,
// leaving excess bytes behind for the next call. // leaving excess bytes behind for the next call.
// //
template<class DynamicBuffer> template<class DynamicBuffer>
@@ -54,7 +54,7 @@ namespace beast {
dynabuf_readstream<DynamicBuffer>& stream) dynabuf_readstream<DynamicBuffer>& stream)
{ {
// Read up to and including the end of the HTTP // Read up to and including the end of the HTTP
// headers, leaving the sequence in the stream's // header, leaving the sequence in the stream's
// buffer. read_until may read past the end of the // buffer. read_until may read past the end of the
// headers; the return value will include only the // headers; the return value will include only the
// part up to the end of the delimiter. // part up to the end of the delimiter.

View File

@@ -8,12 +8,11 @@
#ifndef BEAST_HTTP_HPP #ifndef BEAST_HTTP_HPP
#define BEAST_HTTP_HPP #define BEAST_HTTP_HPP
#include <beast/http/basic_headers.hpp> #include <beast/http/basic_fields.hpp>
#include <beast/http/basic_parser_v1.hpp> #include <beast/http/basic_parser_v1.hpp>
#include <beast/http/body_type.hpp>
#include <beast/http/chunk_encode.hpp> #include <beast/http/chunk_encode.hpp>
#include <beast/http/empty_body.hpp> #include <beast/http/empty_body.hpp>
#include <beast/http/headers.hpp> #include <beast/http/fields.hpp>
#include <beast/http/message.hpp> #include <beast/http/message.hpp>
#include <beast/http/parse.hpp> #include <beast/http/parse.hpp>
#include <beast/http/parse_error.hpp> #include <beast/http/parse_error.hpp>

View File

@@ -8,9 +8,12 @@
#ifndef BEAST_HTTP_BASIC_DYNABUF_BODY_HPP #ifndef BEAST_HTTP_BASIC_DYNABUF_BODY_HPP
#define BEAST_HTTP_BASIC_DYNABUF_BODY_HPP #define BEAST_HTTP_BASIC_DYNABUF_BODY_HPP
#include <beast/http/body_type.hpp> #include <beast/core/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/resume_context.hpp>
#include <beast/core/detail/type_traits.hpp> #include <beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/logic/tribool.hpp>
namespace beast { namespace beast {
namespace http { namespace http {
@@ -34,10 +37,10 @@ private:
value_type& sb_; value_type& sb_;
public: public:
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, reader(message<isRequest,
basic_dynabuf_body, Headers>& m) noexcept basic_dynabuf_body, Fields>& m) noexcept
: sb_(m.body) : sb_(m.body)
{ {
} }
@@ -63,10 +66,10 @@ private:
DynamicBuffer const& body_; DynamicBuffer const& body_;
public: public:
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
explicit explicit
writer(message< writer(message<
isRequest, basic_dynabuf_body, Headers> const& m) noexcept isRequest, basic_dynabuf_body, Fields> const& m) noexcept
: body_(m.body) : body_(m.body)
{ {
} }

View File

@@ -5,11 +5,11 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#ifndef BEAST_HTTP_BASIC_HEADERS_HPP #ifndef BEAST_HTTP_BASIC_FIELDS_HPP
#define BEAST_HTTP_BASIC_HEADERS_HPP #define BEAST_HTTP_BASIC_FIELDS_HPP
#include <beast/core/detail/empty_base_optimization.hpp> #include <beast/core/detail/empty_base_optimization.hpp>
#include <beast/http/detail/basic_headers.hpp> #include <beast/http/detail/basic_fields.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
@@ -21,35 +21,35 @@
namespace beast { namespace beast {
namespace http { namespace http {
/** A container for storing HTTP headers. /** A container for storing HTTP header fields.
This container is designed to store the field value pairs that make 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 up the fields and trailers in a HTTP message. Objects of this type
are iterable, which each element holding the field name and field are iterable, with each element holding the field name and field
value. value.
Field names are stored as-is, but comparison are case-insensitive. Field names are stored as-is, but comparisons are case-insensitive.
When the container is iterated, the fields are presented in the order When the container is iterated, the fields are presented in the order
of insertion. For fields with the same name, the container behaves of insertion. For fields with the same name, the container behaves
as a std::multiset; there will be a separate value for each occurrence as a `std::multiset`; there will be a separate value for each occurrence
of the field name. of the field name.
@note Meets the requirements of @b `FieldSequence`. @note Meets the requirements of @b FieldSequence.
*/ */
template<class Allocator> template<class Allocator>
class basic_headers : class basic_fields :
#if ! GENERATING_DOCS #if ! GENERATING_DOCS
private beast::detail::empty_base_optimization< private beast::detail::empty_base_optimization<
typename std::allocator_traits<Allocator>:: typename std::allocator_traits<Allocator>::
template rebind_alloc< template rebind_alloc<
detail::basic_headers_base::element>>, detail::basic_fields_base::element>>,
#endif #endif
public detail::basic_headers_base public detail::basic_fields_base
{ {
using alloc_type = typename using alloc_type = typename
std::allocator_traits<Allocator>:: std::allocator_traits<Allocator>::
template rebind_alloc< template rebind_alloc<
detail::basic_headers_base::element>; detail::basic_fields_base::element>;
using alloc_traits = using alloc_traits =
std::allocator_traits<alloc_type>; std::allocator_traits<alloc_type>;
@@ -61,16 +61,16 @@ class basic_headers :
delete_all(); delete_all();
void void
move_assign(basic_headers&, std::false_type); move_assign(basic_fields&, std::false_type);
void void
move_assign(basic_headers&, std::true_type); move_assign(basic_fields&, std::true_type);
void void
copy_assign(basic_headers const&, std::false_type); copy_assign(basic_fields const&, std::false_type);
void void
copy_assign(basic_headers const&, std::true_type); copy_assign(basic_fields const&, std::true_type);
template<class FieldSequence> template<class FieldSequence>
void void
@@ -103,17 +103,17 @@ public:
#endif #endif
/// Default constructor. /// Default constructor.
basic_headers() = default; basic_fields() = default;
/// Destructor /// Destructor
~basic_headers(); ~basic_fields();
/** Construct the headers. /** Construct the fields.
@param alloc The allocator to use. @param alloc The allocator to use.
*/ */
explicit explicit
basic_headers(Allocator const& alloc); basic_fields(Allocator const& alloc);
/** Move constructor. /** Move constructor.
@@ -121,7 +121,7 @@ public:
@param other The object to move from. @param other The object to move from.
*/ */
basic_headers(basic_headers&& other); basic_fields(basic_fields&& other);
/** Move assignment. /** Move assignment.
@@ -129,25 +129,25 @@ public:
@param other The object to move from. @param other The object to move from.
*/ */
basic_headers& operator=(basic_headers&& other); basic_fields& operator=(basic_fields&& other);
/// Copy constructor. /// Copy constructor.
basic_headers(basic_headers const&); basic_fields(basic_fields const&);
/// Copy assignment. /// Copy assignment.
basic_headers& operator=(basic_headers const&); basic_fields& operator=(basic_fields const&);
/// Copy constructor. /// Copy constructor.
template<class OtherAlloc> template<class OtherAlloc>
basic_headers(basic_headers<OtherAlloc> const&); basic_fields(basic_fields<OtherAlloc> const&);
/// Copy assignment. /// Copy assignment.
template<class OtherAlloc> template<class OtherAlloc>
basic_headers& operator=(basic_headers<OtherAlloc> const&); basic_fields& operator=(basic_fields<OtherAlloc> const&);
/// Construct from a field sequence. /// Construct from a field sequence.
template<class FwdIt> template<class FwdIt>
basic_headers(FwdIt first, FwdIt last); basic_fields(FwdIt first, FwdIt last);
/// Returns `true` if the field sequence contains no elements. /// Returns `true` if the field sequence contains no elements.
bool bool
@@ -218,7 +218,7 @@ public:
boost::string_ref boost::string_ref
operator[](boost::string_ref const& name) const; operator[](boost::string_ref const& name) const;
/// Clear the contents of the basic_headers. /// Clear the contents of the basic_fields.
void void
clear() noexcept; clear() noexcept;
@@ -301,6 +301,6 @@ public:
} // http } // http
} // beast } // beast
#include <beast/http/impl/basic_headers.ipp> #include <beast/http/impl/basic_fields.ipp>
#endif #endif

View File

@@ -22,8 +22,11 @@
namespace beast { namespace beast {
namespace http { namespace http {
namespace parse_flag { /** Parse flags
enum values
The set of parser bit flags are returned by @ref basic_parser_v1::flags.
*/
enum parse_flag
{ {
chunked = 1, chunked = 1,
connection_keep_alive = 2, connection_keep_alive = 2,
@@ -34,28 +37,6 @@ enum values
skipbody = 64, skipbody = 64,
contentlength = 128 contentlength = 128
}; };
} // parse_flag
/** Headers maximum size option.
Sets the maximum number of cumulative bytes allowed
including all header octets. A value of zero indicates
no limit on the number of header octets
The default headers maximum size is 16KB (16,384 bytes).
@note Objects of this type are used with basic_parser_v1::set_option.
*/
struct headers_max_size
{
std::size_t value;
explicit
headers_max_size(std::size_t v)
: value(v)
{
}
};
/** Body maximum size option. /** Body maximum size option.
@@ -67,7 +48,7 @@ struct headers_max_size
The default body maximum size for requests is 4MB (four The default body maximum size for requests is 4MB (four
megabytes or 4,194,304 bytes) and unlimited for responses. megabytes or 4,194,304 bytes) and unlimited for responses.
@note Objects of this type are used with basic_parser_v1::set_option. @note Objects of this type are used with @ref basic_parser_v1::set_option.
*/ */
struct body_max_size struct body_max_size
{ {
@@ -80,9 +61,30 @@ struct body_max_size
} }
}; };
/** Header maximum size option.
Sets the maximum number of cumulative bytes allowed
including all header octets. A value of zero indicates
no limit on the number of header octets.
The default header maximum size is 16KB (16,384 bytes).
@note Objects of this type are used with @ref basic_parser_v1::set_option.
*/
struct header_max_size
{
std::size_t value;
explicit
header_max_size(std::size_t v)
: value(v)
{
}
};
/** A value indicating how the parser should treat the body. /** A value indicating how the parser should treat the body.
This value is returned from the `on_headers` callback in This value is returned from the `on_header` callback in
the derived class. It controls what the parser does next the derived class. It controls what the parser does next
in terms of the message body. in terms of the message body.
*/ */
@@ -94,7 +96,7 @@ enum class body_what
/** Skip parsing of the body. /** Skip parsing of the body.
When returned by `on_headers` this causes parsing to When returned by `on_header` this causes parsing to
complete and control to return to the caller. This complete and control to return to the caller. This
could be used when sending a response to a HEAD could be used when sending a response to a HEAD
request, for example. request, for example.
@@ -116,8 +118,8 @@ enum class body_what
to the parser will begin reading the message body. to the parser will begin reading the message body.
This could be used by callers to inspect the HTTP This could be used by callers to inspect the HTTP
headers before committing to read the body. For example, header before committing to read the body. For example,
to choose the body type based on the headers. Or to to choose the body type based on the fields. Or to
respond to an Expect: 100-continue request. respond to an Expect: 100-continue request.
*/ */
pause pause
@@ -181,19 +183,19 @@ static std::uint64_t constexpr no_content_length =
// //
void on_value(boost::string_ref const&, error_code&) void on_value(boost::string_ref const&, error_code&)
// Called when all the headers have been parsed successfully. // Called when the entire header has been parsed successfully.
// //
void void
on_headers(std::uint64_t content_length, error_code&); on_header(std::uint64_t content_length, error_code&);
// Called after on_headers, before the body is parsed // Called after on_header, before the body is parsed
// //
body_what body_what
on_body_what(std::uint64_t content_length, error_code&); on_body_what(std::uint64_t content_length, error_code&);
// Called for each piece of the body. // Called for each piece of the body.
// //
// If the headers indicate chunk encoding, the chunk // If the header indicates chunk encoding, the chunk
// encoding is removed from the buffer before being // encoding is removed from the buffer before being
// passed to the callback. // passed to the callback.
// //
@@ -319,9 +321,9 @@ public:
std::forward<An>(an)...); std::forward<An>(an)...);
} }
/// Set the headers maximum size option /// Set the header maximum size option
void void
set_option(headers_max_size const& o) set_option(header_max_size const& o)
{ {
h_max_ = o.value; h_max_ = o.value;
h_left_ = h_max_; h_left_ = h_max_;
@@ -508,7 +510,7 @@ private:
void void
init(std::true_type) init(std::true_type)
{ {
// 16KB max headers, 4MB max body // Request: 16KB max header, 4MB max body
h_max_ = 16 * 1024; h_max_ = 16 * 1024;
b_max_ = 4 * 1024 * 1024; b_max_ = 4 * 1024 * 1024;
} }
@@ -516,7 +518,7 @@ private:
void void
init(std::false_type) init(std::false_type)
{ {
// 16KB max headers, unlimited body // Response: 16KB max header, unlimited body
h_max_ = 16 * 1024; h_max_ = 16 * 1024;
b_max_ = 0; b_max_ = 0;
} }
@@ -616,7 +618,7 @@ private:
template<class T> template<class T>
struct check_on_headers<T, beast::detail::void_t<decltype( struct check_on_headers<T, beast::detail::void_t<decltype(
std::declval<T>().on_headers( std::declval<T>().on_header(
std::declval<std::uint64_t>(), std::declval<std::uint64_t>(),
std::declval<error_code&>()) std::declval<error_code&>())
)>> : std::true_type {}; )>> : std::true_type {};
@@ -674,7 +676,7 @@ private:
"on_method requirements not met"); "on_method requirements not met");
if(h_max_ && s.size() > h_left_) if(h_max_ && s.size() > h_left_)
{ {
ec = parse_error::headers_too_big; ec = parse_error::header_too_big;
return; return;
} }
h_left_ -= s.size(); h_left_ -= s.size();
@@ -700,7 +702,7 @@ private:
"on_uri requirements not met"); "on_uri requirements not met");
if(h_max_ && s.size() > h_left_) if(h_max_ && s.size() > h_left_)
{ {
ec = parse_error::headers_too_big; ec = parse_error::header_too_big;
return; return;
} }
h_left_ -= s.size(); h_left_ -= s.size();
@@ -726,7 +728,7 @@ private:
"on_reason requirements not met"); "on_reason requirements not met");
if(h_max_ && s.size() > h_left_) if(h_max_ && s.size() > h_left_)
{ {
ec = parse_error::headers_too_big; ec = parse_error::header_too_big;
return; return;
} }
h_left_ -= s.size(); h_left_ -= s.size();
@@ -785,7 +787,7 @@ private:
"on_field requirements not met"); "on_field requirements not met");
if(h_max_ && s.size() > h_left_) if(h_max_ && s.size() > h_left_)
{ {
ec = parse_error::headers_too_big; ec = parse_error::header_too_big;
return; return;
} }
h_left_ -= s.size(); h_left_ -= s.size();
@@ -799,7 +801,7 @@ private:
"on_value requirements not met"); "on_value requirements not met");
if(h_max_ && s.size() > h_left_) if(h_max_ && s.size() > h_left_)
{ {
ec = parse_error::headers_too_big; ec = parse_error::header_too_big;
return; return;
} }
h_left_ -= s.size(); h_left_ -= s.size();
@@ -810,8 +812,8 @@ private:
call_on_headers(error_code& ec) call_on_headers(error_code& ec)
{ {
static_assert(check_on_headers<Derived>::value, static_assert(check_on_headers<Derived>::value,
"on_headers requirements not met"); "on_header requirements not met");
impl().on_headers(content_length_, ec); impl().on_header(content_length_, ec);
} }
body_what body_what

View File

@@ -1,19 +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_BODY_TYPE_HPP
#define BEAST_HTTP_BODY_TYPE_HPP
// Convenience header to include everything
// needed when declarating a user defined Body type.
#include <beast/core/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/resume_context.hpp>
#include <boost/logic/tribool.hpp>
#endif

View File

@@ -5,10 +5,11 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#ifndef BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP #ifndef BEAST_HTTP_CHUNK_ENCODE_HPP
#define BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP #define BEAST_HTTP_CHUNK_ENCODE_HPP
#include <beast/core/buffer_cat.hpp> #include <beast/core/buffer_cat.hpp>
#include <beast/http/detail/chunk_encode.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <algorithm> #include <algorithm>
@@ -20,92 +21,6 @@
namespace beast { namespace beast {
namespace http { namespace http {
class chunk_encode_text
{
boost::asio::const_buffer cb_;
// Storage for the longest hex string we might need, plus delimiters.
std::array<char, 2 * sizeof(std::size_t) + 2> buf_;
template<class = void>
void
copy(chunk_encode_text const& other);
template<class = void>
void
setup(std::size_t n);
template<class OutIter>
static
OutIter
to_hex(OutIter last, std::size_t n)
{
if(n == 0)
{
*--last = '0';
return last;
}
while(n)
{
*--last = "0123456789abcdef"[n&0xf];
n>>=4;
}
return last;
}
public:
using value_type = boost::asio::const_buffer;
using const_iterator = value_type const*;
chunk_encode_text(chunk_encode_text const& other)
{
copy(other);
}
explicit
chunk_encode_text(std::size_t n)
{
setup(n);
}
const_iterator
begin() const
{
return &cb_;
}
const_iterator
end() const
{
return begin() + 1;
}
};
template<class>
void
chunk_encode_text::
copy(chunk_encode_text const& other)
{
auto const n =
boost::asio::buffer_size(other.cb_);
buf_ = other.buf_;
cb_ = boost::asio::const_buffer(
&buf_[buf_.size() - n], n);
}
template<class>
void
chunk_encode_text::
setup(std::size_t n)
{
buf_[buf_.size() - 2] = '\r';
buf_[buf_.size() - 1] = '\n';
auto it = to_hex(buf_.end() - 2, n);
cb_ = boost::asio::const_buffer{&*it,
static_cast<std::size_t>(
std::distance(it, buf_.end()))};
}
/** Returns a chunk-encoded ConstBufferSequence. /** Returns a chunk-encoded ConstBufferSequence.
This returns a buffer sequence representing the This returns a buffer sequence representing the
@@ -124,7 +39,7 @@ template<class ConstBufferSequence>
implementation_defined implementation_defined
#else #else
beast::detail::buffer_cat_helper< beast::detail::buffer_cat_helper<
chunk_encode_text, detail::chunk_encode_delim,
ConstBufferSequence, ConstBufferSequence,
boost::asio::const_buffers_1> boost::asio::const_buffers_1>
#endif #endif
@@ -132,7 +47,7 @@ chunk_encode(bool fin, ConstBufferSequence const& buffers)
{ {
using boost::asio::buffer_size; using boost::asio::buffer_size;
return buffer_cat( return buffer_cat(
chunk_encode_text{buffer_size(buffers)}, detail::chunk_encode_delim{buffer_size(buffers)},
buffers, buffers,
fin ? boost::asio::const_buffers_1{"\r\n0\r\n\r\n", 7} fin ? boost::asio::const_buffers_1{"\r\n0\r\n\r\n", 7}
: boost::asio::const_buffers_1{"\r\n", 2}); : boost::asio::const_buffers_1{"\r\n", 2});

View File

@@ -5,8 +5,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#ifndef BEAST_HTTP_DETAIL_BASIC_HEADERS_HPP #ifndef BEAST_HTTP_DETAIL_BASIC_FIELDS_HPP
#define BEAST_HTTP_DETAIL_BASIC_HEADERS_HPP #define BEAST_HTTP_DETAIL_BASIC_FIELDS_HPP
#include <beast/core/detail/ci_char_traits.hpp> #include <beast/core/detail/ci_char_traits.hpp>
#include <boost/intrusive/list.hpp> #include <boost/intrusive/list.hpp>
@@ -17,11 +17,11 @@ namespace beast {
namespace http { namespace http {
template<class Allocator> template<class Allocator>
class basic_headers; class basic_fields;
namespace detail { namespace detail {
class basic_headers_base class basic_fields_base
{ {
public: public:
struct value_type struct value_type
@@ -51,7 +51,7 @@ public:
protected: protected:
template<class Allocator> template<class Allocator>
friend class beast::http::basic_headers; friend class beast::http::basic_fields;
struct element struct element
: boost::intrusive::set_base_hook < : boost::intrusive::set_base_hook <
@@ -105,7 +105,7 @@ protected:
set_t set_; set_t set_;
list_t list_; list_t list_;
basic_headers_base(set_t&& set, list_t&& list) basic_fields_base(set_t&& set, list_t&& list)
: set_(std::move(set)) : set_(std::move(set))
, list_(std::move(list)) , list_(std::move(list))
{ {
@@ -116,21 +116,21 @@ public:
using iterator = const_iterator; using iterator = const_iterator;
basic_headers_base() = default; basic_fields_base() = default;
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
class basic_headers_base::const_iterator class basic_fields_base::const_iterator
{ {
using iter_type = list_t::const_iterator; using iter_type = list_t::const_iterator;
iter_type it_; iter_type it_;
template<class Allocator> template<class Allocator>
friend class beast::http::basic_headers; friend class beast::http::basic_fields;
friend class basic_headers_base; friend class basic_fields_base;
const_iterator(iter_type it) const_iterator(iter_type it)
: it_(it) : it_(it)
@@ -139,7 +139,7 @@ class basic_headers_base::const_iterator
public: public:
using value_type = using value_type =
typename basic_headers_base::value_type; typename basic_fields_base::value_type;
using pointer = value_type const*; using pointer = value_type const*;
using reference = value_type const&; using reference = value_type const&;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;

View File

@@ -0,0 +1,111 @@
//
// 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_DETAIL_CHUNK_ENCODE_HPP
#define BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <array>
#include <cstddef>
namespace beast {
namespace http {
namespace detail {
class chunk_encode_delim
{
boost::asio::const_buffer cb_;
// Storage for the longest hex string we might need, plus delimiters.
std::array<char, 2 * sizeof(std::size_t) + 2> buf_;
template<class = void>
void
copy(chunk_encode_delim const& other);
template<class = void>
void
setup(std::size_t n);
template<class OutIter>
static
OutIter
to_hex(OutIter last, std::size_t n)
{
if(n == 0)
{
*--last = '0';
return last;
}
while(n)
{
*--last = "0123456789abcdef"[n&0xf];
n>>=4;
}
return last;
}
public:
using value_type = boost::asio::const_buffer;
using const_iterator = value_type const*;
chunk_encode_delim(chunk_encode_delim const& other)
{
copy(other);
}
explicit
chunk_encode_delim(std::size_t n)
{
setup(n);
}
const_iterator
begin() const
{
return &cb_;
}
const_iterator
end() const
{
return begin() + 1;
}
};
template<class>
void
chunk_encode_delim::
copy(chunk_encode_delim const& other)
{
auto const n =
boost::asio::buffer_size(other.cb_);
buf_ = other.buf_;
cb_ = boost::asio::const_buffer(
&buf_[buf_.size() - n], n);
}
template<class>
void
chunk_encode_delim::
setup(std::size_t n)
{
buf_[buf_.size() - 2] = '\r';
buf_[buf_.size() - 1] = '\n';
auto it = to_hex(buf_.end() - 2, n);
cb_ = boost::asio::const_buffer{&*it,
static_cast<std::size_t>(
std::distance(it, buf_.end()))};
}
} // detail
} // http
} // beast
#endif

View File

@@ -8,9 +8,12 @@
#ifndef BEAST_HTTP_EMPTY_BODY_HPP #ifndef BEAST_HTTP_EMPTY_BODY_HPP
#define BEAST_HTTP_EMPTY_BODY_HPP #define BEAST_HTTP_EMPTY_BODY_HPP
#include <beast/http/body_type.hpp> #include <beast/core/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/resume_context.hpp>
#include <beast/core/detail/type_traits.hpp> #include <beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/logic/tribool.hpp>
#include <memory> #include <memory>
#include <string> #include <string>
@@ -36,9 +39,9 @@ private:
struct writer struct writer
{ {
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, empty_body, Headers> const& m) noexcept writer(message<isRequest, empty_body, Fields> const& m) noexcept
{ {
beast::detail::ignore_unused(m); beast::detail::ignore_unused(m);
} }

View File

@@ -5,17 +5,18 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#ifndef BEAST_HTTP_HEADERS_HPP #ifndef BEAST_HTTP_FIELDS_HPP
#define BEAST_HTTP_HEADERS_HPP #define BEAST_HTTP_FIELDS_HPP
#include <beast/http/basic_headers.hpp> #include <beast/http/basic_fields.hpp>
#include <memory> #include <memory>
namespace beast { namespace beast {
namespace http { namespace http {
using headers = /// A typical HTTP header fields container
basic_headers<std::allocator<char>>; using fields =
basic_fields<std::allocator<char>>;
} // http } // http
} // beast } // beast

View File

@@ -13,7 +13,6 @@
#include <beast/http/message.hpp> #include <beast/http/message.hpp>
#include <beast/core/error.hpp> #include <beast/core/error.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/optional.hpp>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@@ -36,100 +35,99 @@ struct response_parser_base
} // detail } // detail
/** A parser for HTTP/1 request and response headers. /** A parser for a HTTP/1 request or response header.
This class uses the HTTP/1 wire format parser to This class uses the HTTP/1 wire format parser to
convert a series of octets into a @ref request_headers convert a series of octets into a request or
or @ref response_headers. response @ref header.
@note A new instance of the parser is required for each message. @note A new instance of the parser is required for each message.
*/ */
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
class headers_parser_v1 class header_parser_v1
: public basic_parser_v1<isRequest, : public basic_parser_v1<isRequest,
headers_parser_v1<isRequest, Headers>> header_parser_v1<isRequest, Fields>>
, private std::conditional<isRequest, , private std::conditional<isRequest,
detail::request_parser_base, detail::request_parser_base,
detail::response_parser_base>::type detail::response_parser_base>::type
{ {
public: public:
/// The type of message this parser produces. /// The type of the header this parser produces.
using headers_type = using header_type = header<isRequest, Fields>;
message_headers<isRequest, Headers>;
private: private:
// VFALCO Check Headers requirements? // VFALCO Check Fields requirements?
std::string field_; std::string field_;
std::string value_; std::string value_;
headers_type h_; header_type h_;
bool flush_ = false; bool flush_ = false;
public: public:
/// Default constructor /// Default constructor
headers_parser_v1() = default; header_parser_v1() = default;
/// Move constructor /// Move constructor
headers_parser_v1(headers_parser_v1&&) = default; header_parser_v1(header_parser_v1&&) = default;
/// Copy constructor (disallowed) /// Copy constructor (disallowed)
headers_parser_v1(headers_parser_v1 const&) = delete; header_parser_v1(header_parser_v1 const&) = delete;
/// Move assignment (disallowed) /// Move assignment (disallowed)
headers_parser_v1& operator=(headers_parser_v1&&) = delete; header_parser_v1& operator=(header_parser_v1&&) = delete;
/// Copy assignment (disallowed) /// Copy assignment (disallowed)
headers_parser_v1& operator=(headers_parser_v1 const&) = delete; header_parser_v1& operator=(header_parser_v1 const&) = delete;
/** Construct the parser. /** Construct the parser.
@param args Forwarded to the message headers constructor. @param args Forwarded to the header constructor.
*/ */
#if GENERATING_DOCS #if GENERATING_DOCS
template<class... Args> template<class... Args>
explicit explicit
headers_parser_v1(Args&&... args); header_parser_v1(Args&&... args);
#else #else
template<class Arg1, class... ArgN, template<class Arg1, class... ArgN,
class = typename std::enable_if<! std::is_same< class = typename std::enable_if<! std::is_same<
typename std::decay<Arg1>::type, headers_parser_v1>::value>> typename std::decay<Arg1>::type, header_parser_v1>::value>>
explicit explicit
headers_parser_v1(Arg1&& arg1, ArgN&&... argn) header_parser_v1(Arg1&& arg1, ArgN&&... argn)
: h_(std::forward<Arg1>(arg1), : h_(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...) std::forward<ArgN>(argn)...)
{ {
} }
#endif #endif
/** Returns the parsed headers. /** Returns the parsed header
Only valid if @ref complete would return `true`. Only valid if @ref complete would return `true`.
*/ */
headers_type const& header_type const&
get() const get() const
{ {
return h_; return h_;
} }
/** Returns the parsed headers. /** Returns the parsed header.
Only valid if @ref complete would return `true`. Only valid if @ref complete would return `true`.
*/ */
headers_type& header_type&
get() get()
{ {
return h_; return h_;
} }
/** Returns ownership of the parsed headers. /** Returns ownership of the parsed header.
Ownership is transferred to the caller. Only Ownership is transferred to the caller. Only
valid if @ref complete would return `true`. valid if @ref complete would return `true`.
Requires: Requires:
`message_headers<isRequest, Headers>` is @b MoveConstructible @ref header_type is @b MoveConstructible
*/ */
headers_type header_type
release() release()
{ {
static_assert(std::is_move_constructible<decltype(h_)>::value, static_assert(std::is_move_constructible<decltype(h_)>::value,
@@ -138,7 +136,7 @@ public:
} }
private: private:
friend class basic_parser_v1<isRequest, headers_parser_v1>; friend class basic_parser_v1<isRequest, header_parser_v1>;
void flush() void flush()
{ {
@@ -146,7 +144,7 @@ private:
return; return;
flush_ = false; flush_ = false;
BOOST_ASSERT(! field_.empty()); BOOST_ASSERT(! field_.empty());
h_.headers.insert(field_, value_); h_.fields.insert(field_, value_);
field_.clear(); field_.clear();
value_.clear(); value_.clear();
} }
@@ -207,7 +205,7 @@ private:
} }
void void
on_headers(std::uint64_t, error_code&) on_header(std::uint64_t, error_code&)
{ {
flush(); flush();
h_.version = 10 * this->http_major() + this->http_minor(); h_.version = 10 * this->http_major() + this->http_minor();

View File

@@ -5,8 +5,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP #ifndef BEAST_HTTP_IMPL_BASIC_FIELDS_IPP
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP #define BEAST_HTTP_IMPL_BASIC_FIELDS_IPP
#include <beast/http/detail/rfc7230.hpp> #include <beast/http/detail/rfc7230.hpp>
#include <algorithm> #include <algorithm>
@@ -16,7 +16,7 @@ namespace http {
template<class Allocator> template<class Allocator>
void void
basic_headers<Allocator>:: basic_fields<Allocator>::
delete_all() delete_all()
{ {
for(auto it = list_.begin(); it != list_.end();) for(auto it = list_.begin(); it != list_.end();)
@@ -31,8 +31,8 @@ delete_all()
template<class Allocator> template<class Allocator>
inline inline
void void
basic_headers<Allocator>:: basic_fields<Allocator>::
move_assign(basic_headers& other, std::false_type) move_assign(basic_fields& other, std::false_type)
{ {
if(this->member() != other.member()) if(this->member() != other.member())
{ {
@@ -49,8 +49,8 @@ move_assign(basic_headers& other, std::false_type)
template<class Allocator> template<class Allocator>
inline inline
void void
basic_headers<Allocator>:: basic_fields<Allocator>::
move_assign(basic_headers& other, std::true_type) move_assign(basic_fields& other, std::true_type)
{ {
this->member() = std::move(other.member()); this->member() = std::move(other.member());
set_ = std::move(other.set_); set_ = std::move(other.set_);
@@ -60,8 +60,8 @@ move_assign(basic_headers& other, std::true_type)
template<class Allocator> template<class Allocator>
inline inline
void void
basic_headers<Allocator>:: basic_fields<Allocator>::
copy_assign(basic_headers const& other, std::false_type) copy_assign(basic_fields const& other, std::false_type)
{ {
copy_from(other); copy_from(other);
} }
@@ -69,8 +69,8 @@ copy_assign(basic_headers const& other, std::false_type)
template<class Allocator> template<class Allocator>
inline inline
void void
basic_headers<Allocator>:: basic_fields<Allocator>::
copy_assign(basic_headers const& other, std::true_type) copy_assign(basic_fields const& other, std::true_type)
{ {
this->member() = other.member(); this->member() = other.member();
copy_from(other); copy_from(other);
@@ -79,35 +79,35 @@ copy_assign(basic_headers const& other, std::true_type)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template<class Allocator> template<class Allocator>
basic_headers<Allocator>:: basic_fields<Allocator>::
~basic_headers() ~basic_fields()
{ {
delete_all(); delete_all();
} }
template<class Allocator> template<class Allocator>
basic_headers<Allocator>:: basic_fields<Allocator>::
basic_headers(Allocator const& alloc) basic_fields(Allocator const& alloc)
: beast::detail::empty_base_optimization< : beast::detail::empty_base_optimization<
alloc_type>(alloc) alloc_type>(alloc)
{ {
} }
template<class Allocator> template<class Allocator>
basic_headers<Allocator>:: basic_fields<Allocator>::
basic_headers(basic_headers&& other) basic_fields(basic_fields&& other)
: beast::detail::empty_base_optimization<alloc_type>( : beast::detail::empty_base_optimization<alloc_type>(
std::move(other.member())) std::move(other.member()))
, detail::basic_headers_base( , detail::basic_fields_base(
std::move(other.set_), std::move(other.list_)) std::move(other.set_), std::move(other.list_))
{ {
} }
template<class Allocator> template<class Allocator>
auto auto
basic_headers<Allocator>:: basic_fields<Allocator>::
operator=(basic_headers&& other) -> operator=(basic_fields&& other) ->
basic_headers& basic_fields&
{ {
if(this == &other) if(this == &other)
return *this; return *this;
@@ -118,9 +118,9 @@ operator=(basic_headers&& other) ->
} }
template<class Allocator> template<class Allocator>
basic_headers<Allocator>:: basic_fields<Allocator>::
basic_headers(basic_headers const& other) basic_fields(basic_fields const& other)
: basic_headers(alloc_traits:: : basic_fields(alloc_traits::
select_on_container_copy_construction(other.member())) select_on_container_copy_construction(other.member()))
{ {
copy_from(other); copy_from(other);
@@ -128,9 +128,9 @@ basic_headers(basic_headers const& other)
template<class Allocator> template<class Allocator>
auto auto
basic_headers<Allocator>:: basic_fields<Allocator>::
operator=(basic_headers const& other) -> operator=(basic_fields const& other) ->
basic_headers& basic_fields&
{ {
clear(); clear();
copy_assign(other, std::integral_constant<bool, copy_assign(other, std::integral_constant<bool,
@@ -140,8 +140,8 @@ operator=(basic_headers const& other) ->
template<class Allocator> template<class Allocator>
template<class OtherAlloc> template<class OtherAlloc>
basic_headers<Allocator>:: basic_fields<Allocator>::
basic_headers(basic_headers<OtherAlloc> const& other) basic_fields(basic_fields<OtherAlloc> const& other)
{ {
copy_from(other); copy_from(other);
} }
@@ -149,9 +149,9 @@ basic_headers(basic_headers<OtherAlloc> const& other)
template<class Allocator> template<class Allocator>
template<class OtherAlloc> template<class OtherAlloc>
auto auto
basic_headers<Allocator>:: basic_fields<Allocator>::
operator=(basic_headers<OtherAlloc> const& other) -> operator=(basic_fields<OtherAlloc> const& other) ->
basic_headers& basic_fields&
{ {
clear(); clear();
copy_from(other); copy_from(other);
@@ -160,8 +160,8 @@ operator=(basic_headers<OtherAlloc> const& other) ->
template<class Allocator> template<class Allocator>
template<class FwdIt> template<class FwdIt>
basic_headers<Allocator>:: basic_fields<Allocator>::
basic_headers(FwdIt first, FwdIt last) basic_fields(FwdIt first, FwdIt last)
{ {
for(;first != last; ++first) for(;first != last; ++first)
insert(first->name(), first->value()); insert(first->name(), first->value());
@@ -169,7 +169,7 @@ basic_headers(FwdIt first, FwdIt last)
template<class Allocator> template<class Allocator>
std::size_t std::size_t
basic_headers<Allocator>:: basic_fields<Allocator>::
count(boost::string_ref const& name) const count(boost::string_ref const& name) const
{ {
auto const it = set_.find(name, less{}); auto const it = set_.find(name, less{});
@@ -181,7 +181,7 @@ count(boost::string_ref const& name) const
template<class Allocator> template<class Allocator>
auto auto
basic_headers<Allocator>:: basic_fields<Allocator>::
find(boost::string_ref const& name) const -> find(boost::string_ref const& name) const ->
iterator iterator
{ {
@@ -193,7 +193,7 @@ find(boost::string_ref const& name) const ->
template<class Allocator> template<class Allocator>
boost::string_ref boost::string_ref
basic_headers<Allocator>:: basic_fields<Allocator>::
operator[](boost::string_ref const& name) const operator[](boost::string_ref const& name) const
{ {
auto const it = find(name); auto const it = find(name);
@@ -204,7 +204,7 @@ operator[](boost::string_ref const& name) const
template<class Allocator> template<class Allocator>
void void
basic_headers<Allocator>:: basic_fields<Allocator>::
clear() noexcept clear() noexcept
{ {
delete_all(); delete_all();
@@ -214,7 +214,7 @@ clear() noexcept
template<class Allocator> template<class Allocator>
std::size_t std::size_t
basic_headers<Allocator>:: basic_fields<Allocator>::
erase(boost::string_ref const& name) erase(boost::string_ref const& name)
{ {
auto it = set_.find(name, less{}); auto it = set_.find(name, less{});
@@ -238,7 +238,7 @@ erase(boost::string_ref const& name)
template<class Allocator> template<class Allocator>
void void
basic_headers<Allocator>:: basic_fields<Allocator>::
insert(boost::string_ref const& name, insert(boost::string_ref const& name,
boost::string_ref value) boost::string_ref value)
{ {
@@ -251,7 +251,7 @@ insert(boost::string_ref const& name,
template<class Allocator> template<class Allocator>
void void
basic_headers<Allocator>:: basic_fields<Allocator>::
replace(boost::string_ref const& name, replace(boost::string_ref const& name,
boost::string_ref value) boost::string_ref value)
{ {

View File

@@ -5,6 +5,16 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
#include <beast/http/detail/rfc7230.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <boost/assert.hpp>
namespace beast {
namespace http {
/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev /* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
* *
* Additional changes are licensed under the same terms as NGINX and * Additional changes are licensed under the same terms as NGINX and
@@ -28,21 +38,10 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
/* /* This code is a modified version of nodejs/http-parser, copyright above:
This code is a modified version of nodejs/http-parser, copyright above: https://github.com/nodejs/http-parser
https://github.com/nodejs/http-parser
*/ */
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
#include <beast/http/detail/rfc7230.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <boost/assert.hpp>
namespace beast {
namespace http {
template<bool isRequest, class Derived> template<bool isRequest, class Derived>
basic_parser_v1<isRequest, Derived>:: basic_parser_v1<isRequest, Derived>::
basic_parser_v1() basic_parser_v1()

View File

@@ -20,67 +20,67 @@
namespace beast { namespace beast {
namespace http { namespace http {
template<class Headers> template<class Fields>
void void
swap( swap(
message_headers<true, Headers>& m1, header<true, Fields>& m1,
message_headers<true, Headers>& m2) header<true, Fields>& m2)
{ {
using std::swap; using std::swap;
swap(m1.version, m2.version); swap(m1.version, m2.version);
swap(m1.method, m2.method); swap(m1.method, m2.method);
swap(m1.url, m2.url); swap(m1.url, m2.url);
swap(m1.headers, m2.headers); swap(m1.fields, m2.fields);
} }
template<class Headers> template<class Fields>
void void
swap( swap(
message_headers<false, Headers>& a, header<false, Fields>& a,
message_headers<false, Headers>& b) header<false, Fields>& b)
{ {
using std::swap; using std::swap;
swap(a.version, b.version); swap(a.version, b.version);
swap(a.status, b.status); swap(a.status, b.status);
swap(a.reason, b.reason); swap(a.reason, b.reason);
swap(a.headers, b.headers); swap(a.fields, b.fields);
} }
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
void void
swap( swap(
message<isRequest, Body, Headers>& m1, message<isRequest, Body, Fields>& m1,
message<isRequest, Body, Headers>& m2) message<isRequest, Body, Fields>& m2)
{ {
using std::swap; using std::swap;
swap(m1.base(), m2.base()); swap(m1.base(), m2.base());
swap(m1.body, m2.body); swap(m1.body, m2.body);
} }
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Fields>
bool bool
is_keep_alive(message<isRequest, Body, Headers> const& msg) is_keep_alive(header<isRequest, Fields> const& msg)
{ {
BOOST_ASSERT(msg.version == 10 || msg.version == 11); BOOST_ASSERT(msg.version == 10 || msg.version == 11);
if(msg.version == 11) if(msg.version == 11)
{ {
if(token_list{msg.headers["Connection"]}.exists("close")) if(token_list{msg.fields["Connection"]}.exists("close"))
return false; return false;
return true; return true;
} }
if(token_list{msg.headers["Connection"]}.exists("keep-alive")) if(token_list{msg.fields["Connection"]}.exists("keep-alive"))
return true; return true;
return false; return false;
} }
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Fields>
bool bool
is_upgrade(message<isRequest, Body, Headers> const& msg) is_upgrade(header<isRequest, Fields> const& msg)
{ {
BOOST_ASSERT(msg.version == 10 || msg.version == 11); BOOST_ASSERT(msg.version == 10 || msg.version == 11);
if(msg.version == 10) if(msg.version == 10)
return false; return false;
if(token_list{msg.headers["Connection"]}.exists("upgrade")) if(token_list{msg.fields["Connection"]}.exists("upgrade"))
return true; return true;
return false; return false;
} }
@@ -93,19 +93,19 @@ struct prepare_info
boost::optional<std::uint64_t> content_length; boost::optional<std::uint64_t> content_length;
}; };
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
inline inline
void void
prepare_options(prepare_info& pi, prepare_options(prepare_info& pi,
message<isRequest, Body, Headers>& msg) message<isRequest, Body, Fields>& msg)
{ {
beast::detail::ignore_unused(pi, msg); beast::detail::ignore_unused(pi, msg);
} }
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
void void
prepare_option(prepare_info& pi, prepare_option(prepare_info& pi,
message<isRequest, Body, Headers>& msg, message<isRequest, Body, Fields>& msg,
connection value) connection value)
{ {
beast::detail::ignore_unused(msg); beast::detail::ignore_unused(msg);
@@ -113,11 +113,11 @@ prepare_option(prepare_info& pi,
} }
template< template<
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class Opt, class... Opts> class Opt, class... Opts>
void void
prepare_options(prepare_info& pi, prepare_options(prepare_info& pi,
message<isRequest, Body, Headers>& msg, message<isRequest, Body, Fields>& msg,
Opt&& opt, Opts&&... opts) Opt&& opt, Opts&&... opts)
{ {
prepare_option(pi, msg, opt); prepare_option(pi, msg, opt);
@@ -125,10 +125,10 @@ prepare_options(prepare_info& pi,
std::forward<Opts>(opts)...); std::forward<Opts>(opts)...);
} }
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
void void
prepare_content_length(prepare_info& pi, prepare_content_length(prepare_info& pi,
message<isRequest, Body, Headers> const& msg, message<isRequest, Body, Fields> const& msg,
std::true_type) std::true_type)
{ {
typename Body::writer w(msg); typename Body::writer w(msg);
@@ -140,10 +140,10 @@ prepare_content_length(prepare_info& pi,
pi.content_length = w.content_length(); pi.content_length = w.content_length();
} }
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
void void
prepare_content_length(prepare_info& pi, prepare_content_length(prepare_info& pi,
message<isRequest, Body, Headers> const& msg, message<isRequest, Body, Fields> const& msg,
std::false_type) std::false_type)
{ {
beast::detail::ignore_unused(msg); beast::detail::ignore_unused(msg);
@@ -153,10 +153,10 @@ prepare_content_length(prepare_info& pi,
} // detail } // detail
template< template<
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class... Options> class... Options>
void void
prepare(message<isRequest, Body, Headers>& msg, prepare(message<isRequest, Body, Fields>& msg,
Options&&... options) Options&&... options)
{ {
// VFALCO TODO // VFALCO TODO
@@ -165,7 +165,7 @@ prepare(message<isRequest, Body, Headers>& msg,
static_assert(has_writer<Body>::value, static_assert(has_writer<Body>::value,
"Body has no writer"); "Body has no writer");
static_assert(is_Writer<typename Body::writer, static_assert(is_Writer<typename Body::writer,
message<isRequest, Body, Headers>>::value, message<isRequest, Body, Fields>>::value,
"Writer requirements not met"); "Writer requirements not met");
detail::prepare_info pi; detail::prepare_info pi;
detail::prepare_content_length(pi, msg, detail::prepare_content_length(pi, msg,
@@ -173,15 +173,15 @@ prepare(message<isRequest, Body, Headers>& msg,
detail::prepare_options(pi, msg, detail::prepare_options(pi, msg,
std::forward<Options>(options)...); std::forward<Options>(options)...);
if(msg.headers.exists("Connection")) if(msg.fields.exists("Connection"))
throw std::invalid_argument( throw std::invalid_argument(
"prepare called with Connection field set"); "prepare called with Connection field set");
if(msg.headers.exists("Content-Length")) if(msg.fields.exists("Content-Length"))
throw std::invalid_argument( throw std::invalid_argument(
"prepare called with Content-Length field set"); "prepare called with Content-Length field set");
if(token_list{msg.headers["Transfer-Encoding"]}.exists("chunked")) if(token_list{msg.fields["Transfer-Encoding"]}.exists("chunked"))
throw std::invalid_argument( throw std::invalid_argument(
"prepare called with Transfer-Encoding: chunked set"); "prepare called with Transfer-Encoding: chunked set");
@@ -192,27 +192,27 @@ prepare(message<isRequest, Body, Headers>& msg,
struct set_field struct set_field
{ {
void void
operator()(message<true, Body, Headers>& msg, operator()(message<true, Body, Fields>& msg,
detail::prepare_info const& pi) const detail::prepare_info const& pi) const
{ {
using beast::detail::ci_equal; using beast::detail::ci_equal;
if(*pi.content_length > 0 || if(*pi.content_length > 0 ||
ci_equal(msg.method, "POST")) ci_equal(msg.method, "POST"))
{ {
msg.headers.insert( msg.fields.insert(
"Content-Length", *pi.content_length); "Content-Length", *pi.content_length);
} }
} }
void void
operator()(message<false, Body, Headers>& msg, operator()(message<false, Body, Fields>& msg,
detail::prepare_info const& pi) const detail::prepare_info const& pi) const
{ {
if((msg.status / 100 ) != 1 && if((msg.status / 100 ) != 1 &&
msg.status != 204 && msg.status != 204 &&
msg.status != 304) msg.status != 304)
{ {
msg.headers.insert( msg.fields.insert(
"Content-Length", *pi.content_length); "Content-Length", *pi.content_length);
} }
} }
@@ -221,39 +221,39 @@ prepare(message<isRequest, Body, Headers>& msg,
} }
else if(msg.version >= 11) else if(msg.version >= 11)
{ {
msg.headers.insert("Transfer-Encoding", "chunked"); msg.fields.insert("Transfer-Encoding", "chunked");
} }
} }
auto const content_length = auto const content_length =
msg.headers.exists("Content-Length"); msg.fields.exists("Content-Length");
if(pi.connection_value) if(pi.connection_value)
{ {
switch(*pi.connection_value) switch(*pi.connection_value)
{ {
case connection::upgrade: case connection::upgrade:
msg.headers.insert("Connection", "upgrade"); msg.fields.insert("Connection", "upgrade");
break; break;
case connection::keep_alive: case connection::keep_alive:
if(msg.version < 11) if(msg.version < 11)
{ {
if(content_length) if(content_length)
msg.headers.insert("Connection", "keep-alive"); msg.fields.insert("Connection", "keep-alive");
} }
break; break;
case connection::close: case connection::close:
if(msg.version >= 11) if(msg.version >= 11)
msg.headers.insert("Connection", "close"); msg.fields.insert("Connection", "close");
break; break;
} }
} }
// rfc7230 6.7. // rfc7230 6.7.
if(msg.version < 11 && token_list{ if(msg.version < 11 && token_list{
msg.headers["Connection"]}.exists("upgrade")) msg.fields["Connection"]}.exists("upgrade"))
throw std::invalid_argument( throw std::invalid_argument(
"invalid version for Connection: upgrade"); "invalid version for Connection: upgrade");
} }

View File

@@ -50,7 +50,7 @@ public:
case parse_error::invalid_chunk_size: return "invalid chunk size"; case parse_error::invalid_chunk_size: return "invalid chunk size";
case parse_error::invalid_ext_name: return "invalid ext name"; case parse_error::invalid_ext_name: return "invalid ext name";
case parse_error::invalid_ext_val: return "invalid ext val"; case parse_error::invalid_ext_val: return "invalid ext val";
case parse_error::headers_too_big: return "headers size limit exceeded"; case parse_error::header_too_big: return "header size limit exceeded";
case parse_error::body_too_big: return "body size limit exceeded"; case parse_error::body_too_big: return "body size limit exceeded";
default: default:
case parse_error::short_read: return "unexpected end of data"; case parse_error::short_read: return "unexpected end of data";

View File

@@ -9,7 +9,7 @@
#define BEAST_HTTP_IMPL_READ_IPP_HPP #define BEAST_HTTP_IMPL_READ_IPP_HPP
#include <beast/http/concepts.hpp> #include <beast/http/concepts.hpp>
#include <beast/http/headers_parser_v1.hpp> #include <beast/http/header_parser_v1.hpp>
#include <beast/http/parse.hpp> #include <beast/http/parse.hpp>
#include <beast/http/parser_v1.hpp> #include <beast/http/parser_v1.hpp>
#include <beast/core/bind_handler.hpp> #include <beast/core/bind_handler.hpp>
@@ -23,18 +23,18 @@ namespace http {
namespace detail { namespace detail {
template<class Stream, class DynamicBuffer, template<class Stream, class DynamicBuffer,
bool isRequest, class Headers, bool isRequest, class Fields,
class Handler> class Handler>
class read_headers_op class read_header_op
{ {
using alloc_type = using alloc_type =
handler_alloc<char, Handler>; handler_alloc<char, Handler>;
using parser_type = using parser_type =
headers_parser_v1<isRequest, Headers>; header_parser_v1<isRequest, Fields>;
using message_type = using message_type =
message_headers<isRequest, Headers>; header<isRequest, Fields>;
struct data struct data
{ {
@@ -63,11 +63,11 @@ class read_headers_op
std::shared_ptr<data> d_; std::shared_ptr<data> d_;
public: public:
read_headers_op(read_headers_op&&) = default; read_header_op(read_header_op&&) = default;
read_headers_op(read_headers_op const&) = default; read_header_op(read_header_op const&) = default;
template<class DeducedHandler, class... Args> template<class DeducedHandler, class... Args>
read_headers_op( read_header_op(
DeducedHandler&& h, Stream& s, Args&&... args) DeducedHandler&& h, Stream& s, Args&&... args)
: d_(std::allocate_shared<data>(alloc_type{h}, : d_(std::allocate_shared<data>(alloc_type{h},
std::forward<DeducedHandler>(h), s, std::forward<DeducedHandler>(h), s,
@@ -81,7 +81,7 @@ public:
friend friend
void* asio_handler_allocate( void* asio_handler_allocate(
std::size_t size, read_headers_op* op) std::size_t size, read_header_op* op)
{ {
return boost_asio_handler_alloc_helpers:: return boost_asio_handler_alloc_helpers::
allocate(size, op->d_->h); allocate(size, op->d_->h);
@@ -89,21 +89,21 @@ public:
friend friend
void asio_handler_deallocate( void asio_handler_deallocate(
void* p, std::size_t size, read_headers_op* op) void* p, std::size_t size, read_header_op* op)
{ {
return boost_asio_handler_alloc_helpers:: return boost_asio_handler_alloc_helpers::
deallocate(p, size, op->d_->h); deallocate(p, size, op->d_->h);
} }
friend friend
bool asio_handler_is_continuation(read_headers_op* op) bool asio_handler_is_continuation(read_header_op* op)
{ {
return op->d_->cont; return op->d_->cont;
} }
template<class Function> template<class Function>
friend friend
void asio_handler_invoke(Function&& f, read_headers_op* op) void asio_handler_invoke(Function&& f, read_header_op* op)
{ {
return boost_asio_handler_invoke_helpers:: return boost_asio_handler_invoke_helpers::
invoke(f, op->d_->h); invoke(f, op->d_->h);
@@ -111,10 +111,10 @@ public:
}; };
template<class Stream, class DynamicBuffer, template<class Stream, class DynamicBuffer,
bool isRequest, class Headers, bool isRequest, class Fields,
class Handler> class Handler>
void void
read_headers_op<Stream, DynamicBuffer, isRequest, Headers, Handler>:: read_header_op<Stream, DynamicBuffer, isRequest, Fields, Handler>::
operator()(error_code ec, bool again) operator()(error_code ec, bool again)
{ {
auto& d = *d_; auto& d = *d_;
@@ -141,10 +141,10 @@ operator()(error_code ec, bool again)
} // detail } // detail
template<class SyncReadStream, class DynamicBuffer, template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Headers> bool isRequest, class Fields>
void void
read(SyncReadStream& stream, DynamicBuffer& dynabuf, read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_headers<isRequest, Headers>& msg) header<isRequest, Fields>& msg)
{ {
static_assert(is_SyncReadStream<SyncReadStream>::value, static_assert(is_SyncReadStream<SyncReadStream>::value,
"SyncReadStream requirements not met"); "SyncReadStream requirements not met");
@@ -157,17 +157,17 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
} }
template<class SyncReadStream, class DynamicBuffer, template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Headers> bool isRequest, class Fields>
void void
read(SyncReadStream& stream, DynamicBuffer& dynabuf, read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_headers<isRequest, Headers>& m, header<isRequest, Fields>& m,
error_code& ec) error_code& ec)
{ {
static_assert(is_SyncReadStream<SyncReadStream>::value, static_assert(is_SyncReadStream<SyncReadStream>::value,
"SyncReadStream requirements not met"); "SyncReadStream requirements not met");
static_assert(is_DynamicBuffer<DynamicBuffer>::value, static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met"); "DynamicBuffer requirements not met");
headers_parser_v1<isRequest, Headers> p; header_parser_v1<isRequest, Fields> p;
beast::http::parse(stream, dynabuf, p, ec); beast::http::parse(stream, dynabuf, p, ec);
if(ec) if(ec)
return; return;
@@ -176,12 +176,12 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
} }
template<class AsyncReadStream, class DynamicBuffer, template<class AsyncReadStream, class DynamicBuffer,
bool isRequest, class Headers, bool isRequest, class Fields,
class ReadHandler> class ReadHandler>
typename async_completion< typename async_completion<
ReadHandler, void(error_code)>::result_type ReadHandler, void(error_code)>::result_type
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
message_headers<isRequest, Headers>& m, header<isRequest, Fields>& m,
ReadHandler&& handler) ReadHandler&& handler)
{ {
static_assert(is_AsyncReadStream<AsyncReadStream>::value, static_assert(is_AsyncReadStream<AsyncReadStream>::value,
@@ -190,8 +190,8 @@ async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
"DynamicBuffer requirements not met"); "DynamicBuffer requirements not met");
beast::async_completion<ReadHandler, beast::async_completion<ReadHandler,
void(error_code)> completion(handler); void(error_code)> completion(handler);
detail::read_headers_op<AsyncReadStream, DynamicBuffer, detail::read_header_op<AsyncReadStream, DynamicBuffer,
isRequest, Headers, decltype( isRequest, Fields, decltype(
completion.handler)>{completion.handler, completion.handler)>{completion.handler,
stream, dynabuf, m}; stream, dynabuf, m};
return completion.result.get(); return completion.result.get();
@@ -202,7 +202,7 @@ async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
namespace detail { namespace detail {
template<class Stream, class DynamicBuffer, template<class Stream, class DynamicBuffer,
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class Handler> class Handler>
class read_op class read_op
{ {
@@ -210,10 +210,10 @@ class read_op
handler_alloc<char, Handler>; handler_alloc<char, Handler>;
using parser_type = using parser_type =
parser_v1<isRequest, Body, Headers>; parser_v1<isRequest, Body, Fields>;
using message_type = using message_type =
message<isRequest, Body, Headers>; message<isRequest, Body, Fields>;
struct data struct data
{ {
@@ -289,10 +289,10 @@ public:
}; };
template<class Stream, class DynamicBuffer, template<class Stream, class DynamicBuffer,
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class Handler> class Handler>
void void
read_op<Stream, DynamicBuffer, isRequest, Body, Headers, Handler>:: read_op<Stream, DynamicBuffer, isRequest, Body, Fields, Handler>::
operator()(error_code ec, bool again) operator()(error_code ec, bool again)
{ {
auto& d = *d_; auto& d = *d_;
@@ -319,10 +319,10 @@ operator()(error_code ec, bool again)
} // detail } // detail
template<class SyncReadStream, class DynamicBuffer, template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
void void
read(SyncReadStream& stream, DynamicBuffer& dynabuf, read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message<isRequest, Body, Headers>& msg) message<isRequest, Body, Fields>& msg)
{ {
static_assert(is_SyncReadStream<SyncReadStream>::value, static_assert(is_SyncReadStream<SyncReadStream>::value,
"SyncReadStream requirements not met"); "SyncReadStream requirements not met");
@@ -333,7 +333,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
static_assert(has_reader<Body>::value, static_assert(has_reader<Body>::value,
"Body has no reader"); "Body has no reader");
static_assert(is_Reader<typename Body::reader, static_assert(is_Reader<typename Body::reader,
message<isRequest, Body, Headers>>::value, message<isRequest, Body, Fields>>::value,
"Reader requirements not met"); "Reader requirements not met");
error_code ec; error_code ec;
beast::http::read(stream, dynabuf, msg, ec); beast::http::read(stream, dynabuf, msg, ec);
@@ -342,10 +342,10 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
} }
template<class SyncReadStream, class DynamicBuffer, template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
void void
read(SyncReadStream& stream, DynamicBuffer& dynabuf, read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message<isRequest, Body, Headers>& m, message<isRequest, Body, Fields>& m,
error_code& ec) error_code& ec)
{ {
static_assert(is_SyncReadStream<SyncReadStream>::value, static_assert(is_SyncReadStream<SyncReadStream>::value,
@@ -357,9 +357,9 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
static_assert(has_reader<Body>::value, static_assert(has_reader<Body>::value,
"Body has no reader"); "Body has no reader");
static_assert(is_Reader<typename Body::reader, static_assert(is_Reader<typename Body::reader,
message<isRequest, Body, Headers>>::value, message<isRequest, Body, Fields>>::value,
"Reader requirements not met"); "Reader requirements not met");
parser_v1<isRequest, Body, Headers> p; parser_v1<isRequest, Body, Fields> p;
beast::http::parse(stream, dynabuf, p, ec); beast::http::parse(stream, dynabuf, p, ec);
if(ec) if(ec)
return; return;
@@ -368,12 +368,12 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
} }
template<class AsyncReadStream, class DynamicBuffer, template<class AsyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class ReadHandler> class ReadHandler>
typename async_completion< typename async_completion<
ReadHandler, void(error_code)>::result_type ReadHandler, void(error_code)>::result_type
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
message<isRequest, Body, Headers>& m, message<isRequest, Body, Fields>& m,
ReadHandler&& handler) ReadHandler&& handler)
{ {
static_assert(is_AsyncReadStream<AsyncReadStream>::value, static_assert(is_AsyncReadStream<AsyncReadStream>::value,
@@ -385,12 +385,12 @@ async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
static_assert(has_reader<Body>::value, static_assert(has_reader<Body>::value,
"Body has no reader"); "Body has no reader");
static_assert(is_Reader<typename Body::reader, static_assert(is_Reader<typename Body::reader,
message<isRequest, Body, Headers>>::value, message<isRequest, Body, Fields>>::value,
"Reader requirements not met"); "Reader requirements not met");
beast::async_completion<ReadHandler, beast::async_completion<ReadHandler,
void(error_code)> completion(handler); void(error_code)> completion(handler);
detail::read_op<AsyncReadStream, DynamicBuffer, detail::read_op<AsyncReadStream, DynamicBuffer,
isRequest, Body, Headers, decltype( isRequest, Body, Fields, decltype(
completion.handler)>{completion.handler, completion.handler)>{completion.handler,
stream, dynabuf, m}; stream, dynabuf, m};
return completion.result.get(); return completion.result.get();

View File

@@ -32,10 +32,10 @@ namespace http {
namespace detail { namespace detail {
template<class DynamicBuffer, class Headers> template<class DynamicBuffer, class Fields>
void void
write_start_line(DynamicBuffer& dynabuf, write_start_line(DynamicBuffer& dynabuf,
message_headers<true, Headers> const& msg) header<true, Fields> const& msg)
{ {
BOOST_ASSERT(msg.version == 10 || msg.version == 11); BOOST_ASSERT(msg.version == 10 || msg.version == 11);
write(dynabuf, msg.method); write(dynabuf, msg.method);
@@ -52,10 +52,10 @@ write_start_line(DynamicBuffer& dynabuf,
} }
} }
template<class DynamicBuffer, class Headers> template<class DynamicBuffer, class Fields>
void void
write_start_line(DynamicBuffer& dynabuf, write_start_line(DynamicBuffer& dynabuf,
message_headers<false, Headers> const& msg) header<false, Fields> const& msg)
{ {
BOOST_ASSERT(msg.version == 10 || msg.version == 11); BOOST_ASSERT(msg.version == 10 || msg.version == 11);
switch(msg.version) switch(msg.version)
@@ -205,10 +205,10 @@ operator()(error_code ec, std::size_t, bool again)
} // detail } // detail
template<class SyncWriteStream, template<class SyncWriteStream,
bool isRequest, class Headers> bool isRequest, class Fields>
void void
write(SyncWriteStream& stream, write(SyncWriteStream& stream,
message_headers<isRequest, Headers> const& msg) header<isRequest, Fields> const& msg)
{ {
static_assert(is_SyncWriteStream<SyncWriteStream>::value, static_assert(is_SyncWriteStream<SyncWriteStream>::value,
"SyncWriteStream requirements not met"); "SyncWriteStream requirements not met");
@@ -219,28 +219,28 @@ write(SyncWriteStream& stream,
} }
template<class SyncWriteStream, template<class SyncWriteStream,
bool isRequest, class Headers> bool isRequest, class Fields>
void void
write(SyncWriteStream& stream, write(SyncWriteStream& stream,
message_headers<isRequest, Headers> const& msg, header<isRequest, Fields> const& msg,
error_code& ec) error_code& ec)
{ {
static_assert(is_SyncWriteStream<SyncWriteStream>::value, static_assert(is_SyncWriteStream<SyncWriteStream>::value,
"SyncWriteStream requirements not met"); "SyncWriteStream requirements not met");
streambuf sb; streambuf sb;
detail::write_start_line(sb, msg); detail::write_start_line(sb, msg);
detail::write_fields(sb, msg.headers); detail::write_fields(sb, msg.fields);
beast::write(sb, "\r\n"); beast::write(sb, "\r\n");
boost::asio::write(stream, sb.data(), ec); boost::asio::write(stream, sb.data(), ec);
} }
template<class AsyncWriteStream, template<class AsyncWriteStream,
bool isRequest, class Headers, bool isRequest, class Fields,
class WriteHandler> class WriteHandler>
typename async_completion< typename async_completion<
WriteHandler, void(error_code)>::result_type WriteHandler, void(error_code)>::result_type
async_write(AsyncWriteStream& stream, async_write(AsyncWriteStream& stream,
message_headers<isRequest, Headers> const& msg, header<isRequest, Fields> const& msg,
WriteHandler&& handler) WriteHandler&& handler)
{ {
static_assert(is_AsyncWriteStream<AsyncWriteStream>::value, static_assert(is_AsyncWriteStream<AsyncWriteStream>::value,
@@ -249,7 +249,7 @@ async_write(AsyncWriteStream& stream,
void(error_code)> completion(handler); void(error_code)> completion(handler);
streambuf sb; streambuf sb;
detail::write_start_line(sb, msg); detail::write_start_line(sb, msg);
detail::write_fields(sb, msg.headers); detail::write_fields(sb, msg.fields);
beast::write(sb, "\r\n"); beast::write(sb, "\r\n");
detail::write_streambuf_op<AsyncWriteStream, detail::write_streambuf_op<AsyncWriteStream,
decltype(completion.handler)>{ decltype(completion.handler)>{
@@ -261,10 +261,10 @@ async_write(AsyncWriteStream& stream,
namespace detail { namespace detail {
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
struct write_preparation struct write_preparation
{ {
message<isRequest, Body, Headers> const& msg; message<isRequest, Body, Fields> const& msg;
typename Body::writer w; typename Body::writer w;
streambuf sb; streambuf sb;
bool chunked; bool chunked;
@@ -272,14 +272,14 @@ struct write_preparation
explicit explicit
write_preparation( write_preparation(
message<isRequest, Body, Headers> const& msg_) message<isRequest, Body, Fields> const& msg_)
: msg(msg_) : msg(msg_)
, w(msg) , w(msg)
, chunked(token_list{ , chunked(token_list{
msg.headers["Transfer-Encoding"]}.exists("chunked")) msg.fields["Transfer-Encoding"]}.exists("chunked"))
, close(token_list{ , close(token_list{
msg.headers["Connection"]}.exists("close") || msg.fields["Connection"]}.exists("close") ||
(msg.version < 11 && ! msg.headers.exists( (msg.version < 11 && ! msg.fields.exists(
"Content-Length"))) "Content-Length")))
{ {
} }
@@ -292,13 +292,13 @@ struct write_preparation
return; return;
write_start_line(sb, msg); write_start_line(sb, msg);
write_fields(sb, msg.headers); write_fields(sb, msg.fields);
beast::write(sb, "\r\n"); beast::write(sb, "\r\n");
} }
}; };
template<class Stream, class Handler, template<class Stream, class Handler,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
class write_op class write_op
{ {
using alloc_type = using alloc_type =
@@ -309,7 +309,7 @@ class write_op
Stream& s; Stream& s;
// VFALCO How do we use handler_alloc in write_preparation? // VFALCO How do we use handler_alloc in write_preparation?
write_preparation< write_preparation<
isRequest, Body, Headers> wp; isRequest, Body, Fields> wp;
Handler h; Handler h;
resume_context resume; resume_context resume;
resume_context copy; resume_context copy;
@@ -318,7 +318,7 @@ class write_op
template<class DeducedHandler> template<class DeducedHandler>
data(DeducedHandler&& h_, Stream& s_, data(DeducedHandler&& h_, Stream& s_,
message<isRequest, Body, Headers> const& m_) message<isRequest, Body, Fields> const& m_)
: s(s_) : s(s_)
, wp(m_) , wp(m_)
, h(std::forward<DeducedHandler>(h_)) , h(std::forward<DeducedHandler>(h_))
@@ -343,7 +343,7 @@ class write_op
void operator()(ConstBufferSequence const& buffers) const void operator()(ConstBufferSequence const& buffers) const
{ {
auto& d = *self_.d_; auto& d = *self_.d_;
// write headers and body // write header and body
if(d.wp.chunked) if(d.wp.chunked)
boost::asio::async_write(d.s, boost::asio::async_write(d.s,
buffer_cat(d.wp.sb.data(), buffer_cat(d.wp.sb.data(),
@@ -451,9 +451,9 @@ public:
}; };
template<class Stream, class Handler, template<class Stream, class Handler,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
void void
write_op<Stream, Handler, isRequest, Body, Headers>:: write_op<Stream, Handler, isRequest, Body, Fields>::
operator()(error_code ec, std::size_t, bool again) operator()(error_code ec, std::size_t, bool again)
{ {
auto& d = *d_; auto& d = *d_;
@@ -502,7 +502,7 @@ operator()(error_code ec, std::size_t, bool again)
return; return;
} }
// sent headers and body // sent header and body
case 2: case 2:
d.wp.sb.consume(d.wp.sb.size()); d.wp.sb.consume(d.wp.sb.size());
d.state = 3; d.state = 3;
@@ -578,7 +578,7 @@ public:
template<class ConstBufferSequence> template<class ConstBufferSequence>
void operator()(ConstBufferSequence const& buffers) const void operator()(ConstBufferSequence const& buffers) const
{ {
// write headers and body // write header and body
if(chunked_) if(chunked_)
boost::asio::write(stream_, buffer_cat( boost::asio::write(stream_, buffer_cat(
sb_.data(), chunk_encode(false, buffers)), ec_); sb_.data(), chunk_encode(false, buffers)), ec_);
@@ -619,10 +619,10 @@ public:
} // detail } // detail
template<class SyncWriteStream, template<class SyncWriteStream,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
void void
write(SyncWriteStream& stream, write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg) message<isRequest, Body, Fields> const& msg)
{ {
static_assert(is_SyncWriteStream<SyncWriteStream>::value, static_assert(is_SyncWriteStream<SyncWriteStream>::value,
"SyncWriteStream requirements not met"); "SyncWriteStream requirements not met");
@@ -631,7 +631,7 @@ write(SyncWriteStream& stream,
static_assert(has_writer<Body>::value, static_assert(has_writer<Body>::value,
"Body has no writer"); "Body has no writer");
static_assert(is_Writer<typename Body::writer, static_assert(is_Writer<typename Body::writer,
message<isRequest, Body, Headers>>::value, message<isRequest, Body, Fields>>::value,
"Writer requirements not met"); "Writer requirements not met");
error_code ec; error_code ec;
write(stream, msg, ec); write(stream, msg, ec);
@@ -640,10 +640,10 @@ write(SyncWriteStream& stream,
} }
template<class SyncWriteStream, template<class SyncWriteStream,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
void void
write(SyncWriteStream& stream, write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg, message<isRequest, Body, Fields> const& msg,
error_code& ec) error_code& ec)
{ {
static_assert(is_SyncWriteStream<SyncWriteStream>::value, static_assert(is_SyncWriteStream<SyncWriteStream>::value,
@@ -653,9 +653,9 @@ write(SyncWriteStream& stream,
static_assert(has_writer<Body>::value, static_assert(has_writer<Body>::value,
"Body has no writer"); "Body has no writer");
static_assert(is_Writer<typename Body::writer, static_assert(is_Writer<typename Body::writer,
message<isRequest, Body, Headers>>::value, message<isRequest, Body, Fields>>::value,
"Writer requirements not met"); "Writer requirements not met");
detail::write_preparation<isRequest, Body, Headers> wp(msg); detail::write_preparation<isRequest, Body, Fields> wp(msg);
wp.init(ec); wp.init(ec);
if(ec) if(ec)
return; return;
@@ -729,12 +729,12 @@ write(SyncWriteStream& stream,
} }
template<class AsyncWriteStream, template<class AsyncWriteStream,
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class WriteHandler> class WriteHandler>
typename async_completion< typename async_completion<
WriteHandler, void(error_code)>::result_type WriteHandler, void(error_code)>::result_type
async_write(AsyncWriteStream& stream, async_write(AsyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg, message<isRequest, Body, Fields> const& msg,
WriteHandler&& handler) WriteHandler&& handler)
{ {
static_assert(is_AsyncWriteStream<AsyncWriteStream>::value, static_assert(is_AsyncWriteStream<AsyncWriteStream>::value,
@@ -744,21 +744,21 @@ async_write(AsyncWriteStream& stream,
static_assert(has_writer<Body>::value, static_assert(has_writer<Body>::value,
"Body has no writer"); "Body has no writer");
static_assert(is_Writer<typename Body::writer, static_assert(is_Writer<typename Body::writer,
message<isRequest, Body, Headers>>::value, message<isRequest, Body, Fields>>::value,
"Writer requirements not met"); "Writer requirements not met");
beast::async_completion<WriteHandler, beast::async_completion<WriteHandler,
void(error_code)> completion(handler); void(error_code)> completion(handler);
detail::write_op<AsyncWriteStream, decltype(completion.handler), detail::write_op<AsyncWriteStream, decltype(completion.handler),
isRequest, Body, Headers>{completion.handler, stream, msg}; isRequest, Body, Fields>{completion.handler, stream, msg};
return completion.result.get(); return completion.result.get();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
std::ostream& std::ostream&
operator<<(std::ostream& os, operator<<(std::ostream& os,
message_headers<isRequest, Headers> const& msg) header<isRequest, Fields> const& msg)
{ {
beast::detail::sync_ostream oss{os}; beast::detail::sync_ostream oss{os};
error_code ec; error_code ec;
@@ -768,17 +768,17 @@ operator<<(std::ostream& os,
return os; return os;
} }
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
std::ostream& std::ostream&
operator<<(std::ostream& os, operator<<(std::ostream& os,
message<isRequest, Body, Headers> const& msg) message<isRequest, Body, Fields> const& msg)
{ {
static_assert(is_Body<Body>::value, static_assert(is_Body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_writer<Body>::value, static_assert(has_writer<Body>::value,
"Body has no writer"); "Body has no writer");
static_assert(is_Writer<typename Body::writer, static_assert(is_Writer<typename Body::writer,
message<isRequest, Body, Headers>>::value, message<isRequest, Body, Fields>>::value,
"Writer requirements not met"); "Writer requirements not met");
beast::detail::sync_ostream oss{os}; beast::detail::sync_ostream oss{os};
error_code ec; error_code ec;

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_MESSAGE_HPP #ifndef BEAST_HTTP_MESSAGE_HPP
#define BEAST_HTTP_MESSAGE_HPP #define BEAST_HTTP_MESSAGE_HPP
#include <beast/http/basic_headers.hpp> #include <beast/http/fields.hpp>
#include <beast/core/detail/integer_sequence.hpp> #include <beast/core/detail/integer_sequence.hpp>
#include <memory> #include <memory>
#include <string> #include <string>
@@ -19,27 +19,30 @@ namespace beast {
namespace http { namespace http {
#if GENERATING_DOCS #if GENERATING_DOCS
/** A container for HTTP request or response headers. /** A container for a HTTP request or response header.
The container includes the headers, as well as the A header includes the Start Line and Fields.
request method and URL. Objects of this type may be
used to represent incoming or outgoing requests for Some use-cases:
which the body is not yet known or generated. For
example, when receiving a request with the header value @li When the message has no body, such as a response to a HEAD request.
"Expect: 100-continue".
@li When the caller wishes to defer instantiation of the body.
@li Invoke algorithms which operate on the header only.
*/ */
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
struct message_headers struct header
#else #else
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
struct message_headers; struct header;
template<class Headers> template<class Fields>
struct message_headers<true, Headers> struct header<true, Fields>
#endif #endif
{ {
/// Indicates if the message headers are a request or response. /// Indicates if the header is a request or response.
#if GENERATING_DOCS #if GENERATING_DOCS
static bool constexpr is_request = isRequest; static bool constexpr is_request = isRequest;
@@ -47,8 +50,8 @@ struct message_headers<true, Headers>
static bool constexpr is_request = true; static bool constexpr is_request = true;
#endif #endif
/// The type representing the headers. /// The type representing the fields.
using headers_type = Headers; using fields_type = Fields;
/** The HTTP version. /** The HTTP version.
@@ -74,67 +77,71 @@ struct message_headers<true, Headers>
std::string url; std::string url;
/// The HTTP field values. /// The HTTP field values.
Headers headers; fields_type fields;
/// Default constructor /// Default constructor
message_headers() = default; header() = default;
/// Move constructor /// Move constructor
message_headers(message_headers&&) = default; header(header&&) = default;
/// Copy constructor /// Copy constructor
message_headers(message_headers const&) = default; header(header const&) = default;
/// Move assignment /// Move assignment
message_headers& operator=(message_headers&&) = default; header& operator=(header&&) = default;
/// Copy assignment /// Copy assignment
message_headers& operator=(message_headers const&) = default; header& operator=(header const&) = default;
/** Construct message headers. /** Construct the header.
All arguments are forwarded to the constructor All arguments are forwarded to the constructor
of the `headers` member. of the `fields` member.
@note This constructor participates in overload resolution @note This constructor participates in overload resolution
if and only if the first parameter is not convertible to if and only if the first parameter is not convertible to
`message_headers`. `header`.
*/ */
#if GENERATING_DOCS #if GENERATING_DOCS
template<class... Args> template<class... Args>
explicit explicit
message_headers(Args&&... args); header(Args&&... args);
#else #else
template<class Arg1, class... ArgN, template<class Arg1, class... ArgN,
class = typename std::enable_if< class = typename std::enable_if<
(sizeof...(ArgN) > 0) || ! std::is_convertible< (sizeof...(ArgN) > 0) || ! std::is_convertible<
typename std::decay<Arg1>::type, typename std::decay<Arg1>::type,
message_headers>::value>::type> header>::value>::type>
explicit explicit
message_headers(Arg1&& arg1, ArgN&&... argn) header(Arg1&& arg1, ArgN&&... argn)
: headers(std::forward<Arg1>(arg1), : fields(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...) std::forward<ArgN>(argn)...)
{ {
} }
}; };
/** A container for HTTP request or response headers. /** A container for a HTTP request or response header.
The container includes the headers, as well as the A header includes the Start Line and Fields.
response status and reasons. Objects of this type may
be used to represent incoming or outgoing responses for Some use-cases:
which the body is not yet known or generated. For
example, when responding to a HEAD request. @li When the message has no body, such as a response to a HEAD request.
@li When the caller wishes to defer instantiation of the body.
@li Invoke algorithms which operate on the header only.
*/ */
template<class Headers> template<class Fields>
struct message_headers<false, Headers> struct header<false, Fields>
{ {
/// Indicates if the message headers are a request or response. /// Indicates if the header is a request or response.
static bool constexpr is_request = false; static bool constexpr is_request = false;
/// The type representing the headers. /// The type representing the fields.
using headers_type = Headers; using fields_type = Fields;
/** The HTTP version. /** The HTTP version.
@@ -148,40 +155,40 @@ struct message_headers<false, Headers>
int version; int version;
/// The HTTP field values. /// The HTTP field values.
Headers headers; fields_type fields;
/// Default constructor /// Default constructor
message_headers() = default; header() = default;
/// Move constructor /// Move constructor
message_headers(message_headers&&) = default; header(header&&) = default;
/// Copy constructor /// Copy constructor
message_headers(message_headers const&) = default; header(header const&) = default;
/// Move assignment /// Move assignment
message_headers& operator=(message_headers&&) = default; header& operator=(header&&) = default;
/// Copy assignment /// Copy assignment
message_headers& operator=(message_headers const&) = default; header& operator=(header const&) = default;
/** Construct message headers. /** Construct the header.
All arguments are forwarded to the constructor All arguments are forwarded to the constructor
of the `headers` member. of the `fields` member.
@note This constructor participates in overload resolution @note This constructor participates in overload resolution
if and only if the first parameter is not convertible to if and only if the first parameter is not convertible to
`message_headers`. `header`.
*/ */
template<class Arg1, class... ArgN, template<class Arg1, class... ArgN,
class = typename std::enable_if< class = typename std::enable_if<
(sizeof...(ArgN) > 0) || ! std::is_convertible< (sizeof...(ArgN) > 0) || ! std::is_convertible<
typename std::decay<Arg1>::type, typename std::decay<Arg1>::type,
message_headers>::value>::type> header>::value>::type>
explicit explicit
message_headers(Arg1&& arg1, ArgN&&... argn) header(Arg1&& arg1, ArgN&&... argn)
: headers(std::forward<Arg1>(arg1), : fields(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...) std::forward<ArgN>(argn)...)
{ {
} }
@@ -204,9 +211,10 @@ struct message_headers<false, Headers>
/** A container for a complete HTTP message. /** A container for a complete HTTP message.
A message can be a request or response, depending on the `isRequest` A message can be a request or response, depending on the
template argument value. Requests and responses have different types, `isRequest` template argument value. Requests and responses
so functions may be overloaded on them if desired. have different types; functions may be overloaded based on
the type if desired.
The `Body` template argument type determines the model used The `Body` template argument type determines the model used
to read or write the content body of the message. to read or write the content body of the message.
@@ -217,19 +225,18 @@ struct message_headers<false, Headers>
@tparam Body A type meeting the requirements of Body. @tparam Body A type meeting the requirements of Body.
@tparam Headers The type of container used to hold the @tparam Fields The type of container used to hold the
field value pairs. field value pairs.
*/ */
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
struct message : struct message : header<isRequest, Fields>
message_headers<isRequest, Headers>
{ {
/// The base class used to hold the request or response headers /// The base class used to hold the header portion of the message.
using base_type = message_headers<isRequest, Headers>; using base_type = header<isRequest, Fields>;
/** The type providing the body traits. /** The type providing the body traits.
The `body` member will be of type `body_type::value_type`. The @ref message::body member will be of type `body_type::value_type`.
*/ */
using body_type = Body; using body_type = Body;
@@ -239,7 +246,7 @@ struct message :
/// Default constructor /// Default constructor
message() = default; message() = default;
/** Construct a message from message headers. /** Construct a message from a header.
Additional arguments, if any, are forwarded to Additional arguments, if any, are forwarded to
the constructor of the body member. the constructor of the body member.
@@ -252,7 +259,7 @@ struct message :
{ {
} }
/** Construct a message from message headers. /** Construct a message from a header.
Additional arguments, if any, are forwarded to Additional arguments, if any, are forwarded to
the constructor of the body member. the constructor of the body member.
@@ -288,7 +295,7 @@ struct message :
@param u An argument forwarded to the body constructor. @param u An argument forwarded to the body constructor.
@param v An argument forwarded to the headers constructor. @param v An argument forwarded to the fields constructor.
@note This constructor participates in overload resolution @note This constructor participates in overload resolution
only if `u` is not convertible to `base_type`. only if `u` is not convertible to `base_type`.
@@ -320,7 +327,7 @@ struct message :
@param un A tuple forwarded as a parameter pack to the body constructor. @param un A tuple forwarded as a parameter pack to the body constructor.
@param vn A tuple forwarded as a parameter pack to the headers constructor. @param vn A tuple forwarded as a parameter pack to the fields constructor.
*/ */
template<class... Un, class... Vn> template<class... Un, class... Vn>
message(std::piecewise_construct_t, message(std::piecewise_construct_t,
@@ -331,14 +338,14 @@ struct message :
{ {
} }
/// Returns the message headers portion of the message /// Returns the header portion of the message
base_type& base_type&
base() base()
{ {
return *this; return *this;
} }
/// Returns the message headers portion of the message /// Returns the header portion of the message
base_type const& base_type const&
base() const base() const
{ {
@@ -368,64 +375,60 @@ private:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#if GENERATING_DOCS #if GENERATING_DOCS
/** Swap two HTTP message headers. /** Swap two header objects.
@par Requirements @par Requirements
`Headers` is @b Swappable. `Fields` is @b Swappable.
*/ */
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
void void
swap( swap(
message_headers<isRequest, Headers>& m1, header<isRequest, Fields>& m1,
message_headers<isRequest, Headers>& m2); header<isRequest, Fields>& m2);
#endif #endif
/** Swap two HTTP messages. /** Swap two message objects.
@par Requirements: @par Requirements:
`Body` and `Headers` are @b Swappable. `Body::value_type` and `Fields` are @b Swappable.
*/ */
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
void void
swap( swap(
message<isRequest, Body, Headers>& m1, message<isRequest, Body, Fields>& m1,
message<isRequest, Body, Headers>& m2); message<isRequest, Body, Fields>& m2);
/// Message headers for a typical HTTP request /// A typical HTTP request header
using request_headers = message_headers<true, using request_header = header<true, fields>;
basic_headers<std::allocator<char>>>;
/// Message headers for a typical HTTP response /// Typical HTTP response header
using response_headers = message_headers<false, using response_header = header<false, fields>;
basic_headers<std::allocator<char>>>;
/// A typical HTTP request message /// A typical HTTP request
template<class Body, template<class Body, class Fields = fields>
class Headers = basic_headers<std::allocator<char>>> using request = message<true, Body, Fields>;
using request = message<true, Body, Headers>;
/// A typical HTTP response message /// A typical HTTP response
template<class Body, template<class Body, class Fields = fields>
class Headers = basic_headers<std::allocator<char>>> using response = message<false, Body, Fields>;
using response = message<false, Body, Headers>;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Returns `true` if a HTTP/1 message indicates a keep alive. /** Returns `true` if the HTTP/1 message indicates a keep alive.
Undefined behavior if version is greater than 11. Undefined behavior if version is greater than 11.
*/ */
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Fields>
bool bool
is_keep_alive(message<isRequest, Body, Headers> const& msg); is_keep_alive(header<isRequest, Fields> const& msg);
/** Returns `true` if a HTTP/1 message indicates an Upgrade request or response. /** Returns `true` if the HTTP/1 message indicates an Upgrade request or response.
Undefined behavior if version is greater than 11. Undefined behavior if version is greater than 11.
*/ */
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Fields>
bool bool
is_upgrade(message<isRequest, Body, Headers> const& msg); is_upgrade(header<isRequest, Fields> const& msg);
/** HTTP/1 connection prepare options. /** HTTP/1 connection prepare options.
@@ -446,18 +449,18 @@ enum class connection
/** Prepare a HTTP message. /** Prepare a HTTP message.
This function will adjust the Content-Length, Transfer-Encoding, This function will adjust the Content-Length, Transfer-Encoding,
and Connection headers of the message based on the properties of and Connection fields of the message based on the properties of
the body and the options passed in. the body and the options passed in.
@param msg The message to prepare. The headers may be modified. @param msg The message to prepare. The fields may be modified.
@param options A list of prepare options. @param options A list of prepare options.
*/ */
template< template<
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class... Options> class... Options>
void void
prepare(message<isRequest, Body, Headers>& msg, prepare(message<isRequest, Body, Fields>& msg,
Options&&... options); Options&&... options);
} // http } // http

View File

@@ -34,7 +34,7 @@ enum class parse_error
invalid_ext_name, invalid_ext_name,
invalid_ext_val, invalid_ext_val,
headers_too_big, header_too_big,
body_too_big, body_too_big,
short_read short_read
}; };

View File

@@ -9,7 +9,7 @@
#define BEAST_HTTP_PARSER_V1_HPP #define BEAST_HTTP_PARSER_V1_HPP
#include <beast/http/concepts.hpp> #include <beast/http/concepts.hpp>
#include <beast/http/headers_parser_v1.hpp> #include <beast/http/header_parser_v1.hpp>
#include <beast/http/message.hpp> #include <beast/http/message.hpp>
#include <beast/core/error.hpp> #include <beast/core/error.hpp>
#include <beast/core/detail/type_traits.hpp> #include <beast/core/detail/type_traits.hpp>
@@ -33,11 +33,11 @@ namespace http {
For example, a 200 response to a CONNECT request from a tunneling For example, a 200 response to a CONNECT request from a tunneling
proxy. In these cases, callers use the @ref skip_body option to proxy. In these cases, callers use the @ref skip_body option to
inform the parser that no body is expected. The parser will consider inform the parser that no body is expected. The parser will consider
the message complete after the all headers have been received. the message complete after the header has been received.
Example: Example:
@code @code
parser_v1<true, empty_body, headers> p; parser_v1<true, empty_body, fields> p;
p.set_option(skip_body{true}); p.set_option(skip_body{true});
@endcode @endcode
@@ -61,10 +61,10 @@ struct skip_body
@note A new instance of the parser is required for each message. @note A new instance of the parser is required for each message.
*/ */
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
class parser_v1 class parser_v1
: public basic_parser_v1<isRequest, : public basic_parser_v1<isRequest,
parser_v1<isRequest, Body, Headers>> parser_v1<isRequest, Body, Fields>>
, private std::conditional<isRequest, , private std::conditional<isRequest,
detail::request_parser_base, detail::request_parser_base,
detail::response_parser_base>::type detail::response_parser_base>::type
@@ -72,7 +72,7 @@ class parser_v1
public: public:
/// The type of message this parser produces. /// The type of message this parser produces.
using message_type = using message_type =
message<isRequest, Body, Headers>; message<isRequest, Body, Fields>;
private: private:
using reader = using reader =
@@ -113,7 +113,7 @@ public:
@param args Forwarded to the message constructor. @param args Forwarded to the message constructor.
@note This function participates in overload resolution only @note This function participates in overload resolution only
if the first argument is not a parser or headers parser. if the first argument is not a parser or fields parser.
*/ */
#if GENERATING_DOCS #if GENERATING_DOCS
template<class... Args> template<class... Args>
@@ -124,7 +124,7 @@ public:
class = typename std::enable_if< class = typename std::enable_if<
! std::is_same<typename ! std::is_same<typename
std::decay<Arg1>::type, std::decay<Arg1>::type,
headers_parser_v1<isRequest, Headers>>::value && header_parser_v1<isRequest, Fields>>::value &&
! std::is_same<typename ! std::is_same<typename
std::decay<Arg1>::type, parser_v1>::value std::decay<Arg1>::type, parser_v1>::value
>::type> >::type>
@@ -136,20 +136,20 @@ public:
} }
#endif #endif
/** Construct the parser from a headers parser. /** Construct the parser from a fields parser.
@param parser The headers parser to construct from. @param parser The fields parser to construct from.
@param args Forwarded to the message body constructor. @param args Forwarded to the message body constructor.
*/ */
template<class... Args> template<class... Args>
explicit explicit
parser_v1(headers_parser_v1<isRequest, Headers>& parser, parser_v1(header_parser_v1<isRequest, Fields>& parser,
Args&&... args) Args&&... args)
: m_(parser.release(), std::forward<Args>(args)...) : m_(parser.release(), std::forward<Args>(args)...)
{ {
static_cast<basic_parser_v1< static_cast<basic_parser_v1<
isRequest, parser_v1< isRequest, parser_v1<
isRequest, Body, Headers>>&>(*this) = parser; isRequest, Body, Fields>>&>(*this) = parser;
} }
/// Set the skip body option. /// Set the skip body option.
@@ -185,7 +185,7 @@ public:
valid if @ref complete would return `true`. valid if @ref complete would return `true`.
Requires: Requires:
`message<isRequest, Body, Headers>` is @b MoveConstructible `message<isRequest, Body, Fields>` is @b MoveConstructible
*/ */
message_type message_type
release() release()
@@ -204,7 +204,7 @@ private:
return; return;
flush_ = false; flush_ = false;
BOOST_ASSERT(! field_.empty()); BOOST_ASSERT(! field_.empty());
m_.headers.insert(field_, value_); m_.fields.insert(field_, value_);
field_.clear(); field_.clear();
value_.clear(); value_.clear();
} }
@@ -265,7 +265,7 @@ private:
} }
void void
on_headers(std::uint64_t, error_code&) on_header(std::uint64_t, error_code&)
{ {
flush(); flush();
m_.version = 10 * this->http_major() + this->http_minor(); m_.version = 10 * this->http_major() + this->http_minor();
@@ -291,22 +291,22 @@ private:
} }
}; };
/** Create a new parser from a headers parser. /** Create a new parser from a fields parser.
Associates a Body type with a headers parser, and returns Associates a Body type with a fields parser, and returns
a new parser which parses a complete message object a new parser which parses a complete message object
containing the original message headers and a new body containing the original message fields and a new body
of the specified body type. of the specified body type.
This function allows HTTP messages to be parsed in two stages. This function allows HTTP messages to be parsed in two stages.
First, the headers are parsed and control is returned. Then, First, the fields are parsed and control is returned. Then,
the caller can choose at run-time, the type of Body to the caller can choose at run-time, the type of Body to
associate with the message. And finally, complete the parse associate with the message. And finally, complete the parse
in a second call. in a second call.
@param parser The headers parser to construct from. Ownership @param parser The fields parser to construct from. Ownership
of the message headers in the headers parser is transferred of the message fields in the fields parser is transferred
as if by call to @ref headers_parser_v1::release. as if by call to @ref header_parser_v1::release.
@param args Forwarded to the body constructor of the message @param args Forwarded to the body constructor of the message
in the new parser. in the new parser.
@@ -315,19 +315,20 @@ private:
@par Example @par Example
@code @code
headers_parser<true, headers> ph; headers_parser<true, fields> ph;
... ...
auto p = with_body<string_body>(ph); auto p = with_body<string_body>(ph);
... ...
message<true, string_body, headers> m = p.release(); message<true, string_body, fields> m = p.release();
@endcode @endcode
*/ */
template<class Body, bool isRequest, class Headers, class... Args> template<class Body,
parser_v1<isRequest, Body, Headers> bool isRequest, class Fields, class... Args>
with_body(headers_parser_v1<isRequest, Headers>& parser, parser_v1<isRequest, Body, Fields>
with_body(header_parser_v1<isRequest, Fields>& parser,
Args&&... args) Args&&... args)
{ {
return parser_v1<isRequest, Body, Headers>( return parser_v1<isRequest, Body, Fields>(
parser, std::forward<Args>(args)...); parser, std::forward<Args>(args)...);
} }

View File

@@ -15,22 +15,27 @@
namespace beast { namespace beast {
namespace http { namespace http {
/** Read HTTP/1 message headers from a stream. /** Read a HTTP/1 header from a stream.
This function is used to synchronously read message headers from This function is used to synchronously read a header
the stream. The call blocks until one of the following conditions from a stream. The call blocks until one of the following
is true: conditions is true:
@li The complete message headers are read in. @li An entire header is read in.
@li An error occurs in the stream or parser. @li An error occurs in the stream or parser.
This function is implemented in terms of one or more calls This function is implemented in terms of one or more calls
to the stream's `read_some` function. The implementation may to the stream's `read_some` function. The implementation may
read additional octets that lie past the end of the message read additional octets that lie past the end of the message
headers being parsed. This additional data is stored in the fields being parsed. This additional data is stored in the
stream buffer, which may be used in subsequent calls. stream buffer, which may be used in subsequent calls.
If the message corresponding to the header being received
contains a message body, it is the callers responsibility
to cause the body to be read in before attempting to read
the next message.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b `SyncReadStream` concept. The type must support the @b `SyncReadStream` concept.
@@ -40,37 +45,38 @@ namespace http {
stream buffer's input sequence will be given to the parser stream buffer's input sequence will be given to the parser
first. first.
@param msg An object used to store the message headers. @param msg An object used to store the header. Any contents
Any contents will be overwritten. The type must support will be overwritten. The type must support copy assignment
copy assignment or move assignment. or move assignment.
@throws system_error Thrown on failure. @throws system_error Thrown on failure.
*/ */
template<class SyncReadStream, class DynamicBuffer, template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Headers> bool isRequest, class Fields>
void void
read(SyncReadStream& stream, DynamicBuffer& dynabuf, read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_headers<isRequest, Headers>& msg); header<isRequest, Fields>& msg);
/** Read HTTP/1 message headers from a stream. /** Read a HTTP/1 header from a stream.
This function is used to synchronously read message headers from This function is used to synchronously read a header
the stream. The call blocks until one of the following conditions from a stream. The call blocks until one of the following
is true: conditions is true:
@li The complete message headers are read in. @li An entire header is read in.
@li An error occurs in the stream or parser. @li An error occurs in the stream or parser.
This function is implemented in terms of one or more calls This function is implemented in terms of one or more calls
to the stream's `read_some` function. The implementation may to the stream's `read_some` function. The implementation may
read additional octets that lie past the end of the message read additional octets that lie past the end of the message
headers being parsed. This additional data is stored in the fields being parsed. This additional data is stored in the
stream buffer, which may be used in subsequent calls. stream buffer, which may be used in subsequent calls.
If the message being received contains a message body, it If the message corresponding to the header being received
is the callers responsibility to cause the body to be read contains a message body, it is the callers responsibility
in before attempting to read the next message. to cause the body to be read in before attempting to read
the next message.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b `SyncReadStream` concept. The type must support the @b `SyncReadStream` concept.
@@ -81,40 +87,42 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
stream buffer's input sequence will be given to the parser stream buffer's input sequence will be given to the parser
first. first.
@param msg An object used to store the message headers. @param msg An object used to store the header. Any contents
Any contents will be overwritten. The type must support will be overwritten. The type must support copy assignment
copy assignment or move assignment. or move assignment.
@param ec Set to the error, if any occurred. @param ec Set to the error, if any occurred.
*/ */
template<class SyncReadStream, class DynamicBuffer, template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Headers> bool isRequest, class Fields>
void void
read(SyncReadStream& stream, DynamicBuffer& dynabuf, read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_headers<isRequest, Headers>& msg, header<isRequest, Fields>& msg,
error_code& ec); error_code& ec);
/** Start an asynchronous operation to read HTTP/1 message headers from a stream. /** Read a HTTP/1 header asynchronously from a stream.
This function is used to asynchronously read a message from the This function is used to asynchronously read a header from
stream. The function call always returns immediately. The asynchronous a stream. The function call always returns immediately. The
operation will continue until one of the following conditions is true: asynchronous operation will continue until one of the following
conditions is true:
@li A complete message is read in. @li An entire header is read in.
@li An error occurs in the stream or parser. @li An error occurs in the stream or parser.
This operation is implemented in terms of one or more calls to 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 the stream's `async_read_some` function, and is known as a
<em>composed operation</em>. The program must ensure that the <em>composed operation</em>. The program must ensure that the
stream performs no other operations until this operation completes. stream performs no other operations until this operation completes.
The implementation may read additional octets that lie past the The implementation may read additional octets that lie past the
end of the message headers being parsed. This additional data is end of the message fields being parsed. This additional data is
stored in the stream buffer, which may be used in subsequent calls. stored in the stream buffer, which may be used in subsequent calls.
If the message being received contains a message body, it If the message corresponding to the header being received
is the callers responsibility to cause the body to be read contains a message body, it is the callers responsibility
in before attempting to read the next message. to cause the body to be read in before attempting to read
the next message.
@param stream The stream to read the message from. @param stream The stream to read the message from.
The type must support the @b `AsyncReadStream` concept. The type must support the @b `AsyncReadStream` concept.
@@ -125,13 +133,14 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
stream buffer's input sequence will be given to the parser stream buffer's input sequence will be given to the parser
first. first.
@param msg An object used to store the message. Any contents @param msg An object used to store the header. Any contents
will be overwritten. The type must support copy assignment or will be overwritten. The type must support copy assignment or
move assignment. move assignment. The object must remain valid at least until
the completion handler is called; ownership is not transferred.
@param handler The handler to be called when the request completes. @param handler The handler to be called when the operation
Copies will be made of the handler as required. The equivalent completes. Copies will be made of the handler as required.
function signature of the handler must be: The equivalent function signature of the handler must be:
@code void handler( @code void handler(
error_code const& error // result of operation error_code const& error // result of operation
); @endcode ); @endcode
@@ -141,7 +150,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
manner equivalent to using `boost::asio::io_service::post`. manner equivalent to using `boost::asio::io_service::post`.
*/ */
template<class AsyncReadStream, class DynamicBuffer, template<class AsyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class ReadHandler> class ReadHandler>
#if GENERATING_DOCS #if GENERATING_DOCS
void_or_deduced void_or_deduced
@@ -150,13 +159,13 @@ typename async_completion<
ReadHandler, void(error_code)>::result_type ReadHandler, void(error_code)>::result_type
#endif #endif
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
message_headers<isRequest, Headers>& msg, header<isRequest, Fields>& msg,
ReadHandler&& handler); ReadHandler&& handler);
/** Read a HTTP/1 message from a stream. /** Read a HTTP/1 message from a stream.
This function is used to synchronously read a message from This function is used to synchronously read a message from
the stream. The call blocks until one of the following conditions a stream. The call blocks until one of the following conditions
is true: is true:
@li A complete message is read in. @li A complete message is read in.
@@ -185,15 +194,15 @@ async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
@throws system_error Thrown on failure. @throws system_error Thrown on failure.
*/ */
template<class SyncReadStream, class DynamicBuffer, template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
void void
read(SyncReadStream& stream, DynamicBuffer& dynabuf, read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message<isRequest, Body, Headers>& msg); message<isRequest, Body, Fields>& msg);
/** Read a HTTP/1 message from a stream. /** Read a HTTP/1 message from a stream.
This function is used to synchronously read a message from This function is used to synchronously read a message from
the stream. The call blocks until one of the following conditions a stream. The call blocks until one of the following conditions
is true: is true:
@li A complete message is read in. @li A complete message is read in.
@@ -222,24 +231,25 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
@param ec Set to the error, if any occurred. @param ec Set to the error, if any occurred.
*/ */
template<class SyncReadStream, class DynamicBuffer, template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
void void
read(SyncReadStream& stream, DynamicBuffer& dynabuf, read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message<isRequest, Body, Headers>& msg, message<isRequest, Body, Fields>& msg,
error_code& ec); error_code& ec);
/** Start an asynchronous operation to read a HTTP/1 message from a stream. /** Read a HTTP/1 message asynchronously from a stream.
This function is used to asynchronously read a message from the This function is used to asynchronously read a message from
stream. The function call always returns immediately. The asynchronous a stream. The function call always returns immediately. The
operation will continue until one of the following conditions is true: asynchronous operation will continue until one of the following
conditions is true:
@li A complete message is read in. @li A complete message is read in.
@li An error occurs in the stream or parser. @li An error occurs in the stream or parser.
This operation is implemented in terms of one or more calls to 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 the stream's `async_read_some` function, and is known as a
<em>composed operation</em>. The program must ensure that the <em>composed operation</em>. The program must ensure that the
stream performs no other operations until this operation completes. stream performs no other operations until this operation completes.
The implementation may read additional octets that lie past the The implementation may read additional octets that lie past the
@@ -255,13 +265,14 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
stream buffer's input sequence will be given to the parser stream buffer's input sequence will be given to the parser
first. first.
@param msg An object used to store the message. Any contents @param msg An object used to store the header. Any contents
will be overwritten. The type must support copy assignment or will be overwritten. The type must support copy assignment or
move assignment. move assignment. The object must remain valid at least until
the completion handler is called; ownership is not transferred.
@param handler The handler to be called when the request completes. @param handler The handler to be called when the operation
Copies will be made of the handler as required. The equivalent completes. Copies will be made of the handler as required.
function signature of the handler must be: The equivalent function signature of the handler must be:
@code void handler( @code void handler(
error_code const& error // result of operation error_code const& error // result of operation
); @endcode ); @endcode
@@ -271,7 +282,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
manner equivalent to using `boost::asio::io_service::post`. manner equivalent to using `boost::asio::io_service::post`.
*/ */
template<class AsyncReadStream, class DynamicBuffer, template<class AsyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class ReadHandler> class ReadHandler>
#if GENERATING_DOCS #if GENERATING_DOCS
void_or_deduced void_or_deduced
@@ -280,7 +291,7 @@ typename async_completion<
ReadHandler, void(error_code)>::result_type ReadHandler, void(error_code)>::result_type
#endif #endif
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
message<isRequest, Body, Headers>& msg, message<isRequest, Body, Fields>& msg,
ReadHandler&& handler); ReadHandler&& handler);
} // http } // http

View File

@@ -11,7 +11,8 @@
namespace beast { namespace beast {
namespace http { namespace http {
/** Returns the text for a known status code integer. */ namespace detail {
template<class = void> template<class = void>
char const* char const*
reason_string(int status) reason_string(int status)
@@ -66,6 +67,16 @@ reason_string(int status)
return "<unknown-status>"; return "<unknown-status>";
} }
} // detail
/** Returns the text for a known status code integer. */
inline
char const*
reason_string(int status)
{
return detail::reason_string(status);
}
} // http } // http
} // beast } // beast

View File

@@ -8,9 +8,12 @@
#ifndef BEAST_HTTP_STRING_BODY_HPP #ifndef BEAST_HTTP_STRING_BODY_HPP
#define BEAST_HTTP_STRING_BODY_HPP #define BEAST_HTTP_STRING_BODY_HPP
#include <beast/http/body_type.hpp> #include <beast/core/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/resume_context.hpp>
#include <beast/core/detail/type_traits.hpp> #include <beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/logic/tribool.hpp>
#include <memory> #include <memory>
#include <string> #include <string>
@@ -35,10 +38,10 @@ private:
value_type& s_; value_type& s_;
public: public:
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, reader(message<isRequest,
string_body, Headers>& m) noexcept string_body, Fields>& m) noexcept
: s_(m.body) : s_(m.body)
{ {
} }
@@ -63,10 +66,10 @@ private:
value_type const& body_; value_type const& body_;
public: public:
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
explicit explicit
writer(message< writer(message<
isRequest, string_body, Headers> const& msg) noexcept isRequest, string_body, Fields> const& msg) noexcept
: body_(msg.body) : body_(msg.body)
{ {
} }

View File

@@ -17,94 +17,98 @@
namespace beast { namespace beast {
namespace http { namespace http {
/** Write HTTP/1 message headers on a stream. /** Write a HTTP/1 header to a stream.
This function is used to write message headers to a stream. The This function is used to synchronously write a header to
call will block until one of the following conditions is true: a stream. The call will block until one of the following
conditions is true:
@li All the message headers are sent. @li The entire header is written.
@li An error occurs. @li An error occurs.
This operation is implemented in terms of one or more calls This operation is implemented in terms of one or more calls
to the stream's `write_some` function. to the stream's `write_some` function.
Regardless of the semantic meaning of the headers (for example, Regardless of the semantic meaning of the header (for example,
specifying a zero-length message body and Connection: Close), specifying "Content-Length: 0" and "Connection: close"),
this function will not return `boost::asio::error::eof`. this function will not return `boost::asio::error::eof`.
@param stream The stream to which the data is to be written. @param stream The stream to which the data is to be written.
The type must support the @b `SyncWriteStream` concept. The type must support the @b `SyncWriteStream` concept.
@param msg The message headers to write. @param msg The header to write.
@throws system_error Thrown on failure. @throws system_error Thrown on failure.
*/ */
template<class SyncWriteStream, template<class SyncWriteStream,
bool isRequest, class Headers> bool isRequest, class Fields>
void void
write(SyncWriteStream& stream, write(SyncWriteStream& stream,
message_headers<isRequest, Headers> const& msg); header<isRequest, Fields> const& msg);
/** Write HTTP/1 message headers on a stream. /** Write a HTTP/1 header to a stream.
This function is used to write message headers to a stream. The This function is used to synchronously write a header to
call will block until one of the following conditions is true: a stream. The call will block until one of the following
conditions is true:
@li All the message headers are sent. @li The entire header is written.
@li An error occurs. @li An error occurs.
This operation is implemented in terms of one or more calls This operation is implemented in terms of one or more calls
to the stream's `write_some` function. to the stream's `write_some` function.
Regardless of the semantic meaning of the headers (for example, Regardless of the semantic meaning of the header (for example,
specifying a zero-length message body and Connection: Close), specifying "Content-Length: 0" and "Connection: close"),
this function will not return `boost::asio::error::eof`. this function will not return `boost::asio::error::eof`.
@param stream The stream to which the data is to be written. @param stream The stream to which the data is to be written.
The type must support the @b `SyncWriteStream` concept. The type must support the @b `SyncWriteStream` concept.
@param msg The message headers to write. @param msg The header to write.
@param ec Set to the error, if any occurred. @param ec Set to the error, if any occurred.
*/ */
template<class SyncWriteStream, template<class SyncWriteStream,
bool isRequest, class Headers> bool isRequest, class Fields>
void void
write(SyncWriteStream& stream, write(SyncWriteStream& stream,
message_headers<isRequest, Headers> const& msg, header<isRequest, Fields> const& msg,
error_code& ec); error_code& ec);
/** Start an asynchronous operation to write HTTP/1 message headers to a stream. /** Write a HTTP/1 header asynchronously to a stream.
This function is used to asynchronously write message headers to a stream. This function is used to asynchronously write a header to
The function call always returns immediately. The asynchronous a stream. The function call always returns immediately. The
operation will continue until one of the following conditions is true: asynchronous operation will continue until one of the following
conditions is true:
@li The entire message headers are sent. @li The entire header is written.
@li An error occurs. @li An error occurs.
This operation is implemented in terms of one or more calls to the This operation is implemented in terms of one or more calls to
stream's `async_write_some` functions, and is known as a <em>composed the stream's `async_write_some` functions, and is known as a
operation</em>. The program must ensure that the stream performs no <em>composed operation</em>. The program must ensure that the
other write operations (such as @ref async_write, the stream's stream performs no other write operations until this operation
`async_write_some` function, or any other composed operations that completes.
perform writes) until this operation completes.
Regardless of the semantic meaning of the headers (for example, Regardless of the semantic meaning of the header (for example,
specifying a zero-length message body and Connection: Close), specifying "Content-Length: 0" and "Connection: close"),
the handler will not be called with `boost::asio::error::eof`. this function will not return `boost::asio::error::eof`.
@param stream The stream to which the data is to be written. @param stream The stream to which the data is to be written.
The type must support the @b `AsyncWriteStream` concept. The type must support the @b `AsyncWriteStream` concept.
@param msg The message headers to send. @param msg The header to write. The object must remain valid
at least until the completion handler is called; ownership is
not transferred.
@param handler The handler to be called when the request completes. @param handler The handler to be called when the operation
Copies will be made of the handler as required. The equivalent completes. Copies will be made of the handler as required.
function signature of the handler must be: The equivalent function signature of the handler must be:
@code void handler( @code void handler(
error_code const& error // result of operation error_code const& error // result of operation
); @endcode ); @endcode
@@ -112,12 +116,9 @@ write(SyncWriteStream& stream,
immediately or not, the handler will not be invoked from within immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a 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 object must remain valid at least until the
completion handler is called, no copies are made.
*/ */
template<class AsyncWriteStream, template<class AsyncWriteStream,
bool isRequest, class Headers, bool isRequest, class Fields,
class WriteHandler> class WriteHandler>
#if GENERATING_DOCS #if GENERATING_DOCS
void_or_deduced void_or_deduced
@@ -126,17 +127,17 @@ typename async_completion<
WriteHandler, void(error_code)>::result_type WriteHandler, void(error_code)>::result_type
#endif #endif
async_write(AsyncWriteStream& stream, async_write(AsyncWriteStream& stream,
message_headers<isRequest, Headers> const& msg, header<isRequest, Fields> const& msg,
WriteHandler&& handler); WriteHandler&& handler);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Write a HTTP/1 message on a stream. /** Write a HTTP/1 message to a stream.
This function is used to write a message to a stream. The call This function is used to write a message to a stream. The call
will block until one of the following conditions is true: will block until one of the following conditions is true:
@li The entire message is sent. @li The entire message is written.
@li An error occurs. @li An error occurs.
@@ -157,17 +158,17 @@ async_write(AsyncWriteStream& stream,
@throws system_error Thrown on failure. @throws system_error Thrown on failure.
*/ */
template<class SyncWriteStream, template<class SyncWriteStream,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
void void
write(SyncWriteStream& stream, write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg); message<isRequest, Body, Fields> const& msg);
/** Write a HTTP/1 message on a stream. /** Write a HTTP/1 message on a stream.
This function is used to write a message to a stream. The call This function is used to write a message to a stream. The call
will block until one of the following conditions is true: will block until one of the following conditions is true:
@li The entire message is sent. @li The entire message is written.
@li An error occurs. @li An error occurs.
@@ -188,28 +189,28 @@ write(SyncWriteStream& stream,
@param ec Set to the error, if any occurred. @param ec Set to the error, if any occurred.
*/ */
template<class SyncWriteStream, template<class SyncWriteStream,
bool isRequest, class Body, class Headers> bool isRequest, class Body, class Fields>
void void
write(SyncWriteStream& stream, write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg, message<isRequest, Body, Fields> const& msg,
error_code& ec); error_code& ec);
/** Start an asynchronous operation to write a HTTP/1 message to a stream. /** Write a HTTP/1 message asynchronously to a stream.
This function is used to asynchronously write a message to a stream. This function is used to asynchronously write a message to
The function call always returns immediately. The asynchronous a stream. The function call always returns immediately. The
operation will continue until one of the following conditions is true: asynchronous operation will continue until one of the following
conditions is true:
@li The entire message is sent. @li The entire message is written.
@li An error occurs. @li An error occurs.
This operation is implemented in terms of one or more calls to the This operation is implemented in terms of one or more calls to
stream's `async_write_some` functions, and is known as a <em>composed the stream's `async_write_some` functions, and is known as a
operation</em>. The program must ensure that the stream performs no <em>composed operation</em>. The program must ensure that the
other write operations (such as @ref async_write, the stream's stream performs no other write operations until this operation
`async_write_some` function, or any other composed operations that completes.
perform writes) until this operation completes.
The implementation will automatically perform chunk encoding if The implementation will automatically perform chunk encoding if
the contents of the message indicate that chunk encoding is required. the contents of the message indicate that chunk encoding is required.
@@ -220,11 +221,13 @@ write(SyncWriteStream& stream,
@param stream The stream to which the data is to be written. @param stream The stream to which the data is to be written.
The type must support the @b `AsyncWriteStream` concept. The type must support the @b `AsyncWriteStream` concept.
@param msg The message to send. @param msg The message to write. The object must remain valid
at least until the completion handler is called; ownership is
not transferred.
@param handler The handler to be called when the request completes. @param handler The handler to be called when the operation
Copies will be made of the handler as required. The equivalent completes. Copies will be made of the handler as required.
function signature of the handler must be: The equivalent function signature of the handler must be:
@code void handler( @code void handler(
error_code const& error // result of operation error_code const& error // result of operation
); @endcode ); @endcode
@@ -232,12 +235,9 @@ write(SyncWriteStream& stream,
immediately or not, the handler will not be invoked from within immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a 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 object must remain valid at least until the
completion handler is called, no copies are made.
*/ */
template<class AsyncWriteStream, template<class AsyncWriteStream,
bool isRequest, class Body, class Headers, bool isRequest, class Body, class Fields,
class WriteHandler> class WriteHandler>
#if GENERATING_DOCS #if GENERATING_DOCS
void_or_deduced void_or_deduced
@@ -246,25 +246,24 @@ typename async_completion<
WriteHandler, void(error_code)>::result_type WriteHandler, void(error_code)>::result_type
#endif #endif
async_write(AsyncWriteStream& stream, async_write(AsyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg, message<isRequest, Body, Fields> const& msg,
WriteHandler&& handler); WriteHandler&& handler);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Serialize HTTP/1 message headers to a `std::ostream`. /** Serialize a HTTP/1 header to a `std::ostream`.
The function converts the message headers to its HTTP/1 The function converts the header to its HTTP/1 serialized
serialized representation and stores the result in the output representation and stores the result in the output stream.
stream.
@param os The output stream to write to. @param os The output stream to write to.
@param msg The message headers to write. @param msg The message fields to write.
*/ */
template<bool isRequest, class Headers> template<bool isRequest, class Fields>
std::ostream& std::ostream&
operator<<(std::ostream& os, operator<<(std::ostream& os,
message_headers<isRequest, Headers> const& msg); header<isRequest, Fields> const& msg);
/** Serialize a HTTP/1 message to a `std::ostream`. /** Serialize a HTTP/1 message to a `std::ostream`.
@@ -278,10 +277,10 @@ operator<<(std::ostream& os,
@param msg The message to write. @param msg The message to write.
*/ */
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
std::ostream& std::ostream&
operator<<(std::ostream& os, operator<<(std::ostream& os,
message<isRequest, Body, Headers> const& msg); message<isRequest, Body, Fields> const& msg);
} // http } // http
} // beast } // beast

View File

@@ -102,7 +102,7 @@ private:
void void
operator()(request_type& req, std::false_type) operator()(request_type& req, std::false_type)
{ {
req.headers.replace("User-Agent", req.fields.replace("User-Agent",
std::string{"Beast/"} + BEAST_VERSION_STRING); std::string{"Beast/"} + BEAST_VERSION_STRING);
} }
@@ -115,7 +115,7 @@ private:
void void
operator()(response_type& res, std::false_type) operator()(response_type& res, std::false_type)
{ {
res.headers.replace("Server", res.fields.replace("Server",
std::string{"Beast/"} + BEAST_VERSION_STRING); std::string{"Beast/"} + BEAST_VERSION_STRING);
} }
}; };

View File

@@ -43,9 +43,9 @@ class stream<NextLayer>::response_op
int state = 0; int state = 0;
template<class DeducedHandler, template<class DeducedHandler,
class Body, class Headers> class Body, class Fields>
data(DeducedHandler&& h_, stream<NextLayer>& ws_, data(DeducedHandler&& h_, stream<NextLayer>& ws_,
http::request<Body, Headers> const& req, http::request<Body, Fields> const& req,
bool cont_) bool cont_)
: ws(ws_) : ws(ws_)
, resp(ws_.build_response(req)) , resp(ws_.build_response(req))
@@ -305,11 +305,11 @@ async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler)
} }
template<class NextLayer> template<class NextLayer>
template<class Body, class Headers, class AcceptHandler> template<class Body, class Fields, class AcceptHandler>
typename async_completion< typename async_completion<
AcceptHandler, void(error_code)>::result_type AcceptHandler, void(error_code)>::result_type
stream<NextLayer>:: stream<NextLayer>::
async_accept(http::request<Body, Headers> const& req, async_accept(http::request<Body, Fields> const& req,
AcceptHandler&& handler) AcceptHandler&& handler)
{ {
static_assert(is_AsyncStream<next_layer_type>::value, static_assert(is_AsyncStream<next_layer_type>::value,
@@ -390,10 +390,10 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
} }
template<class NextLayer> template<class NextLayer>
template<class Body, class Headers> template<class Body, class Fields>
void void
stream<NextLayer>:: stream<NextLayer>::
accept(http::request<Body, Headers> const& request) accept(http::request<Body, Fields> const& request)
{ {
static_assert(is_SyncStream<next_layer_type>::value, static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met"); "SyncStream requirements not met");
@@ -404,10 +404,10 @@ accept(http::request<Body, Headers> const& request)
} }
template<class NextLayer> template<class NextLayer>
template<class Body, class Headers> template<class Body, class Fields>
void void
stream<NextLayer>:: stream<NextLayer>::
accept(http::request<Body, Headers> const& req, accept(http::request<Body, Fields> const& req,
error_code& ec) error_code& ec)
{ {
static_assert(is_SyncStream<next_layer_type>::value, static_assert(is_SyncStream<next_layer_type>::value,

View File

@@ -66,21 +66,21 @@ build_request(boost::string_ref const& host,
req.url = { resource.data(), resource.size() }; req.url = { resource.data(), resource.size() };
req.version = 11; req.version = 11;
req.method = "GET"; req.method = "GET";
req.headers.insert("Host", host); req.fields.insert("Host", host);
req.headers.insert("Upgrade", "websocket"); req.fields.insert("Upgrade", "websocket");
key = detail::make_sec_ws_key(maskgen_); key = detail::make_sec_ws_key(maskgen_);
req.headers.insert("Sec-WebSocket-Key", key); req.fields.insert("Sec-WebSocket-Key", key);
req.headers.insert("Sec-WebSocket-Version", "13"); req.fields.insert("Sec-WebSocket-Version", "13");
(*d_)(req); (*d_)(req);
http::prepare(req, http::connection::upgrade); http::prepare(req, http::connection::upgrade);
return req; return req;
} }
template<class NextLayer> template<class NextLayer>
template<class Body, class Headers> template<class Body, class Fields>
http::response<http::string_body> http::response<http::string_body>
stream<NextLayer>:: stream<NextLayer>::
build_response(http::request<Body, Headers> const& req) build_response(http::request<Body, Fields> const& req)
{ {
auto err = auto err =
[&](std::string const& text) [&](std::string const& text)
@@ -103,15 +103,15 @@ build_response(http::request<Body, Headers> const& req)
return err("Wrong method"); return err("Wrong method");
if(! is_upgrade(req)) if(! is_upgrade(req))
return err("Expected Upgrade request"); return err("Expected Upgrade request");
if(! req.headers.exists("Host")) if(! req.fields.exists("Host"))
return err("Missing Host"); return err("Missing Host");
if(! req.headers.exists("Sec-WebSocket-Key")) if(! req.fields.exists("Sec-WebSocket-Key"))
return err("Missing Sec-WebSocket-Key"); return err("Missing Sec-WebSocket-Key");
if(! http::token_list{req.headers["Upgrade"]}.exists("websocket")) if(! http::token_list{req.fields["Upgrade"]}.exists("websocket"))
return err("Missing websocket Upgrade token"); return err("Missing websocket Upgrade token");
{ {
auto const version = auto const version =
req.headers["Sec-WebSocket-Version"]; req.fields["Sec-WebSocket-Version"];
if(version.empty()) if(version.empty())
return err("Missing Sec-WebSocket-Version"); return err("Missing Sec-WebSocket-Version");
if(version != "13") if(version != "13")
@@ -120,7 +120,7 @@ build_response(http::request<Body, Headers> const& req)
res.status = 426; res.status = 426;
res.reason = http::reason_string(res.status); res.reason = http::reason_string(res.status);
res.version = req.version; res.version = req.version;
res.headers.insert("Sec-WebSocket-Version", "13"); res.fields.insert("Sec-WebSocket-Version", "13");
prepare(res, prepare(res,
(is_keep_alive(req) && keep_alive_) ? (is_keep_alive(req) && keep_alive_) ?
http::connection::keep_alive : http::connection::keep_alive :
@@ -132,24 +132,24 @@ build_response(http::request<Body, Headers> const& req)
res.status = 101; res.status = 101;
res.reason = http::reason_string(res.status); res.reason = http::reason_string(res.status);
res.version = req.version; res.version = req.version;
res.headers.insert("Upgrade", "websocket"); res.fields.insert("Upgrade", "websocket");
{ {
auto const key = auto const key =
req.headers["Sec-WebSocket-Key"]; req.fields["Sec-WebSocket-Key"];
res.headers.insert("Sec-WebSocket-Accept", res.fields.insert("Sec-WebSocket-Accept",
detail::make_sec_ws_accept(key)); detail::make_sec_ws_accept(key));
} }
res.headers.replace("Server", "Beast.WSProto"); res.fields.replace("Server", "Beast.WSProto");
(*d_)(res); (*d_)(res);
http::prepare(res, http::connection::upgrade); http::prepare(res, http::connection::upgrade);
return res; return res;
} }
template<class NextLayer> template<class NextLayer>
template<class Body, class Headers> template<class Body, class Fields>
void void
stream<NextLayer>:: stream<NextLayer>::
do_response(http::response<Body, Headers> const& res, do_response(http::response<Body, Fields> const& res,
boost::string_ref const& key, error_code& ec) boost::string_ref const& key, error_code& ec)
{ {
// VFALCO Review these error codes // VFALCO Review these error codes
@@ -160,11 +160,11 @@ do_response(http::response<Body, Headers> const& res,
return fail(); return fail();
if(! is_upgrade(res)) if(! is_upgrade(res))
return fail(); return fail();
if(! http::token_list{res.headers["Upgrade"]}.exists("websocket")) if(! http::token_list{res.fields["Upgrade"]}.exists("websocket"))
return fail(); return fail();
if(! res.headers.exists("Sec-WebSocket-Accept")) if(! res.fields.exists("Sec-WebSocket-Accept"))
return fail(); return fail();
if(res.headers["Sec-WebSocket-Accept"] != if(res.fields["Sec-WebSocket-Accept"] !=
detail::make_sec_ws_accept(key)) detail::make_sec_ws_accept(key))
return fail(); return fail();
open(detail::role_type::client); open(detail::role_type::client);

View File

@@ -86,14 +86,14 @@ struct auto_fragment
@code @code
struct identity struct identity
{ {
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
void void
operator()(http::message<isRequest, Body, Headers>& m) operator()(http::message<isRequest, Body, Fields>& m)
{ {
if(isRequest) if(isRequest)
m.headers.replace("User-Agent", "MyClient"); m.fields.replace("User-Agent", "MyClient");
else else
m.headers.replace("Server", "MyServer"); m.fields.replace("Server", "MyServer");
} }
}; };
... ...
@@ -284,7 +284,7 @@ struct read_buffer_size
/** Maximum incoming message size option. /** Maximum incoming message size option.
Sets the largest permissible incoming message size. Message Sets the largest permissible incoming message size. Message
frame headers indicating a size that would bring the total frame fields indicating a size that would bring the total
message size over this limit will cause a protocol failure. message size over this limit will cause a protocol failure.
The default setting is 16 megabytes. A value of zero indicates The default setting is 16 megabytes. A value of zero indicates

View File

@@ -583,9 +583,9 @@ public:
@throws system_error Thrown on failure. @throws system_error Thrown on failure.
*/ */
// VFALCO TODO This should also take a DynamicBuffer with any leftover bytes. // VFALCO TODO This should also take a DynamicBuffer with any leftover bytes.
template<class Body, class Headers> template<class Body, class Fields>
void void
accept(http::request<Body, Headers> const& request); accept(http::request<Body, Fields> const& request);
/** Respond to a WebSocket HTTP Upgrade request /** Respond to a WebSocket HTTP Upgrade request
@@ -615,9 +615,9 @@ public:
@param ec Set to indicate what error occurred, if any. @param ec Set to indicate what error occurred, if any.
*/ */
template<class Body, class Headers> template<class Body, class Fields>
void void
accept(http::request<Body, Headers> const& request, accept(http::request<Body, Fields> const& request,
error_code& ec); error_code& ec);
/** Start responding to a WebSocket HTTP Upgrade request. /** Start responding to a WebSocket HTTP Upgrade request.
@@ -661,14 +661,14 @@ public:
this function. Invocation of the handler will be performed in a 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 Body, class Headers, class AcceptHandler> template<class Body, class Fields, class AcceptHandler>
#if GENERATING_DOCS #if GENERATING_DOCS
void_or_deduced void_or_deduced
#else #else
typename async_completion< typename async_completion<
AcceptHandler, void(error_code)>::result_type AcceptHandler, void(error_code)>::result_type
#endif #endif
async_accept(http::request<Body, Headers> const& request, async_accept(http::request<Body, Fields> const& request,
AcceptHandler&& handler); AcceptHandler&& handler);
/** Send a HTTP WebSocket Upgrade request and receive the response. /** Send a HTTP WebSocket Upgrade request and receive the response.
@@ -1627,13 +1627,13 @@ private:
boost::string_ref const& resource, boost::string_ref const& resource,
std::string& key); std::string& key);
template<class Body, class Headers> template<class Body, class Fields>
http::response<http::string_body> http::response<http::string_body>
build_response(http::request<Body, Headers> const& req); build_response(http::request<Body, Fields> const& req);
template<class Body, class Headers> template<class Body, class Fields>
void void
do_response(http::response<Body, Headers> const& resp, do_response(http::response<Body, Fields> const& resp,
boost::string_ref const& key, error_code& ec); boost::string_ref const& key, error_code& ec);
void void

View File

@@ -43,13 +43,12 @@ unit-test core-tests :
unit-test http-tests : unit-test http-tests :
../extras/beast/unit_test/main.cpp ../extras/beast/unit_test/main.cpp
http/basic_dynabuf_body.cpp http/basic_dynabuf_body.cpp
http/basic_headers.cpp http/basic_fields.cpp
http/basic_parser_v1.cpp http/basic_parser_v1.cpp
http/body_type.cpp
http/concepts.cpp http/concepts.cpp
http/empty_body.cpp http/empty_body.cpp
http/headers.cpp http/fields.cpp
http/headers_parser_v1.cpp http/header_parser_v1.cpp
http/message.cpp http/message.cpp
http/parse.cpp http/parse.cpp
http/parse_error.cpp http/parse_error.cpp

View File

@@ -11,13 +11,12 @@ add_executable (http-tests
fail_parser.hpp fail_parser.hpp
../../extras/beast/unit_test/main.cpp ../../extras/beast/unit_test/main.cpp
basic_dynabuf_body.cpp basic_dynabuf_body.cpp
basic_headers.cpp basic_fields.cpp
basic_parser_v1.cpp basic_parser_v1.cpp
body_type.cpp
concepts.cpp concepts.cpp
empty_body.cpp empty_body.cpp
headers.cpp fields.cpp
headers_parser_v1.cpp header_parser_v1.cpp
message.cpp message.cpp
parse.cpp parse.cpp
parse_error.cpp parse_error.cpp

View File

@@ -6,7 +6,7 @@
// //
// Test that header file is self-contained. // Test that header file is self-contained.
#include <beast/http/basic_headers.hpp> #include <beast/http/basic_fields.hpp>
#include <beast/unit_test/suite.hpp> #include <beast/unit_test/suite.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
@@ -14,18 +14,18 @@
namespace beast { namespace beast {
namespace http { namespace http {
class basic_headers_test : public beast::unit_test::suite class basic_fields_test : public beast::unit_test::suite
{ {
public: public:
template<class Allocator> template<class Allocator>
using bha = basic_headers<Allocator>; using bha = basic_fields<Allocator>;
using bh = basic_headers<std::allocator<char>>; using bh = basic_fields<std::allocator<char>>;
template<class Allocator> template<class Allocator>
static static
void void
fill(std::size_t n, basic_headers<Allocator>& h) fill(std::size_t n, basic_fields<Allocator>& h)
{ {
for(std::size_t i = 1; i<= n; ++i) for(std::size_t i = 1; i<= n; ++i)
h.insert(boost::lexical_cast<std::string>(i), i); h.insert(boost::lexical_cast<std::string>(i), i);
@@ -90,7 +90,7 @@ public:
} }
}; };
BEAST_DEFINE_TESTSUITE(basic_headers,http,beast); BEAST_DEFINE_TESTSUITE(basic_fields,http,beast);
} // http } // http
} // beast } // beast

View File

@@ -51,7 +51,7 @@ public:
bool start = false; bool start = false;
bool field = false; bool field = false;
bool value = false; bool value = false;
bool headers = false; bool fields = false;
bool _body_what = false; bool _body_what = false;
bool body = false; bool body = false;
bool complete = false; bool complete = false;
@@ -92,9 +92,9 @@ public:
value = true; value = true;
} }
void void
on_headers(std::uint64_t, error_code&) on_header(std::uint64_t, error_code&)
{ {
headers = true; fields = true;
} }
body_what body_what
on_body_what(std::uint64_t, error_code&) on_body_what(std::uint64_t, error_code&)
@@ -135,7 +135,7 @@ public:
BEAST_EXPECT(p.request); BEAST_EXPECT(p.request);
BEAST_EXPECT(p.field); BEAST_EXPECT(p.field);
BEAST_EXPECT(p.value); BEAST_EXPECT(p.value);
BEAST_EXPECT(p.headers); BEAST_EXPECT(p.fields);
BEAST_EXPECT(p._body_what); BEAST_EXPECT(p._body_what);
BEAST_EXPECT(p.body); BEAST_EXPECT(p.body);
BEAST_EXPECT(p.complete); BEAST_EXPECT(p.complete);
@@ -158,7 +158,7 @@ public:
BEAST_EXPECT(p.response); BEAST_EXPECT(p.response);
BEAST_EXPECT(p.field); BEAST_EXPECT(p.field);
BEAST_EXPECT(p.value); BEAST_EXPECT(p.value);
BEAST_EXPECT(p.headers); BEAST_EXPECT(p.fields);
BEAST_EXPECT(p.body); BEAST_EXPECT(p.body);
BEAST_EXPECT(p.complete); BEAST_EXPECT(p.complete);
} }
@@ -1104,7 +1104,7 @@ public:
{ {
test::fail_counter fc(1000); test::fail_counter fc(1000);
fail_parser<true> p(fc); fail_parser<true> p(fc);
p.set_option(headers_max_size{n}); p.set_option(header_max_size{n});
error_code ec; error_code ec;
p.write(buf( p.write(buf(
"GET / HTTP/1.1\r\n" "GET / HTTP/1.1\r\n"
@@ -1113,7 +1113,7 @@ public:
), ec); ), ec);
if(! ec) if(! ec)
break; break;
BEAST_EXPECT(ec == parse_error::headers_too_big); BEAST_EXPECT(ec == parse_error::header_too_big);
} }
BEAST_EXPECT(n < Limit); BEAST_EXPECT(n < Limit);
} }
@@ -1122,7 +1122,7 @@ public:
{ {
test::fail_counter fc(1000); test::fail_counter fc(1000);
fail_parser<false> p(fc); fail_parser<false> p(fc);
p.set_option(headers_max_size{n}); p.set_option(header_max_size{n});
error_code ec; error_code ec;
p.write(buf( p.write(buf(
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
@@ -1133,7 +1133,7 @@ public:
), ec); ), ec);
if(! ec) if(! ec)
break; break;
BEAST_EXPECT(ec == parse_error::headers_too_big); BEAST_EXPECT(ec == parse_error::header_too_big);
} }
BEAST_EXPECT(n < Limit); BEAST_EXPECT(n < Limit);
} }

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

View File

@@ -86,7 +86,7 @@ public:
} }
void void
on_headers(std::uint64_t content_length, error_code& ec) on_header(std::uint64_t content_length, error_code& ec)
{ {
if(fc_.fail(ec)) if(fc_.fail(ec))
return; return;

View File

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

View File

@@ -6,23 +6,23 @@
// //
// Test that header file is self-contained. // Test that header file is self-contained.
#include <beast/http/headers_parser_v1.hpp> #include <beast/http/header_parser_v1.hpp>
#include <beast/http/headers.hpp> #include <beast/http/fields.hpp>
#include <beast/unit_test/suite.hpp> #include <beast/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
namespace beast { namespace beast {
namespace http { namespace http {
class headers_parser_v1_test : public beast::unit_test::suite class header_parser_v1_test : public beast::unit_test::suite
{ {
public: public:
void testParser() void testParser()
{ {
{ {
error_code ec; error_code ec;
headers_parser_v1<true, headers> p; header_parser_v1<true, fields> p;
BEAST_EXPECT(! p.complete()); BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer( auto const n = p.write(boost::asio::buffer(
"GET / HTTP/1.1\r\n" "GET / HTTP/1.1\r\n"
@@ -35,7 +35,7 @@ public:
} }
{ {
error_code ec; error_code ec;
headers_parser_v1<true, headers> p; header_parser_v1<true, fields> p;
BEAST_EXPECT(! p.complete()); BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer( auto const n = p.write(boost::asio::buffer(
"GET / HTTP/1.1\r\n" "GET / HTTP/1.1\r\n"
@@ -50,7 +50,7 @@ public:
} }
{ {
error_code ec; error_code ec;
headers_parser_v1<false, headers> p; header_parser_v1<false, fields> p;
BEAST_EXPECT(! p.complete()); BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer( auto const n = p.write(boost::asio::buffer(
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
@@ -63,7 +63,7 @@ public:
} }
{ {
error_code ec; error_code ec;
headers_parser_v1<false, headers> p; header_parser_v1<false, fields> p;
BEAST_EXPECT(! p.complete()); BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer( auto const n = p.write(boost::asio::buffer(
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
@@ -84,7 +84,7 @@ public:
} }
}; };
BEAST_DEFINE_TESTSUITE(headers_parser_v1,http,beast); BEAST_DEFINE_TESTSUITE(header_parser_v1,http,beast);
} // http } // http
} // beast } // beast

View File

@@ -9,7 +9,7 @@
#include <beast/http/message.hpp> #include <beast/http/message.hpp>
#include <beast/http/empty_body.hpp> #include <beast/http/empty_body.hpp>
#include <beast/http/headers.hpp> #include <beast/http/fields.hpp>
#include <beast/http/string_body.hpp> #include <beast/http/string_body.hpp>
#include <beast/unit_test/suite.hpp> #include <beast/unit_test/suite.hpp>
#include <type_traits> #include <type_traits>
@@ -73,66 +73,66 @@ public:
void testMessage() void testMessage()
{ {
static_assert(std::is_constructible< static_assert(std::is_constructible<
message<true, default_body, headers>>::value, ""); message<true, default_body, fields>>::value, "");
static_assert(std::is_constructible< static_assert(std::is_constructible<
message<true, one_arg_body, headers>, Arg1>::value, ""); message<true, one_arg_body, fields>, Arg1>::value, "");
static_assert(std::is_constructible< static_assert(std::is_constructible<
message<true, one_arg_body, headers>, Arg1 const>::value, ""); message<true, one_arg_body, fields>, Arg1 const>::value, "");
static_assert(std::is_constructible< static_assert(std::is_constructible<
message<true, one_arg_body, headers>, Arg1 const&>::value, ""); message<true, one_arg_body, fields>, Arg1 const&>::value, "");
static_assert(std::is_constructible< static_assert(std::is_constructible<
message<true, one_arg_body, headers>, Arg1&&>::value, ""); message<true, one_arg_body, fields>, Arg1&&>::value, "");
static_assert(! std::is_constructible< static_assert(! std::is_constructible<
message<true, one_arg_body, headers>>::value, ""); message<true, one_arg_body, fields>>::value, "");
static_assert(std::is_constructible< static_assert(std::is_constructible<
message<true, one_arg_body, headers>, message<true, one_arg_body, fields>,
Arg1, headers::allocator_type>::value, ""); Arg1, fields::allocator_type>::value, "");
static_assert(std::is_constructible< static_assert(std::is_constructible<
message<true, one_arg_body, headers>, std::piecewise_construct_t, message<true, one_arg_body, fields>, std::piecewise_construct_t,
std::tuple<Arg1>>::value, ""); std::tuple<Arg1>>::value, "");
static_assert(std::is_constructible< static_assert(std::is_constructible<
message<true, two_arg_body, headers>, std::piecewise_construct_t, message<true, two_arg_body, fields>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>>::value, ""); std::tuple<Arg1, Arg2>>::value, "");
static_assert(std::is_constructible< static_assert(std::is_constructible<
message<true, two_arg_body, headers>, std::piecewise_construct_t, message<true, two_arg_body, fields>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>, std::tuple<headers::allocator_type>>::value, ""); std::tuple<Arg1, Arg2>, std::tuple<fields::allocator_type>>::value, "");
{ {
Arg1 arg1; Arg1 arg1;
message<true, one_arg_body, headers>{std::move(arg1)}; message<true, one_arg_body, fields>{std::move(arg1)};
BEAST_EXPECT(arg1.moved); BEAST_EXPECT(arg1.moved);
} }
{ {
headers h; fields h;
h.insert("User-Agent", "test"); h.insert("User-Agent", "test");
message<true, one_arg_body, headers> m{Arg1{}, h}; message<true, one_arg_body, fields> m{Arg1{}, h};
BEAST_EXPECT(h["User-Agent"] == "test"); BEAST_EXPECT(h["User-Agent"] == "test");
BEAST_EXPECT(m.headers["User-Agent"] == "test"); BEAST_EXPECT(m.fields["User-Agent"] == "test");
} }
{ {
headers h; fields h;
h.insert("User-Agent", "test"); h.insert("User-Agent", "test");
message<true, one_arg_body, headers> m{Arg1{}, std::move(h)}; message<true, one_arg_body, fields> m{Arg1{}, std::move(h)};
BEAST_EXPECT(! h.exists("User-Agent")); BEAST_EXPECT(! h.exists("User-Agent"));
BEAST_EXPECT(m.headers["User-Agent"] == "test"); BEAST_EXPECT(m.fields["User-Agent"] == "test");
} }
// swap // swap
message<true, string_body, headers> m1; message<true, string_body, fields> m1;
message<true, string_body, headers> m2; message<true, string_body, fields> m2;
m1.url = "u"; m1.url = "u";
m1.body = "1"; m1.body = "1";
m1.headers.insert("h", "v"); m1.fields.insert("h", "v");
m2.method = "G"; m2.method = "G";
m2.body = "2"; m2.body = "2";
swap(m1, m2); swap(m1, m2);
@@ -142,8 +142,8 @@ public:
BEAST_EXPECT(m2.url == "u"); BEAST_EXPECT(m2.url == "u");
BEAST_EXPECT(m1.body == "2"); BEAST_EXPECT(m1.body == "2");
BEAST_EXPECT(m2.body == "1"); BEAST_EXPECT(m2.body == "1");
BEAST_EXPECT(! m1.headers.exists("h")); BEAST_EXPECT(! m1.fields.exists("h"));
BEAST_EXPECT(m2.headers.exists("h")); BEAST_EXPECT(m2.fields.exists("h"));
} }
struct MoveHeaders struct MoveHeaders
@@ -168,13 +168,13 @@ public:
void testHeaders() void testHeaders()
{ {
{ {
using req_type = request_headers; using req_type = request_header;
static_assert(std::is_copy_constructible<req_type>::value, ""); static_assert(std::is_copy_constructible<req_type>::value, "");
static_assert(std::is_move_constructible<req_type>::value, ""); static_assert(std::is_move_constructible<req_type>::value, "");
static_assert(std::is_copy_assignable<req_type>::value, ""); static_assert(std::is_copy_assignable<req_type>::value, "");
static_assert(std::is_move_assignable<req_type>::value, ""); static_assert(std::is_move_assignable<req_type>::value, "");
using res_type = response_headers; using res_type = response_header;
static_assert(std::is_copy_constructible<res_type>::value, ""); static_assert(std::is_copy_constructible<res_type>::value, "");
static_assert(std::is_move_constructible<res_type>::value, ""); static_assert(std::is_move_constructible<res_type>::value, "");
static_assert(std::is_copy_assignable<res_type>::value, ""); static_assert(std::is_copy_assignable<res_type>::value, "");
@@ -183,12 +183,12 @@ public:
{ {
MoveHeaders h; MoveHeaders h;
message_headers<true, MoveHeaders> r{std::move(h)}; header<true, MoveHeaders> r{std::move(h)};
BEAST_EXPECT(h.moved_from); BEAST_EXPECT(h.moved_from);
BEAST_EXPECT(r.headers.moved_to); BEAST_EXPECT(r.fields.moved_to);
request<string_body, MoveHeaders> m{std::move(r)}; request<string_body, MoveHeaders> m{std::move(r)};
BEAST_EXPECT(r.headers.moved_from); BEAST_EXPECT(r.fields.moved_from);
BEAST_EXPECT(m.headers.moved_to); BEAST_EXPECT(m.fields.moved_to);
} }
} }
@@ -199,12 +199,12 @@ public:
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 11; m.version = 11;
m.headers.insert("Upgrade", "test"); m.fields.insert("Upgrade", "test");
BEAST_EXPECT(! is_upgrade(m)); BEAST_EXPECT(! is_upgrade(m));
prepare(m, connection::upgrade); prepare(m, connection::upgrade);
BEAST_EXPECT(is_upgrade(m)); BEAST_EXPECT(is_upgrade(m));
BEAST_EXPECT(m.headers["Connection"] == "upgrade"); BEAST_EXPECT(m.fields["Connection"] == "upgrade");
m.version = 10; m.version = 10;
BEAST_EXPECT(! is_upgrade(m)); BEAST_EXPECT(! is_upgrade(m));
@@ -216,7 +216,7 @@ public:
request<empty_body> m; request<empty_body> m;
m.version = 10; m.version = 10;
BEAST_EXPECT(! is_upgrade(m)); BEAST_EXPECT(! is_upgrade(m));
m.headers.insert("Transfer-Encoding", "chunked"); m.fields.insert("Transfer-Encoding", "chunked");
try try
{ {
prepare(m); prepare(m);
@@ -225,8 +225,8 @@ public:
catch(std::exception const&) catch(std::exception const&)
{ {
} }
m.headers.erase("Transfer-Encoding"); m.fields.erase("Transfer-Encoding");
m.headers.insert("Content-Length", "0"); m.fields.insert("Content-Length", "0");
try try
{ {
prepare(m); prepare(m);
@@ -236,8 +236,8 @@ public:
{ {
pass(); pass();
} }
m.headers.erase("Content-Length"); m.fields.erase("Content-Length");
m.headers.insert("Connection", "keep-alive"); m.fields.insert("Connection", "keep-alive");
try try
{ {
prepare(m); prepare(m);
@@ -248,19 +248,19 @@ public:
pass(); pass();
} }
m.version = 11; m.version = 11;
m.headers.erase("Connection"); m.fields.erase("Connection");
m.headers.insert("Connection", "close"); m.fields.insert("Connection", "close");
BEAST_EXPECT(! is_keep_alive(m)); BEAST_EXPECT(! is_keep_alive(m));
} }
void testSwap() void testSwap()
{ {
message<false, string_body, headers> m1; message<false, string_body, fields> m1;
message<false, string_body, headers> m2; message<false, string_body, fields> m2;
m1.status = 200; m1.status = 200;
m1.version = 10; m1.version = 10;
m1.body = "1"; m1.body = "1";
m1.headers.insert("h", "v"); m1.fields.insert("h", "v");
m2.status = 404; m2.status = 404;
m2.reason = "OK"; m2.reason = "OK";
m2.body = "2"; m2.body = "2";
@@ -274,8 +274,8 @@ public:
BEAST_EXPECT(m2.version == 10); BEAST_EXPECT(m2.version == 10);
BEAST_EXPECT(m1.body == "2"); BEAST_EXPECT(m1.body == "2");
BEAST_EXPECT(m2.body == "1"); BEAST_EXPECT(m2.body == "1");
BEAST_EXPECT(! m1.headers.exists("h")); BEAST_EXPECT(! m1.fields.exists("h"));
BEAST_EXPECT(m2.headers.exists("h")); BEAST_EXPECT(m2.fields.exists("h"));
} }
void run() override void run() override

View File

@@ -475,7 +475,7 @@ public:
template<class DynamicBuffer> template<class DynamicBuffer>
void void
headers(DynamicBuffer& db) fields(DynamicBuffer& db)
{ {
while(rand(6)) while(rand(6))
{ {
@@ -536,7 +536,7 @@ public:
request(DynamicBuffer& db) request(DynamicBuffer& db)
{ {
write(db, method(), " ", uri(), " HTTP/1.1\r\n"); write(db, method(), " ", uri(), " HTTP/1.1\r\n");
headers(db); fields(db);
body(db); body(db);
} }
@@ -549,7 +549,7 @@ public:
write(db, " ", 100 + rand(401), " "); write(db, " ", 100 + rand(401), " ");
write(db, token()); write(db, token());
write(db, "\r\n"); write(db, "\r\n");
headers(db); fields(db);
body(db); body(db);
write(db, "\r\n"); write(db, "\r\n");
} }

View File

@@ -736,12 +736,12 @@ nodejs_basic_parser<Derived>::cb_chunk_complete(http_parser*)
The parser may only be used once. The parser may only be used once.
*/ */
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
class nodejs_parser class nodejs_parser
: public nodejs_basic_parser<nodejs_parser<isRequest, Body, Headers>> : public nodejs_basic_parser<nodejs_parser<isRequest, Body, Fields>>
{ {
using message_type = using message_type =
message<isRequest, Body, Headers>; message<isRequest, Body, Fields>;
message_type m_; message_type m_;
typename message_type::body_type::reader r_; typename message_type::body_type::reader r_;
@@ -781,7 +781,7 @@ private:
void void
on_field(std::string const& field, std::string const& value) on_field(std::string const& field, std::string const& value)
{ {
m_.headers.insert(field, value); m_.fields.insert(field, value);
} }
void void

View File

@@ -48,7 +48,7 @@ public:
check("http", parse_error::invalid_chunk_size); check("http", parse_error::invalid_chunk_size);
check("http", parse_error::invalid_ext_name); check("http", parse_error::invalid_ext_name);
check("http", parse_error::invalid_ext_val); check("http", parse_error::invalid_ext_val);
check("http", parse_error::headers_too_big); check("http", parse_error::header_too_big);
check("http", parse_error::body_too_big); check("http", parse_error::body_too_big);
check("http", parse_error::short_read); check("http", parse_error::short_read);
} }

View File

@@ -122,20 +122,20 @@ public:
[&] [&]
{ {
testParser<nodejs_parser< testParser<nodejs_parser<
true, streambuf_body, headers>>( true, streambuf_body, fields>>(
Repeat, creq_); Repeat, creq_);
testParser<nodejs_parser< testParser<nodejs_parser<
false, streambuf_body, headers>>( false, streambuf_body, fields>>(
Repeat, cres_); Repeat, cres_);
}); });
timedTest(Trials, "http::basic_parser_v1", timedTest(Trials, "http::basic_parser_v1",
[&] [&]
{ {
testParser<parser_v1< testParser<parser_v1<
true, streambuf_body, headers>>( true, streambuf_body, fields>>(
Repeat, creq_); Repeat, creq_);
testParser<parser_v1< testParser<parser_v1<
false, streambuf_body, headers>>( false, streambuf_body, fields>>(
Repeat, cres_); Repeat, cres_);
}); });
pass(); pass();

View File

@@ -9,8 +9,8 @@
#include <beast/http/parser_v1.hpp> #include <beast/http/parser_v1.hpp>
#include <beast/core/streambuf.hpp> #include <beast/core/streambuf.hpp>
#include <beast/http/headers.hpp> #include <beast/http/fields.hpp>
#include <beast/http/headers_parser_v1.hpp> #include <beast/http/header_parser_v1.hpp>
#include <beast/http/parse.hpp> #include <beast/http/parse.hpp>
#include <beast/http/string_body.hpp> #include <beast/http/string_body.hpp>
#include <beast/test/string_stream.hpp> #include <beast/test/string_stream.hpp>
@@ -32,7 +32,7 @@ public:
// consecutive empty header values // consecutive empty header values
{ {
error_code ec; error_code ec;
parser_v1<true, string_body, headers> p; parser_v1<true, string_body, fields> p;
std::string const s = std::string const s =
"GET / HTTP/1.1\r\n" "GET / HTTP/1.1\r\n"
"X1:\r\n" "X1:\r\n"
@@ -44,12 +44,12 @@ public:
return; return;
BEAST_EXPECT(p.complete()); BEAST_EXPECT(p.complete());
auto const msg = p.release(); auto const msg = p.release();
BEAST_EXPECT(msg.headers.exists("X1")); BEAST_EXPECT(msg.fields.exists("X1"));
BEAST_EXPECT(msg.headers["X1"] == ""); BEAST_EXPECT(msg.fields["X1"] == "");
BEAST_EXPECT(msg.headers.exists("X2")); BEAST_EXPECT(msg.fields.exists("X2"));
BEAST_EXPECT(msg.headers["X2"] == ""); BEAST_EXPECT(msg.fields["X2"] == "");
BEAST_EXPECT(msg.headers.exists("X3")); BEAST_EXPECT(msg.fields.exists("X3"));
BEAST_EXPECT(msg.headers["X3"] == "x"); BEAST_EXPECT(msg.fields["X3"] == "x");
} }
} }
@@ -62,23 +62,23 @@ public:
"\r\n" "\r\n"
"*"}; "*"};
streambuf rb; streambuf rb;
headers_parser_v1<true, headers> p0; header_parser_v1<true, fields> p0;
parse(ss, rb, p0); parse(ss, rb, p0);
request_headers const& reqh = p0.get(); request_header const& reqh = p0.get();
BEAST_EXPECT(reqh.method == "GET"); BEAST_EXPECT(reqh.method == "GET");
BEAST_EXPECT(reqh.url == "/"); BEAST_EXPECT(reqh.url == "/");
BEAST_EXPECT(reqh.version == 11); BEAST_EXPECT(reqh.version == 11);
BEAST_EXPECT(reqh.headers["User-Agent"] == "test"); BEAST_EXPECT(reqh.fields["User-Agent"] == "test");
BEAST_EXPECT(reqh.headers["Content-Length"] == "1"); BEAST_EXPECT(reqh.fields["Content-Length"] == "1");
parser_v1<true, string_body, headers> p = parser_v1<true, string_body, fields> p =
with_body<string_body>(p0); with_body<string_body>(p0);
BEAST_EXPECT(p.get().method == "GET"); BEAST_EXPECT(p.get().method == "GET");
BEAST_EXPECT(p.get().url == "/"); BEAST_EXPECT(p.get().url == "/");
BEAST_EXPECT(p.get().version == 11); BEAST_EXPECT(p.get().version == 11);
BEAST_EXPECT(p.get().headers["User-Agent"] == "test"); BEAST_EXPECT(p.get().fields["User-Agent"] == "test");
BEAST_EXPECT(p.get().headers["Content-Length"] == "1"); BEAST_EXPECT(p.get().fields["Content-Length"] == "1");
parse(ss, rb, p); parse(ss, rb, p);
request<string_body, headers> req = p.release(); request<string_body, fields> req = p.release();
BEAST_EXPECT(req.body == "*"); BEAST_EXPECT(req.body == "*");
} }
@@ -88,7 +88,7 @@ public:
{ {
error_code ec; error_code ec;
parser_v1<true, string_body, parser_v1<true, string_body,
basic_headers<std::allocator<char>>> p; basic_fields<std::allocator<char>>> p;
std::string const s = std::string const s =
"GET / HTTP/1.1\r\n" "GET / HTTP/1.1\r\n"
"User-Agent: test\r\n" "User-Agent: test\r\n"
@@ -102,13 +102,13 @@ public:
BEAST_EXPECT(m.method == "GET"); BEAST_EXPECT(m.method == "GET");
BEAST_EXPECT(m.url == "/"); BEAST_EXPECT(m.url == "/");
BEAST_EXPECT(m.version == 11); BEAST_EXPECT(m.version == 11);
BEAST_EXPECT(m.headers["User-Agent"] == "test"); BEAST_EXPECT(m.fields["User-Agent"] == "test");
BEAST_EXPECT(m.body == "*"); BEAST_EXPECT(m.body == "*");
} }
{ {
error_code ec; error_code ec;
parser_v1<false, string_body, parser_v1<false, string_body,
basic_headers<std::allocator<char>>> p; basic_fields<std::allocator<char>>> p;
std::string const s = std::string const s =
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
"Server: test\r\n" "Server: test\r\n"
@@ -122,13 +122,13 @@ public:
BEAST_EXPECT(m.status == 200); BEAST_EXPECT(m.status == 200);
BEAST_EXPECT(m.reason == "OK"); BEAST_EXPECT(m.reason == "OK");
BEAST_EXPECT(m.version == 11); BEAST_EXPECT(m.version == 11);
BEAST_EXPECT(m.headers["Server"] == "test"); BEAST_EXPECT(m.fields["Server"] == "test");
BEAST_EXPECT(m.body == "*"); BEAST_EXPECT(m.body == "*");
} }
// skip body // skip body
{ {
error_code ec; error_code ec;
parser_v1<false, string_body, headers> p; parser_v1<false, string_body, fields> p;
std::string const s = std::string const s =
"HTTP/1.1 200 Connection Established\r\n" "HTTP/1.1 200 Connection Established\r\n"
"Proxy-Agent: Zscaler/5.1\r\n" "Proxy-Agent: Zscaler/5.1\r\n"

View File

@@ -10,7 +10,7 @@
#include "fail_parser.hpp" #include "fail_parser.hpp"
#include <beast/http/headers.hpp> #include <beast/http/fields.hpp>
#include <beast/http/streambuf_body.hpp> #include <beast/http/streambuf_body.hpp>
#include <beast/test/fail_stream.hpp> #include <beast/test/fail_stream.hpp>
#include <beast/test/string_stream.hpp> #include <beast/test/string_stream.hpp>
@@ -157,7 +157,7 @@ public:
sb.prepare(len), buffer(s, len))); sb.prepare(len), buffer(s, len)));
test::fail_counter fc{n}; test::fail_counter fc{n};
test::string_stream ss{ios_, s}; test::string_stream ss{ios_, s};
parser_v1<isRequest, fail_body, headers> p{fc}; parser_v1<isRequest, fail_body, fields> p{fc};
error_code ec; error_code ec;
parse(ss, sb, p, ec); parse(ss, sb, p, ec);
if(! ec) if(! ec)
@@ -172,7 +172,7 @@ public:
{ {
streambuf sb; streambuf sb;
test::string_stream ss(ios_, "GET / X"); test::string_stream ss(ios_, "GET / X");
parser_v1<true, streambuf_body, headers> p; parser_v1<true, streambuf_body, fields> p;
parse(ss, sb, p); parse(ss, sb, p);
fail(); fail();
} }
@@ -258,7 +258,7 @@ public:
"Content-Length: 5\r\n" "Content-Length: 5\r\n"
"\r\n" "\r\n"
}; };
request_headers m; request_header m;
try try
{ {
streambuf sb; streambuf sb;
@@ -280,7 +280,7 @@ public:
"Content-Length: 0\r\n" "Content-Length: 0\r\n"
"\r\n" "\r\n"
); );
request_headers m; request_header m;
error_code ec; error_code ec;
streambuf sb; streambuf sb;
async_read(fs, sb, m, do_yield[ec]); async_read(fs, sb, m, do_yield[ec]);
@@ -359,7 +359,7 @@ public:
{ {
streambuf sb; streambuf sb;
test::string_stream ss(ios_, ""); test::string_stream ss(ios_, "");
parser_v1<true, streambuf_body, headers> p; parser_v1<true, streambuf_body, fields> p;
error_code ec; error_code ec;
parse(ss, sb, p, ec); parse(ss, sb, p, ec);
BEAST_EXPECT(ec == boost::asio::error::eof); BEAST_EXPECT(ec == boost::asio::error::eof);
@@ -367,7 +367,7 @@ public:
{ {
streambuf sb; streambuf sb;
test::string_stream ss(ios_, ""); test::string_stream ss(ios_, "");
parser_v1<true, streambuf_body, headers> p; parser_v1<true, streambuf_body, fields> p;
error_code ec; error_code ec;
async_parse(ss, sb, p, do_yield[ec]); async_parse(ss, sb, p, do_yield[ec]);
BEAST_EXPECT(ec == boost::asio::error::eof); BEAST_EXPECT(ec == boost::asio::error::eof);

View File

@@ -9,7 +9,7 @@
#include <beast/http/streambuf_body.hpp> #include <beast/http/streambuf_body.hpp>
#include <beast/core/to_string.hpp> #include <beast/core/to_string.hpp>
#include <beast/http/headers.hpp> #include <beast/http/fields.hpp>
#include <beast/http/parser_v1.hpp> #include <beast/http/parser_v1.hpp>
#include <beast/http/read.hpp> #include <beast/http/read.hpp>
#include <beast/http/write.hpp> #include <beast/http/write.hpp>
@@ -34,7 +34,7 @@ public:
"\r\n" "\r\n"
"xyz"; "xyz";
test::string_stream ss(ios_, s); test::string_stream ss(ios_, s);
parser_v1<false, streambuf_body, headers> p; parser_v1<false, streambuf_body, fields> p;
streambuf sb; streambuf sb;
parse(ss, sb, p); parse(ss, sb, p);
BEAST_EXPECT(to_string(p.get().body.data()) == "xyz"); BEAST_EXPECT(to_string(p.get().body.data()) == "xyz");

View File

@@ -8,7 +8,7 @@
// Test that header file is self-contained. // Test that header file is self-contained.
#include <beast/http/write.hpp> #include <beast/http/write.hpp>
#include <beast/http/headers.hpp> #include <beast/http/fields.hpp>
#include <beast/http/message.hpp> #include <beast/http/message.hpp>
#include <beast/http/empty_body.hpp> #include <beast/http/empty_body.hpp>
#include <beast/http/string_body.hpp> #include <beast/http/string_body.hpp>
@@ -221,9 +221,9 @@ public:
}; };
}; };
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
std::string std::string
str(message<isRequest, Body, Headers> const& m) str(message<isRequest, Body, Fields> const& m)
{ {
string_write_stream ss(ios_); string_write_stream ss(ios_);
write(ss, m); write(ss, m);
@@ -234,11 +234,11 @@ public:
testAsyncWriteHeaders(yield_context do_yield) testAsyncWriteHeaders(yield_context do_yield)
{ {
{ {
message_headers<true, headers> m; header<true, fields> m;
m.version = 11; m.version = 11;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
error_code ec; error_code ec;
string_write_stream ss{ios_}; string_write_stream ss{ios_};
async_write(ss, m, do_yield[ec]); async_write(ss, m, do_yield[ec]);
@@ -249,12 +249,12 @@ public:
"\r\n"); "\r\n");
} }
{ {
message_headers<false, headers> m; header<false, fields> m;
m.version = 10; m.version = 10;
m.status = 200; m.status = 200;
m.reason = "OK"; m.reason = "OK";
m.headers.insert("Server", "test"); m.fields.insert("Server", "test");
m.headers.insert("Content-Length", "5"); m.fields.insert("Content-Length", "5");
error_code ec; error_code ec;
string_write_stream ss{ios_}; string_write_stream ss{ios_};
async_write(ss, m, do_yield[ec]); async_write(ss, m, do_yield[ec]);
@@ -271,12 +271,12 @@ public:
testAsyncWrite(yield_context do_yield) testAsyncWrite(yield_context do_yield)
{ {
{ {
message<false, string_body, headers> m; message<false, string_body, fields> m;
m.version = 10; m.version = 10;
m.status = 200; m.status = 200;
m.reason = "OK"; m.reason = "OK";
m.headers.insert("Server", "test"); m.fields.insert("Server", "test");
m.headers.insert("Content-Length", "5"); m.fields.insert("Content-Length", "5");
m.body = "*****"; m.body = "*****";
error_code ec; error_code ec;
string_write_stream ss{ios_}; string_write_stream ss{ios_};
@@ -290,12 +290,12 @@ public:
"*****"); "*****");
} }
{ {
message<false, string_body, headers> m; message<false, string_body, fields> m;
m.version = 11; m.version = 11;
m.status = 200; m.status = 200;
m.reason = "OK"; m.reason = "OK";
m.headers.insert("Server", "test"); m.fields.insert("Server", "test");
m.headers.insert("Transfer-Encoding", "chunked"); m.fields.insert("Transfer-Encoding", "chunked");
m.body = "*****"; m.body = "*****";
error_code ec; error_code ec;
string_write_stream ss(ios_); string_write_stream ss(ios_);
@@ -323,14 +323,14 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
string_write_stream> fs(fc, ios_); string_write_stream> fs(fc, ios_);
message<true, fail_body, headers> m( message<true, fail_body, fields> m(
std::piecewise_construct, std::piecewise_construct,
std::forward_as_tuple(fc, ios_)); std::forward_as_tuple(fc, ios_));
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 10; m.version = 10;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.headers.insert("Content-Length", "5"); m.fields.insert("Content-Length", "5");
m.body = "*****"; m.body = "*****";
try try
{ {
@@ -356,14 +356,14 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
string_write_stream> fs(fc, ios_); string_write_stream> fs(fc, ios_);
message<true, fail_body, headers> m( message<true, fail_body, fields> m(
std::piecewise_construct, std::piecewise_construct,
std::forward_as_tuple(fc, ios_)); std::forward_as_tuple(fc, ios_));
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 10; m.version = 10;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.headers.insert("Transfer-Encoding", "chunked"); m.fields.insert("Transfer-Encoding", "chunked");
m.body = "*****"; m.body = "*****";
error_code ec; error_code ec;
write(fs, m, ec); write(fs, m, ec);
@@ -391,14 +391,14 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
string_write_stream> fs(fc, ios_); string_write_stream> fs(fc, ios_);
message<true, fail_body, headers> m( message<true, fail_body, fields> m(
std::piecewise_construct, std::piecewise_construct,
std::forward_as_tuple(fc, ios_)); std::forward_as_tuple(fc, ios_));
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 10; m.version = 10;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.headers.insert("Transfer-Encoding", "chunked"); m.fields.insert("Transfer-Encoding", "chunked");
m.body = "*****"; m.body = "*****";
error_code ec; error_code ec;
async_write(fs, m, do_yield[ec]); async_write(fs, m, do_yield[ec]);
@@ -426,14 +426,14 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
string_write_stream> fs(fc, ios_); string_write_stream> fs(fc, ios_);
message<true, fail_body, headers> m( message<true, fail_body, fields> m(
std::piecewise_construct, std::piecewise_construct,
std::forward_as_tuple(fc, ios_)); std::forward_as_tuple(fc, ios_));
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 10; m.version = 10;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.headers.insert("Content-Length", "5"); m.fields.insert("Content-Length", "5");
m.body = "*****"; m.body = "*****";
error_code ec; error_code ec;
write(fs, m, ec); write(fs, m, ec);
@@ -456,14 +456,14 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
string_write_stream> fs(fc, ios_); string_write_stream> fs(fc, ios_);
message<true, fail_body, headers> m( message<true, fail_body, fields> m(
std::piecewise_construct, std::piecewise_construct,
std::forward_as_tuple(fc, ios_)); std::forward_as_tuple(fc, ios_));
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 10; m.version = 10;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.headers.insert("Content-Length", "5"); m.fields.insert("Content-Length", "5");
m.body = "*****"; m.body = "*****";
error_code ec; error_code ec;
async_write(fs, m, do_yield[ec]); async_write(fs, m, do_yield[ec]);
@@ -487,11 +487,11 @@ public:
{ {
// auto content-length HTTP/1.0 // auto content-length HTTP/1.0
{ {
message<true, string_body, headers> m; message<true, string_body, fields> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 10; m.version = 10;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
prepare(m); prepare(m);
BEAST_EXPECT(str(m) == BEAST_EXPECT(str(m) ==
@@ -504,11 +504,11 @@ public:
} }
// keep-alive HTTP/1.0 // keep-alive HTTP/1.0
{ {
message<true, string_body, headers> m; message<true, string_body, fields> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 10; m.version = 10;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
prepare(m, connection::keep_alive); prepare(m, connection::keep_alive);
BEAST_EXPECT(str(m) == BEAST_EXPECT(str(m) ==
@@ -522,11 +522,11 @@ public:
} }
// upgrade HTTP/1.0 // upgrade HTTP/1.0
{ {
message<true, string_body, headers> m; message<true, string_body, fields> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 10; m.version = 10;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
try try
{ {
@@ -540,11 +540,11 @@ public:
} }
// no content-length HTTP/1.0 // no content-length HTTP/1.0
{ {
message<true, unsized_body, headers> m; message<true, unsized_body, fields> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 10; m.version = 10;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
prepare(m); prepare(m);
string_write_stream ss(ios_); string_write_stream ss(ios_);
@@ -560,11 +560,11 @@ public:
} }
// auto content-length HTTP/1.1 // auto content-length HTTP/1.1
{ {
message<true, string_body, headers> m; message<true, string_body, fields> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 11; m.version = 11;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
prepare(m); prepare(m);
BEAST_EXPECT(str(m) == BEAST_EXPECT(str(m) ==
@@ -577,11 +577,11 @@ public:
} }
// close HTTP/1.1 // close HTTP/1.1
{ {
message<true, string_body, headers> m; message<true, string_body, fields> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 11; m.version = 11;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
prepare(m, connection::close); prepare(m, connection::close);
string_write_stream ss(ios_); string_write_stream ss(ios_);
@@ -599,11 +599,11 @@ public:
} }
// upgrade HTTP/1.1 // upgrade HTTP/1.1
{ {
message<true, empty_body, headers> m; message<true, empty_body, fields> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 11; m.version = 11;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
prepare(m, connection::upgrade); prepare(m, connection::upgrade);
BEAST_EXPECT(str(m) == BEAST_EXPECT(str(m) ==
"GET / HTTP/1.1\r\n" "GET / HTTP/1.1\r\n"
@@ -614,11 +614,11 @@ public:
} }
// no content-length HTTP/1.1 // no content-length HTTP/1.1
{ {
message<true, unsized_body, headers> m; message<true, unsized_body, fields> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 11; m.version = 11;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
prepare(m); prepare(m);
string_write_stream ss(ios_); string_write_stream ss(ios_);
@@ -639,11 +639,11 @@ public:
void test_std_ostream() void test_std_ostream()
{ {
// Conversion to std::string via operator<< // Conversion to std::string via operator<<
message<true, string_body, headers> m; message<true, string_body, fields> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 11; m.version = 11;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
BEAST_EXPECT(boost::lexical_cast<std::string>(m) == BEAST_EXPECT(boost::lexical_cast<std::string>(m) ==
"GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n*"); "GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n*");
@@ -656,7 +656,7 @@ public:
std::stringstream::failbit); std::stringstream::failbit);
try try
{ {
// message_headers // header
ss << m.base(); ss << m.base();
fail("", __FILE__, __LINE__); fail("", __FILE__, __LINE__);
} }
@@ -679,11 +679,11 @@ public:
void testOstream() void testOstream()
{ {
message<true, string_body, headers> m; message<true, string_body, fields> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 11; m.version = 11;
m.headers.insert("User-Agent", "test"); m.fields.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
prepare(m); prepare(m);
std::stringstream ss; std::stringstream ss;

View File

@@ -68,7 +68,7 @@ public:
void testFrameHeader() void testFrameHeader()
{ {
// good frame headers // good frame fields
{ {
role_type role = role_type::client; role_type role = role_type::client;
@@ -118,7 +118,7 @@ public:
check(fh); check(fh);
} }
// bad frame headers // bad frame fields
{ {
role_type role = role_type::client; role_type role = role_type::client;
@@ -211,7 +211,7 @@ public:
void testBadFrameHeaders() void testBadFrameHeaders()
{ {
// bad frame headers // bad frame fields
// //
// can't be created by the library // can't be created by the library
// so we produce them manually. // so we produce them manually.

View File

@@ -133,15 +133,15 @@ public:
struct identity struct identity
{ {
template<class Body, class Headers> template<class Body, class Fields>
void void
operator()(http::message<true, Body, Headers>&) operator()(http::message<true, Body, Fields>&)
{ {
} }
template<class Body, class Headers> template<class Body, class Fields>
void void
operator()(http::message<false, Body, Headers>&) operator()(http::message<false, Body, Fields>&)
{ {
} }
}; };
@@ -188,11 +188,11 @@ public:
req.method = "GET"; req.method = "GET";
req.url = "/"; req.url = "/";
req.version = 11; req.version = 11;
req.headers.insert("Host", "localhost"); req.fields.insert("Host", "localhost");
req.headers.insert("Upgrade", "websocket"); req.fields.insert("Upgrade", "websocket");
req.headers.insert("Connection", "upgrade"); req.fields.insert("Connection", "upgrade");
req.headers.insert("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ=="); req.fields.insert("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==");
req.headers.insert("Sec-WebSocket-Version", "13"); req.fields.insert("Sec-WebSocket-Version", "13");
stream<test::fail_stream< stream<test::fail_stream<
test::string_stream>> ws(n, ios_, ""); test::string_stream>> ws(n, ios_, "");
try try

View File

@@ -135,18 +135,18 @@ private:
struct identity struct identity
{ {
template<class Body, class Headers> template<class Body, class Fields>
void void
operator()(http::message<true, Body, Headers>& req) operator()(http::message<true, Body, Fields>& req)
{ {
req.headers.replace("User-Agent", "async_echo_client"); req.fields.replace("User-Agent", "async_echo_client");
} }
template<class Body, class Headers> template<class Body, class Fields>
void void
operator()(http::message<false, Body, Headers>& resp) operator()(http::message<false, Body, Fields>& resp)
{ {
resp.headers.replace("Server", "async_echo_server"); resp.fields.replace("Server", "async_echo_server");
} }
}; };

View File

@@ -138,18 +138,18 @@ private:
struct identity struct identity
{ {
template<class Body, class Headers> template<class Body, class Fields>
void void
operator()(http::message<true, Body, Headers>& req) operator()(http::message<true, Body, Fields>& req)
{ {
req.headers.replace("User-Agent", "sync_echo_client"); req.fields.replace("User-Agent", "sync_echo_client");
} }
template<class Body, class Headers> template<class Body, class Fields>
void void
operator()(http::message<false, Body, Headers>& resp) operator()(http::message<false, Body, Fields>& resp)
{ {
resp.headers.replace("Server", "sync_echo_server"); resp.fields.replace("Server", "sync_echo_server");
} }
}; };