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

View File

@@ -5,30 +5,62 @@
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]
[block '''
<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.headers">Headers</link></member>
<member><link linkend="beast.http.message">Message</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.algorithms">Algorithms</link></member>
<member><link linkend="beast.http.sockets">Sockets</link></member>
</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
writing of messages 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.
writing of messages and headers in the HTTP/1 wire format using Boost.Asio.
[note
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
declarations are in effect:
```
#include <beast/core.hpp>
#include <beast/http.hpp>
using namespace beast;
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<
bool isRequest,
class Body,
class Headers
>
class message;
using request_header = header<true, fields>;
using response_header = header<false, fields>;
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.
Depending on the value, different data members will be present in the resulting
type.
The code examples below show how to create and fill in a request and response
object:
* [*`Body`]: determines both the kind of container used to represent the
message body and the algorithms used to parse and serialize it.
* [*`Headers`]: determines the container used to represent the HTTP headers.
For notational convenience, the following template type aliases are provided:
```
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
[table Create Message
[[HTTP Request] [HTTP Response]]
[[
```
request<empty_body> req;
req.version = 11; // HTTP/1.1
req.method = "GET";
req.url = "/index.html";
req.headers.insert("User-Agent", "Beast.HTTP");
req.body = "";
req.url = "/index.htm"
req.fields.insert("Accept", "text/html");
req.fields.insert("Connection", "keep-alive");
req.fields.insert("User-Agent", "Beast");
```
][
```
response<string_body> res;
res.version = 10; // HTTP/1.0
res.status = 404;
res.reason = "Not Found";
res.headers.insert("Server", "Beast.HTTP");
res.body = "The requested resource was not found.";
```
res.version = 11; // HTTP/1.1
res.status = 200;
res.reason = "OK";
res.fields.insert("Sever", "Beast");
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]
[section:headers Headers]
The [*`Headers`] type represents a container that can set or retrieve the
headers in a message. Beast provides the
[link beast.ref.http__basic_headers `basic_headers`] class which serves
[section:fields Fields]
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 field names are not case-sensitive.
@@ -157,15 +213,7 @@ These statements change the values of the headers in the message passed:
}
```
[heading Advanced]
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
User defined [*`Fields`] types are possible. To support serialization, the
type must meet the requirements of __FieldSequence__. To support parsing using
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]
In addition to the universal message model, Beast provides synchronous
algorithms which operate on HTTP/1 messages:
Algorithms are provided to serialize and deserialize HTTP/1 messages on
streams.
* [link beast.ref.http__read [*read]]: Parse a message from a stream
* [link beast.ref.http__write [*write]]: Serialize a message into its wire format on 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.
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]
[section:sockets Using Sockets]
The library provides simple free functions modeled after Boost.Asio to
send and receive messages on TCP/IP sockets, SSL streams, or any object
which meets the Boost.Asio type requirements (SyncReadStream, SyncWriteStream,
AsyncReadStream, and AsyncWriteStream depending on the types of operations
performed). To send messages synchronously, use one of the
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
operations performed). To send messages synchronously, use one of the
[link beast.ref.http__write `write`] functions:
```
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 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 __rfc6455__ [@https://tools.ietf.org/html/rfc6455 rfc6455]]
[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 __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
provides implementations of the HTTP and WebSocket protocols.

View File

@@ -30,24 +30,25 @@
<bridgehead renderas="sect3">Classes</bridgehead>
<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_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__empty_body">empty_body</link></member>
<member><link linkend="beast.ref.http__headers">headers</link></member>
<member><link linkend="beast.ref.http__headers_parser_v1">headers_parser_v1</link></member>
<member><link linkend="beast.ref.http__fields">fields</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_headers">message_headers</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_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_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__streambuf_body">streambuf_body</link></member>
<member><link linkend="beast.ref.http__string_body">string_body</link></member>
</simplelist>
<bridgehead renderas="sect3">rfc7230</bridgehead>
<simplelist type="vert" columns="1">
<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__token_list">token_list</link></member>
@@ -56,20 +57,21 @@
<entry valign="top">
<bridgehead renderas="sect3">Functions</bridgehead>
<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_parse">async_parse</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_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_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__prepare">prepare</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__write">write</link></member>
<member><link linkend="beast.ref.http__operator_ls_">operator&lt;&lt;</link></member>
</simplelist>
<bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1">
@@ -84,14 +86,17 @@
<entry valign="top">
<bridgehead renderas="sect3">Options</bridgehead>
<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__headers_max_size">headers_max_size</link></member>
<member><link linkend="beast.ref.http__skip_body">skip_body</link></member>
</simplelist>
<bridgehead renderas="sect3">Constants</bridgehead>
<simplelist type="vert" columns="1">
<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__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>
<bridgehead renderas="sect3">Concepts</bridgehead>
<simplelist type="vert" columns="1">

View File

@@ -8,9 +8,12 @@
#ifndef 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/filesystem.hpp>
#include <boost/logic/tribool.hpp>
#include <cstdio>
#include <cstdint>
@@ -34,8 +37,8 @@ struct file_body
writer(writer const&) = delete;
writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers>
writer(message<isRequest, file_body, Headers> const& m) noexcept
template<bool isRequest, class Fields>
writer(message<isRequest, file_body, Fields> const& m) noexcept
: path_(m.body)
{
}

View File

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

View File

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

View File

@@ -26,9 +26,9 @@ int main()
req.method = "GET";
req.url = "/";
req.version = 11;
req.headers.replace("Host", host + ":" +
req.fields.replace("Host", host + ":" +
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::write(sock, req);

View File

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

View File

@@ -38,9 +38,9 @@ int main()
req.method = "GET";
req.url = "/";
req.version = 11;
req.headers.insert("Host", host + ":" +
req.fields.insert("Host", host + ":" +
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::write(stream, req);

View File

@@ -46,7 +46,7 @@ namespace beast {
Example:
@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.
//
template<class DynamicBuffer>
@@ -54,7 +54,7 @@ namespace beast {
dynabuf_readstream<DynamicBuffer>& stream)
{
// 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
// headers; the return value will include only the
// part up to the end of the delimiter.

View File

@@ -8,12 +8,11 @@
#ifndef 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/body_type.hpp>
#include <beast/http/chunk_encode.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/parse.hpp>
#include <beast/http/parse_error.hpp>

View File

@@ -8,9 +8,12 @@
#ifndef 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 <boost/asio/buffer.hpp>
#include <boost/logic/tribool.hpp>
namespace beast {
namespace http {
@@ -34,10 +37,10 @@ private:
value_type& sb_;
public:
template<bool isRequest, class Headers>
template<bool isRequest, class Fields>
explicit
reader(message<isRequest,
basic_dynabuf_body, Headers>& m) noexcept
basic_dynabuf_body, Fields>& m) noexcept
: sb_(m.body)
{
}
@@ -63,10 +66,10 @@ private:
DynamicBuffer const& body_;
public:
template<bool isRequest, class Headers>
template<bool isRequest, class Fields>
explicit
writer(message<
isRequest, basic_dynabuf_body, Headers> const& m) noexcept
isRequest, basic_dynabuf_body, Fields> const& m) noexcept
: 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)
//
#ifndef BEAST_HTTP_BASIC_HEADERS_HPP
#define BEAST_HTTP_BASIC_HEADERS_HPP
#ifndef BEAST_HTTP_BASIC_FIELDS_HPP
#define BEAST_HTTP_BASIC_FIELDS_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 <algorithm>
#include <cctype>
@@ -21,35 +21,35 @@
namespace beast {
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
up the headers and trailers in a HTTP message. Objects of this type
are iterable, which each element holding the field name and field
up the fields and trailers in a HTTP message. Objects of this type
are iterable, with each element holding the field name and field
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
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.
@note Meets the requirements of @b `FieldSequence`.
@note Meets the requirements of @b FieldSequence.
*/
template<class Allocator>
class basic_headers :
class basic_fields :
#if ! GENERATING_DOCS
private beast::detail::empty_base_optimization<
typename std::allocator_traits<Allocator>::
template rebind_alloc<
detail::basic_headers_base::element>>,
detail::basic_fields_base::element>>,
#endif
public detail::basic_headers_base
public detail::basic_fields_base
{
using alloc_type = typename
std::allocator_traits<Allocator>::
template rebind_alloc<
detail::basic_headers_base::element>;
detail::basic_fields_base::element>;
using alloc_traits =
std::allocator_traits<alloc_type>;
@@ -61,16 +61,16 @@ class basic_headers :
delete_all();
void
move_assign(basic_headers&, std::false_type);
move_assign(basic_fields&, std::false_type);
void
move_assign(basic_headers&, std::true_type);
move_assign(basic_fields&, std::true_type);
void
copy_assign(basic_headers const&, std::false_type);
copy_assign(basic_fields const&, std::false_type);
void
copy_assign(basic_headers const&, std::true_type);
copy_assign(basic_fields const&, std::true_type);
template<class FieldSequence>
void
@@ -103,17 +103,17 @@ public:
#endif
/// Default constructor.
basic_headers() = default;
basic_fields() = default;
/// Destructor
~basic_headers();
~basic_fields();
/** Construct the headers.
/** Construct the fields.
@param alloc The allocator to use.
*/
explicit
basic_headers(Allocator const& alloc);
basic_fields(Allocator const& alloc);
/** Move constructor.
@@ -121,7 +121,7 @@ public:
@param other The object to move from.
*/
basic_headers(basic_headers&& other);
basic_fields(basic_fields&& other);
/** Move assignment.
@@ -129,25 +129,25 @@ public:
@param other The object to move from.
*/
basic_headers& operator=(basic_headers&& other);
basic_fields& operator=(basic_fields&& other);
/// Copy constructor.
basic_headers(basic_headers const&);
basic_fields(basic_fields const&);
/// Copy assignment.
basic_headers& operator=(basic_headers const&);
basic_fields& operator=(basic_fields const&);
/// Copy constructor.
template<class OtherAlloc>
basic_headers(basic_headers<OtherAlloc> const&);
basic_fields(basic_fields<OtherAlloc> const&);
/// Copy assignment.
template<class OtherAlloc>
basic_headers& operator=(basic_headers<OtherAlloc> const&);
basic_fields& operator=(basic_fields<OtherAlloc> const&);
/// Construct from a field sequence.
template<class FwdIt>
basic_headers(FwdIt first, FwdIt last);
basic_fields(FwdIt first, FwdIt last);
/// Returns `true` if the field sequence contains no elements.
bool
@@ -218,7 +218,7 @@ public:
boost::string_ref
operator[](boost::string_ref const& name) const;
/// Clear the contents of the basic_headers.
/// Clear the contents of the basic_fields.
void
clear() noexcept;
@@ -301,6 +301,6 @@ public:
} // http
} // beast
#include <beast/http/impl/basic_headers.ipp>
#include <beast/http/impl/basic_fields.ipp>
#endif

View File

@@ -22,8 +22,11 @@
namespace beast {
namespace http {
namespace parse_flag {
enum values
/** Parse flags
The set of parser bit flags are returned by @ref basic_parser_v1::flags.
*/
enum parse_flag
{
chunked = 1,
connection_keep_alive = 2,
@@ -34,28 +37,6 @@ enum values
skipbody = 64,
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.
@@ -67,7 +48,7 @@ struct headers_max_size
The default body maximum size for requests is 4MB (four
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
{
@@ -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.
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
in terms of the message body.
*/
@@ -94,7 +96,7 @@ enum class body_what
/** 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
could be used when sending a response to a HEAD
request, for example.
@@ -116,8 +118,8 @@ enum class body_what
to the parser will begin reading the message body.
This could be used by callers to inspect the HTTP
headers before committing to read the body. For example,
to choose the body type based on the headers. Or to
header before committing to read the body. For example,
to choose the body type based on the fields. Or to
respond to an Expect: 100-continue request.
*/
pause
@@ -181,19 +183,19 @@ static std::uint64_t constexpr no_content_length =
//
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
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
on_body_what(std::uint64_t content_length, error_code&);
// 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
// passed to the callback.
//
@@ -319,9 +321,9 @@ public:
std::forward<An>(an)...);
}
/// Set the headers maximum size option
/// Set the header maximum size option
void
set_option(headers_max_size const& o)
set_option(header_max_size const& o)
{
h_max_ = o.value;
h_left_ = h_max_;
@@ -508,7 +510,7 @@ private:
void
init(std::true_type)
{
// 16KB max headers, 4MB max body
// Request: 16KB max header, 4MB max body
h_max_ = 16 * 1024;
b_max_ = 4 * 1024 * 1024;
}
@@ -516,7 +518,7 @@ private:
void
init(std::false_type)
{
// 16KB max headers, unlimited body
// Response: 16KB max header, unlimited body
h_max_ = 16 * 1024;
b_max_ = 0;
}
@@ -616,7 +618,7 @@ private:
template<class T>
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<error_code&>())
)>> : std::true_type {};
@@ -674,7 +676,7 @@ private:
"on_method requirements not met");
if(h_max_ && s.size() > h_left_)
{
ec = parse_error::headers_too_big;
ec = parse_error::header_too_big;
return;
}
h_left_ -= s.size();
@@ -700,7 +702,7 @@ private:
"on_uri requirements not met");
if(h_max_ && s.size() > h_left_)
{
ec = parse_error::headers_too_big;
ec = parse_error::header_too_big;
return;
}
h_left_ -= s.size();
@@ -726,7 +728,7 @@ private:
"on_reason requirements not met");
if(h_max_ && s.size() > h_left_)
{
ec = parse_error::headers_too_big;
ec = parse_error::header_too_big;
return;
}
h_left_ -= s.size();
@@ -785,7 +787,7 @@ private:
"on_field requirements not met");
if(h_max_ && s.size() > h_left_)
{
ec = parse_error::headers_too_big;
ec = parse_error::header_too_big;
return;
}
h_left_ -= s.size();
@@ -799,7 +801,7 @@ private:
"on_value requirements not met");
if(h_max_ && s.size() > h_left_)
{
ec = parse_error::headers_too_big;
ec = parse_error::header_too_big;
return;
}
h_left_ -= s.size();
@@ -810,8 +812,8 @@ private:
call_on_headers(error_code& ec)
{
static_assert(check_on_headers<Derived>::value,
"on_headers requirements not met");
impl().on_headers(content_length_, ec);
"on_header requirements not met");
impl().on_header(content_length_, ec);
}
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)
//
#ifndef BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
#define BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
#ifndef BEAST_HTTP_CHUNK_ENCODE_HPP
#define BEAST_HTTP_CHUNK_ENCODE_HPP
#include <beast/core/buffer_cat.hpp>
#include <beast/http/detail/chunk_encode.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/assert.hpp>
#include <algorithm>
@@ -20,92 +21,6 @@
namespace beast {
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.
This returns a buffer sequence representing the
@@ -124,7 +39,7 @@ template<class ConstBufferSequence>
implementation_defined
#else
beast::detail::buffer_cat_helper<
chunk_encode_text,
detail::chunk_encode_delim,
ConstBufferSequence,
boost::asio::const_buffers_1>
#endif
@@ -132,7 +47,7 @@ chunk_encode(bool fin, ConstBufferSequence const& buffers)
{
using boost::asio::buffer_size;
return buffer_cat(
chunk_encode_text{buffer_size(buffers)},
detail::chunk_encode_delim{buffer_size(buffers)},
buffers,
fin ? boost::asio::const_buffers_1{"\r\n0\r\n\r\n", 7}
: 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)
//
#ifndef BEAST_HTTP_DETAIL_BASIC_HEADERS_HPP
#define BEAST_HTTP_DETAIL_BASIC_HEADERS_HPP
#ifndef BEAST_HTTP_DETAIL_BASIC_FIELDS_HPP
#define BEAST_HTTP_DETAIL_BASIC_FIELDS_HPP
#include <beast/core/detail/ci_char_traits.hpp>
#include <boost/intrusive/list.hpp>
@@ -17,11 +17,11 @@ namespace beast {
namespace http {
template<class Allocator>
class basic_headers;
class basic_fields;
namespace detail {
class basic_headers_base
class basic_fields_base
{
public:
struct value_type
@@ -51,7 +51,7 @@ public:
protected:
template<class Allocator>
friend class beast::http::basic_headers;
friend class beast::http::basic_fields;
struct element
: boost::intrusive::set_base_hook <
@@ -105,7 +105,7 @@ protected:
set_t set_;
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))
, list_(std::move(list))
{
@@ -116,21 +116,21 @@ public:
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;
iter_type it_;
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)
: it_(it)
@@ -139,7 +139,7 @@ class basic_headers_base::const_iterator
public:
using value_type =
typename basic_headers_base::value_type;
typename basic_fields_base::value_type;
using pointer = value_type const*;
using reference = value_type const&;
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
#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 <boost/asio/buffer.hpp>
#include <boost/logic/tribool.hpp>
#include <memory>
#include <string>
@@ -36,9 +39,9 @@ private:
struct writer
{
template<bool isRequest, class Headers>
template<bool isRequest, class Fields>
explicit
writer(message<isRequest, empty_body, Headers> const& m) noexcept
writer(message<isRequest, empty_body, Fields> const& m) noexcept
{
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)
//
#ifndef BEAST_HTTP_HEADERS_HPP
#define BEAST_HTTP_HEADERS_HPP
#ifndef BEAST_HTTP_FIELDS_HPP
#define BEAST_HTTP_FIELDS_HPP
#include <beast/http/basic_headers.hpp>
#include <beast/http/basic_fields.hpp>
#include <memory>
namespace beast {
namespace http {
using headers =
basic_headers<std::allocator<char>>;
/// A typical HTTP header fields container
using fields =
basic_fields<std::allocator<char>>;
} // http
} // beast

View File

@@ -13,7 +13,6 @@
#include <beast/http/message.hpp>
#include <beast/core/error.hpp>
#include <boost/assert.hpp>
#include <boost/optional.hpp>
#include <string>
#include <type_traits>
#include <utility>
@@ -36,100 +35,99 @@ struct response_parser_base
} // 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
convert a series of octets into a @ref request_headers
or @ref response_headers.
convert a series of octets into a request or
response @ref header.
@note A new instance of the parser is required for each message.
*/
template<bool isRequest, class Headers>
class headers_parser_v1
template<bool isRequest, class Fields>
class header_parser_v1
: public basic_parser_v1<isRequest,
headers_parser_v1<isRequest, Headers>>
header_parser_v1<isRequest, Fields>>
, private std::conditional<isRequest,
detail::request_parser_base,
detail::response_parser_base>::type
{
public:
/// The type of message this parser produces.
using headers_type =
message_headers<isRequest, Headers>;
/// The type of the header this parser produces.
using header_type = header<isRequest, Fields>;
private:
// VFALCO Check Headers requirements?
// VFALCO Check Fields requirements?
std::string field_;
std::string value_;
headers_type h_;
header_type h_;
bool flush_ = false;
public:
/// Default constructor
headers_parser_v1() = default;
header_parser_v1() = default;
/// Move constructor
headers_parser_v1(headers_parser_v1&&) = default;
header_parser_v1(header_parser_v1&&) = default;
/// Copy constructor (disallowed)
headers_parser_v1(headers_parser_v1 const&) = delete;
header_parser_v1(header_parser_v1 const&) = delete;
/// Move assignment (disallowed)
headers_parser_v1& operator=(headers_parser_v1&&) = delete;
header_parser_v1& operator=(header_parser_v1&&) = delete;
/// Copy assignment (disallowed)
headers_parser_v1& operator=(headers_parser_v1 const&) = delete;
header_parser_v1& operator=(header_parser_v1 const&) = delete;
/** Construct the parser.
@param args Forwarded to the message headers constructor.
@param args Forwarded to the header constructor.
*/
#if GENERATING_DOCS
template<class... Args>
explicit
headers_parser_v1(Args&&... args);
header_parser_v1(Args&&... args);
#else
template<class Arg1, class... ArgN,
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
headers_parser_v1(Arg1&& arg1, ArgN&&... argn)
header_parser_v1(Arg1&& arg1, ArgN&&... argn)
: h_(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...)
{
}
#endif
/** Returns the parsed headers.
/** Returns the parsed header
Only valid if @ref complete would return `true`.
*/
headers_type const&
header_type const&
get() const
{
return h_;
}
/** Returns the parsed headers.
/** Returns the parsed header.
Only valid if @ref complete would return `true`.
*/
headers_type&
header_type&
get()
{
return h_;
}
/** Returns ownership of the parsed headers.
/** Returns ownership of the parsed header.
Ownership is transferred to the caller. Only
valid if @ref complete would return `true`.
Requires:
`message_headers<isRequest, Headers>` is @b MoveConstructible
@ref header_type is @b MoveConstructible
*/
headers_type
header_type
release()
{
static_assert(std::is_move_constructible<decltype(h_)>::value,
@@ -138,7 +136,7 @@ public:
}
private:
friend class basic_parser_v1<isRequest, headers_parser_v1>;
friend class basic_parser_v1<isRequest, header_parser_v1>;
void flush()
{
@@ -146,7 +144,7 @@ private:
return;
flush_ = false;
BOOST_ASSERT(! field_.empty());
h_.headers.insert(field_, value_);
h_.fields.insert(field_, value_);
field_.clear();
value_.clear();
}
@@ -207,7 +205,7 @@ private:
}
void
on_headers(std::uint64_t, error_code&)
on_header(std::uint64_t, error_code&)
{
flush();
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)
//
#ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
#ifndef BEAST_HTTP_IMPL_BASIC_FIELDS_IPP
#define BEAST_HTTP_IMPL_BASIC_FIELDS_IPP
#include <beast/http/detail/rfc7230.hpp>
#include <algorithm>
@@ -16,7 +16,7 @@ namespace http {
template<class Allocator>
void
basic_headers<Allocator>::
basic_fields<Allocator>::
delete_all()
{
for(auto it = list_.begin(); it != list_.end();)
@@ -31,8 +31,8 @@ delete_all()
template<class Allocator>
inline
void
basic_headers<Allocator>::
move_assign(basic_headers& other, std::false_type)
basic_fields<Allocator>::
move_assign(basic_fields& other, std::false_type)
{
if(this->member() != other.member())
{
@@ -49,8 +49,8 @@ move_assign(basic_headers& other, std::false_type)
template<class Allocator>
inline
void
basic_headers<Allocator>::
move_assign(basic_headers& other, std::true_type)
basic_fields<Allocator>::
move_assign(basic_fields& other, std::true_type)
{
this->member() = std::move(other.member());
set_ = std::move(other.set_);
@@ -60,8 +60,8 @@ move_assign(basic_headers& other, std::true_type)
template<class Allocator>
inline
void
basic_headers<Allocator>::
copy_assign(basic_headers const& other, std::false_type)
basic_fields<Allocator>::
copy_assign(basic_fields const& other, std::false_type)
{
copy_from(other);
}
@@ -69,8 +69,8 @@ copy_assign(basic_headers const& other, std::false_type)
template<class Allocator>
inline
void
basic_headers<Allocator>::
copy_assign(basic_headers const& other, std::true_type)
basic_fields<Allocator>::
copy_assign(basic_fields const& other, std::true_type)
{
this->member() = other.member();
copy_from(other);
@@ -79,35 +79,35 @@ copy_assign(basic_headers const& other, std::true_type)
//------------------------------------------------------------------------------
template<class Allocator>
basic_headers<Allocator>::
~basic_headers()
basic_fields<Allocator>::
~basic_fields()
{
delete_all();
}
template<class Allocator>
basic_headers<Allocator>::
basic_headers(Allocator const& alloc)
basic_fields<Allocator>::
basic_fields(Allocator const& alloc)
: beast::detail::empty_base_optimization<
alloc_type>(alloc)
{
}
template<class Allocator>
basic_headers<Allocator>::
basic_headers(basic_headers&& other)
basic_fields<Allocator>::
basic_fields(basic_fields&& other)
: beast::detail::empty_base_optimization<alloc_type>(
std::move(other.member()))
, detail::basic_headers_base(
, detail::basic_fields_base(
std::move(other.set_), std::move(other.list_))
{
}
template<class Allocator>
auto
basic_headers<Allocator>::
operator=(basic_headers&& other) ->
basic_headers&
basic_fields<Allocator>::
operator=(basic_fields&& other) ->
basic_fields&
{
if(this == &other)
return *this;
@@ -118,9 +118,9 @@ operator=(basic_headers&& other) ->
}
template<class Allocator>
basic_headers<Allocator>::
basic_headers(basic_headers const& other)
: basic_headers(alloc_traits::
basic_fields<Allocator>::
basic_fields(basic_fields const& other)
: basic_fields(alloc_traits::
select_on_container_copy_construction(other.member()))
{
copy_from(other);
@@ -128,9 +128,9 @@ basic_headers(basic_headers const& other)
template<class Allocator>
auto
basic_headers<Allocator>::
operator=(basic_headers const& other) ->
basic_headers&
basic_fields<Allocator>::
operator=(basic_fields const& other) ->
basic_fields&
{
clear();
copy_assign(other, std::integral_constant<bool,
@@ -140,8 +140,8 @@ operator=(basic_headers const& other) ->
template<class Allocator>
template<class OtherAlloc>
basic_headers<Allocator>::
basic_headers(basic_headers<OtherAlloc> const& other)
basic_fields<Allocator>::
basic_fields(basic_fields<OtherAlloc> const& other)
{
copy_from(other);
}
@@ -149,9 +149,9 @@ basic_headers(basic_headers<OtherAlloc> const& other)
template<class Allocator>
template<class OtherAlloc>
auto
basic_headers<Allocator>::
operator=(basic_headers<OtherAlloc> const& other) ->
basic_headers&
basic_fields<Allocator>::
operator=(basic_fields<OtherAlloc> const& other) ->
basic_fields&
{
clear();
copy_from(other);
@@ -160,8 +160,8 @@ operator=(basic_headers<OtherAlloc> const& other) ->
template<class Allocator>
template<class FwdIt>
basic_headers<Allocator>::
basic_headers(FwdIt first, FwdIt last)
basic_fields<Allocator>::
basic_fields(FwdIt first, FwdIt last)
{
for(;first != last; ++first)
insert(first->name(), first->value());
@@ -169,7 +169,7 @@ basic_headers(FwdIt first, FwdIt last)
template<class Allocator>
std::size_t
basic_headers<Allocator>::
basic_fields<Allocator>::
count(boost::string_ref const& name) const
{
auto const it = set_.find(name, less{});
@@ -181,7 +181,7 @@ count(boost::string_ref const& name) const
template<class Allocator>
auto
basic_headers<Allocator>::
basic_fields<Allocator>::
find(boost::string_ref const& name) const ->
iterator
{
@@ -193,7 +193,7 @@ find(boost::string_ref const& name) const ->
template<class Allocator>
boost::string_ref
basic_headers<Allocator>::
basic_fields<Allocator>::
operator[](boost::string_ref const& name) const
{
auto const it = find(name);
@@ -204,7 +204,7 @@ operator[](boost::string_ref const& name) const
template<class Allocator>
void
basic_headers<Allocator>::
basic_fields<Allocator>::
clear() noexcept
{
delete_all();
@@ -214,7 +214,7 @@ clear() noexcept
template<class Allocator>
std::size_t
basic_headers<Allocator>::
basic_fields<Allocator>::
erase(boost::string_ref const& name)
{
auto it = set_.find(name, less{});
@@ -238,7 +238,7 @@ erase(boost::string_ref const& name)
template<class Allocator>
void
basic_headers<Allocator>::
basic_fields<Allocator>::
insert(boost::string_ref const& name,
boost::string_ref value)
{
@@ -251,7 +251,7 @@ insert(boost::string_ref const& name,
template<class Allocator>
void
basic_headers<Allocator>::
basic_fields<Allocator>::
replace(boost::string_ref const& name,
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)
//
#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
*
* 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
* IN THE SOFTWARE.
*/
/*
This code is a modified version of nodejs/http-parser, copyright above:
https://github.com/nodejs/http-parser
/* This code is a modified version of nodejs/http-parser, copyright above:
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>
basic_parser_v1<isRequest, Derived>::
basic_parser_v1()

View File

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

View File

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

View File

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

View File

@@ -8,7 +8,7 @@
#ifndef 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 <memory>
#include <string>
@@ -19,27 +19,30 @@ namespace beast {
namespace http {
#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
request method and URL. Objects of this type may be
used to represent incoming or outgoing requests for
which the body is not yet known or generated. For
example, when receiving a request with the header value
"Expect: 100-continue".
A header includes the Start Line and Fields.
Some use-cases:
@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<bool isRequest, class Headers>
struct message_headers
template<bool isRequest, class Fields>
struct header
#else
template<bool isRequest, class Headers>
struct message_headers;
template<bool isRequest, class Fields>
struct header;
template<class Headers>
struct message_headers<true, Headers>
template<class Fields>
struct header<true, Fields>
#endif
{
/// Indicates if the message headers are a request or response.
/// Indicates if the header is a request or response.
#if GENERATING_DOCS
static bool constexpr is_request = isRequest;
@@ -47,8 +50,8 @@ struct message_headers<true, Headers>
static bool constexpr is_request = true;
#endif
/// The type representing the headers.
using headers_type = Headers;
/// The type representing the fields.
using fields_type = Fields;
/** The HTTP version.
@@ -74,67 +77,71 @@ struct message_headers<true, Headers>
std::string url;
/// The HTTP field values.
Headers headers;
fields_type fields;
/// Default constructor
message_headers() = default;
header() = default;
/// Move constructor
message_headers(message_headers&&) = default;
header(header&&) = default;
/// Copy constructor
message_headers(message_headers const&) = default;
header(header const&) = default;
/// Move assignment
message_headers& operator=(message_headers&&) = default;
header& operator=(header&&) = default;
/// 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
of the `headers` member.
of the `fields` member.
@note This constructor participates in overload resolution
if and only if the first parameter is not convertible to
`message_headers`.
`header`.
*/
#if GENERATING_DOCS
template<class... Args>
explicit
message_headers(Args&&... args);
header(Args&&... args);
#else
template<class Arg1, class... ArgN,
class = typename std::enable_if<
(sizeof...(ArgN) > 0) || ! std::is_convertible<
typename std::decay<Arg1>::type,
message_headers>::value>::type>
header>::value>::type>
explicit
message_headers(Arg1&& arg1, ArgN&&... argn)
: headers(std::forward<Arg1>(arg1),
header(Arg1&& arg1, ArgN&&... argn)
: fields(std::forward<Arg1>(arg1),
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
response status and reasons. Objects of this type may
be used to represent incoming or outgoing responses for
which the body is not yet known or generated. For
example, when responding to a HEAD request.
A header includes the Start Line and Fields.
Some use-cases:
@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>
struct message_headers<false, Headers>
template<class Fields>
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;
/// The type representing the headers.
using headers_type = Headers;
/// The type representing the fields.
using fields_type = Fields;
/** The HTTP version.
@@ -148,40 +155,40 @@ struct message_headers<false, Headers>
int version;
/// The HTTP field values.
Headers headers;
fields_type fields;
/// Default constructor
message_headers() = default;
header() = default;
/// Move constructor
message_headers(message_headers&&) = default;
header(header&&) = default;
/// Copy constructor
message_headers(message_headers const&) = default;
header(header const&) = default;
/// Move assignment
message_headers& operator=(message_headers&&) = default;
header& operator=(header&&) = default;
/// 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
of the `headers` member.
of the `fields` member.
@note This constructor participates in overload resolution
if and only if the first parameter is not convertible to
`message_headers`.
`header`.
*/
template<class Arg1, class... ArgN,
class = typename std::enable_if<
(sizeof...(ArgN) > 0) || ! std::is_convertible<
typename std::decay<Arg1>::type,
message_headers>::value>::type>
header>::value>::type>
explicit
message_headers(Arg1&& arg1, ArgN&&... argn)
: headers(std::forward<Arg1>(arg1),
header(Arg1&& arg1, ArgN&&... argn)
: fields(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...)
{
}
@@ -204,9 +211,10 @@ struct message_headers<false, Headers>
/** A container for a complete HTTP message.
A message can be a request or response, depending on the `isRequest`
template argument value. Requests and responses have different types,
so functions may be overloaded on them if desired.
A message can be a request or response, depending on the
`isRequest` template argument value. Requests and responses
have different types; functions may be overloaded based on
the type if desired.
The `Body` template argument type determines the model used
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 Headers The type of container used to hold the
@tparam Fields The type of container used to hold the
field value pairs.
*/
template<bool isRequest, class Body, class Headers>
struct message :
message_headers<isRequest, Headers>
template<bool isRequest, class Body, class Fields>
struct message : header<isRequest, Fields>
{
/// The base class used to hold the request or response headers
using base_type = message_headers<isRequest, Headers>;
/// The base class used to hold the header portion of the message.
using base_type = header<isRequest, Fields>;
/** 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;
@@ -239,7 +246,7 @@ struct message :
/// Default constructor
message() = default;
/** Construct a message from message headers.
/** Construct a message from a header.
Additional arguments, if any, are forwarded to
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
the constructor of the body member.
@@ -288,7 +295,7 @@ struct message :
@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
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 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>
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()
{
return *this;
}
/// Returns the message headers portion of the message
/// Returns the header portion of the message
base_type const&
base() const
{
@@ -368,64 +375,60 @@ private:
//------------------------------------------------------------------------------
#if GENERATING_DOCS
/** Swap two HTTP message headers.
/** Swap two header objects.
@par Requirements
`Headers` is @b Swappable.
`Fields` is @b Swappable.
*/
template<bool isRequest, class Headers>
template<bool isRequest, class Fields>
void
swap(
message_headers<isRequest, Headers>& m1,
message_headers<isRequest, Headers>& m2);
header<isRequest, Fields>& m1,
header<isRequest, Fields>& m2);
#endif
/** Swap two HTTP messages.
/** Swap two message objects.
@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
swap(
message<isRequest, Body, Headers>& m1,
message<isRequest, Body, Headers>& m2);
message<isRequest, Body, Fields>& m1,
message<isRequest, Body, Fields>& m2);
/// Message headers for a typical HTTP request
using request_headers = message_headers<true,
basic_headers<std::allocator<char>>>;
/// A typical HTTP request header
using request_header = header<true, fields>;
/// Message headers for a typical HTTP response
using response_headers = message_headers<false,
basic_headers<std::allocator<char>>>;
/// Typical HTTP response header
using response_header = header<false, fields>;
/// A typical HTTP request message
template<class Body,
class Headers = basic_headers<std::allocator<char>>>
using request = message<true, Body, Headers>;
/// A typical HTTP request
template<class Body, class Fields = fields>
using request = message<true, Body, Fields>;
/// A typical HTTP response message
template<class Body,
class Headers = basic_headers<std::allocator<char>>>
using response = message<false, Body, Headers>;
/// A typical HTTP response
template<class Body, class Fields = fields>
using response = message<false, Body, Fields>;
//------------------------------------------------------------------------------
/** 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.
*/
template<bool isRequest, class Body, class Headers>
template<bool isRequest, class Fields>
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.
*/
template<bool isRequest, class Body, class Headers>
template<bool isRequest, class Fields>
bool
is_upgrade(message<isRequest, Body, Headers> const& msg);
is_upgrade(header<isRequest, Fields> const& msg);
/** HTTP/1 connection prepare options.
@@ -446,18 +449,18 @@ enum class connection
/** Prepare a HTTP message.
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.
@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.
*/
template<
bool isRequest, class Body, class Headers,
bool isRequest, class Body, class Fields,
class... Options>
void
prepare(message<isRequest, Body, Headers>& msg,
prepare(message<isRequest, Body, Fields>& msg,
Options&&... options);
} // http

View File

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

View File

@@ -9,7 +9,7 @@
#define BEAST_HTTP_PARSER_V1_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/core/error.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
proxy. In these cases, callers use the @ref skip_body option to
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:
@code
parser_v1<true, empty_body, headers> p;
parser_v1<true, empty_body, fields> p;
p.set_option(skip_body{true});
@endcode
@@ -61,10 +61,10 @@ struct skip_body
@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
: public basic_parser_v1<isRequest,
parser_v1<isRequest, Body, Headers>>
parser_v1<isRequest, Body, Fields>>
, private std::conditional<isRequest,
detail::request_parser_base,
detail::response_parser_base>::type
@@ -72,7 +72,7 @@ class parser_v1
public:
/// The type of message this parser produces.
using message_type =
message<isRequest, Body, Headers>;
message<isRequest, Body, Fields>;
private:
using reader =
@@ -113,7 +113,7 @@ public:
@param args Forwarded to the message constructor.
@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
template<class... Args>
@@ -124,7 +124,7 @@ public:
class = typename std::enable_if<
! std::is_same<typename
std::decay<Arg1>::type,
headers_parser_v1<isRequest, Headers>>::value &&
header_parser_v1<isRequest, Fields>>::value &&
! std::is_same<typename
std::decay<Arg1>::type, parser_v1>::value
>::type>
@@ -136,20 +136,20 @@ public:
}
#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.
*/
template<class... Args>
explicit
parser_v1(headers_parser_v1<isRequest, Headers>& parser,
parser_v1(header_parser_v1<isRequest, Fields>& parser,
Args&&... args)
: m_(parser.release(), std::forward<Args>(args)...)
{
static_cast<basic_parser_v1<
isRequest, parser_v1<
isRequest, Body, Headers>>&>(*this) = parser;
isRequest, Body, Fields>>&>(*this) = parser;
}
/// Set the skip body option.
@@ -185,7 +185,7 @@ public:
valid if @ref complete would return `true`.
Requires:
`message<isRequest, Body, Headers>` is @b MoveConstructible
`message<isRequest, Body, Fields>` is @b MoveConstructible
*/
message_type
release()
@@ -204,7 +204,7 @@ private:
return;
flush_ = false;
BOOST_ASSERT(! field_.empty());
m_.headers.insert(field_, value_);
m_.fields.insert(field_, value_);
field_.clear();
value_.clear();
}
@@ -265,7 +265,7 @@ private:
}
void
on_headers(std::uint64_t, error_code&)
on_header(std::uint64_t, error_code&)
{
flush();
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
containing the original message headers and a new body
containing the original message fields and a new body
of the specified body type.
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
associate with the message. And finally, complete the parse
in a second call.
@param parser The headers parser to construct from. Ownership
of the message headers in the headers parser is transferred
as if by call to @ref headers_parser_v1::release.
@param parser The fields parser to construct from. Ownership
of the message fields in the fields parser is transferred
as if by call to @ref header_parser_v1::release.
@param args Forwarded to the body constructor of the message
in the new parser.
@@ -315,19 +315,20 @@ private:
@par Example
@code
headers_parser<true, headers> ph;
headers_parser<true, fields> 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
*/
template<class Body, bool isRequest, class Headers, class... Args>
parser_v1<isRequest, Body, Headers>
with_body(headers_parser_v1<isRequest, Headers>& parser,
template<class Body,
bool isRequest, class Fields, class... Args>
parser_v1<isRequest, Body, Fields>
with_body(header_parser_v1<isRequest, Fields>& parser,
Args&&... args)
{
return parser_v1<isRequest, Body, Headers>(
return parser_v1<isRequest, Body, Fields>(
parser, std::forward<Args>(args)...);
}

View File

@@ -15,22 +15,27 @@
namespace beast {
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
the stream. The call blocks until one of the following conditions
is true:
This function is used to synchronously read a header
from a stream. The call blocks until one of the following
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.
This function is implemented in terms of one or more calls
to the stream's `read_some` function. The implementation may
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.
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.
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
first.
@param msg An object used to store the message headers.
Any contents will be overwritten. The type must support
copy assignment or move assignment.
@param msg An object used to store the header. Any contents
will be overwritten. The type must support copy assignment
or move assignment.
@throws system_error Thrown on failure.
*/
template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Headers>
bool isRequest, class Fields>
void
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
the stream. The call blocks until one of the following conditions
is true:
This function is used to synchronously read a header
from a stream. The call blocks until one of the following
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.
This function is implemented in terms of one or more calls
to the stream's `read_some` function. The implementation may
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.
If the message 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.
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.
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
first.
@param msg An object used to store the message headers.
Any contents will be overwritten. The type must support
copy assignment or move assignment.
@param msg An object used to store the header. Any contents
will be overwritten. The type must support copy assignment
or move assignment.
@param ec Set to the error, if any occurred.
*/
template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Headers>
bool isRequest, class Fields>
void
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_headers<isRequest, Headers>& msg,
header<isRequest, Fields>& msg,
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
stream. The function call always returns immediately. The asynchronous
operation will continue until one of the following conditions is true:
This function is used to asynchronously read a header from
a stream. The function call always returns immediately. The
asynchronous operation will continue until one of the following
conditions is true:
@li A complete message is read in.
@li An entire header is read in.
@li An error occurs in the stream or parser.
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
stream performs no other operations until this operation completes.
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.
If the message 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.
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 to read the message from.
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
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
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.
Copies will be made of the handler as required. The equivalent
function signature of the handler must be:
@param handler The handler to be called when the operation
completes. Copies will be made of the handler as required.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error // result of operation
); @endcode
@@ -141,7 +150,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class AsyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers,
bool isRequest, class Body, class Fields,
class ReadHandler>
#if GENERATING_DOCS
void_or_deduced
@@ -150,13 +159,13 @@ typename async_completion<
ReadHandler, void(error_code)>::result_type
#endif
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
message_headers<isRequest, Headers>& msg,
header<isRequest, Fields>& msg,
ReadHandler&& handler);
/** Read a HTTP/1 message from a stream.
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:
@li A complete message is read in.
@@ -185,15 +194,15 @@ async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
@throws system_error Thrown on failure.
*/
template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers>
bool isRequest, class Body, class Fields>
void
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message<isRequest, Body, Headers>& msg);
message<isRequest, Body, Fields>& msg);
/** Read a HTTP/1 message from a stream.
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:
@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.
*/
template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers>
bool isRequest, class Body, class Fields>
void
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message<isRequest, Body, Headers>& msg,
message<isRequest, Body, Fields>& msg,
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
stream. The function call always returns immediately. The asynchronous
operation will continue until one of the following conditions is true:
This function is used to asynchronously read a message from
a stream. The function call always returns immediately. The
asynchronous operation will continue until one of the following
conditions is true:
@li A complete message is read in.
@li An error occurs in the stream or parser.
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
stream performs no other operations until this operation completes.
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
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
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.
Copies will be made of the handler as required. The equivalent
function signature of the handler must be:
@param handler The handler to be called when the operation
completes. Copies will be made of the handler as required.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error // result of operation
); @endcode
@@ -271,7 +282,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class AsyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers,
bool isRequest, class Body, class Fields,
class ReadHandler>
#if GENERATING_DOCS
void_or_deduced
@@ -280,7 +291,7 @@ typename async_completion<
ReadHandler, void(error_code)>::result_type
#endif
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
message<isRequest, Body, Headers>& msg,
message<isRequest, Body, Fields>& msg,
ReadHandler&& handler);
} // http

View File

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

View File

@@ -8,9 +8,12 @@
#ifndef 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 <boost/asio/buffer.hpp>
#include <boost/logic/tribool.hpp>
#include <memory>
#include <string>
@@ -35,10 +38,10 @@ private:
value_type& s_;
public:
template<bool isRequest, class Headers>
template<bool isRequest, class Fields>
explicit
reader(message<isRequest,
string_body, Headers>& m) noexcept
string_body, Fields>& m) noexcept
: s_(m.body)
{
}
@@ -63,10 +66,10 @@ private:
value_type const& body_;
public:
template<bool isRequest, class Headers>
template<bool isRequest, class Fields>
explicit
writer(message<
isRequest, string_body, Headers> const& msg) noexcept
isRequest, string_body, Fields> const& msg) noexcept
: body_(msg.body)
{
}

View File

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

View File

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

View File

@@ -43,9 +43,9 @@ class stream<NextLayer>::response_op
int state = 0;
template<class DeducedHandler,
class Body, class Headers>
class Body, class Fields>
data(DeducedHandler&& h_, stream<NextLayer>& ws_,
http::request<Body, Headers> const& req,
http::request<Body, Fields> const& req,
bool cont_)
: ws(ws_)
, resp(ws_.build_response(req))
@@ -305,11 +305,11 @@ async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler)
}
template<class NextLayer>
template<class Body, class Headers, class AcceptHandler>
template<class Body, class Fields, class AcceptHandler>
typename async_completion<
AcceptHandler, void(error_code)>::result_type
stream<NextLayer>::
async_accept(http::request<Body, Headers> const& req,
async_accept(http::request<Body, Fields> const& req,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
@@ -390,10 +390,10 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
}
template<class NextLayer>
template<class Body, class Headers>
template<class Body, class Fields>
void
stream<NextLayer>::
accept(http::request<Body, Headers> const& request)
accept(http::request<Body, Fields> const& request)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
@@ -404,10 +404,10 @@ accept(http::request<Body, Headers> const& request)
}
template<class NextLayer>
template<class Body, class Headers>
template<class Body, class Fields>
void
stream<NextLayer>::
accept(http::request<Body, Headers> const& req,
accept(http::request<Body, Fields> const& req,
error_code& ec)
{
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.version = 11;
req.method = "GET";
req.headers.insert("Host", host);
req.headers.insert("Upgrade", "websocket");
req.fields.insert("Host", host);
req.fields.insert("Upgrade", "websocket");
key = detail::make_sec_ws_key(maskgen_);
req.headers.insert("Sec-WebSocket-Key", key);
req.headers.insert("Sec-WebSocket-Version", "13");
req.fields.insert("Sec-WebSocket-Key", key);
req.fields.insert("Sec-WebSocket-Version", "13");
(*d_)(req);
http::prepare(req, http::connection::upgrade);
return req;
}
template<class NextLayer>
template<class Body, class Headers>
template<class Body, class Fields>
http::response<http::string_body>
stream<NextLayer>::
build_response(http::request<Body, Headers> const& req)
build_response(http::request<Body, Fields> const& req)
{
auto err =
[&](std::string const& text)
@@ -103,15 +103,15 @@ build_response(http::request<Body, Headers> const& req)
return err("Wrong method");
if(! is_upgrade(req))
return err("Expected Upgrade request");
if(! req.headers.exists("Host"))
if(! req.fields.exists("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");
if(! http::token_list{req.headers["Upgrade"]}.exists("websocket"))
if(! http::token_list{req.fields["Upgrade"]}.exists("websocket"))
return err("Missing websocket Upgrade token");
{
auto const version =
req.headers["Sec-WebSocket-Version"];
req.fields["Sec-WebSocket-Version"];
if(version.empty())
return err("Missing Sec-WebSocket-Version");
if(version != "13")
@@ -120,7 +120,7 @@ build_response(http::request<Body, Headers> const& req)
res.status = 426;
res.reason = http::reason_string(res.status);
res.version = req.version;
res.headers.insert("Sec-WebSocket-Version", "13");
res.fields.insert("Sec-WebSocket-Version", "13");
prepare(res,
(is_keep_alive(req) && keep_alive_) ?
http::connection::keep_alive :
@@ -132,24 +132,24 @@ build_response(http::request<Body, Headers> const& req)
res.status = 101;
res.reason = http::reason_string(res.status);
res.version = req.version;
res.headers.insert("Upgrade", "websocket");
res.fields.insert("Upgrade", "websocket");
{
auto const key =
req.headers["Sec-WebSocket-Key"];
res.headers.insert("Sec-WebSocket-Accept",
req.fields["Sec-WebSocket-Key"];
res.fields.insert("Sec-WebSocket-Accept",
detail::make_sec_ws_accept(key));
}
res.headers.replace("Server", "Beast.WSProto");
res.fields.replace("Server", "Beast.WSProto");
(*d_)(res);
http::prepare(res, http::connection::upgrade);
return res;
}
template<class NextLayer>
template<class Body, class Headers>
template<class Body, class Fields>
void
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)
{
// VFALCO Review these error codes
@@ -160,11 +160,11 @@ do_response(http::response<Body, Headers> const& res,
return fail();
if(! is_upgrade(res))
return fail();
if(! http::token_list{res.headers["Upgrade"]}.exists("websocket"))
if(! http::token_list{res.fields["Upgrade"]}.exists("websocket"))
return fail();
if(! res.headers.exists("Sec-WebSocket-Accept"))
if(! res.fields.exists("Sec-WebSocket-Accept"))
return fail();
if(res.headers["Sec-WebSocket-Accept"] !=
if(res.fields["Sec-WebSocket-Accept"] !=
detail::make_sec_ws_accept(key))
return fail();
open(detail::role_type::client);

View File

@@ -86,14 +86,14 @@ struct auto_fragment
@code
struct identity
{
template<bool isRequest, class Body, class Headers>
template<bool isRequest, class Body, class Fields>
void
operator()(http::message<isRequest, Body, Headers>& m)
operator()(http::message<isRequest, Body, Fields>& m)
{
if(isRequest)
m.headers.replace("User-Agent", "MyClient");
m.fields.replace("User-Agent", "MyClient");
else
m.headers.replace("Server", "MyServer");
m.fields.replace("Server", "MyServer");
}
};
...
@@ -284,7 +284,7 @@ struct read_buffer_size
/** Maximum incoming message size option.
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.
The default setting is 16 megabytes. A value of zero indicates

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@
//
// 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 <boost/lexical_cast.hpp>
@@ -14,18 +14,18 @@
namespace beast {
namespace http {
class basic_headers_test : public beast::unit_test::suite
class basic_fields_test : public beast::unit_test::suite
{
public:
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>
static
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)
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
} // beast

View File

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

View File

@@ -6,4 +6,4 @@
//
// 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.
#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 <boost/asio/buffer.hpp>
namespace beast {
namespace http {
class headers_parser_v1_test : public beast::unit_test::suite
class header_parser_v1_test : public beast::unit_test::suite
{
public:
void testParser()
{
{
error_code ec;
headers_parser_v1<true, headers> p;
header_parser_v1<true, fields> p;
BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer(
"GET / HTTP/1.1\r\n"
@@ -35,7 +35,7 @@ public:
}
{
error_code ec;
headers_parser_v1<true, headers> p;
header_parser_v1<true, fields> p;
BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer(
"GET / HTTP/1.1\r\n"
@@ -50,7 +50,7 @@ public:
}
{
error_code ec;
headers_parser_v1<false, headers> p;
header_parser_v1<false, fields> p;
BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer(
"HTTP/1.1 200 OK\r\n"
@@ -63,7 +63,7 @@ public:
}
{
error_code ec;
headers_parser_v1<false, headers> p;
header_parser_v1<false, fields> p;
BEAST_EXPECT(! p.complete());
auto const n = p.write(boost::asio::buffer(
"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
} // beast

View File

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

View File

@@ -475,7 +475,7 @@ public:
template<class DynamicBuffer>
void
headers(DynamicBuffer& db)
fields(DynamicBuffer& db)
{
while(rand(6))
{
@@ -536,7 +536,7 @@ public:
request(DynamicBuffer& db)
{
write(db, method(), " ", uri(), " HTTP/1.1\r\n");
headers(db);
fields(db);
body(db);
}
@@ -549,7 +549,7 @@ public:
write(db, " ", 100 + rand(401), " ");
write(db, token());
write(db, "\r\n");
headers(db);
fields(db);
body(db);
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.
*/
template<bool isRequest, class Body, class Headers>
template<bool isRequest, class Body, class Fields>
class nodejs_parser
: public nodejs_basic_parser<nodejs_parser<isRequest, Body, Headers>>
: public nodejs_basic_parser<nodejs_parser<isRequest, Body, Fields>>
{
using message_type =
message<isRequest, Body, Headers>;
message<isRequest, Body, Fields>;
message_type m_;
typename message_type::body_type::reader r_;
@@ -781,7 +781,7 @@ private:
void
on_field(std::string const& field, std::string const& value)
{
m_.headers.insert(field, value);
m_.fields.insert(field, value);
}
void

View File

@@ -48,7 +48,7 @@ public:
check("http", parse_error::invalid_chunk_size);
check("http", parse_error::invalid_ext_name);
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::short_read);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -135,18 +135,18 @@ private:
struct identity
{
template<class Body, class Headers>
template<class Body, class Fields>
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
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
{
template<class Body, class Headers>
template<class Body, class Fields>
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
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");
}
};