From e3848e72814272171d62ee33209c076745451712 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Thu, 10 Nov 2016 05:34:49 -0500 Subject: [PATCH] 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. --- CHANGELOG.md | 9 + doc/design.qbk | 11 +- doc/http.qbk | 280 ++++++++++-------- doc/images/message.png | Bin 9532 -> 30460 bytes doc/master.qbk | 36 ++- doc/quickref.xml | 25 +- examples/file_body.hpp | 9 +- examples/http_async_server.hpp | 24 +- examples/http_crawl.cpp | 4 +- examples/http_example.cpp | 4 +- examples/http_sync_server.hpp | 12 +- examples/ssl/http_ssl_example.cpp | 4 +- include/beast/core/dynabuf_readstream.hpp | 4 +- include/beast/http.hpp | 5 +- include/beast/http/basic_dynabuf_body.hpp | 13 +- .../{basic_headers.hpp => basic_fields.hpp} | 60 ++-- include/beast/http/basic_parser_v1.hpp | 92 +++--- include/beast/http/body_type.hpp | 19 -- include/beast/http/chunk_encode.hpp | 95 +----- .../{basic_headers.hpp => basic_fields.hpp} | 22 +- include/beast/http/detail/chunk_encode.hpp | 111 +++++++ include/beast/http/empty_body.hpp | 9 +- .../beast/http/{headers.hpp => fields.hpp} | 11 +- ...ers_parser_v1.hpp => header_parser_v1.hpp} | 60 ++-- .../{basic_headers.ipp => basic_fields.ipp} | 82 ++--- include/beast/http/impl/basic_parser_v1.ipp | 25 +- include/beast/http/impl/message.ipp | 88 +++--- include/beast/http/impl/parse_error.ipp | 2 +- include/beast/http/impl/read.ipp | 78 ++--- include/beast/http/impl/write.ipp | 86 +++--- include/beast/http/message.hpp | 209 ++++++------- include/beast/http/parse_error.hpp | 2 +- include/beast/http/parser_v1.hpp | 57 ++-- include/beast/http/read.hpp | 131 ++++---- include/beast/http/reason.hpp | 13 +- include/beast/http/string_body.hpp | 13 +- include/beast/http/write.hpp | 153 +++++----- include/beast/websocket/detail/decorator.hpp | 4 +- include/beast/websocket/impl/accept.ipp | 16 +- include/beast/websocket/impl/stream.ipp | 40 +-- include/beast/websocket/option.hpp | 10 +- include/beast/websocket/stream.hpp | 20 +- test/Jamfile | 7 +- test/http/CMakeLists.txt | 7 +- .../{basic_headers.cpp => basic_fields.cpp} | 12 +- test/http/basic_parser_v1.cpp | 18 +- test/http/body_type.cpp | 9 - test/http/fail_parser.hpp | 2 +- test/http/{headers.cpp => fields.cpp} | 2 +- ...ers_parser_v1.cpp => header_parser_v1.cpp} | 16 +- test/http/message.cpp | 90 +++--- test/http/message_fuzz.hpp | 6 +- test/http/nodejs_parser.hpp | 8 +- test/http/parse_error.cpp | 2 +- test/http/parser_bench.cpp | 8 +- test/http/parser_v1.cpp | 44 +-- test/http/read.cpp | 14 +- test/http/streambuf_body.cpp | 4 +- test/http/write.cpp | 100 +++---- test/websocket/frame.cpp | 6 +- test/websocket/stream.cpp | 18 +- .../websocket/websocket_async_echo_server.hpp | 12 +- test/websocket/websocket_sync_echo_server.hpp | 12 +- 63 files changed, 1220 insertions(+), 1125 deletions(-) rename include/beast/http/{basic_headers.hpp => basic_fields.hpp} (81%) delete mode 100644 include/beast/http/body_type.hpp rename include/beast/http/detail/{basic_headers.hpp => basic_fields.hpp} (90%) create mode 100644 include/beast/http/detail/chunk_encode.hpp rename include/beast/http/{headers.hpp => fields.hpp} (62%) rename include/beast/http/{headers_parser_v1.hpp => header_parser_v1.hpp} (74%) rename include/beast/http/impl/{basic_headers.ipp => basic_fields.ipp} (76%) rename test/http/{basic_headers.cpp => basic_fields.cpp} (86%) delete mode 100644 test/http/body_type.cpp rename test/http/{headers.cpp => fields.cpp} (89%) rename test/http/{headers_parser_v1.cpp => header_parser_v1.cpp} (85%) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecde73a9..f84ebee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +1.0.0-b20 + +API Changes: + +* Rename HTTP identifiers + +-------------------------------------------------------------------------------- + +>>>>>>> b152207... . 1.0.0-b19 * Boost library min/max guidance diff --git a/doc/design.qbk b/doc/design.qbk index c3947d6b..698c6c80 100644 --- a/doc/design.qbk +++ b/doc/design.qbk @@ -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 [ diff --git a/doc/http.qbk b/doc/http.qbk index 3553f3ee..8ef784ff 100644 --- a/doc/http.qbk +++ b/doc/http.qbk @@ -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 ''' - Messages - Headers + Message + Fields Body Algorithms - Sockets '''] -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 #include 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; +using response_header = header; +template +using request = message; + +template +using response = message; ``` -* [*`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>> - using request = message; - - template< - class Body, - class Headers = basic_headers>> - using response = message; -``` - -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 - 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 - 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 req; - req.version = 11; // HTTP/1.1 +[table Create Message +[[HTTP Request] [HTTP Response]] +[[ + ``` + request 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 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) diff --git a/doc/images/message.png b/doc/images/message.png index cb07efc82fb17c79d46203234e71e2be83191183..9b88298a162c184f59dea151a5da913acd7019fe 100644 GIT binary patch delta 29899 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 S1i3*AHauPZT-G@yGywqG&}WGN diff --git a/doc/master.qbk b/doc/master.qbk index 4075e301..d8155f2d 100644 --- a/doc/master.qbk +++ b/doc/master.qbk @@ -23,25 +23,33 @@ [template indexterm1[term1] ''''''[term1]''''''] [template indexterm2[term1 term2] ''''''[term1]''''''[term2]''''''] -[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. diff --git a/doc/quickref.xml b/doc/quickref.xml index 2f75e68a..a51832ba 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -30,24 +30,25 @@ Classes basic_dynabuf_body - basic_headers + basic_fields basic_parser_v1 empty_body - headers - headers_parser_v1 + fields + header + header_parser_v1 message - message_headers parser_v1 request - request_headers + request_header response - response_headers + response_header resume_context streambuf_body string_body rfc7230 + ext_list param_list token_list @@ -56,20 +57,21 @@ Functions - async_parse async_read + async_parse async_write chunk_encode chunk_encode_final + swap is_keep_alive is_upgrade + operator<< parse prepare read - swap + reason_string with_body write - operator<< Type Traits @@ -84,14 +86,17 @@ Options + header_max_size body_max_size - headers_max_size skip_body Constants body_what connection + no_content_length + parse_error + parse_flag Concepts diff --git a/examples/file_body.hpp b/examples/file_body.hpp index 8e7bb55b..c92d4fe7 100644 --- a/examples/file_body.hpp +++ b/examples/file_body.hpp @@ -8,9 +8,12 @@ #ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED #define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED -#include +#include +#include +#include #include #include +#include #include #include @@ -34,8 +37,8 @@ struct file_body writer(writer const&) = delete; writer& operator=(writer const&) = delete; - template - writer(message const& m) noexcept + template + writer(message const& m) noexcept : path_(m.body) { } diff --git a/examples/http_async_server.hpp b/examples/http_async_server.hpp index fdc94ef9..350f4a38 100644 --- a/examples/http_async_server.hpp +++ b/examples/http_async_server.hpp @@ -85,7 +85,7 @@ public: private: template + bool isRequest, class Body, class Fields> class write_op { using alloc_type = @@ -94,13 +94,13 @@ private: struct data { Stream& s; - message m; + message m; Handler h; bool cont; template data(DeducedHandler&& h_, Stream& s_, - message&& m_) + message&& m_) : s(s_) , m(std::move(m_)) , h(std::forward(h_)) @@ -170,16 +170,16 @@ private: }; template static void async_write(Stream& stream, message< - isRequest, Body, Headers>&& msg, + isRequest, Body, Fields>&& msg, DeducedHandler&& handler) { write_op::type, - isRequest, Body, Headers>{std::forward( + isRequest, Body, Fields>{std::forward( 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); diff --git a/examples/http_crawl.cpp b/examples/http_crawl.cpp index b968abbb..3e67a14e 100644 --- a/examples/http_crawl.cpp +++ b/examples/http_crawl.cpp @@ -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(ep.port())); - req.headers.insert("User-Agent", "beast/http"); + req.fields.insert("User-Agent", "beast/http"); prepare(req); write(sock, req); response res; diff --git a/examples/http_example.cpp b/examples/http_example.cpp index 2ccbc3be..55910fee 100644 --- a/examples/http_example.cpp +++ b/examples/http_example.cpp @@ -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(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); diff --git a/examples/http_sync_server.hpp b/examples/http_sync_server.hpp index 8dfe45d4..bd6df50d 100644 --- a/examples/http_sync_server.hpp +++ b/examples/http_sync_server.hpp @@ -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); diff --git a/examples/ssl/http_ssl_example.cpp b/examples/ssl/http_ssl_example.cpp index 09e921cf..ff6224c2 100644 --- a/examples/ssl/http_ssl_example.cpp +++ b/examples/ssl/http_ssl_example.cpp @@ -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(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); diff --git a/include/beast/core/dynabuf_readstream.hpp b/include/beast/core/dynabuf_readstream.hpp index 458bcc2c..32c545cc 100644 --- a/include/beast/core/dynabuf_readstream.hpp +++ b/include/beast/core/dynabuf_readstream.hpp @@ -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 @@ -54,7 +54,7 @@ namespace beast { dynabuf_readstream& 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. diff --git a/include/beast/http.hpp b/include/beast/http.hpp index 02cb4b0d..ee475791 100644 --- a/include/beast/http.hpp +++ b/include/beast/http.hpp @@ -8,12 +8,11 @@ #ifndef BEAST_HTTP_HPP #define BEAST_HTTP_HPP -#include +#include #include -#include #include #include -#include +#include #include #include #include diff --git a/include/beast/http/basic_dynabuf_body.hpp b/include/beast/http/basic_dynabuf_body.hpp index 4d331380..de2f43cd 100644 --- a/include/beast/http/basic_dynabuf_body.hpp +++ b/include/beast/http/basic_dynabuf_body.hpp @@ -8,9 +8,12 @@ #ifndef BEAST_HTTP_BASIC_DYNABUF_BODY_HPP #define BEAST_HTTP_BASIC_DYNABUF_BODY_HPP -#include +#include +#include +#include #include #include +#include namespace beast { namespace http { @@ -34,10 +37,10 @@ private: value_type& sb_; public: - template + template explicit reader(message& m) noexcept + basic_dynabuf_body, Fields>& m) noexcept : sb_(m.body) { } @@ -63,10 +66,10 @@ private: DynamicBuffer const& body_; public: - template + template explicit writer(message< - isRequest, basic_dynabuf_body, Headers> const& m) noexcept + isRequest, basic_dynabuf_body, Fields> const& m) noexcept : body_(m.body) { } diff --git a/include/beast/http/basic_headers.hpp b/include/beast/http/basic_fields.hpp similarity index 81% rename from include/beast/http/basic_headers.hpp rename to include/beast/http/basic_fields.hpp index b4010196..3bc95774 100644 --- a/include/beast/http/basic_headers.hpp +++ b/include/beast/http/basic_fields.hpp @@ -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 -#include +#include #include #include #include @@ -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 basic_headers : +class basic_fields : #if ! GENERATING_DOCS private beast::detail::empty_base_optimization< typename std::allocator_traits:: 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:: template rebind_alloc< - detail::basic_headers_base::element>; + detail::basic_fields_base::element>; using alloc_traits = std::allocator_traits; @@ -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 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 - basic_headers(basic_headers const&); + basic_fields(basic_fields const&); /// Copy assignment. template - basic_headers& operator=(basic_headers const&); + basic_fields& operator=(basic_fields const&); /// Construct from a field sequence. template - 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 +#include #endif diff --git a/include/beast/http/basic_parser_v1.hpp b/include/beast/http/basic_parser_v1.hpp index 9db48bf3..70e9e06c 100644 --- a/include/beast/http/basic_parser_v1.hpp +++ b/include/beast/http/basic_parser_v1.hpp @@ -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)...); } - /// 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 struct check_on_headers().on_headers( + std::declval().on_header( std::declval(), std::declval()) )>> : 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::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 diff --git a/include/beast/http/body_type.hpp b/include/beast/http/body_type.hpp deleted file mode 100644 index 5b3f9601..00000000 --- a/include/beast/http/body_type.hpp +++ /dev/null @@ -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 -#include -#include -#include - -#endif diff --git a/include/beast/http/chunk_encode.hpp b/include/beast/http/chunk_encode.hpp index 6d9836f2..cb2881b4 100644 --- a/include/beast/http/chunk_encode.hpp +++ b/include/beast/http/chunk_encode.hpp @@ -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 +#include #include #include #include @@ -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 buf_; - - template - void - copy(chunk_encode_text const& other); - - template - void - setup(std::size_t n); - - template - 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 -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 -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::distance(it, buf_.end()))}; -} - /** Returns a chunk-encoded ConstBufferSequence. This returns a buffer sequence representing the @@ -124,7 +39,7 @@ template 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}); diff --git a/include/beast/http/detail/basic_headers.hpp b/include/beast/http/detail/basic_fields.hpp similarity index 90% rename from include/beast/http/detail/basic_headers.hpp rename to include/beast/http/detail/basic_fields.hpp index 49bc678d..a60b30f2 100644 --- a/include/beast/http/detail/basic_headers.hpp +++ b/include/beast/http/detail/basic_fields.hpp @@ -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 #include @@ -17,11 +17,11 @@ namespace beast { namespace http { template -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 - 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 - 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; diff --git a/include/beast/http/detail/chunk_encode.hpp b/include/beast/http/detail/chunk_encode.hpp new file mode 100644 index 00000000..e2ebb812 --- /dev/null +++ b/include/beast/http/detail/chunk_encode.hpp @@ -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 +#include +#include +#include + +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 buf_; + + template + void + copy(chunk_encode_delim const& other); + + template + void + setup(std::size_t n); + + template + 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 +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 +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::distance(it, buf_.end()))}; +} + +} // detail +} // http +} // beast + +#endif diff --git a/include/beast/http/empty_body.hpp b/include/beast/http/empty_body.hpp index b76e02d7..e497b87f 100644 --- a/include/beast/http/empty_body.hpp +++ b/include/beast/http/empty_body.hpp @@ -8,9 +8,12 @@ #ifndef BEAST_HTTP_EMPTY_BODY_HPP #define BEAST_HTTP_EMPTY_BODY_HPP -#include +#include +#include +#include #include #include +#include #include #include @@ -36,9 +39,9 @@ private: struct writer { - template + template explicit - writer(message const& m) noexcept + writer(message const& m) noexcept { beast::detail::ignore_unused(m); } diff --git a/include/beast/http/headers.hpp b/include/beast/http/fields.hpp similarity index 62% rename from include/beast/http/headers.hpp rename to include/beast/http/fields.hpp index 3268fa50..fb80ad7f 100644 --- a/include/beast/http/headers.hpp +++ b/include/beast/http/fields.hpp @@ -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 +#include #include namespace beast { namespace http { -using headers = - basic_headers>; +/// A typical HTTP header fields container +using fields = + basic_fields>; } // http } // beast diff --git a/include/beast/http/headers_parser_v1.hpp b/include/beast/http/header_parser_v1.hpp similarity index 74% rename from include/beast/http/headers_parser_v1.hpp rename to include/beast/http/header_parser_v1.hpp index 21236fd5..9caafa44 100644 --- a/include/beast/http/headers_parser_v1.hpp +++ b/include/beast/http/header_parser_v1.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -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 -class headers_parser_v1 +template +class header_parser_v1 : public basic_parser_v1> + header_parser_v1> , private std::conditional::type { public: - /// The type of message this parser produces. - using headers_type = - message_headers; + /// The type of the header this parser produces. + using header_type = header; 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 explicit - headers_parser_v1(Args&&... args); + header_parser_v1(Args&&... args); #else template::type, headers_parser_v1>::value>> + typename std::decay::type, header_parser_v1>::value>> explicit - headers_parser_v1(Arg1&& arg1, ArgN&&... argn) + header_parser_v1(Arg1&& arg1, ArgN&&... argn) : h_(std::forward(arg1), std::forward(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` is @b MoveConstructible + @ref header_type is @b MoveConstructible */ - headers_type + header_type release() { static_assert(std::is_move_constructible::value, @@ -138,7 +136,7 @@ public: } private: - friend class basic_parser_v1; + friend class basic_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(); diff --git a/include/beast/http/impl/basic_headers.ipp b/include/beast/http/impl/basic_fields.ipp similarity index 76% rename from include/beast/http/impl/basic_headers.ipp rename to include/beast/http/impl/basic_fields.ipp index 1186731b..8c421e9e 100644 --- a/include/beast/http/impl/basic_headers.ipp +++ b/include/beast/http/impl/basic_fields.ipp @@ -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 #include @@ -16,7 +16,7 @@ namespace http { template void -basic_headers:: +basic_fields:: delete_all() { for(auto it = list_.begin(); it != list_.end();) @@ -31,8 +31,8 @@ delete_all() template inline void -basic_headers:: -move_assign(basic_headers& other, std::false_type) +basic_fields:: +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 inline void -basic_headers:: -move_assign(basic_headers& other, std::true_type) +basic_fields:: +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 inline void -basic_headers:: -copy_assign(basic_headers const& other, std::false_type) +basic_fields:: +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 inline void -basic_headers:: -copy_assign(basic_headers const& other, std::true_type) +basic_fields:: +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 -basic_headers:: -~basic_headers() +basic_fields:: +~basic_fields() { delete_all(); } template -basic_headers:: -basic_headers(Allocator const& alloc) +basic_fields:: +basic_fields(Allocator const& alloc) : beast::detail::empty_base_optimization< alloc_type>(alloc) { } template -basic_headers:: -basic_headers(basic_headers&& other) +basic_fields:: +basic_fields(basic_fields&& other) : beast::detail::empty_base_optimization( std::move(other.member())) - , detail::basic_headers_base( + , detail::basic_fields_base( std::move(other.set_), std::move(other.list_)) { } template auto -basic_headers:: -operator=(basic_headers&& other) -> - basic_headers& +basic_fields:: +operator=(basic_fields&& other) -> + basic_fields& { if(this == &other) return *this; @@ -118,9 +118,9 @@ operator=(basic_headers&& other) -> } template -basic_headers:: -basic_headers(basic_headers const& other) - : basic_headers(alloc_traits:: +basic_fields:: +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 auto -basic_headers:: -operator=(basic_headers const& other) -> - basic_headers& +basic_fields:: +operator=(basic_fields const& other) -> + basic_fields& { clear(); copy_assign(other, std::integral_constant template template -basic_headers:: -basic_headers(basic_headers const& other) +basic_fields:: +basic_fields(basic_fields const& other) { copy_from(other); } @@ -149,9 +149,9 @@ basic_headers(basic_headers const& other) template template auto -basic_headers:: -operator=(basic_headers const& other) -> - basic_headers& +basic_fields:: +operator=(basic_fields const& other) -> + basic_fields& { clear(); copy_from(other); @@ -160,8 +160,8 @@ operator=(basic_headers const& other) -> template template -basic_headers:: -basic_headers(FwdIt first, FwdIt last) +basic_fields:: +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 std::size_t -basic_headers:: +basic_fields:: 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 auto -basic_headers:: +basic_fields:: find(boost::string_ref const& name) const -> iterator { @@ -193,7 +193,7 @@ find(boost::string_ref const& name) const -> template boost::string_ref -basic_headers:: +basic_fields:: operator[](boost::string_ref const& name) const { auto const it = find(name); @@ -204,7 +204,7 @@ operator[](boost::string_ref const& name) const template void -basic_headers:: +basic_fields:: clear() noexcept { delete_all(); @@ -214,7 +214,7 @@ clear() noexcept template std::size_t -basic_headers:: +basic_fields:: erase(boost::string_ref const& name) { auto it = set_.find(name, less{}); @@ -238,7 +238,7 @@ erase(boost::string_ref const& name) template void -basic_headers:: +basic_fields:: insert(boost::string_ref const& name, boost::string_ref value) { @@ -251,7 +251,7 @@ insert(boost::string_ref const& name, template void -basic_headers:: +basic_fields:: replace(boost::string_ref const& name, boost::string_ref value) { diff --git a/include/beast/http/impl/basic_parser_v1.ipp b/include/beast/http/impl/basic_parser_v1.ipp index 069656b7..9757b92a 100644 --- a/include/beast/http/impl/basic_parser_v1.ipp +++ b/include/beast/http/impl/basic_parser_v1.ipp @@ -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 +#include +#include + +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 -#include -#include - -namespace beast { -namespace http { - template basic_parser_v1:: basic_parser_v1() diff --git a/include/beast/http/impl/message.ipp b/include/beast/http/impl/message.ipp index ea6c26f5..9a818cd8 100644 --- a/include/beast/http/impl/message.ipp +++ b/include/beast/http/impl/message.ipp @@ -20,67 +20,67 @@ namespace beast { namespace http { -template +template void swap( - message_headers& m1, - message_headers& m2) + header& m1, + header& 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 +template void swap( - message_headers& a, - message_headers& b) + header& a, + header& 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 +template void swap( - message& m1, - message& m2) + message& m1, + message& m2) { using std::swap; swap(m1.base(), m2.base()); swap(m1.body, m2.body); } -template +template bool -is_keep_alive(message const& msg) +is_keep_alive(header 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 +template bool -is_upgrade(message const& msg) +is_upgrade(header 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 content_length; }; -template +template inline void prepare_options(prepare_info& pi, - message& msg) + message& msg) { beast::detail::ignore_unused(pi, msg); } -template +template void prepare_option(prepare_info& pi, - message& msg, + message& 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& msg, + message& msg, Opt&& opt, Opts&&... opts) { prepare_option(pi, msg, opt); @@ -125,10 +125,10 @@ prepare_options(prepare_info& pi, std::forward(opts)...); } -template +template void prepare_content_length(prepare_info& pi, - message const& msg, + message 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 +template void prepare_content_length(prepare_info& pi, - message const& msg, + message 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& msg, +prepare(message& msg, Options&&... options) { // VFALCO TODO @@ -165,7 +165,7 @@ prepare(message& msg, static_assert(has_writer::value, "Body has no writer"); static_assert(is_Writer>::value, + message>::value, "Writer requirements not met"); detail::prepare_info pi; detail::prepare_content_length(pi, msg, @@ -173,15 +173,15 @@ prepare(message& msg, detail::prepare_options(pi, msg, std::forward(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& msg, struct set_field { void - operator()(message& msg, + operator()(message& 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& msg, + operator()(message& 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& 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"); } diff --git a/include/beast/http/impl/parse_error.ipp b/include/beast/http/impl/parse_error.ipp index 25b5374e..83578ceb 100644 --- a/include/beast/http/impl/parse_error.ipp +++ b/include/beast/http/impl/parse_error.ipp @@ -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"; diff --git a/include/beast/http/impl/read.ipp b/include/beast/http/impl/read.ipp index 50b19867..6a96355a 100644 --- a/include/beast/http/impl/read.ipp +++ b/include/beast/http/impl/read.ipp @@ -9,7 +9,7 @@ #define BEAST_HTTP_IMPL_READ_IPP_HPP #include -#include +#include #include #include #include @@ -23,18 +23,18 @@ namespace http { namespace detail { template -class read_headers_op +class read_header_op { using alloc_type = handler_alloc; using parser_type = - headers_parser_v1; + header_parser_v1; using message_type = - message_headers; + header; struct data { @@ -63,11 +63,11 @@ class read_headers_op std::shared_ptr 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 - read_headers_op( + read_header_op( DeducedHandler&& h, Stream& s, Args&&... args) : d_(std::allocate_shared(alloc_type{h}, std::forward(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 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 void -read_headers_op:: +read_header_op:: operator()(error_code ec, bool again) { auto& d = *d_; @@ -141,10 +141,10 @@ operator()(error_code ec, bool again) } // detail template + bool isRequest, class Fields> void read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message_headers& msg) + header& msg) { static_assert(is_SyncReadStream::value, "SyncReadStream requirements not met"); @@ -157,17 +157,17 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf, } template + bool isRequest, class Fields> void read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message_headers& m, + header& m, error_code& ec) { static_assert(is_SyncReadStream::value, "SyncReadStream requirements not met"); static_assert(is_DynamicBuffer::value, "DynamicBuffer requirements not met"); - headers_parser_v1 p; + header_parser_v1 p; beast::http::parse(stream, dynabuf, p, ec); if(ec) return; @@ -176,12 +176,12 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf, } template typename async_completion< ReadHandler, void(error_code)>::result_type async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, - message_headers& m, + header& m, ReadHandler&& handler) { static_assert(is_AsyncReadStream::value, @@ -190,8 +190,8 @@ async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, "DynamicBuffer requirements not met"); beast::async_completion completion(handler); - detail::read_headers_op{completion.handler, stream, dynabuf, m}; return completion.result.get(); @@ -202,7 +202,7 @@ async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, namespace detail { template class read_op { @@ -210,10 +210,10 @@ class read_op handler_alloc; using parser_type = - parser_v1; + parser_v1; using message_type = - message; + message; struct data { @@ -289,10 +289,10 @@ public: }; template void -read_op:: +read_op:: operator()(error_code ec, bool again) { auto& d = *d_; @@ -319,10 +319,10 @@ operator()(error_code ec, bool again) } // detail template + bool isRequest, class Body, class Fields> void read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message& msg) + message& msg) { static_assert(is_SyncReadStream::value, "SyncReadStream requirements not met"); @@ -333,7 +333,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf, static_assert(has_reader::value, "Body has no reader"); static_assert(is_Reader>::value, + message>::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 + bool isRequest, class Body, class Fields> void read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message& m, + message& m, error_code& ec) { static_assert(is_SyncReadStream::value, @@ -357,9 +357,9 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf, static_assert(has_reader::value, "Body has no reader"); static_assert(is_Reader>::value, + message>::value, "Reader requirements not met"); - parser_v1 p; + parser_v1 p; beast::http::parse(stream, dynabuf, p, ec); if(ec) return; @@ -368,12 +368,12 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf, } template typename async_completion< ReadHandler, void(error_code)>::result_type async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, - message& m, + message& m, ReadHandler&& handler) { static_assert(is_AsyncReadStream::value, @@ -385,12 +385,12 @@ async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, static_assert(has_reader::value, "Body has no reader"); static_assert(is_Reader>::value, + message>::value, "Reader requirements not met"); beast::async_completion completion(handler); detail::read_op{completion.handler, stream, dynabuf, m}; return completion.result.get(); diff --git a/include/beast/http/impl/write.ipp b/include/beast/http/impl/write.ipp index 44f37c53..e5b83ab2 100644 --- a/include/beast/http/impl/write.ipp +++ b/include/beast/http/impl/write.ipp @@ -32,10 +32,10 @@ namespace http { namespace detail { -template +template void write_start_line(DynamicBuffer& dynabuf, - message_headers const& msg) + header const& msg) { BOOST_ASSERT(msg.version == 10 || msg.version == 11); write(dynabuf, msg.method); @@ -52,10 +52,10 @@ write_start_line(DynamicBuffer& dynabuf, } } -template +template void write_start_line(DynamicBuffer& dynabuf, - message_headers const& msg) + header 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 + bool isRequest, class Fields> void write(SyncWriteStream& stream, - message_headers const& msg) + header const& msg) { static_assert(is_SyncWriteStream::value, "SyncWriteStream requirements not met"); @@ -219,28 +219,28 @@ write(SyncWriteStream& stream, } template + bool isRequest, class Fields> void write(SyncWriteStream& stream, - message_headers const& msg, + header const& msg, error_code& ec) { static_assert(is_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 typename async_completion< WriteHandler, void(error_code)>::result_type async_write(AsyncWriteStream& stream, - message_headers const& msg, + header const& msg, WriteHandler&& handler) { static_assert(is_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{ @@ -261,10 +261,10 @@ async_write(AsyncWriteStream& stream, namespace detail { -template +template struct write_preparation { - message const& msg; + message const& msg; typename Body::writer w; streambuf sb; bool chunked; @@ -272,14 +272,14 @@ struct write_preparation explicit write_preparation( - message const& msg_) + message 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 + 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 data(DeducedHandler&& h_, Stream& s_, - message const& m_) + message const& m_) : s(s_) , wp(m_) , h(std::forward(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 + bool isRequest, class Body, class Fields> void -write_op:: +write_op:: 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 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 + bool isRequest, class Body, class Fields> void write(SyncWriteStream& stream, - message const& msg) + message const& msg) { static_assert(is_SyncWriteStream::value, "SyncWriteStream requirements not met"); @@ -631,7 +631,7 @@ write(SyncWriteStream& stream, static_assert(has_writer::value, "Body has no writer"); static_assert(is_Writer>::value, + message>::value, "Writer requirements not met"); error_code ec; write(stream, msg, ec); @@ -640,10 +640,10 @@ write(SyncWriteStream& stream, } template + bool isRequest, class Body, class Fields> void write(SyncWriteStream& stream, - message const& msg, + message const& msg, error_code& ec) { static_assert(is_SyncWriteStream::value, @@ -653,9 +653,9 @@ write(SyncWriteStream& stream, static_assert(has_writer::value, "Body has no writer"); static_assert(is_Writer>::value, + message>::value, "Writer requirements not met"); - detail::write_preparation wp(msg); + detail::write_preparation wp(msg); wp.init(ec); if(ec) return; @@ -729,12 +729,12 @@ write(SyncWriteStream& stream, } template typename async_completion< WriteHandler, void(error_code)>::result_type async_write(AsyncWriteStream& stream, - message const& msg, + message const& msg, WriteHandler&& handler) { static_assert(is_AsyncWriteStream::value, @@ -744,21 +744,21 @@ async_write(AsyncWriteStream& stream, static_assert(has_writer::value, "Body has no writer"); static_assert(is_Writer>::value, + message>::value, "Writer requirements not met"); beast::async_completion completion(handler); detail::write_op{completion.handler, stream, msg}; + isRequest, Body, Fields>{completion.handler, stream, msg}; return completion.result.get(); } //------------------------------------------------------------------------------ -template +template std::ostream& operator<<(std::ostream& os, - message_headers const& msg) + header const& msg) { beast::detail::sync_ostream oss{os}; error_code ec; @@ -768,17 +768,17 @@ operator<<(std::ostream& os, return os; } -template +template std::ostream& operator<<(std::ostream& os, - message const& msg) + message const& msg) { static_assert(is_Body::value, "Body requirements not met"); static_assert(has_writer::value, "Body has no writer"); static_assert(is_Writer>::value, + message>::value, "Writer requirements not met"); beast::detail::sync_ostream oss{os}; error_code ec; diff --git a/include/beast/http/message.hpp b/include/beast/http/message.hpp index 8a136abd..ebe17238 100644 --- a/include/beast/http/message.hpp +++ b/include/beast/http/message.hpp @@ -8,7 +8,7 @@ #ifndef BEAST_HTTP_MESSAGE_HPP #define BEAST_HTTP_MESSAGE_HPP -#include +#include #include #include #include @@ -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 -struct message_headers +template +struct header #else -template -struct message_headers; +template +struct header; -template -struct message_headers +template +struct header #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 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 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 explicit - message_headers(Args&&... args); + header(Args&&... args); #else template 0) || ! std::is_convertible< typename std::decay::type, - message_headers>::value>::type> + header>::value>::type> explicit - message_headers(Arg1&& arg1, ArgN&&... argn) - : headers(std::forward(arg1), + header(Arg1&& arg1, ArgN&&... argn) + : fields(std::forward(arg1), std::forward(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 -struct message_headers +template +struct header { - /// 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 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 0) || ! std::is_convertible< typename std::decay::type, - message_headers>::value>::type> + header>::value>::type> explicit - message_headers(Arg1&& arg1, ArgN&&... argn) - : headers(std::forward(arg1), + header(Arg1&& arg1, ArgN&&... argn) + : fields(std::forward(arg1), std::forward(argn)...) { } @@ -204,9 +211,10 @@ struct message_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 @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 -struct message : - message_headers +template +struct message : header { - /// The base class used to hold the request or response headers - using base_type = message_headers; + /// The base class used to hold the header portion of the message. + using base_type = header; /** 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 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 +template void swap( - message_headers& m1, - message_headers& m2); + header& m1, + header& 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 +template void swap( - message& m1, - message& m2); + message& m1, + message& m2); -/// Message headers for a typical HTTP request -using request_headers = message_headers>>; +/// A typical HTTP request header +using request_header = header; -/// Message headers for a typical HTTP response -using response_headers = message_headers>>; +/// Typical HTTP response header +using response_header = header; -/// A typical HTTP request message -template>> -using request = message; +/// A typical HTTP request +template +using request = message; -/// A typical HTTP response message -template>> -using response = message; +/// A typical HTTP response +template +using response = message; //------------------------------------------------------------------------------ -/** 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 +template bool -is_keep_alive(message const& msg); +is_keep_alive(header 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 +template bool -is_upgrade(message const& msg); +is_upgrade(header 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& msg, +prepare(message& msg, Options&&... options); } // http diff --git a/include/beast/http/parse_error.hpp b/include/beast/http/parse_error.hpp index 56f8dc2b..43a66468 100644 --- a/include/beast/http/parse_error.hpp +++ b/include/beast/http/parse_error.hpp @@ -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 }; diff --git a/include/beast/http/parser_v1.hpp b/include/beast/http/parser_v1.hpp index 9d013843..fbcd3401 100644 --- a/include/beast/http/parser_v1.hpp +++ b/include/beast/http/parser_v1.hpp @@ -9,7 +9,7 @@ #define BEAST_HTTP_PARSER_V1_HPP #include -#include +#include #include #include #include @@ -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 p; + parser_v1 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 +template class parser_v1 : public basic_parser_v1> + parser_v1> , private std::conditional::type @@ -72,7 +72,7 @@ class parser_v1 public: /// The type of message this parser produces. using message_type = - message; + message; 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 @@ -124,7 +124,7 @@ public: class = typename std::enable_if< ! std::is_same::type, - headers_parser_v1>::value && + header_parser_v1>::value && ! std::is_same::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 explicit - parser_v1(headers_parser_v1& parser, + parser_v1(header_parser_v1& parser, Args&&... args) : m_(parser.release(), std::forward(args)...) { static_cast>&>(*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` is @b MoveConstructible + `message` 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 ph; + headers_parser ph; ... auto p = with_body(ph); ... - message m = p.release(); + message m = p.release(); @endcode */ -template -parser_v1 -with_body(headers_parser_v1& parser, +template +parser_v1 +with_body(header_parser_v1& parser, Args&&... args) { - return parser_v1( + return parser_v1( parser, std::forward(args)...); } diff --git a/include/beast/http/read.hpp b/include/beast/http/read.hpp index e5f0bb70..67610e65 100644 --- a/include/beast/http/read.hpp +++ b/include/beast/http/read.hpp @@ -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 + bool isRequest, class Fields> void read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message_headers& msg); + header& 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 + bool isRequest, class Fields> void read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message_headers& msg, + header& 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 composed operation. 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 #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& msg, + header& 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 + bool isRequest, class Body, class Fields> void read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message& msg); + message& 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 + bool isRequest, class Body, class Fields> void read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message& msg, + message& 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 composed operation. 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 #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& msg, + message& msg, ReadHandler&& handler); } // http diff --git a/include/beast/http/reason.hpp b/include/beast/http/reason.hpp index ab3b51b7..14b9bf7c 100644 --- a/include/beast/http/reason.hpp +++ b/include/beast/http/reason.hpp @@ -11,7 +11,8 @@ namespace beast { namespace http { -/** Returns the text for a known status code integer. */ +namespace detail { + template char const* reason_string(int status) @@ -66,6 +67,16 @@ reason_string(int status) return ""; } +} // detail + +/** Returns the text for a known status code integer. */ +inline +char const* +reason_string(int status) +{ + return detail::reason_string(status); +} + } // http } // beast diff --git a/include/beast/http/string_body.hpp b/include/beast/http/string_body.hpp index f5445e2f..5b8101c7 100644 --- a/include/beast/http/string_body.hpp +++ b/include/beast/http/string_body.hpp @@ -8,9 +8,12 @@ #ifndef BEAST_HTTP_STRING_BODY_HPP #define BEAST_HTTP_STRING_BODY_HPP -#include +#include +#include +#include #include #include +#include #include #include @@ -35,10 +38,10 @@ private: value_type& s_; public: - template + template explicit reader(message& m) noexcept + string_body, Fields>& m) noexcept : s_(m.body) { } @@ -63,10 +66,10 @@ private: value_type const& body_; public: - template + template explicit writer(message< - isRequest, string_body, Headers> const& msg) noexcept + isRequest, string_body, Fields> const& msg) noexcept : body_(msg.body) { } diff --git a/include/beast/http/write.hpp b/include/beast/http/write.hpp index 15a7bd12..f27937bd 100644 --- a/include/beast/http/write.hpp +++ b/include/beast/http/write.hpp @@ -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 + bool isRequest, class Fields> void write(SyncWriteStream& stream, - message_headers const& msg); + header 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 + bool isRequest, class Fields> void write(SyncWriteStream& stream, - message_headers const& msg, + header 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 composed - operation. The program must ensure that the stream performs no - other write operations (such as @ref async_write, the stream's - `async_write_some` function, or any other composed operations that - perform writes) until this operation completes. + This operation is implemented in terms of one or more calls to + the stream's `async_write_some` functions, and is known as a + composed operation. The program must ensure that the + stream performs no other write operations 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 #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 const& msg, + header 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 + bool isRequest, class Body, class Fields> void write(SyncWriteStream& stream, - message const& msg); + message 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 + bool isRequest, class Body, class Fields> void write(SyncWriteStream& stream, - message const& msg, + message 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 composed - operation. The program must ensure that the stream performs no - other write operations (such as @ref async_write, the stream's - `async_write_some` function, or any other composed operations that - perform writes) until this operation completes. + This operation is implemented in terms of one or more calls to + the stream's `async_write_some` functions, and is known as a + composed operation. The program must ensure that the + stream performs no other write operations 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 #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 const& msg, + message 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 +template std::ostream& operator<<(std::ostream& os, - message_headers const& msg); + header 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 +template std::ostream& operator<<(std::ostream& os, - message const& msg); + message const& msg); } // http } // beast diff --git a/include/beast/websocket/detail/decorator.hpp b/include/beast/websocket/detail/decorator.hpp index 4bf1a54a..1250d35b 100644 --- a/include/beast/websocket/detail/decorator.hpp +++ b/include/beast/websocket/detail/decorator.hpp @@ -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); } }; diff --git a/include/beast/websocket/impl/accept.ipp b/include/beast/websocket/impl/accept.ipp index 99b7d2f8..1ce54d32 100644 --- a/include/beast/websocket/impl/accept.ipp +++ b/include/beast/websocket/impl/accept.ipp @@ -43,9 +43,9 @@ class stream::response_op int state = 0; template + class Body, class Fields> data(DeducedHandler&& h_, stream& ws_, - http::request const& req, + http::request const& req, bool cont_) : ws(ws_) , resp(ws_.build_response(req)) @@ -305,11 +305,11 @@ async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler) } template -template +template typename async_completion< AcceptHandler, void(error_code)>::result_type stream:: -async_accept(http::request const& req, +async_accept(http::request const& req, AcceptHandler&& handler) { static_assert(is_AsyncStream::value, @@ -390,10 +390,10 @@ accept(ConstBufferSequence const& buffers, error_code& ec) } template -template +template void stream:: -accept(http::request const& request) +accept(http::request const& request) { static_assert(is_SyncStream::value, "SyncStream requirements not met"); @@ -404,10 +404,10 @@ accept(http::request const& request) } template -template +template void stream:: -accept(http::request const& req, +accept(http::request const& req, error_code& ec) { static_assert(is_SyncStream::value, diff --git a/include/beast/websocket/impl/stream.ipp b/include/beast/websocket/impl/stream.ipp index 671dfd9c..bd04db45 100644 --- a/include/beast/websocket/impl/stream.ipp +++ b/include/beast/websocket/impl/stream.ipp @@ -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 -template +template http::response stream:: -build_response(http::request const& req) +build_response(http::request const& req) { auto err = [&](std::string const& text) @@ -103,15 +103,15 @@ build_response(http::request 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 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 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 -template +template void stream:: -do_response(http::response const& res, +do_response(http::response const& res, boost::string_ref const& key, error_code& ec) { // VFALCO Review these error codes @@ -160,11 +160,11 @@ do_response(http::response 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); diff --git a/include/beast/websocket/option.hpp b/include/beast/websocket/option.hpp index 127aa158..d2864cdd 100644 --- a/include/beast/websocket/option.hpp +++ b/include/beast/websocket/option.hpp @@ -86,14 +86,14 @@ struct auto_fragment @code struct identity { - template + template void - operator()(http::message& m) + operator()(http::message& 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 diff --git a/include/beast/websocket/stream.hpp b/include/beast/websocket/stream.hpp index a5bedaf3..23c9e344 100644 --- a/include/beast/websocket/stream.hpp +++ b/include/beast/websocket/stream.hpp @@ -583,9 +583,9 @@ public: @throws system_error Thrown on failure. */ // VFALCO TODO This should also take a DynamicBuffer with any leftover bytes. - template + template void - accept(http::request const& request); + accept(http::request 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 + template void - accept(http::request const& request, + accept(http::request 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 + template #if GENERATING_DOCS void_or_deduced #else typename async_completion< AcceptHandler, void(error_code)>::result_type #endif - async_accept(http::request const& request, + async_accept(http::request 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 + template http::response - build_response(http::request const& req); + build_response(http::request const& req); - template + template void - do_response(http::response const& resp, + do_response(http::response const& resp, boost::string_ref const& key, error_code& ec); void diff --git a/test/Jamfile b/test/Jamfile index 41ba85e2..331a8ade 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -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 diff --git a/test/http/CMakeLists.txt b/test/http/CMakeLists.txt index 03647196..a01c92cb 100644 --- a/test/http/CMakeLists.txt +++ b/test/http/CMakeLists.txt @@ -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 diff --git a/test/http/basic_headers.cpp b/test/http/basic_fields.cpp similarity index 86% rename from test/http/basic_headers.cpp rename to test/http/basic_fields.cpp index 25b55a59..622d2f78 100644 --- a/test/http/basic_headers.cpp +++ b/test/http/basic_fields.cpp @@ -6,7 +6,7 @@ // // Test that header file is self-contained. -#include +#include #include #include @@ -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 - using bha = basic_headers; + using bha = basic_fields; - using bh = basic_headers>; + using bh = basic_fields>; template static void - fill(std::size_t n, basic_headers& h) + fill(std::size_t n, basic_fields& h) { for(std::size_t i = 1; i<= n; ++i) h.insert(boost::lexical_cast(i), i); @@ -90,7 +90,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(basic_headers,http,beast); +BEAST_DEFINE_TESTSUITE(basic_fields,http,beast); } // http } // beast diff --git a/test/http/basic_parser_v1.cpp b/test/http/basic_parser_v1.cpp index 54214aba..5cbe1c19 100644 --- a/test/http/basic_parser_v1.cpp +++ b/test/http/basic_parser_v1.cpp @@ -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 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 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); } diff --git a/test/http/body_type.cpp b/test/http/body_type.cpp deleted file mode 100644 index cfddca65..00000000 --- a/test/http/body_type.cpp +++ /dev/null @@ -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 diff --git a/test/http/fail_parser.hpp b/test/http/fail_parser.hpp index 46a228ce..3cb04960 100644 --- a/test/http/fail_parser.hpp +++ b/test/http/fail_parser.hpp @@ -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; diff --git a/test/http/headers.cpp b/test/http/fields.cpp similarity index 89% rename from test/http/headers.cpp rename to test/http/fields.cpp index 79d68ffb..4a0f5fa8 100644 --- a/test/http/headers.cpp +++ b/test/http/fields.cpp @@ -6,4 +6,4 @@ // // Test that header file is self-contained. -#include +#include diff --git a/test/http/headers_parser_v1.cpp b/test/http/header_parser_v1.cpp similarity index 85% rename from test/http/headers_parser_v1.cpp rename to test/http/header_parser_v1.cpp index e15997dd..61a35c2b 100644 --- a/test/http/headers_parser_v1.cpp +++ b/test/http/header_parser_v1.cpp @@ -6,23 +6,23 @@ // // Test that header file is self-contained. -#include +#include -#include +#include #include #include 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 p; + header_parser_v1 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 p; + header_parser_v1 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 p; + header_parser_v1 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 p; + header_parser_v1 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 diff --git a/test/http/message.cpp b/test/http/message.cpp index e01ad2e5..d5db86e0 100644 --- a/test/http/message.cpp +++ b/test/http/message.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include @@ -73,66 +73,66 @@ public: void testMessage() { static_assert(std::is_constructible< - message>::value, ""); + message>::value, ""); static_assert(std::is_constructible< - message, Arg1>::value, ""); + message, Arg1>::value, ""); static_assert(std::is_constructible< - message, Arg1 const>::value, ""); + message, Arg1 const>::value, ""); static_assert(std::is_constructible< - message, Arg1 const&>::value, ""); + message, Arg1 const&>::value, ""); static_assert(std::is_constructible< - message, Arg1&&>::value, ""); + message, Arg1&&>::value, ""); static_assert(! std::is_constructible< - message>::value, ""); + message>::value, ""); static_assert(std::is_constructible< - message, - Arg1, headers::allocator_type>::value, ""); + message, + Arg1, fields::allocator_type>::value, ""); static_assert(std::is_constructible< - message, std::piecewise_construct_t, + message, std::piecewise_construct_t, std::tuple>::value, ""); static_assert(std::is_constructible< - message, std::piecewise_construct_t, + message, std::piecewise_construct_t, std::tuple>::value, ""); static_assert(std::is_constructible< - message, std::piecewise_construct_t, - std::tuple, std::tuple>::value, ""); + message, std::piecewise_construct_t, + std::tuple, std::tuple>::value, ""); { Arg1 arg1; - message{std::move(arg1)}; + message{std::move(arg1)}; BEAST_EXPECT(arg1.moved); } { - headers h; + fields h; h.insert("User-Agent", "test"); - message m{Arg1{}, h}; + message 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 m{Arg1{}, std::move(h)}; + message 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 m1; - message m2; + message m1; + message 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::value, ""); static_assert(std::is_move_constructible::value, ""); static_assert(std::is_copy_assignable::value, ""); static_assert(std::is_move_assignable::value, ""); - using res_type = response_headers; + using res_type = response_header; static_assert(std::is_copy_constructible::value, ""); static_assert(std::is_move_constructible::value, ""); static_assert(std::is_copy_assignable::value, ""); @@ -183,12 +183,12 @@ public: { MoveHeaders h; - message_headers r{std::move(h)}; + header r{std::move(h)}; BEAST_EXPECT(h.moved_from); - BEAST_EXPECT(r.headers.moved_to); + BEAST_EXPECT(r.fields.moved_to); request 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 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 m1; - message m2; + message m1; + message 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 diff --git a/test/http/message_fuzz.hpp b/test/http/message_fuzz.hpp index 2e0287fb..d76ebedc 100644 --- a/test/http/message_fuzz.hpp +++ b/test/http/message_fuzz.hpp @@ -475,7 +475,7 @@ public: template 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"); } diff --git a/test/http/nodejs_parser.hpp b/test/http/nodejs_parser.hpp index 3dd98ad6..a9611e55 100644 --- a/test/http/nodejs_parser.hpp +++ b/test/http/nodejs_parser.hpp @@ -736,12 +736,12 @@ nodejs_basic_parser::cb_chunk_complete(http_parser*) The parser may only be used once. */ -template +template class nodejs_parser - : public nodejs_basic_parser> + : public nodejs_basic_parser> { using message_type = - message; + message; 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 diff --git a/test/http/parse_error.cpp b/test/http/parse_error.cpp index ac8c95ca..626c8e50 100644 --- a/test/http/parse_error.cpp +++ b/test/http/parse_error.cpp @@ -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); } diff --git a/test/http/parser_bench.cpp b/test/http/parser_bench.cpp index c1840069..a51d4822 100644 --- a/test/http/parser_bench.cpp +++ b/test/http/parser_bench.cpp @@ -122,20 +122,20 @@ public: [&] { testParser>( + true, streambuf_body, fields>>( Repeat, creq_); testParser>( + false, streambuf_body, fields>>( Repeat, cres_); }); timedTest(Trials, "http::basic_parser_v1", [&] { testParser>( + true, streambuf_body, fields>>( Repeat, creq_); testParser>( + false, streambuf_body, fields>>( Repeat, cres_); }); pass(); diff --git a/test/http/parser_v1.cpp b/test/http/parser_v1.cpp index 02075d86..d9e5259e 100644 --- a/test/http/parser_v1.cpp +++ b/test/http/parser_v1.cpp @@ -9,8 +9,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -32,7 +32,7 @@ public: // consecutive empty header values { error_code ec; - parser_v1 p; + parser_v1 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 p0; + header_parser_v1 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 p = + BEAST_EXPECT(reqh.fields["User-Agent"] == "test"); + BEAST_EXPECT(reqh.fields["Content-Length"] == "1"); + parser_v1 p = with_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 req = p.release(); + request req = p.release(); BEAST_EXPECT(req.body == "*"); } @@ -88,7 +88,7 @@ public: { error_code ec; parser_v1>> p; + basic_fields>> 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>> p; + basic_fields>> 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 p; + parser_v1 p; std::string const s = "HTTP/1.1 200 Connection Established\r\n" "Proxy-Agent: Zscaler/5.1\r\n" diff --git a/test/http/read.cpp b/test/http/read.cpp index 3d4f57b3..8775dc2f 100644 --- a/test/http/read.cpp +++ b/test/http/read.cpp @@ -10,7 +10,7 @@ #include "fail_parser.hpp" -#include +#include #include #include #include @@ -157,7 +157,7 @@ public: sb.prepare(len), buffer(s, len))); test::fail_counter fc{n}; test::string_stream ss{ios_, s}; - parser_v1 p{fc}; + parser_v1 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 p; + parser_v1 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 p; + parser_v1 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 p; + parser_v1 p; error_code ec; async_parse(ss, sb, p, do_yield[ec]); BEAST_EXPECT(ec == boost::asio::error::eof); diff --git a/test/http/streambuf_body.cpp b/test/http/streambuf_body.cpp index eec84122..e2ed3811 100644 --- a/test/http/streambuf_body.cpp +++ b/test/http/streambuf_body.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include @@ -34,7 +34,7 @@ public: "\r\n" "xyz"; test::string_stream ss(ios_, s); - parser_v1 p; + parser_v1 p; streambuf sb; parse(ss, sb, p); BEAST_EXPECT(to_string(p.get().body.data()) == "xyz"); diff --git a/test/http/write.cpp b/test/http/write.cpp index 0a70ef42..514086d3 100644 --- a/test/http/write.cpp +++ b/test/http/write.cpp @@ -8,7 +8,7 @@ // Test that header file is self-contained. #include -#include +#include #include #include #include @@ -221,9 +221,9 @@ public: }; }; - template + template std::string - str(message const& m) + str(message const& m) { string_write_stream ss(ios_); write(ss, m); @@ -234,11 +234,11 @@ public: testAsyncWriteHeaders(yield_context do_yield) { { - message_headers m; + header 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 m; + header 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 m; + message 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 m; + message 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 m( + message 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 m( + message 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 m( + message 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 m( + message 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 m( + message 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 m; + message 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 m; + message 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 m; + message 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 m; + message 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 m; + message 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 m; + message 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 m; + message 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 m; + message 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 m; + message 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(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 m; + message 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; diff --git a/test/websocket/frame.cpp b/test/websocket/frame.cpp index b3aee27d..522c72f8 100644 --- a/test/websocket/frame.cpp +++ b/test/websocket/frame.cpp @@ -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. diff --git a/test/websocket/stream.cpp b/test/websocket/stream.cpp index 8c396b2d..084019eb 100644 --- a/test/websocket/stream.cpp +++ b/test/websocket/stream.cpp @@ -133,15 +133,15 @@ public: struct identity { - template + template void - operator()(http::message&) + operator()(http::message&) { } - template + template void - operator()(http::message&) + operator()(http::message&) { } }; @@ -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> ws(n, ios_, ""); try diff --git a/test/websocket/websocket_async_echo_server.hpp b/test/websocket/websocket_async_echo_server.hpp index 21b56e6b..ae496324 100644 --- a/test/websocket/websocket_async_echo_server.hpp +++ b/test/websocket/websocket_async_echo_server.hpp @@ -135,18 +135,18 @@ private: struct identity { - template + template void - operator()(http::message& req) + operator()(http::message& req) { - req.headers.replace("User-Agent", "async_echo_client"); + req.fields.replace("User-Agent", "async_echo_client"); } - template + template void - operator()(http::message& resp) + operator()(http::message& resp) { - resp.headers.replace("Server", "async_echo_server"); + resp.fields.replace("Server", "async_echo_server"); } }; diff --git a/test/websocket/websocket_sync_echo_server.hpp b/test/websocket/websocket_sync_echo_server.hpp index fd3dba2d..97276292 100644 --- a/test/websocket/websocket_sync_echo_server.hpp +++ b/test/websocket/websocket_sync_echo_server.hpp @@ -138,18 +138,18 @@ private: struct identity { - template + template void - operator()(http::message& req) + operator()(http::message& req) { - req.headers.replace("User-Agent", "sync_echo_client"); + req.fields.replace("User-Agent", "sync_echo_client"); } - template + template void - operator()(http::message& resp) + operator()(http::message& resp) { - resp.headers.replace("Server", "sync_echo_server"); + resp.fields.replace("Server", "sync_echo_server"); } };