diff --git a/.gitignore b/.gitignore
index 99f984bdaa..1740b535d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,7 @@
bin/
bin64/
+
+# Because of CMake and VS2017
+Win32/
+x64/
+
diff --git a/.travis.yml b/.travis.yml
index 236e8da718..fe86fa15c6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -83,4 +83,4 @@ after_script:
notifications:
email:
- false
+ false
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2dcb1650c7..bdb9691f81 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,32 @@
+* CMake hide command lines in .vcxproj Output windows"
+
+WebSocket:
+
+* Add is_upgrade() free function
+
+API Changes:
+
+* Provide websocket::stream accept() overloads
+* Refactor websocket decorators
+
+--------------------------------------------------------------------------------
+
+1.0.0-b35
+
+* Add Appveyor build scripts and badge
+* Tidy up MSVC CMake configuration
+* Make close_code a proper enum
+* Add flat_streambuf
+* Rename to BEAST_DOXYGEN
+* Update .gitignore for VS2017
+* Fix README.md CMake instructions
+
+API Changes:
+
+* New HTTP interfaces
+
+--------------------------------------------------------------------------------
+
1.0.0-b34
* Fix and tidy up CMake build scripts
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c82014589f..ed8c97cc18 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,12 +7,13 @@ project (Beast)
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
if (MSVC)
- # /wd4244 /wd4127
+ set (CMAKE_VERBOSE_MAKEFILE FALSE)
+
add_definitions (-D_WIN32_WINNT=0x0601)
add_definitions (-D_SCL_SECURE_NO_WARNINGS=1)
add_definitions (-D_CRT_SECURE_NO_WARNINGS=1)
- set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4100 /wd4244 /wd4251 /MP /W4 /bigobj")
+ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4100 /wd4244 /MP /W4 /bigobj")
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /Oi /Ot /GL")
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Oi /Ot")
@@ -44,29 +45,30 @@ option (Boost_USE_STATIC_LIBS "Use static libraries for boost" ON)
set (Boost_NO_SYSTEM_PATHS ON)
set (Boost_USE_MULTITHREADED ON)
+add_definitions (-DBOOST_COROUTINES_NO_DEPRECATION_WARNING=1) # for asio
unset (Boost_INCLUDE_DIR CACHE)
unset (Boost_LIBRARY_DIRS CACHE)
-find_package (Boost REQUIRED COMPONENTS
- coroutine
- context
- filesystem
- program_options
- system
- thread
- )
+if (MSVC)
+ find_package (Boost REQUIRED)
+else()
+ find_package (Boost REQUIRED COMPONENTS
+ coroutine
+ context
+ filesystem
+ program_options
+ system
+ thread
+ )
+ link_libraries (${Boost_LIBRARIES})
+endif()
include_directories (SYSTEM ${Boost_INCLUDE_DIRS})
-link_libraries (${Boost_LIBRARIES})
-if (MSVC)
- add_definitions (-DBOOST_ALL_NO_LIB) # disable autolinking
-elseif (MINGW)
+if (MINGW)
link_libraries(ws2_32 mswsock)
endif()
-add_definitions (-DBOOST_COROUTINES_NO_DEPRECATION_WARNING=1) # for asio
-
#-------------------------------------------------------------------------------
#
# OpenSSL
@@ -164,15 +166,4 @@ file(GLOB_RECURSE EXTRAS_INCLUDES
${PROJECT_SOURCE_DIR}/extras/beast/*.ipp
)
-add_subdirectory (examples)
-if (NOT OPENSSL_FOUND)
- message("OpenSSL not found. Not building examples/ssl")
-else()
- add_subdirectory (examples/ssl)
-endif()
-
-add_subdirectory (test)
-add_subdirectory (test/core)
-add_subdirectory (test/http)
add_subdirectory (test/websocket)
-add_subdirectory (test/zlib)
diff --git a/Jamroot b/Jamroot
index 277100ab23..aa9c5695c4 100644
--- a/Jamroot
+++ b/Jamroot
@@ -8,6 +8,8 @@
import os ;
import feature ;
import boost ;
+import modules ;
+import testing ;
boost.use-project ;
@@ -125,4 +127,3 @@ project beast
;
build-project test ;
-build-project examples ;
diff --git a/README.md b/README.md
index 1dcf4b52a1..0bc8cba4b8 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,13 @@
-[![Join the chat at https://gitter.im/vinniefalco/Beast](https://badges.gitter.im/vinniefalco/Beast.svg)](https://gitter.im/vinniefalco/Beast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/vinniefalco/Beast.svg?branch=master)](https://travis-ci.org/vinniefalco/Beast) [![codecov](https://codecov.io/gh/vinniefalco/Beast/branch/master/graph/badge.svg)](https://codecov.io/gh/vinniefalco/Beast) [![coveralls](https://coveralls.io/repos/github/vinniefalco/Beast/badge.svg?branch=master)](https://coveralls.io/github/vinniefalco/Beast?branch=master) [![Documentation](https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/) [![License](https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)
+[![Join the chat at https://gitter.im/vinniefalco/Beast](https://badges.gitter.im/vinniefalco/Beast.svg)](https://gitter.im/vinniefalco/Beast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Build Status](https://travis-ci.org/vinniefalco/Beast.svg?branch=master)](https://travis-ci.org/vinniefalco/Beast)
+[![Build status](https://ci.appveyor.com/api/projects/status/g0llpbvhpjuxjnlw?svg=true)](https://ci.appveyor.com/project/vinniefalco/beast)
+[![codecov](https://codecov.io/gh/vinniefalco/Beast/branch/master/graph/badge.svg)](https://codecov.io/gh/vinniefalco/Beast)
+[![coveralls](https://coveralls.io/repos/github/vinniefalco/Beast/badge.svg?branch=master)](https://coveralls.io/github/vinniefalco/Beast?branch=master)
+[![Documentation](https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/)
+[![License](https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)
# HTTP and WebSocket built on Boost.Asio in C++11
@@ -106,24 +112,18 @@ instructions on how to do this for your particular build system.
For the examples and tests, Beast provides build scripts for Boost.Build (bjam)
and CMake. It is possible to generate Microsoft Visual Studio or Apple
-Developers using Microsoft Visual Studio can generate Visual Studio
-project files by executing these commands from the root of the repository:
+Xcode project files using CMake by executing these commands from
+the root of the repository:
```
cd bin
cmake .. # for 32-bit Windows builds
+cmake -G Xcode .. # for Apple Xcode builds
cd ../bin64
-cmake .. # for Linux/Mac builds, OR
-cmake -G"Visual Studio 14 2015 Win64" .. # for 64-bit Windows builds
-```
-
-When using Apple Xcode it is possible to generate Xcode project files
-using these commands:
+cmake -G"Visual Studio 14 2015 Win64" .. # for 64-bit Windows builds (VS2015)
+cmake -G"Visual Studio 15 2017 Win64" .. # for 64-bit Windows builds (VS2017)
-```
-cd bin
-cmake -G Xcode .. # for Apple Xcode builds
```
To build with Boost.Build, it is necessary to have the bjam executable
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000000..8e25c74451
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,100 @@
+# Copyright 2016 Peter Dimov
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
+
+#version: 1.0.{build}-{branch}
+version: "{branch} (#{build})"
+
+shallow_clone: true
+
+platform:
+ - x86
+ - x64
+
+configuration:
+ - Debug
+ - Release
+
+install:
+ - cd ..
+ - git clone https://github.com/boostorg/boost.git boost
+ - cd boost
+ - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\beast\
+ - git submodule update --init tools/build
+ - git submodule update --init libs/config
+ - git submodule update --init tools/boostdep
+# - python tools/boostdep/depinst/depinst.py beast
+ - git submodule update --init libs/any
+ - git submodule update --init libs/asio
+ - git submodule update --init libs/algorithm
+ - git submodule update --init libs/array
+ - git submodule update --init libs/assert
+ - git submodule update --init libs/atomic
+ - git submodule update --init libs/bind
+ - git submodule update --init libs/chrono
+ - git submodule update --init libs/concept_check
+ - git submodule update --init libs/config
+ - git submodule update --init libs/container
+ - git submodule update --init libs/context
+ - git submodule update --init libs/conversion
+ - git submodule update --init libs/core
+ - git submodule update --init libs/coroutine
+ - git submodule update --init libs/date_time
+ - git submodule update --init libs/detail
+ - git submodule update --init libs/endian
+ - git submodule update --init libs/exception
+ - git submodule update --init libs/filesystem
+ - git submodule update --init libs/foreach
+ - git submodule update --init libs/function
+ - git submodule update --init libs/function_types
+ - git submodule update --init libs/functional
+ - git submodule update --init libs/fusion
+ - git submodule update --init libs/integer
+ - git submodule update --init libs/intrusive
+ - git submodule update --init libs/io
+ - git submodule update --init libs/iostreams
+ - git submodule update --init libs/iterator
+ - git submodule update --init libs/lambda
+ - git submodule update --init libs/lexical_cast
+ - git submodule update --init libs/locale
+ - git submodule update --init libs/math
+ - git submodule update --init libs/move
+ - git submodule update --init libs/mpl
+ - git submodule update --init libs/numeric/conversion
+ - git submodule update --init libs/optional
+# - git submodule update --init libs/phoenix
+ - git submodule update --init libs/pool
+ - git submodule update --init libs/predef
+ - git submodule update --init libs/preprocessor
+ - git submodule update --init libs/program_options
+ - git submodule update --init libs/proto
+ - git submodule update --init libs/random
+ - git submodule update --init libs/range
+ - git submodule update --init libs/ratio
+ - git submodule update --init libs/rational
+ - git submodule update --init libs/regex
+ - git submodule update --init libs/serialization
+ - git submodule update --init libs/smart_ptr
+# - git submodule update --init libs/spirit
+ - git submodule update --init libs/static_assert
+ - git submodule update --init libs/system
+ - git submodule update --init libs/thread
+ - git submodule update --init libs/throw_exception
+ - git submodule update --init libs/tokenizer
+ - git submodule update --init libs/tti
+ - git submodule update --init libs/tuple
+ - git submodule update --init libs/type_index
+ - git submodule update --init libs/type_traits
+ - git submodule update --init libs/typeof
+ - git submodule update --init libs/unordered
+ - git submodule update --init libs/utility
+ - git submodule update --init libs/variant
+ - git submodule update --init libs/winapi
+ - bootstrap
+ - b2 headers
+
+build: off
+
+test_script:
+ - b2 libs/beast/examples toolset=msvc-14.0
+ - b2 libs/beast/test toolset=msvc-14.0
diff --git a/doc/http.qbk b/doc/http.qbk
index 9249fd64fb..d08a3046f5 100644
--- a/doc/http.qbk
+++ b/doc/http.qbk
@@ -26,7 +26,6 @@ contents:
Algorithms
Write
Read
- Parse
Examples
Send Request
Receive Response
@@ -136,7 +135,7 @@ object:
[[HTTP Request] [HTTP Response]]
[[
```
- request req;
+ request req;
req.version = 11; // HTTP/1.1
req.method = "GET";
req.url = "/index.htm"
@@ -227,15 +226,6 @@ The message [*`Body`] template parameter controls both the type of the data
member of the resulting message object, and the algorithms used during parsing
and serialization. Beast provides three very common [*`Body`] types:
-* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
-Used in GET requests where there is no message body. Example:
-```
- request req;
- req.version = 11;
- req.method = "GET";
- req.url = "/index.html";
-```
-
* [link beast.ref.http__string_body [*`string_body`:]] A body with a
`value_type` as `std::string`. Useful for quickly putting together a request
or response with simple text in the message body (such as an error message).
@@ -303,7 +293,7 @@ operations performed). To send messages synchronously, use one of the
```
void send_request(boost::asio::ip::tcp::socket& sock)
{
- request req;
+ request req;
req.version = 11;
req.method = "GET";
req.url = "/index.html";
@@ -322,7 +312,7 @@ An asynchronous interface is available:
```
void handle_write(boost::system::error_code);
...
- request req;
+ request req;
...
async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
```
diff --git a/doc/master.qbk b/doc/master.qbk
index 24494c3886..90b697c351 100644
--- a/doc/master.qbk
+++ b/doc/master.qbk
@@ -107,7 +107,6 @@ provides implementations of the HTTP and WebSocket protocols.
[include types/DynamicBuffer.qbk]
[include types/Field.qbk]
[include types/FieldSequence.qbk]
-[include types/Parser.qbk]
[include types/Reader.qbk]
[include types/Streams.qbk]
[include types/Writer.qbk]
diff --git a/doc/quickref.xml b/doc/quickref.xml
index 874c5a6936..f623a339e2 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -31,13 +31,12 @@
basic_dynabuf_bodybasic_fields
- basic_parser_v1
- empty_body
+ basic_parserfieldsheader
- header_parser_v1
+ header_parsermessage
- parser_v1
+ message_parserrequestrequest_headerresponse
@@ -49,6 +48,7 @@
ext_list
+ opt_token_listparam_listtoken_list
@@ -57,7 +57,7 @@
Functionsasync_read
- async_parse
+ async_read_someasync_writechunk_encodechunk_encode_final
@@ -65,17 +65,15 @@
is_keep_aliveis_upgradeoperator<<
- parseprepareread
+ read_somereason_string
- with_bodywriteType Traitsis_Body
- is_Parseris_Readeris_Writerhas_reader
@@ -83,26 +81,16 @@
- Options
-
- header_max_size
- body_max_size
- skip_body
- Constants
- body_whatconnection
- no_content_length
- parse_error
- parse_flag
+ errorConceptsBodyFieldFieldSequence
- ParserReaderWriter
@@ -119,12 +107,12 @@
Functionsasync_teardown
+ is_upgradeteardownOptionsauto_fragment
- decoratekeep_alivemessage_typepermessage_deflate
@@ -165,6 +153,7 @@
Classesasync_completion
+ basic_flat_streambufbasic_streambufbuffers_adapterconsuming_buffers
@@ -173,6 +162,7 @@
error_categoryerror_codeerror_condition
+ flat_streambufhandler_allochandler_ptrstatic_streambuf
diff --git a/doc/reference.xsl b/doc/reference.xsl
index 7a4420983e..5e27971e03 100644
--- a/doc/reference.xsl
+++ b/doc/reference.xsl
@@ -61,6 +61,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -394,13 +410,34 @@
`
+
+
+
+
+
+
+
+
- *
-
-
-
-
+
+
+
+
+
+
+
+
+ #
+
+
+ *
+
+
+ [*]
@@ -429,6 +466,25 @@
]]
+
+
+
[table
+
+ ]
+
+
+
+ [
+
+ ]
+
+
+
+ [
+
+ ]
+
+
diff --git a/doc/source.dox b/doc/source.dox
index 624ab63310..f4707c4198 100644
--- a/doc/source.dox
+++ b/doc/source.dox
@@ -282,8 +282,7 @@ EXPAND_ONLY_PREDEF = YES
SEARCH_INCLUDES = YES
INCLUDE_PATH = ../
INCLUDE_FILE_PATTERNS =
-PREDEFINED = DOXYGEN \
- GENERATING_DOCS
+PREDEFINED = BEAST_DOXYGEN
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
diff --git a/doc/types/DynamicBuffer.qbk b/doc/types/DynamicBuffer.qbk
index 792c25914d..009abbdd3a 100644
--- a/doc/types/DynamicBuffer.qbk
+++ b/doc/types/DynamicBuffer.qbk
@@ -19,7 +19,9 @@ The interface to this concept is intended to permit the following
implementation strategies:
* A single contiguous octet array, which is reallocated as necessary to
- accommodate changes in the size of the octet sequence.
+ accommodate changes in the size of the octet sequence. This is the
+ implementation approach currently offered by
+ [link beast.ref.basic_flat_streambuf `basic_flat_streambuf`].
* A sequence of one or more octet arrays, where each array is of the same
size. Additional octet array objects are appended to the sequence to
diff --git a/doc/types/Parser.qbk b/doc/types/Parser.qbk
deleted file mode 100644
index 12cd7b749b..0000000000
--- a/doc/types/Parser.qbk
+++ /dev/null
@@ -1,61 +0,0 @@
-[/
- Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
-
- Distributed under the Boost Software License, Version 1.0. (See accompanying
- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-]
-
-[section:Parser Parser requirements]
-
-A [*Parser] is used to deserialize objects from
-[link beast.ref.streams streams]. Objects of this type are used with
-[link beast.ref.http__parse http::parse] and
-[link beast.ref.http__async_parse http::async_parse]. The definition of
-an object, and the predicate defining when the parse is complete, are
-determined by the implementation.
-
-In this table:
-
-* `X` denotes a type meeting the requirements of [*Parser].
-
-* `a` denotes a value of type `X`.
-
-* `b` is a value meeting the requirements of __ConstBufferSequence__.
-
-* `ec` is a value of type [link beast.ref.error_code `error_code&`].
-
-[table Parser requirements
-[[operation] [type] [semantics, pre/post-conditions]]
-[
- [`a.complete()`]
- [`bool`]
- [
- Returns `true` when parsing is complete.
- ]
-]
-[
- [`a.write(b, ec)`]
- [`std::size_t`]
- [
- Sequentially parses the octets in the specified input buffer sequence
- until an error occurs, the end of the buffer is reached, or parsing is
- complete. Upon success, this function returns the number of bytes used
- from the input. If an error occurs, `ec` is set to the error code and
- parsing stops.
- ]
-]
-[
- [`a.write_eof(ec)`]
- [`void`]
- [
- Indicates to the parser that no more octets will be available.
- Typically this function is called when the end of stream is reached.
- For example, if a call to `boost::asio::ip::tcp::socket::read_some`
- generates a `boost::asio::error::eof` error. Some objects, such as
- certain HTTP/1 messages, determine the end of the message body by
- an end of file marker or closing of the connection.
- ]
-]
-]
-
-[endsect]
diff --git a/doc/types/Reader.qbk b/doc/types/Reader.qbk
index 0fd852f1c9..bbf7739643 100644
--- a/doc/types/Reader.qbk
+++ b/doc/types/Reader.qbk
@@ -10,57 +10,198 @@
Parsers provided by the implementation will construct the corresponding
`reader` object during parsing. This customization point allows the
Body to determine the strategy for storing incoming message body data.
+Readers come in two flavors, direct and indirect:
-In this table:
+Direct readers provide a buffer to callers, in which body data is placed.
+This type of reader is used when the bytes corresponding to the body data
+are stored without transformation. The parse algorithm performs stream or
+socket reads directly into the reader provided buffer, hence the name
+"direct." This model avoids an unnecessary buffer copy. An example of
+a [*Body] type with a direct reader is
+[link beast.ref.http__string_body `string_body`].
+
+Indirect readers are passed body data in a buffer managed by the parser
+algorithm. This reader is appropriate when the body data is transformed
+or not otherwised stored verbatim. Some examples of when an indirect
+reader is appropriate:
+
+* When bytes corresponding to the body are written to a file
+ as they are parsed.
+
+* The content of the message is JSON, which is parsed as it is
+ being read in, and stored in a structured, hierarchical format.
+
+In the tables below:
* `X` denotes a type meeting the requirements of [*`Reader`].
* `a` denotes a value of type `X`.
-* `n` is a value convertible to `std::size_t`.
+* `n` is a value convertible to `std::size_t` without loss of precision.
+
+* `v` is a value convertible to `std::uint64_t` without loss of precision.
-* `p` is a `void const*` to valid memory of at least `n` bytes.
+* `s` is a value of type `boost::string_ref`.
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
* `m` denotes a value of type `message&` where
`std::is_same::value == true`.
-[table Reader requirements
+[table Direct Reader requirements
[[operation] [type] [semantics, pre/post-conditions]]
[
- [`X a(m);`]
+ [`X::is_direct`]
+ [`bool`]
+ [
+ This static constant must be set to `true` to indicate that
+ the reader is a direct reader.
+ ]
+]
+[
+ [`X::mutable_buffers_type`]
+ []
+ [
+ This member type must be present, and meet the requirements
+ of [*MutableBufferSequence]. It represents the type of
+ the writable buffers returned by the reader, in which
+ bytes representing the body are stored by the implementation.
+ ]
+]
+[
+ [`X a{m};`]
[]
[
`a` is constructible from `m`. The lifetime of `m` is guaranteed
to end no earlier than after `a` is destroyed. The constructor
will be called after all headers have been stored in `m`, and
- before any body data is deserialized. This function must be
- `noexcept`.
+ just before parsing bytes corresponding to the body for messages
+ whose semantics indicate that a body is present with non-zero
+ length.
]
]
[
- [`a.init(ec)`]
- [`void`]
+ [`a.init()`]
+ []
+ [
+ This function is called once before any bytes corresponding
+ to the body are presented to the reader, for messages whose
+ body is determined by the end-of-file marker on a stream,
+ or for messages where the chunked Transfer-Encoding is
+ specified.
+ ]
+]
+[
+ [`a.init(v)`]
+ []
[
- Called immediately after construction. If the function sets
- an error code in `ec`, the parse is aborted and the error is
- propagated to the caller. This function must be `noexcept`.
+ This function is called once before any bytes corresponding
+ to the body are presented to the reader, for messages where
+ the Content-Length is specified. The value of `v` will be
+ set to the number of bytes indicated by the content length.
]
]
[
- [`a.write(p, n, ec)`]
- [`void`]
+ [`a.prepare(n)`]
+ [`mutable_buffers_type`]
[
- Deserializes the input sequence into the body. If `ec` is set,
- the deserialization is aborted and the error is propagated to
- the caller. If the message headers specify a chunked transfer
- encoding, the reader will receive the decoded version of the
- body. This function must be `noexcept`.
+ The implementation calls this function to obtain a mutable
+ buffer sequence of up to `n` bytes in size in which to place
+ data corresponding to the body. The buffer returned must
+ be at least one byte in size, and may be smaller than `n`.
+ ]
+]
+[
+ [`a.commit(n)`]
+ []
+ [
+ The implementation calls this function to indicate to the
+ reader that `n` bytes of data have been successfully placed
+ into the buffer obtained through a prior call to `prepare`.
+ The value of `n` will be less than or equal to the size of
+ the buffer returned in the previous call to `prepare`.
+ ]
+]
+[
+ [`a.finish()`]
+ []
+ [
+ This function is called after all the bytes corresponding
+ to the body have been written to the buffers and committed.
]
]
]
+[table Indirect Reader requirements
+[[operation] [type] [semantics, pre/post-conditions]]
+[
+ [`X::is_direct`]
+ [`bool`]
+ [
+ This static constant must be set to `false` to indicate that
+ the reader is an indirect reader.
+ ]
+]
+[
+ [`X a{m};`]
+ []
+ [
+ `a` is constructible from `m`. The lifetime of `m` is guaranteed
+ to end no earlier than after `a` is destroyed. The constructor
+ will be called after all headers have been stored in `m`, and
+ just before parsing bytes corresponding to the body for messages
+ whose semantics indicate that a body is present with non-zero
+ length.
+ ]
+]
+[
+ [`a.init(ec)`]
+ []
+ [
+ This function is called once before any bytes corresponding
+ to the body are presented to the reader, for messages whose
+ body is determined by the end-of-file market on a stream,
+ or for messages where the chunked Transfer-Encoding is
+ specified.
+ If `ec` is set before returning, parsing will stop
+ and the error will be returned to the caller.
+
+ ]
+]
+[
+ [`a.init(v,ec)`]
+ []
+ [
+ This function is called once before any bytes corresponding
+ to the body are presented to the reader, for messages where
+ the Content-Length is specified. The value of `v` will be
+ set to the number of bytes indicated by the content length.
+ If `ec` is set before returning, parsing will stop
+ and the error will be returned to the caller.
+ ]
+]
+[
+ [`a.write(s,ec)`]
+ []
+ [
+ The implementation calls this function with `s` containing
+ bytes corresponding to the body, after removing any present
+ chunked encoding transformation.
+ If `ec` is set before returning, parsing will stop
+ and the error will be returned to the caller.
+ ]
+]
+[
+ [`a.finish(ec)`]
+ []
+ [
+ This function is called after all the bytes corresponding
+ to the body have been written to the buffers and committed.
+ If `ec` is set before returning, parsing will stop
+ and the error will be returned to the caller.
+ ]
+]
+]
[note
Definitions for required `Reader` member functions should be declared
inline so the generated code can become part of the implementation.
diff --git a/doc/websocket.qbk b/doc/websocket.qbk
index 77bcc2bde0..494b27a358 100644
--- a/doc/websocket.qbk
+++ b/doc/websocket.qbk
@@ -50,7 +50,7 @@ The WebSocket protocol is described fully in
The interface to Beast's WebSocket implementation is a single template
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
wraps a "next layer" object. The next layer object must meet the requirements
-of [link beast.ref.streams.SyncStream [*`SyncReadStream`]] if synchronous
+of [link beast.ref.streams.SyncStream [*`SyncStream`]] if synchronous
operations are performed, or
[link beast.ref.streams.AsyncStream [*`AsyncStream`]] if asynchronous
operations are performed, or both. Arguments supplied during construction are
diff --git a/examples/http_crawl.cpp b/examples/http_crawl.cpp
index 1a794169b0..a34f067d0d 100644
--- a/examples/http_crawl.cpp
+++ b/examples/http_crawl.cpp
@@ -36,7 +36,7 @@ int main(int, char const*[])
ip::tcp::socket sock(ios);
connect(sock, it);
auto ep = sock.remote_endpoint();
- request req;
+ request req;
req.method = "GET";
req.url = "/";
req.version = 11;
diff --git a/examples/http_example.cpp b/examples/http_example.cpp
index 038ac2e24d..6c060817e9 100644
--- a/examples/http_example.cpp
+++ b/examples/http_example.cpp
@@ -22,7 +22,7 @@ int main()
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
// Send HTTP request using beast
- beast::http::request req;
+ beast::http::request req;
req.method = "GET";
req.url = "/";
req.version = 11;
diff --git a/examples/ssl/http_ssl_example.cpp b/examples/ssl/http_ssl_example.cpp
index 30c8194043..3b9992b4a1 100644
--- a/examples/ssl/http_ssl_example.cpp
+++ b/examples/ssl/http_ssl_example.cpp
@@ -34,7 +34,7 @@ int main()
stream.handshake(ssl::stream_base::client);
// Send HTTP request over SSL using Beast
- beast::http::request req;
+ beast::http::request req;
req.method = "GET";
req.url = "/";
req.version = 11;
diff --git a/examples/websocket_async_echo_server.hpp b/examples/websocket_async_echo_server.hpp
index bd0c8481b6..e6ed81ef1b 100644
--- a/examples/websocket_async_echo_server.hpp
+++ b/examples/websocket_async_echo_server.hpp
@@ -38,25 +38,6 @@ class async_echo_server
using endpoint_type = boost::asio::ip::tcp::endpoint;
private:
- struct identity
- {
- template
- void
- operator()(beast::http::message<
- true, Body, Fields>& req) const
- {
- req.fields.replace("User-Agent", "async_echo_client");
- }
-
- template
- void
- operator()(beast::http::message<
- false, Body, Fields>& resp) const
- {
- resp.fields.replace("Server", "async_echo_server");
- }
- };
-
/** A container of type-erased option setters.
*/
template
@@ -159,8 +140,6 @@ class async_echo_server
, acceptor_(ios_)
, work_(ios_)
{
- opts_.set_option(
- beast::websocket::decorate(identity{}));
thread_.reserve(threads);
for(std::size_t i = 0; i < threads; ++i)
thread_.emplace_back(
@@ -282,7 +261,13 @@ class async_echo_server
void run()
{
auto& d = *d_;
- d.ws.async_accept(std::move(*this));
+ d.ws.async_accept_ex(
+ [](beast::websocket::response_type& res)
+ {
+ res.fields.insert(
+ "Server", "async_echo_server");
+ },
+ std::move(*this));
}
void operator()(error_code ec, std::size_t)
diff --git a/examples/websocket_sync_echo_server.hpp b/examples/websocket_sync_echo_server.hpp
index 1f41b52ce1..ab8bd5d597 100644
--- a/examples/websocket_sync_echo_server.hpp
+++ b/examples/websocket_sync_echo_server.hpp
@@ -38,25 +38,6 @@ class sync_echo_server
using socket_type = boost::asio::ip::tcp::socket;
private:
- struct identity
- {
- template
- void
- operator()(beast::http::message<
- true, Body, Fields>& req) const
- {
- req.fields.replace("User-Agent", "sync_echo_client");
- }
-
- template
- void
- operator()(beast::http::message<
- false, Body, Fields>& resp) const
- {
- resp.fields.replace("Server", "sync_echo_server");
- }
- };
-
/** A container of type-erased option setters.
*/
template
@@ -151,8 +132,6 @@ class sync_echo_server
, sock_(ios_)
, acceptor_(ios_)
{
- opts_.set_option(
- beast::websocket::decorate(identity{}));
}
/** Destructor.
@@ -293,7 +272,13 @@ class sync_echo_server
socket_type> ws{std::move(sock)};
opts_.set_options(ws);
error_code ec;
- ws.accept(ec);
+ ws.accept_ex(
+ [](beast::websocket::response_type& res)
+ {
+ res.fields.insert(
+ "Server", "sync_echo_server");
+ },
+ ec);
if(ec)
{
fail("accept", ec, id, ep);
diff --git a/extras/beast/doc_debug.hpp b/extras/beast/doc_debug.hpp
index 5b5587f0dd..7023c8a2cf 100644
--- a/extras/beast/doc_debug.hpp
+++ b/extras/beast/doc_debug.hpp
@@ -10,7 +10,7 @@
namespace beast {
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
/// doc type (documentation debug helper)
using doc_type = int;
diff --git a/extras/beast/test/string_iostream.hpp b/extras/beast/test/string_iostream.hpp
new file mode 100644
index 0000000000..81417084ff
--- /dev/null
+++ b/extras/beast/test/string_iostream.hpp
@@ -0,0 +1,166 @@
+//
+// Copyright (c) 2013-2017 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_TEST_STRING_IOSTREAM_HPP
+#define BEAST_TEST_STRING_IOSTREAM_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace test {
+
+/** A SyncStream and AsyncStream that reads from a string and writes to another string.
+
+ This class behaves like a socket, except that written data is
+ appended to a string exposed as a public data member, and when
+ data is read it comes from a string provided at construction.
+*/
+class string_iostream
+{
+ std::string s_;
+ boost::asio::const_buffer cb_;
+ boost::asio::io_service& ios_;
+ std::size_t read_max_;
+
+public:
+ std::string str;
+
+ string_iostream(boost::asio::io_service& ios,
+ std::string s, std::size_t read_max =
+ (std::numeric_limits::max)())
+ : s_(std::move(s))
+ , cb_(boost::asio::buffer(s_))
+ , ios_(ios)
+ , read_max_(read_max)
+ {
+ }
+
+ boost::asio::io_service&
+ get_io_service()
+ {
+ return ios_;
+ }
+
+ template
+ std::size_t
+ read_some(MutableBufferSequence const& buffers)
+ {
+ error_code ec;
+ auto const n = read_some(buffers, ec);
+ if(ec)
+ throw system_error{ec};
+ return n;
+ }
+
+ template
+ std::size_t
+ read_some(MutableBufferSequence const& buffers,
+ error_code& ec)
+ {
+ auto const n = boost::asio::buffer_copy(
+ buffers, prepare_buffer(read_max_, cb_));
+ if(n > 0)
+ cb_ = cb_ + n;
+ else
+ ec = boost::asio::error::eof;
+ return n;
+ }
+
+ template
+ typename async_completion::result_type
+ async_read_some(MutableBufferSequence const& buffers,
+ ReadHandler&& handler)
+ {
+ auto const n = boost::asio::buffer_copy(
+ buffers, boost::asio::buffer(s_));
+ error_code ec;
+ if(n > 0)
+ s_.erase(0, n);
+ else
+ ec = boost::asio::error::eof;
+ async_completion completion{handler};
+ ios_.post(bind_handler(
+ completion.handler, ec, n));
+ return completion.result.get();
+ }
+
+ template
+ std::size_t
+ write_some(ConstBufferSequence const& buffers)
+ {
+ error_code ec;
+ auto const n = write_some(buffers, ec);
+ if(ec)
+ throw system_error{ec};
+ return n;
+ }
+
+ template
+ std::size_t
+ write_some(
+ ConstBufferSequence const& buffers, error_code&)
+ {
+ auto const n = buffer_size(buffers);
+ using boost::asio::buffer_size;
+ using boost::asio::buffer_cast;
+ str.reserve(str.size() + n);
+ for(auto const& buffer : buffers)
+ str.append(buffer_cast(buffer),
+ buffer_size(buffer));
+ return n;
+ }
+
+ template
+ typename async_completion<
+ WriteHandler, void(error_code)>::result_type
+ async_write_some(ConstBufferSequence const& buffers,
+ WriteHandler&& handler)
+ {
+ error_code ec;
+ auto const bytes_transferred = write_some(buffers, ec);
+ async_completion<
+ WriteHandler, void(error_code, std::size_t)
+ > completion{handler};
+ get_io_service().post(
+ bind_handler(completion.handler, ec, bytes_transferred));
+ return completion.result.get();
+ }
+
+ friend
+ void
+ teardown(websocket::teardown_tag,
+ string_iostream& stream,
+ boost::system::error_code& ec)
+ {
+ }
+
+ template
+ friend
+ void
+ async_teardown(websocket::teardown_tag,
+ string_iostream& stream,
+ TeardownHandler&& handler)
+ {
+ stream.get_io_service().post(
+ bind_handler(std::move(handler),
+ error_code{}));
+ }
+};
+
+} // test
+} // beast
+
+#endif
diff --git a/extras/beast/test/string_istream.hpp b/extras/beast/test/string_istream.hpp
index e7c32064e1..c630505c76 100644
--- a/extras/beast/test/string_istream.hpp
+++ b/extras/beast/test/string_istream.hpp
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -125,6 +126,26 @@ class string_istream
error_code{}, boost::asio::buffer_size(buffers)));
return completion.result.get();
}
+
+ friend
+ void
+ teardown(websocket::teardown_tag,
+ string_istream& stream,
+ boost::system::error_code& ec)
+ {
+ }
+
+ template
+ friend
+ void
+ async_teardown(websocket::teardown_tag,
+ string_istream& stream,
+ TeardownHandler&& handler)
+ {
+ stream.get_io_service().post(
+ bind_handler(std::move(handler),
+ error_code{}));
+ }
};
} // test
diff --git a/extras/beast/test/string_ostream.hpp b/extras/beast/test/string_ostream.hpp
index a939da7aab..bc5b7896e7 100644
--- a/extras/beast/test/string_ostream.hpp
+++ b/extras/beast/test/string_ostream.hpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -53,6 +54,7 @@ class string_ostream
read_some(MutableBufferSequence const& buffers,
error_code& ec)
{
+ ec = boost::asio::error::eof;
return 0;
}
@@ -65,7 +67,7 @@ class string_ostream
async_completion completion{handler};
ios_.post(bind_handler(completion.handler,
- error_code{}, 0));
+ boost::asio::error::eof, 0));
return completion.result.get();
}
@@ -110,6 +112,26 @@ class string_ostream
bind_handler(completion.handler, ec, bytes_transferred));
return completion.result.get();
}
+
+ friend
+ void
+ teardown(websocket::teardown_tag,
+ string_ostream& stream,
+ boost::system::error_code& ec)
+ {
+ }
+
+ template
+ friend
+ void
+ async_teardown(websocket::teardown_tag,
+ string_ostream& stream,
+ TeardownHandler&& handler)
+ {
+ stream.get_io_service().post(
+ bind_handler(std::move(handler),
+ error_code{}));
+ }
};
} // test
diff --git a/extras/beast/test/yield_to.hpp b/extras/beast/test/yield_to.hpp
index c6b3a8679a..16dea02d57 100644
--- a/extras/beast/test/yield_to.hpp
+++ b/extras/beast/test/yield_to.hpp
@@ -79,7 +79,7 @@ class enable_yield_to
@param args Optional arguments forwarded to the callable object.
*/
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
template
void
yield_to(F&& f, Args&&... args);
diff --git a/include/beast/core.hpp b/include/beast/core.hpp
index 9377cd99fe..b0dd3fc36c 100644
--- a/include/beast/core.hpp
+++ b/include/beast/core.hpp
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/beast/core/bind_handler.hpp b/include/beast/core/bind_handler.hpp
index 1b2d11daf8..18c2652069 100644
--- a/include/beast/core/bind_handler.hpp
+++ b/include/beast/core/bind_handler.hpp
@@ -50,7 +50,7 @@ namespace beast {
arguments are forwarded into the returned object.
*/
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
implementation_defined
#else
detail::bound_handler<
diff --git a/include/beast/core/buffer_cat.hpp b/include/beast/core/buffer_cat.hpp
index a0c892a716..c2ab78ee17 100644
--- a/include/beast/core/buffer_cat.hpp
+++ b/include/beast/core/buffer_cat.hpp
@@ -37,7 +37,7 @@ namespace beast {
also a @b MutableBufferSequence, else the returned buffer sequence
will be a @b ConstBufferSequence.
*/
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
template
implementation_defined
buffer_cat(BufferSequence const&... buffers)
diff --git a/include/beast/core/buffer_concepts.hpp b/include/beast/core/buffer_concepts.hpp
index 545689eb3f..aeef682f91 100644
--- a/include/beast/core/buffer_concepts.hpp
+++ b/include/beast/core/buffer_concepts.hpp
@@ -17,7 +17,7 @@ namespace beast {
/// Determine if `T` meets the requirements of @b `BufferSequence`.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct is_BufferSequence : std::integral_constant
#else
struct is_BufferSequence : detail::is_BufferSequence::type
@@ -27,7 +27,7 @@ struct is_BufferSequence : detail::is_BufferSequence::type
/// Determine if `T` meets the requirements of @b `ConstBufferSequence`.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct is_ConstBufferSequence : std::integral_constant
#else
struct is_ConstBufferSequence :
@@ -38,7 +38,7 @@ struct is_ConstBufferSequence :
/// Determine if `T` meets the requirements of @b `DynamicBuffer`.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct is_DynamicBuffer : std::integral_constant
#else
struct is_DynamicBuffer : detail::is_DynamicBuffer::type
@@ -48,7 +48,7 @@ struct is_DynamicBuffer : detail::is_DynamicBuffer::type
/// Determine if `T` meets the requirements of @b `MutableBufferSequence`.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct is_MutableBufferSequence : std::integral_constant
#else
struct is_MutableBufferSequence :
diff --git a/include/beast/core/buffers_adapter.hpp b/include/beast/core/buffers_adapter.hpp
index 36220d0564..df9edf70fa 100644
--- a/include/beast/core/buffers_adapter.hpp
+++ b/include/beast/core/buffers_adapter.hpp
@@ -64,7 +64,7 @@ class buffers_adapter
}
public:
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
/// The type used to represent the input sequence as a list of buffers.
using const_buffers_type = implementation_defined;
diff --git a/include/beast/core/consuming_buffers.hpp b/include/beast/core/consuming_buffers.hpp
index 4d8d42a641..2e09a418c2 100644
--- a/include/beast/core/consuming_buffers.hpp
+++ b/include/beast/core/consuming_buffers.hpp
@@ -59,7 +59,7 @@ class consuming_buffers
`boost::asio::mutable_buffer`, else this type will be
`boost::asio::const_buffer`.
*/
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
using value_type = ...;
#else
using value_type = typename std::conditional<
@@ -70,7 +70,7 @@ class consuming_buffers
boost::asio::const_buffer>::type;
#endif
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
/// A bidirectional iterator type that may be used to read elements.
using const_iterator = implementation_defined;
diff --git a/include/beast/core/detail/ci_char_traits.hpp b/include/beast/core/detail/ci_char_traits.hpp
index 7dfd0c18ce..07fecc81a0 100644
--- a/include/beast/core/detail/ci_char_traits.hpp
+++ b/include/beast/core/detail/ci_char_traits.hpp
@@ -10,17 +10,15 @@
#include
#include
-#include
-#include
namespace beast {
namespace detail {
inline
char
-tolower(char c)
+tolower(signed char c)
{
- static std::array constexpr tab = {{
+ static unsigned char constexpr tab[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
@@ -37,8 +35,9 @@ tolower(char c)
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
- }};
- return static_cast(tab[static_cast(c)]);
+ };
+ return static_cast(
+ tab[static_cast(c)]);
}
template
diff --git a/include/beast/core/detail/prepare_buffers.hpp b/include/beast/core/detail/prepare_buffers.hpp
index 4f9441c9b3..040e087fe5 100644
--- a/include/beast/core/detail/prepare_buffers.hpp
+++ b/include/beast/core/detail/prepare_buffers.hpp
@@ -61,7 +61,7 @@ class prepared_buffers
boost::asio::mutable_buffer,
boost::asio::const_buffer>::type;
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
/// A bidirectional iterator type that may be used to read elements.
using const_iterator = implementation_defined;
diff --git a/include/beast/core/dynabuf_readstream.hpp b/include/beast/core/dynabuf_readstream.hpp
index e914d434d3..e749ba0150 100644
--- a/include/beast/core/dynabuf_readstream.hpp
+++ b/include/beast/core/dynabuf_readstream.hpp
@@ -110,7 +110,7 @@ class dynabuf_readstream
/// The type of the lowest layer.
using lowest_layer_type =
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
implementation_defined;
#else
typename detail::get_lowest_layer<
@@ -272,7 +272,7 @@ class dynabuf_readstream
manner equivalent to using `boost::asio::io_service::post`.
*/
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
void_or_deduced
#else
typename async_completion::result_type
@@ -347,7 +347,7 @@ class dynabuf_readstream
manner equivalent to using `boost::asio::io_service::post`.
*/
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
void_or_deduced
#else
typename async_completion::result_type
diff --git a/include/beast/core/error.hpp b/include/beast/core/error.hpp
index b8c78687c0..0b9b667e83 100644
--- a/include/beast/core/error.hpp
+++ b/include/beast/core/error.hpp
@@ -24,7 +24,7 @@ using system_error = boost::system::system_error;
using error_category = boost::system::error_category;
/// A function to return the system error category used by the library
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
error_category const&
system_category();
#else
@@ -35,7 +35,7 @@ using boost::system::system_category;
using error_condition = boost::system::error_condition;
/// The set of constants used for cross-platform error codes
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
enum errc{};
#else
namespace errc = boost::system::errc;
diff --git a/include/beast/core/flat_streambuf.hpp b/include/beast/core/flat_streambuf.hpp
new file mode 100644
index 0000000000..8e2cba2ccf
--- /dev/null
+++ b/include/beast/core/flat_streambuf.hpp
@@ -0,0 +1,297 @@
+//
+// 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_FLAT_STREAMBUF_HPP
+#define BEAST_FLAT_STREAMBUF_HPP
+
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+
+/** A linear dynamic buffer.
+
+ Objects of this type meet the requirements of
+ @b `DynamicBuffer` and offer an additional invariant:
+ Buffer sequences returned by @ref data and @ref prepare
+ will always be of length one.
+
+ @note This class is designed for use with algorithms that
+ take dynamic buffers as parameters, and are optimized
+ for the case where the input sequence or output sequence
+ is stored in a single contiguous buffer.
+*/
+template
+class basic_flat_streambuf
+#if ! BEAST_DOXYGEN
+ : private detail::empty_base_optimization<
+ typename std::allocator_traits::
+ template rebind_alloc>
+#endif
+{
+public:
+#if BEAST_DOXYGEN
+ /// The type of allocator used.
+ using allocator_type = Allocator;
+#else
+ using allocator_type = typename
+ std::allocator_traits::
+ template rebind_alloc;
+#endif
+
+private:
+ template
+ friend class basic_flat_streambuf;
+
+ using alloc_traits =
+ std::allocator_traits;
+
+ static
+ inline
+ std::size_t
+ dist(char const* first, char const* last)
+ {
+ return static_cast(last - first);
+ }
+
+ char* p_;
+ char* in_;
+ char* out_;
+ char* last_;
+ char* end_;
+ std::size_t max_;
+
+public:
+ /// The type used to represent the input sequence as a list of buffers.
+ using const_buffers_type = boost::asio::const_buffers_1;
+
+ /// The type used to represent the output sequence as a list of buffers.
+ using mutable_buffers_type = boost::asio::mutable_buffers_1;
+
+ /// Copy assignment (disallowed).
+ basic_flat_streambuf&
+ operator=(basic_flat_streambuf const&) = delete;
+
+ /// Destructor.
+ ~basic_flat_streambuf();
+
+ /** Move constructor.
+
+ The new object will have the same input sequence
+ and an empty output sequence.
+
+ @note After the move, the moved-from object will
+ have a capacity of zero, an empty input sequence,
+ and an empty output sequence.
+ */
+ basic_flat_streambuf(basic_flat_streambuf&&);
+
+ /** Move constructor.
+
+ The new object will have the same input sequence
+ and an empty output sequence.
+
+ @note After the move, the moved-from object will
+ have a capacity of zero, an empty input sequence,
+ and an empty output sequence.
+
+ @param alloc The allocator to associate with the
+ stream buffer.
+ */
+ basic_flat_streambuf(basic_flat_streambuf&&,
+ Allocator const& alloc);
+
+ /** Copy constructor.
+
+ The new object will have a copy of the input sequence
+ and an empty output sequence.
+ */
+ basic_flat_streambuf(basic_flat_streambuf const&);
+
+ /** Copy constructor.
+
+ The new object will have a copy of the input sequence
+ and an empty output sequence.
+
+ @param alloc The allocator to associate with the
+ stream buffer.
+ */
+ basic_flat_streambuf(basic_flat_streambuf const&,
+ Allocator const& alloc);
+
+ /** Copy constructor.
+
+ The new object will have a copy of the input sequence
+ and an empty output sequence.
+ */
+ template
+ basic_flat_streambuf(
+ basic_flat_streambuf const&);
+
+ /** Copy constructor.
+
+ The new object will have a copy of the input sequence
+ and an empty output sequence.
+
+ @param alloc The allocator to associate with the
+ stream buffer.
+ */
+ template
+ basic_flat_streambuf(
+ basic_flat_streambuf const&,
+ Allocator const& alloc);
+
+ /** Construct a flat stream buffer.
+
+ The buffer will have a empty input and output sequences.
+
+ @param size The initial size of the buffer, which must be
+ greater than zero.
+
+ @param limit An optional parameter specifying the maximum
+ of the sum of the input and output sequence sizes that can
+ be allocated. If unspecified, the largest value of `std::size_t`
+ is used.
+ */
+ explicit
+ basic_flat_streambuf(std::size_t size, std::size_t limit = (
+ std::numeric_limits::max()));
+
+ /** Construct a flat stream buffer.
+
+ The buffer will have a empty input and output sequences.
+
+ @param alloc The allocator to associate with the
+ stream buffer.
+
+ @param size The initial size of the buffer, which must be
+ greater than zero.
+
+ @param limit An optional parameter specifying the maximum
+ of the sum of the input and output sequence sizes that can
+ be allocated. If unspecified, the largest value of `std::size_t`
+ is used.
+ */
+ basic_flat_streambuf(Allocator const& alloc,
+ std::size_t size, std::size_t limit = (
+ std::numeric_limits::max()));
+
+ /// Returns a copy of the associated allocator.
+ allocator_type
+ get_allocator() const
+ {
+ return this->member();
+ }
+
+ /// Returns the size of the input sequence.
+ std::size_t
+ size() const
+ {
+ return dist(in_, out_);
+ }
+
+ /// Return the maximum sum of the input and output sequence sizes.
+ std::size_t
+ max_size() const
+ {
+ return max_;
+ }
+
+ /// Return the maximum sum of input and output sizes that can be held without an allocation.
+ std::size_t
+ capacity() const
+ {
+ if(out_ < end_)
+ return dist(in_, end_);
+ return dist(p_, end_);
+ }
+
+ /// Get a list of buffers that represent the input sequence.
+ const_buffers_type
+ data() const
+ {
+ return {in_, dist(in_, out_)};
+ }
+
+ /** Get a list of buffers that represent the output sequence, with the given size.
+
+ @throws std::length_error if `size() + n` exceeds `max_size()`.
+
+ @note All previous buffers sequences obtained from
+ calls to @ref data or @ref prepare are invalidated.
+ */
+ mutable_buffers_type
+ prepare(std::size_t n);
+
+ /** Move bytes from the output sequence to the input sequence.
+
+ @param n The number of bytes to move. If this is larger than
+ the number of bytes in the output sequences, then the entire
+ output sequences is moved.
+
+ @note All previous buffers sequences obtained from
+ calls to @ref data or @ref prepare are invalidated.
+ */
+ void
+ commit(std::size_t n)
+ {
+ out_ += (std::min)(n, dist(out_, last_));
+ }
+
+ /** Remove bytes from the input sequence.
+
+ If `n` is greater than the number of bytes in the input
+ sequence, all bytes in the input sequence are removed.
+
+ @note All previous buffers sequences obtained from
+ calls to @ref data or @ref prepare are invalidated.
+ */
+ void
+ consume(std::size_t n);
+
+ /** Reserve space in the stream.
+
+ This reallocates the buffer if necessary.
+
+ @note All previous buffers sequences obtained from
+ calls to @ref data or @ref prepare are invalidated.
+
+ @param n The number of bytes to reserve.
+ If `n` is greater than the maximum allowed
+ sum of the input and output sequences, this function will
+ attempt to reserve space for the allowed maximum.
+ */
+ void
+ reserve(std::size_t n);
+
+ /** Reallocate the buffer to fit the input sequence.
+
+ @note All previous buffers sequences obtained from
+ calls to @ref data or @ref prepare are invalidated.
+ */
+ void
+ shrink_to_fit();
+
+ // Helper for boost::asio::read_until
+ template
+ friend
+ std::size_t
+ read_size_helper(basic_flat_streambuf<
+ OtherAllocator> const&, std::size_t);
+};
+
+using flat_streambuf =
+ basic_flat_streambuf>;
+
+} // beast
+
+#include
+
+#endif
diff --git a/include/beast/core/handler_alloc.hpp b/include/beast/core/handler_alloc.hpp
index 08a395c3ec..b110ec44d4 100644
--- a/include/beast/core/handler_alloc.hpp
+++ b/include/beast/core/handler_alloc.hpp
@@ -35,7 +35,7 @@ namespace beast {
the handler is invoked or undefined behavior results. This behavior
is described as the "deallocate before invocation" Asio guarantee.
*/
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
template
class handler_alloc;
#else
diff --git a/include/beast/core/handler_concepts.hpp b/include/beast/core/handler_concepts.hpp
index e118072aeb..0f4fd9f2a9 100644
--- a/include/beast/core/handler_concepts.hpp
+++ b/include/beast/core/handler_concepts.hpp
@@ -16,7 +16,7 @@ namespace beast {
/// Determine if `T` meets the requirements of @b `CompletionHandler`.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
using is_CompletionHandler = std::integral_constant;
#else
using is_CompletionHandler = std::integral_constant
+#include
+
+namespace beast {
+
+/* Memory is laid out thusly:
+
+ p_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
+*/
+
+template
+basic_flat_streambuf::
+~basic_flat_streambuf()
+{
+ if(p_)
+ alloc_traits::deallocate(
+ this->member(), p_, dist(p_, end_));
+}
+
+template
+basic_flat_streambuf::
+basic_flat_streambuf(basic_flat_streambuf&& other)
+ : detail::empty_base_optimization<
+ allocator_type>(std::move(other.member()))
+{
+ p_ = other.p_;
+ in_ = other.in_;
+ out_ = other.out_;
+ last_ = out_;
+ end_ = other.end_;
+ max_ = other.max_;
+ other.p_ = nullptr;
+ other.in_ = nullptr;
+ other.out_ = nullptr;
+ other.last_ = nullptr;
+ other.end_ = nullptr;
+}
+
+template
+basic_flat_streambuf::
+basic_flat_streambuf(basic_flat_streambuf&& other,
+ Allocator const& alloc)
+ : detail::empty_base_optimization<
+ allocator_type>(alloc)
+{
+ if(this->member() != other.member())
+ {
+ auto const n = other.size();
+ p_ = alloc_traits::allocate(
+ this->member(), n);
+ in_ = p_;
+ out_ = p_ + n;
+ last_ = out_;
+ end_ = out_;
+ max_ = other.max_;
+ std::memcpy(in_, other.in_, n);
+ return;
+ }
+ p_ = other.p_;
+ in_ = other.in_;
+ out_ = other.out_;
+ last_ = out_;
+ end_ = other.end_;
+ max_ = other.max_;
+ other.p_ = nullptr;
+ other.in_ = nullptr;
+ other.out_ = nullptr;
+ other.last_ = nullptr;
+ other.end_ = nullptr;
+}
+
+template
+basic_flat_streambuf::
+basic_flat_streambuf(
+ basic_flat_streambuf const& other)
+ : detail::empty_base_optimization(
+ alloc_traits::select_on_container_copy_construction(
+ other.member()))
+{
+ auto const n = other.size();
+ p_ = alloc_traits::allocate(
+ this->member(), n);
+ in_ = p_;
+ out_ = p_ + n;
+ last_ = out_;
+ end_ = out_;
+ max_ = other.max_;
+ std::memcpy(in_, other.in_, n);
+}
+
+template
+basic_flat_streambuf::
+basic_flat_streambuf(
+ basic_flat_streambuf const& other,
+ Allocator const& alloc)
+ : detail::empty_base_optimization<
+ allocator_type>(alloc)
+{
+ auto const n = other.size();
+ p_ = alloc_traits::allocate(
+ this->member(), n);
+ in_ = p_;
+ out_ = p_ + n;
+ last_ = out_;
+ end_ = out_;
+ max_ = other.max_;
+ std::memcpy(in_, other.in_, n);
+}
+
+template
+template
+basic_flat_streambuf::
+basic_flat_streambuf(
+ basic_flat_streambuf const& other)
+{
+ auto const n = other.size();
+ p_ = alloc_traits::allocate(
+ this->member(), n);
+ in_ = p_;
+ out_ = p_ + n;
+ last_ = out_;
+ end_ = out_;
+ max_ = other.max_;
+ std::memcpy(in_, other.in_, n);
+}
+
+template
+template
+basic_flat_streambuf::
+basic_flat_streambuf(
+ basic_flat_streambuf const& other,
+ Allocator const& alloc)
+ : detail::empty_base_optimization<
+ allocator_type>(alloc)
+{
+ auto const n = other.size();
+ p_ = alloc_traits::allocate(
+ this->member(), n);
+ in_ = p_;
+ out_ = p_ + n;
+ last_ = out_;
+ end_ = out_;
+ max_ = other.max_;
+ std::memcpy(in_, other.in_, n);
+}
+
+template
+basic_flat_streambuf::
+basic_flat_streambuf(
+ std::size_t size, std::size_t limit)
+ : p_(nullptr)
+ , in_(nullptr)
+ , out_(nullptr)
+ , last_(nullptr)
+ , end_(nullptr)
+ , max_(limit)
+{
+ BOOST_ASSERT(size > 0);
+ reserve(size);
+}
+
+template
+basic_flat_streambuf::
+basic_flat_streambuf(Allocator const& alloc,
+ std::size_t size, std::size_t limit)
+ : detail::empty_base_optimization<
+ allocator_type>(alloc)
+ , p_(nullptr)
+ , in_(nullptr)
+ , out_(nullptr)
+ , last_(nullptr)
+ , end_(nullptr)
+ , max_(limit)
+{
+ BOOST_ASSERT(size > 0);
+ reserve(size);
+}
+
+template
+auto
+basic_flat_streambuf::
+prepare(std::size_t n) ->
+ mutable_buffers_type
+{
+ if(n <= dist(out_, end_))
+ {
+ last_ = out_ + n;
+ return{out_, n};
+ }
+ auto const len = size();
+ if(n <= dist(p_, end_) - len)
+ {
+ std::memmove(p_, in_, len);
+ in_ = p_;
+ out_ = in_ + len;
+ last_ = out_ + n;
+ return {out_, n};
+ }
+ if(n > max_ - len)
+ throw std::length_error{
+ "flat_streambuf overflow"};
+ auto const p = alloc_traits::allocate(
+ this->member(), len + n);
+ if(len > 0)
+ std::memcpy(p, in_, len);
+ alloc_traits::deallocate(
+ this->member(), p_, dist(p_, end_));
+ p_ = p;
+ in_ = p_;
+ out_ = in_ + len;
+ last_ = out_ + n;
+ end_ = last_;
+ return {out_, n};
+}
+
+template
+void
+basic_flat_streambuf::
+consume(std::size_t n)
+{
+ if(n >= dist(in_, out_))
+ {
+ in_ = p_;
+ out_ = p_;
+ return;
+ }
+ in_ += n;
+}
+
+template
+void
+basic_flat_streambuf::
+reserve(std::size_t n)
+{
+ if(n <= dist(p_, end_))
+ return;
+ if(n > max_)
+ throw std::length_error{
+ "flat_streambuf overflow"};
+ auto const p = alloc_traits::allocate(
+ this->member(), n);
+ auto const len = size();
+ if(len > 0)
+ std::memcpy(p, in_, len);
+ alloc_traits::deallocate(
+ this->member(), p_, dist(p_, end_));
+ p_ = p;
+ in_ = p_;
+ out_ = p_ + len;
+ last_ = out_;
+ end_ = p + n;
+}
+
+template
+void
+basic_flat_streambuf::
+shrink_to_fit()
+{
+ auto const len = size();
+ if(len == dist(p_, end_))
+ return;
+ char* p;
+ if(len > 0)
+ {
+ p = alloc_traits::allocate(
+ this->member(), len);
+ std::memcpy(p, in_, len);
+ }
+ else
+ {
+ p = nullptr;
+ }
+ alloc_traits::deallocate(
+ this->member(), p_, dist(p_, end_));
+ p_ = p;
+ in_ = p_;
+ out_ = p_ + len;
+ last_ = out_;
+ end_ = out_;
+}
+
+template
+std::size_t
+read_size_helper(basic_flat_streambuf<
+ Allocator> const& fb, std::size_t max_size)
+{
+ // If this goes off it means you forgot to
+ // call reserve() before using the buffer.
+ BOOST_ASSERT(fb.capacity() != 0);
+ BOOST_ASSERT(max_size >= 1);
+ auto const len = fb.size();
+ auto const avail = fb.capacity() - len;
+ if (avail > 0)
+ return (std::min)(avail, max_size);
+ auto size = (std::min)(
+ fb.capacity() * 2, fb.max_size()) - len;
+ if(size == 0)
+ size = 1;
+ return (std::min)(size, max_size);
+}
+
+} // beast
+
+#endif
diff --git a/include/beast/core/prepare_buffers.hpp b/include/beast/core/prepare_buffers.hpp
index 7db31b5b80..0a960ea8e4 100644
--- a/include/beast/core/prepare_buffers.hpp
+++ b/include/beast/core/prepare_buffers.hpp
@@ -37,7 +37,7 @@ namespace beast {
memory is not transferred.
*/
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
implementation_defined
#else
inline
diff --git a/include/beast/core/static_streambuf.hpp b/include/beast/core/static_streambuf.hpp
index 75ced50a37..2a0d49e159 100644
--- a/include/beast/core/static_streambuf.hpp
+++ b/include/beast/core/static_streambuf.hpp
@@ -28,7 +28,7 @@ namespace beast {
*/
class static_streambuf
{
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
private:
#else
protected:
@@ -40,7 +40,7 @@ class static_streambuf
std::uint8_t* end_;
public:
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
/// The type used to represent the input sequence as a list of buffers.
using const_buffers_type = implementation_defined;
@@ -116,7 +116,7 @@ class static_streambuf
in_ += std::min(n, out_ - in_);
}
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
private:
#else
protected:
@@ -150,7 +150,7 @@ class static_streambuf
template
class static_streambuf_n
: public static_streambuf
-#if ! GENERATING_DOCS
+#if ! BEAST_DOXYGEN
, private boost::base_from_member<
std::array>
#endif
@@ -158,14 +158,14 @@ class static_streambuf_n
using member_type = boost::base_from_member<
std::array>;
public:
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
private:
#endif
static_streambuf_n(
static_streambuf_n const&) = delete;
static_streambuf_n& operator=(
static_streambuf_n const&) = delete;
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
public:
#endif
diff --git a/include/beast/core/stream_concepts.hpp b/include/beast/core/stream_concepts.hpp
index 5f0ba3adfa..f3609e4b97 100644
--- a/include/beast/core/stream_concepts.hpp
+++ b/include/beast/core/stream_concepts.hpp
@@ -16,7 +16,7 @@ namespace beast {
/// Determine if `T` has the `get_io_service` member.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct has_get_io_service : std::integral_constant{};
#else
using has_get_io_service = typename detail::has_get_io_service::type;
@@ -24,7 +24,7 @@ using has_get_io_service = typename detail::has_get_io_service::type;
/// Determine if `T` meets the requirements of @b `AsyncReadStream`.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct is_AsyncReadStream : std::integral_constant{};
#else
using is_AsyncReadStream = typename detail::is_AsyncReadStream::type;
@@ -32,7 +32,7 @@ using is_AsyncReadStream = typename detail::is_AsyncReadStream::type;
/// Determine if `T` meets the requirements of @b `AsyncWriteStream`.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct is_AsyncWriteStream : std::integral_constant{};
#else
using is_AsyncWriteStream = typename detail::is_AsyncWriteStream::type;
@@ -40,7 +40,7 @@ using is_AsyncWriteStream = typename detail::is_AsyncWriteStream::type;
/// Determine if `T` meets the requirements of @b `SyncReadStream`.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct is_SyncReadStream : std::integral_constant{};
#else
using is_SyncReadStream = typename detail::is_SyncReadStream::type;
@@ -48,7 +48,7 @@ using is_SyncReadStream = typename detail::is_SyncReadStream::type;
/// Determine if `T` meets the requirements of @b `SyncWriterStream`.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct is_SyncWriteStream : std::integral_constant{};
#else
using is_SyncWriteStream = typename detail::is_SyncWriteStream::type;
@@ -56,7 +56,7 @@ using is_SyncWriteStream = typename detail::is_SyncWriteStream::type;
/// Determine if `T` meets the requirements of @b `AsyncStream`.
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct is_AsyncStream : std::integral_constant{};
#else
using is_AsyncStream = std::integral_constant
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
struct is_SyncStream : std::integral_constant{};
#else
using is_SyncStream = std::integral_constant
class basic_streambuf
-#if ! GENERATING_DOCS
+#if ! BEAST_DOXYGEN
: private detail::empty_base_optimization<
typename std::allocator_traits::
template rebind_alloc>
#endif
{
public:
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
/// The type of allocator used.
using allocator_type = Allocator;
#else
@@ -81,7 +81,7 @@ class basic_streambuf
size_type out_end_ = 0; // output end offset in list_.back()
public:
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
/// The type used to represent the input sequence as a list of buffers.
using const_buffers_type = implementation_defined;
diff --git a/include/beast/core/to_string.hpp b/include/beast/core/to_string.hpp
index e391ea2d57..14d32589aa 100644
--- a/include/beast/core/to_string.hpp
+++ b/include/beast/core/to_string.hpp
@@ -29,7 +29,7 @@ namespace beast {
the buffers parameter meets the requirements of @b `ConstBufferSequence`.
*/
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
std::string
#else
typename std::enable_if<
diff --git a/include/beast/core/write_dynabuf.hpp b/include/beast/core/write_dynabuf.hpp
index 646e787498..c91b984c69 100644
--- a/include/beast/core/write_dynabuf.hpp
+++ b/include/beast/core/write_dynabuf.hpp
@@ -49,7 +49,7 @@ namespace beast {
the `dynabuf` parameter meets the requirements of @b `DynamicBuffer`.
*/
template
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
void
#else
typename std::enable_if::value>::type
diff --git a/include/beast/http.hpp b/include/beast/http.hpp
index b4c7734f17..8a8c3ff34f 100644
--- a/include/beast/http.hpp
+++ b/include/beast/http.hpp
@@ -11,14 +11,14 @@
#include
#include
-#include
+#include
#include
-#include
+#include
#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 a2c090149e..8ad5f69186 100644
--- a/include/beast/http/basic_dynabuf_body.hpp
+++ b/include/beast/http/basic_dynabuf_body.hpp
@@ -27,36 +27,53 @@ struct basic_dynabuf_body
/// The type of the `message::body` member
using value_type = DynamicBuffer;
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
private:
#endif
class reader
{
- value_type& sb_;
+ value_type& body_;
public:
+ static bool constexpr is_direct = true;
+
+ using mutable_buffers_type =
+ typename DynamicBuffer::mutable_buffers_type;
+
template
explicit
reader(message& m) noexcept
- : sb_(m.body)
+ basic_dynabuf_body, Fields>& msg)
+ : body_(msg.body)
+ {
+ }
+
+ void
+ init()
+ {
+ }
+
+ void
+ init(std::uint64_t content_length)
+ {
+ }
+
+ mutable_buffers_type
+ prepare(std::size_t n)
{
+ return body_.prepare(n);
}
void
- init(error_code&) noexcept
+ commit(std::size_t n)
{
+ body_.commit(n);
}
void
- write(void const* data,
- std::size_t size, error_code&) noexcept
+ finish()
{
- using boost::asio::buffer;
- using boost::asio::buffer_copy;
- sb_.commit(buffer_copy(
- sb_.prepare(size), buffer(data, size)));
}
};
diff --git a/include/beast/http/basic_fields.hpp b/include/beast/http/basic_fields.hpp
index 2589c827a9..f4f73ba9f1 100644
--- a/include/beast/http/basic_fields.hpp
+++ b/include/beast/http/basic_fields.hpp
@@ -39,7 +39,7 @@ namespace http {
*/
template
class basic_fields :
-#if ! GENERATING_DOCS
+#if ! BEAST_DOXYGEN
private beast::detail::empty_base_optimization<
typename std::allocator_traits::
template rebind_alloc<
@@ -89,17 +89,17 @@ class basic_fields :
Meets the requirements of @b Field.
*/
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
using value_type = implementation_defined;
#endif
/// A const iterator to the field sequence
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
using iterator = implementation_defined;
#endif
/// A const iterator to the field sequence
-#if GENERATING_DOCS
+#if BEAST_DOXYGEN
using const_iterator = implementation_defined;
#endif
diff --git a/include/beast/http/basic_parser.hpp b/include/beast/http/basic_parser.hpp
new file mode 100644
index 0000000000..755cccc179
--- /dev/null
+++ b/include/beast/http/basic_parser.hpp
@@ -0,0 +1,643 @@
+//
+// Copyright (c) 2013-2017 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_BASIC_PARSER_HPP
+#define BEAST_HTTP_BASIC_PARSER_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace http {
+
+/** Describes the parser's current state.
+
+ The state is expressed as the type of data that
+ @ref basic_parser is expecting to see in subsequently
+ provided octets.
+*/
+enum class parse_state
+{
+ /// Expecting one or more header octets
+ header = 0,
+
+ /// Expecting one or more body octets
+ body = 1,
+
+ /// Expecting zero or more body octets followed by EOF
+ body_to_eof = 2,
+
+ /// Expecting additional chunk header octets
+ chunk_header = 3,
+
+ /// Expecting one or more chunk body octets
+ chunk_body = 4,
+
+ /** The parsing is complete.
+
+ The parse is considered complete when the full header
+ is received and either the full body is received, or
+ the semantics of the message indicate that no body
+ is expected. This includes the case where the caller
+ has indicated to the parser that no body is expected,
+ for example when receiving a response to a HEAD request.
+ */
+ complete = 5
+};
+
+/** A parser for decoding HTTP/1 wire format messages.
+
+ This parser is designed to efficiently parse messages in the
+ HTTP/1 wire format. It allocates no memory when input is
+ presented as a single contiguous buffer, and uses minimal
+ state. It will handle chunked encoding and it understands
+ the semantics of the Connection, Content-Length, and Upgrade
+ fields.
+
+ The interface uses CRTP (Curiously Recurring Template Pattern).
+ To use this class, derive from @ref basic_parser. When bytes
+ are presented, the implementation will make a series of zero
+ or more calls to derived class members functions (referred to
+ as "callbacks" from here on) matching a specific signature.
+
+ Every callback must be provided by the derived class, or else
+ a compilation error will be generated. This exemplar shows
+ the signature and description of the callbacks required in
+ the derived class.
+
+ @par Derived Example
+
+ @code
+ template
+ struct derived
+ : basic_parser>
+ {
+ // The type used when providing a mutable
+ // buffer sequence in which to store body data.
+ //
+ using mutable_buffers_type = ...;
+
+ // When isRequest == true, called
+ // after the Request Line is received.
+ //
+ void
+ on_request(
+ boost::string_ref const& method,
+ boost::string_ref const& path,
+ int version,
+ error_code& ec);
+
+ // When isRequest == false, called
+ // after the Status Line is received.
+ //
+ void
+ on_response(
+ int status,
+ boost::string_ref const& reason,
+ int version,
+ error_code& ec);
+
+ // Called after receiving a field/value pair.
+ //
+ void
+ on_field(
+ boost::string_ref const& name,
+ boost::string_ref const& value,
+ error_code& ec);
+
+ // Called after the header is complete.
+ //
+ void
+ on_header(
+ error_code& ec);
+
+ // Called once before the body, if any, is started.
+ // This will only be called if the semantics of the
+ // message indicate that a body exists, including
+ // an indicated body of zero length.
+ //
+ void
+ on_body();
+
+ // Called zero or more times to provide body data.
+ //
+ // Only used if isDirect == false
+ //
+ void
+ on_data(
+ boost::string_ref const& s,
+ error_code& ec);
+
+ // Called zero or more times to retrieve a mutable
+ // buffer sequence in which to store body data.
+ //
+ // Only used if isDirect == true
+ //
+ mutable_buffers_type
+ on_prepare(
+ std::size_t n);
+
+ // Called after body data has been stored in the
+ // buffer returned by the previous call to on_prepare.
+ //
+ // Only used if isDirect == true
+ //
+ void
+ on_commit(
+ std::size_t n);
+
+ // If the Transfer-Encoding is specified, and the
+ // last item in the list of encodings is "chunked",
+ // called after receiving a chunk header or a final
+ // chunk.
+ //
+ void
+ on_chunk(
+ std::uint64_t length, // Length of this chunk
+ boost::string_ref const& ext, // The chunk extensions, if any
+ error_code& ec);
+
+ // Called once when the message is complete.
+ // This will be called even if there is no body.
+ //
+ void
+ on_complete(error_code& ec);
+ };
+ @endcode
+
+ If a callback sets the error code, the error will be propagated
+ to the caller of the parser. Behavior of parsing after an error
+ is returned is undefined.
+
+ When the parser state is positioned to read bytes belonging to
+ the body, calling @ref write or @ref write will implicitly
+ cause a buffer copy (because bytes are first transferred to the
+ dynamic buffer). To avoid this copy, the additional functions
+ @ref copy_body, @ref prepare_body, and @ref commit_body are
+ provided to allow the caller to read bytes directly into buffers
+ supplied by the parser.
+
+ The parser is optimized for the case where the input buffer
+ sequence consists of a single contiguous buffer. The
+ @ref beast::flat_streambuf class is provided, which guarantees
+ that the input sequence of the stream buffer will be represented
+ by exactly one contiguous buffer. To ensure the optimum performance
+ of the parser, use @ref beast::flat_streambuf with HTTP algorithms
+ such as @ref beast::http::read, @ref beast::http::read_some,
+ @ref beast::http::async_read, and @ref beast::http::async_read_some.
+ Alternatively, the caller may use custom techniques to ensure that
+ the structured portion of the HTTP message (header or chunk header)
+ is contained in a linear buffer.
+
+ @tparam isRequest A `bool` indicating whether the parser will be
+ presented with request or response message.
+
+ @tparam isDirect A `bool` indicating whether the parser interface
+ supports reading body data directly into parser-provided buffers.
+
+ @tparam Derived The derived class type. This is part of the
+ Curiously Recurring Template Pattern interface.
+*/
+template
+class basic_parser
+ : private detail::basic_parser_base
+{
+ template
+ friend class basic_parser;
+
+ // Message will be complete after reading header
+ static unsigned constexpr flagSkipBody = 1<< 0;
+
+
+
+ static unsigned constexpr flagOnBody = 1<< 1;
+
+ // The parser has read at least one byte
+ static unsigned constexpr flagGotSome = 1<< 2;
+
+ // Message semantics indicate a body is expected.
+ // cleared if flagSkipBody set
+ //
+ static unsigned constexpr flagHasBody = 1<< 3;
+
+ static unsigned constexpr flagHTTP11 = 1<< 4;
+ static unsigned constexpr flagNeedEOF = 1<< 5;
+ static unsigned constexpr flagExpectCRLF = 1<< 6;
+ static unsigned constexpr flagFinalChunk = 1<< 7;
+ static unsigned constexpr flagConnectionClose = 1<< 8;
+ static unsigned constexpr flagConnectionUpgrade = 1<< 9;
+ static unsigned constexpr flagConnectionKeepAlive = 1<< 10;
+ static unsigned constexpr flagContentLength = 1<< 11;
+ static unsigned constexpr flagChunked = 1<< 12;
+ static unsigned constexpr flagUpgrade = 1<< 13;
+
+ std::uint64_t len_; // size of chunk or body
+ std::unique_ptr buf_;
+ std::size_t buf_len_ = 0;
+ std::size_t skip_ = 0; // search from here
+ std::size_t x_; // scratch variable
+ unsigned f_ = 0; // flags
+ parse_state state_ = parse_state::header;
+ boost::string_ref ext_;
+ boost::string_ref body_;
+
+public:
+ /// Copy constructor (disallowed)
+ basic_parser(basic_parser const&) = delete;
+
+ /// Copy assignment (disallowed)
+ basic_parser& operator=(basic_parser const&) = delete;
+
+ /// Default constructor
+ basic_parser() = default;
+
+ /// `true` if this parser parses requests, `false` for responses.
+ static bool constexpr is_request = isRequest;
+
+ /// Destructor
+ ~basic_parser() = default;
+
+ /** Move constructor
+
+ After the move, the only valid operation on the
+ moved-from object is destruction.
+ */
+ template
+ basic_parser(basic_parser<
+ isRequest, OtherIsDirect, OtherDerived>&&);
+
+ /** Set the skip body option.
+
+ The option controls whether or not the parser expects to
+ see an HTTP body, regardless of the presence or absence of
+ certain fields such as Content-Length.
+
+ Depending on the request, some responses do not carry a body.
+ For example, a 200 response to a CONNECT request from a
+ tunneling proxy. In these cases, callers may use this function
+ inform the parser that no body is expected. The parser will
+ consider the message complete after the header has been received.
+
+ @note This function must called before any bytes are processed.
+ */
+ void
+ skip_body();
+
+ /** Returns the current parser state.
+
+ The parser state indicates what octets the parser
+ expects to see next in the input stream.
+ */
+ parse_state
+ state() const
+ {
+ return state_;
+ }
+
+ /// Returns `true` if the parser has received at least one byte of input.
+ bool
+ got_some() const
+ {
+ return (f_ & flagGotSome) != 0;
+ }
+
+ /// Returns `true` if the complete header has been parsed.
+ bool
+ got_header() const
+ {
+ return state_ != parse_state::header;
+ }
+
+ /** Returns `true` if a Content-Length is specified.
+
+ @note Only valid after parsing a complete header.
+ */
+ bool
+ got_content_length() const
+ {
+ return (f_ & flagContentLength) != 0;
+ }
+
+ /** Returns `true` if the message is complete.
+
+ The message is complete after a full header is
+ parsed and one of the following is true:
+
+ @li @ref skip_body was called
+
+ @li The semantics of the message indicate there is no body.
+
+ @li The semantics of the message indicate a body is
+ expected, and the entire body was received.
+ */
+ bool
+ is_complete() const
+ {
+ return state_ == parse_state::complete;
+ }
+
+ /** Returns `true` if the message is an upgrade message.
+
+ @note Only valid after parsing a complete header.
+ */
+ bool
+ is_upgrade() const
+ {
+ return (f_ & flagConnectionUpgrade) != 0;
+ }
+
+ /** Returns `true` if keep-alive is specified
+
+ @note Only valid after parsing a complete header.
+ */
+ bool
+ is_keep_alive() const;
+
+ /** Returns `true` if the chunked Transfer-Encoding is specified.
+
+ @note Only valid after parsing a complete header.
+ */
+ bool
+ is_chunked() const
+ {
+ return (f_ & flagChunked) != 0;
+ }
+
+ /** Write part of a buffer sequence to the parser.
+
+ This function attempts to parse the HTTP message
+ stored in the caller provided buffers. Upon success,
+ a positive return value indicates that the parser
+ made forward progress, consuming that number of
+ bytes.
+
+ A return value of zero indicates that the parser
+ requires additional input. In this case the caller
+ should append additional bytes to the input buffer
+ sequence and call @ref write again.
+
+ @param buffers An object meeting the requirements of
+ @b ConstBufferSequence that represents the message.
+
+ @param ec Set to the error, if any occurred.
+
+ @return The number of bytes consumed in the buffer
+ sequence.
+ */
+ template
+ std::size_t
+ write(ConstBufferSequence const& buffers, error_code& ec);
+
+#if ! GENERATING_DOCS
+ std::size_t
+ write(boost::asio::const_buffers_1 const& buffer,
+ error_code& ec);
+#endif
+
+ /** Inform the parser that the end of stream was reached.
+
+ In certain cases, HTTP needs to know where the end of
+ the stream is. For example, sometimes servers send
+ responses without Content-Length and expect the client
+ to consume input (for the body) until EOF. Callbacks
+ and errors will still be processed as usual.
+
+ This is typically called when a read from the
+ underlying stream object sets the error code to
+ `boost::asio::error::eof`.
+
+ @note Only valid after parsing a complete header.
+
+ @param ec Set to the error, if any occurred.
+ */
+ void
+ write_eof(error_code& ec);
+
+ /** Returns the number of bytes remaining in the body or chunk.
+
+ If a Content-Length is specified and the parser state
+ is equal to @ref beast::http::parse_state::body, this will return
+ the number of bytes remaining in the body. If the
+ chunked Transfer-Encoding is indicated and the parser
+ state is equal to @ref beast::http::parse_state::chunk_body, this
+ will return the number of bytes remaining in the chunk.
+ Otherwise, the function behavior is undefined.
+ */
+ std::uint64_t
+ size() const
+ {
+ BOOST_ASSERT(
+ state_ == parse_state::body ||
+ state_ == parse_state::chunk_body);
+ return len_;
+ }
+
+ /** Returns the body data parsed in the last call to @ref write.
+
+ This buffer is invalidated after any call to @ref write
+ or @ref write_eof.
+
+ @note If the last call to @ref write came from the input
+ area of a @b DynamicBuffer object, a call to the dynamic
+ buffer's `consume` function may invalidate this return
+ value.
+ */
+ boost::string_ref const&
+ body() const
+ {
+ // This function not available when isDirect==true
+ static_assert(! isDirect, "");
+ return body_;
+ }
+
+ /** Returns the chunk extension parsed in the last call to @ref write.
+
+ This buffer is invalidated after any call to @ref write
+ or @ref write_eof.
+
+ @note If the last call to @ref write came from the input
+ area of a @b DynamicBuffer object, a call to the dynamic
+ buffer's `consume` function may invalidate this return
+ value.
+ */
+ boost::string_ref const&
+ chunk_extension() const
+ {
+ // This function not available when isDirect==true
+ static_assert(! isDirect, "");
+ return ext_;
+ }
+
+ /** Returns the optional value of Content-Length if known.
+
+ @note The return value is undefined unless a complete
+ header has been parsed.
+ */
+ boost::optional
+ content_length() const
+ {
+ BOOST_ASSERT(got_header());
+ if(! (f_ & flagContentLength))
+ return boost::none;
+ return len_;
+ }
+
+ /** Copy leftover body data from the dynamic buffer.
+
+ @note This member function is only available when
+ `isDirect==true`.
+
+ @return The number of bytes processed from the dynamic
+ buffer. The caller should remove these bytes by calling
+ `consume` on the buffer.
+ */
+ template
+ std::size_t
+ copy_body(DynamicBuffer& dynabuf);
+
+ /** Returns a set of buffers for storing body data.
+
+ @note This member function is only available when
+ `isDirect==true`.
+
+ @param limit The maximum number of bytes in the
+ size of the returned buffer sequence. The actual size
+ of the buffer sequence may be lower than this number.
+ */
+ template
+ void
+ prepare_body(boost::optional<
+ MutableBufferSequence>& buffers, std::size_t limit);
+
+ /** Commit body data.
+
+ @note This member function is only available when
+ `isDirect==true`.
+ */
+ void
+ commit_body(std::size_t n);
+
+ /** Indicate that body octets have been consumed.
+ */
+ void
+ consume(std::size_t n)
+ {
+ BOOST_ASSERT(n <= len_);
+ BOOST_ASSERT(
+ state_ == parse_state::body ||
+ state_ == parse_state::chunk_body);
+ len_ -= n;
+ if(len_ == 0)
+ {
+ if(state_ == parse_state::body)
+ state_ = parse_state::complete;
+ else
+ state_ = parse_state::chunk_header;
+ }
+ }
+
+ /** Consume all remaining body data.
+
+ This function instructs the parser to advance the
+ state past any expected body octets. Callers who
+ wish to read and process the body themselves will
+ call this function.
+ */
+ void
+ consume_body(error_code& ec);
+
+private:
+ inline
+ Derived&
+ impl()
+ {
+ return *static_cast(this);
+ }
+
+ template
+ boost::string_ref
+ maybe_flatten(
+ ConstBufferSequence const& buffers);
+
+ std::size_t
+ do_write(boost::asio::const_buffers_1 const& buffer,
+ error_code& ec, std::true_type);
+
+ std::size_t
+ do_write(boost::asio::const_buffers_1 const& buffer,
+ error_code& ec, std::false_type);
+
+ void
+ parse_startline(char const*& it,
+ int& version, int& status,
+ error_code& ec, std::true_type);
+
+ void
+ parse_startline(char const*& it,
+ int& version, int& status,
+ error_code& ec, std::false_type);
+
+ void
+ parse_fields(char const*& it,
+ char const* last, error_code& ec);
+
+ void
+ do_field(
+ boost::string_ref const& name,
+ boost::string_ref const& value,
+ error_code& ec);
+
+ std::size_t
+ parse_header(char const* p,
+ std::size_t n, error_code& ec);
+
+ void
+ do_header(int, std::true_type);
+
+ void
+ do_header(int status, std::false_type);
+
+ void
+ maybe_do_body_direct();
+
+ void
+ maybe_do_body_indirect(error_code& ec);
+
+ std::size_t
+ parse_chunk_header(char const* p,
+ std::size_t n, error_code& ec);
+
+ std::size_t
+ parse_body(char const* p,
+ std::size_t n, error_code& ec);
+
+ std::size_t
+ parse_body_to_eof(char const* p,
+ std::size_t n, error_code& ec);
+
+ std::size_t
+ parse_chunk_body(char const* p,
+ std::size_t n, error_code& ec);
+
+ void
+ do_complete(error_code& ec);
+};
+
+} // http
+} // beast
+
+#include
+
+#endif
diff --git a/include/beast/http/basic_parser_v1.hpp b/include/beast/http/basic_parser_v1.hpp
deleted file mode 100644
index cda14a0023..0000000000
--- a/include/beast/http/basic_parser_v1.hpp
+++ /dev/null
@@ -1,856 +0,0 @@
-//
-// Copyright (c) 2013-2017 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_BASIC_PARSER_v1_HPP
-#define BEAST_HTTP_BASIC_PARSER_v1_HPP
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace beast {
-namespace http {
-
-/** 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,
- connection_close = 4,
- connection_upgrade = 8,
- trailing = 16,
- upgrade = 32,
- skipbody = 64,
- contentlength = 128,
- paused = 256
-};
-
-/** Body maximum size option.
-
- Sets the maximum number of cumulative bytes allowed including
- all body octets. Octets in chunk-encoded bodies are counted
- after decoding. A value of zero indicates no limit on
- the number of body octets.
-
- 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 @ref basic_parser_v1::set_option.
-*/
-struct body_max_size
-{
- std::size_t value;
-
- explicit
- body_max_size(std::size_t v)
- : value(v)
- {
- }
-};
-
-/** 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_header` callback in
- the derived class. It controls what the parser does next
- in terms of the message body.
-*/
-enum class body_what
-{
- /** The parser should expect a body, keep reading.
- */
- normal,
-
- /** Skip parsing of the body.
-
- 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.
- */
- skip,
-
- /** The message represents an UPGRADE request.
-
- When returned by `on_body_prepare` this causes parsing
- to complete and control to return to the caller.
- */
- upgrade,
-
- /** Suspend parsing before reading the body.
-
- When returned by `on_body_prepare` this causes parsing
- to pause. Control is returned to the caller, and the
- parser state is preserved such that a subsequent call
- to the parser will begin reading the message body.
-
- This could be used by callers to inspect the HTTP
- 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
-};
-
-/// The value returned when no content length is known or applicable.
-static std::uint64_t constexpr no_content_length =
- (std::numeric_limits::max)();
-
-/** A parser for decoding HTTP/1 wire format messages.
-
- This parser is designed to efficiently parse messages in the
- HTTP/1 wire format. It allocates no memory and uses minimal
- state. It will handle chunked encoding and it understands the
- semantics of the Connection and Content-Length header fields.
-
- The interface uses CRTP (Curiously Recurring Template Pattern).
- To use this class, derive from basic_parser. When bytes are
- presented, the implementation will make a series of zero or
- more calls to derived class members functions (referred to as
- "callbacks" from here on) matching a specific signature.
-
- Every callback must be provided by the derived class, or else
- a compilation error will be generated. This exemplar shows
- the signature and description of the callbacks required in
- the derived class.
-
- @code
- template
- struct exemplar : basic_parser_v1
- {
- // Called when the first valid octet of a new message is received
- //
- void on_start(error_code&);
-
- // Called for each piece of the Request-Method
- //
- void on_method(boost::string_ref const&, error_code&);
-
- // Called for each piece of the Request-URI
- //
- void on_uri(boost::string_ref const&, error_code&);
-
- // Called for each piece of the reason-phrase
- //
- void on_reason(boost::string_ref const&, error_code&);
-
- // Called after the entire Request-Line has been parsed successfully.
- //
- void on_request(error_code&);
-
- // Called after the entire Response-Line has been parsed successfully.
- //
- void on_response(error_code&);
-
- // Called for each piece of the current header field.
- //
- void on_field(boost::string_ref const&, error_code&);
-
- // Called for each piece of the current header value.
- //
- void on_value(boost::string_ref const&, error_code&)
-
- // Called when the entire header has been parsed successfully.
- //
- void
- on_header(std::uint64_t content_length, error_code&);
-
- // 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 header indicates chunk encoding, the chunk
- // encoding is removed from the buffer before being
- // passed to the callback.
- //
- void on_body(boost::string_ref const&, error_code&);
-
- // Called when the entire message has been parsed successfully.
- // At this point, @ref complete returns `true`, and the parser
- // is ready to parse another message if `keep_alive` would
- // return `true`.
- //
- void on_complete(error_code&) {}
- };
- @endcode
-
- The return value of `on_body_what` is special, it controls
- whether or not the parser should expect a body. See @ref body_what
- for choices of the return value.
-
- If a callback sets an error, parsing stops at the current octet
- and the error is returned to the caller. Callbacks must not throw
- exceptions.
-
- @tparam isRequest A `bool` indicating whether the parser will be
- presented with request or response message.
-
- @tparam Derived The derived class type. This is part of the
- Curiously Recurring Template Pattern interface.
-*/
-template
-class basic_parser_v1 : public detail::parser_base
-{
-private:
- template
- friend class basic_parser_v1;
-
- using self = basic_parser_v1;
- typedef void(self::*pmf_t)(error_code&, boost::string_ref const&);
-
- enum field_state : std::uint8_t
- {
- h_general = 0,
- h_C,
- h_CO,
- h_CON,
-
- h_matching_connection,
- h_matching_proxy_connection,
- h_matching_content_length,
- h_matching_transfer_encoding,
- h_matching_upgrade,
-
- h_connection,
- h_content_length0,
- h_content_length,
- h_content_length_ows,
- h_transfer_encoding,
- h_upgrade,
-
- h_matching_transfer_encoding_chunked,
- h_matching_transfer_encoding_general,
- h_matching_connection_keep_alive,
- h_matching_connection_close,
- h_matching_connection_upgrade,
-
- h_transfer_encoding_chunked,
- h_transfer_encoding_chunked_ows,
-
- h_connection_keep_alive,
- h_connection_keep_alive_ows,
- h_connection_close,
- h_connection_close_ows,
- h_connection_upgrade,
- h_connection_upgrade_ows,
- h_connection_token,
- h_connection_token_ows
- };
-
- std::size_t h_max_;
- std::size_t h_left_;
- std::size_t b_max_;
- std::size_t b_left_;
- std::uint64_t content_length_;
- pmf_t cb_;
- state s_ : 8;
- unsigned fs_ : 8;
- unsigned pos_ : 8; // position in field state
- unsigned http_major_ : 16;
- unsigned http_minor_ : 16;
- unsigned status_code_ : 16;
- unsigned flags_ : 9;
- bool upgrade_ : 1; // true if parser exited for upgrade
-
-public:
- /// Default constructor
- basic_parser_v1();
-
- /// Copy constructor.
- template
- basic_parser_v1(basic_parser_v1<
- isRequest, OtherDerived> const& other);
-
- /// Copy assignment.
- template
- basic_parser_v1& operator=(basic_parser_v1<
- isRequest, OtherDerived> const& other);
-
- /** Set options on the parser.
-
- @param args One or more parser options to set.
- */
-#if GENERATING_DOCS
- template
- void
- set_option(Args&&... args)
-#else
- template