mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-27 06:25:51 +00:00
Merge commit 'af4fe2493925bc57c5c3343c383719fa72dea262' into b4.2
This commit is contained in:
@@ -10,8 +10,8 @@ env:
|
|||||||
# to boost's .tar.gz.
|
# to boost's .tar.gz.
|
||||||
- LCOV_ROOT=$HOME/lcov
|
- LCOV_ROOT=$HOME/lcov
|
||||||
- VALGRIND_ROOT=$HOME/valgrind-install
|
- VALGRIND_ROOT=$HOME/valgrind-install
|
||||||
- BOOST_ROOT=$HOME/boost_1_60_0
|
- BOOST_ROOT=$HOME/boost_1_61_0
|
||||||
- BOOST_URL='http://downloads.sourceforge.net/project/boost/boost/1.60.0/boost_1_60_0.tar.gz?r=https%3A%2F%2Fsourceforge.net%2Fprojects%2Fboost%2Ffiles%2Fboost%2F1.60.0%2Fboost_1_60_0.tar.gz&ts=1460417589&use_mirror=netix'
|
- BOOST_URL='http://downloads.sourceforge.net/project/boost/boost/1.61.0/boost_1_61_0.tar.gz?use_mirror=netix'
|
||||||
packages: &gcc5_pkgs
|
packages: &gcc5_pkgs
|
||||||
- gcc-5
|
- gcc-5
|
||||||
- g++-5
|
- g++-5
|
||||||
|
|||||||
@@ -1,3 +1,183 @@
|
|||||||
|
1.0.0-b22
|
||||||
|
|
||||||
|
* Fix broken Intellisense
|
||||||
|
* Implement the Asio deallocation-before-invocation guarantee
|
||||||
|
* Add handler helpers
|
||||||
|
* Avoid copies in handler_alloc
|
||||||
|
* Update README.md example programs
|
||||||
|
* Fix websocket stream read documentation
|
||||||
|
* Disable Boost.Coroutine deprecation warning
|
||||||
|
* Update documentation examples
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b21
|
||||||
|
|
||||||
|
* Remove extraneous includes
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b20
|
||||||
|
|
||||||
|
ZLib
|
||||||
|
|
||||||
|
* Add ZLib module
|
||||||
|
|
||||||
|
API Changes:
|
||||||
|
|
||||||
|
* Rename HTTP identifiers
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b19
|
||||||
|
|
||||||
|
* Boost library min/max guidance
|
||||||
|
* Improvements to code coverage
|
||||||
|
* Use boost::lexical_cast instead of std::to_string
|
||||||
|
* Fix prepare_buffers value_type
|
||||||
|
* Fix consuming_buffers value_type
|
||||||
|
* Better buffer_cat
|
||||||
|
|
||||||
|
HTTP
|
||||||
|
|
||||||
|
* Make chunk_encode public
|
||||||
|
* Add write, async_write, operator<< for message_headers
|
||||||
|
* Add read, async_read for message_headers
|
||||||
|
* Fix with_body example
|
||||||
|
|
||||||
|
WebSocket
|
||||||
|
|
||||||
|
* Optimize utf8 validation
|
||||||
|
* Optimize mask operations
|
||||||
|
|
||||||
|
API Changes:
|
||||||
|
|
||||||
|
* Refactor message and message_headers declarations
|
||||||
|
* prepared_buffers is private
|
||||||
|
* consume_buffers is removed
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b18
|
||||||
|
|
||||||
|
* Increase optimization settings for MSVC builds
|
||||||
|
|
||||||
|
HTTP
|
||||||
|
|
||||||
|
* Check invariants in parse_op:
|
||||||
|
* Clean up message docs
|
||||||
|
|
||||||
|
WebSocket
|
||||||
|
|
||||||
|
* Write buffer option does not change capacity
|
||||||
|
* Close connection during async_read on close frame
|
||||||
|
* Add pong, async pong to stream
|
||||||
|
|
||||||
|
Core
|
||||||
|
|
||||||
|
* Meet DynamicBuffer requirements for static_streambuf
|
||||||
|
* Fix write_frame masking and auto-fragment handling
|
||||||
|
|
||||||
|
Extras
|
||||||
|
|
||||||
|
* unit_test::suite fixes:
|
||||||
|
- New overload of fail() specifies file and line
|
||||||
|
- BEAST_EXPECTS only evaluates the reason string on a failure
|
||||||
|
* Add zlib module
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b17
|
||||||
|
|
||||||
|
* Change implicit to default value in example
|
||||||
|
* Tidy up some declarations
|
||||||
|
* Fix basic_streambuf::capacity
|
||||||
|
* Add basic_streambuf::alloc_size
|
||||||
|
* Parser callbacks may not throw
|
||||||
|
* Fix Reader concept doc typo
|
||||||
|
* Add is_Reader trait
|
||||||
|
* Tidy up basic_headers for documentation
|
||||||
|
* Tidy up documentation
|
||||||
|
* Add basic_parser_v1::reset
|
||||||
|
* Fix handling of body_what::pause in basic_parser_v1
|
||||||
|
* Add headers_parser
|
||||||
|
* Engaged invokable is destructible
|
||||||
|
* Improve websocket example in README.md
|
||||||
|
* Refactor read_size_helper
|
||||||
|
|
||||||
|
API Changes:
|
||||||
|
|
||||||
|
* Added init() to Reader requirements
|
||||||
|
* Reader must be nothrow constructible
|
||||||
|
* Reader is now constructed right before reading the body
|
||||||
|
- The message passed on construction is filled in
|
||||||
|
* Rework HTTP concepts:
|
||||||
|
- Writer uses write instead of operator()
|
||||||
|
- Refactor traits to use void_t
|
||||||
|
- Remove is_ReadableBody, is_WritableBody
|
||||||
|
- Add has_reader, has_writer, is_Reader, is_Writer
|
||||||
|
- More friendly compile errors on failed concept checks
|
||||||
|
* basic_parser_v1 requires all callbacks present
|
||||||
|
* on_headers parser callback now returns void
|
||||||
|
* on_body_what is a new required parser callback returning body_what
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b16
|
||||||
|
|
||||||
|
* Make value optional in param-list
|
||||||
|
* Frame processing routines are member functions
|
||||||
|
* Fix on_headers called twice from basic_parser_v1
|
||||||
|
* Constrain parser_v1 constructor
|
||||||
|
* Improve first line serialization
|
||||||
|
* Add pause option to on_headers interface
|
||||||
|
* Refactor base_parser_v1 callback traits:
|
||||||
|
* Refine Parser concept
|
||||||
|
* Relax ForwardIterator requirements in FieldSequence
|
||||||
|
* Fix websocket failure testing
|
||||||
|
* Refine Writer concept and fix exemplar in documentation
|
||||||
|
|
||||||
|
API Changes:
|
||||||
|
|
||||||
|
* Rename mask_buffer_size to write_buffer_size
|
||||||
|
* Make auto_fragment a boolean option
|
||||||
|
|
||||||
|
The message class hierarchy is refactored (breaking change):
|
||||||
|
|
||||||
|
* One message class now models both HTTP/1 and HTTP/2 messages
|
||||||
|
* message_v1, request_v1, response_v1 removed
|
||||||
|
* New classes basic_request and basic_response model
|
||||||
|
messages without the body.
|
||||||
|
|
||||||
|
Error resolution: Callers should use message, request,
|
||||||
|
and response instead of message_v1, request_v1, and
|
||||||
|
response_v1 respectively.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b15
|
||||||
|
|
||||||
|
* rfc7230 section 3.3.2 compliance
|
||||||
|
* Add HTTPS example
|
||||||
|
* Add Secure WebSocket example
|
||||||
|
* Fix message_v1 constructor
|
||||||
|
* Tidy up DynamicBuffer requirements
|
||||||
|
* Tidy up error types and headers
|
||||||
|
* Fix handling empty HTTP headers in parser_v1
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b14
|
||||||
|
|
||||||
|
* Add missing rebind to handler_alloc
|
||||||
|
* Fix error handling in http server examples
|
||||||
|
* Fix CMake scripts for MinGW
|
||||||
|
* Use BOOST_ASSERT
|
||||||
|
* Better WebSocket decorator
|
||||||
|
* Update and tidy documentation
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
1.0.0-b13
|
1.0.0-b13
|
||||||
|
|
||||||
* dstream improvements
|
* dstream improvements
|
||||||
|
|||||||
@@ -6,21 +6,51 @@ project (Beast)
|
|||||||
|
|
||||||
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
|
||||||
if (WIN32)
|
if (MSVC)
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4 /wd4100 /bigobj /D _WIN32_WINNT=0x0601 /D_SCL_SECURE_NO_WARNINGS=1 /D_CRT_SECURE_NO_WARNINGS=1")
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /MP /W4 /wd4100 /bigobj /D _WIN32_WINNT=0x0601 /D _SCL_SECURE_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
||||||
|
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||||
|
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /Oi /Ot /GL /MT")
|
||||||
|
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Oi /Ot /MT")
|
||||||
|
|
||||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
|
||||||
|
|
||||||
|
# for RelWithDebInfo builds, disable incremental linking
|
||||||
|
# since CMake sets it ON by default for that build type and it
|
||||||
|
# causes warnings
|
||||||
|
string (REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" replacement_flags
|
||||||
|
${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO})
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO ${replacement_flags})
|
||||||
|
|
||||||
else()
|
else()
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
set(Boost_USE_MULTITHREADED ON)
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
find_package(Boost REQUIRED COMPONENTS coroutine context thread filesystem program_options system)
|
find_package(Boost REQUIRED COMPONENTS coroutine context thread filesystem program_options system)
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||||
link_directories(${Boost_LIBRARY_DIR})
|
link_directories(${Boost_LIBRARY_DIR})
|
||||||
|
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS
|
set(CMAKE_CXX_FLAGS
|
||||||
"${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wpedantic")
|
"${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_definitions ("-DBOOST_COROUTINES_NO_DEPRECATION_WARNING")
|
||||||
|
|
||||||
|
if (APPLE AND NOT DEFINED ENV{OPENSSL_ROOT_DIR})
|
||||||
|
find_program(HOMEBREW brew)
|
||||||
|
if (NOT HOMEBREW STREQUAL "HOMEBREW-NOTFOUND")
|
||||||
|
execute_process(COMMAND brew --prefix openssl
|
||||||
|
OUTPUT_VARIABLE OPENSSL_ROOT_DIR
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(OpenSSL)
|
||||||
|
|
||||||
|
if (MINGW)
|
||||||
|
link_libraries(${Boost_LIBRARIES} ws2_32 mswsock)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if ("${VARIANT}" STREQUAL "coverage")
|
if ("${VARIANT}" STREQUAL "coverage")
|
||||||
@@ -53,7 +83,6 @@ function(DoGroupSources curdir rootdir folder)
|
|||||||
source_group("" FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
source_group("" FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
||||||
else()
|
else()
|
||||||
string(REGEX REPLACE ^${rootdir} ${folder} groupname ${curdir})
|
string(REGEX REPLACE ^${rootdir} ${folder} groupname ${curdir})
|
||||||
#set(groupname ${curdir})
|
|
||||||
string(REPLACE "/" "\\" groupname ${groupname})
|
string(REPLACE "/" "\\" groupname ${groupname})
|
||||||
source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
||||||
endif()
|
endif()
|
||||||
@@ -78,7 +107,14 @@ file(GLOB_RECURSE EXTRAS_INCLUDES
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory (examples)
|
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)
|
||||||
add_subdirectory (test/core)
|
add_subdirectory (test/core)
|
||||||
add_subdirectory (test/http)
|
add_subdirectory (test/http)
|
||||||
add_subdirectory (test/websocket)
|
add_subdirectory (test/websocket)
|
||||||
|
add_subdirectory (test/zlib)
|
||||||
|
|||||||
@@ -87,20 +87,20 @@ project beast
|
|||||||
<library>/boost/coroutine//boost_coroutine
|
<library>/boost/coroutine//boost_coroutine
|
||||||
<library>/boost/filesystem//boost_filesystem
|
<library>/boost/filesystem//boost_filesystem
|
||||||
<library>/boost/program_options//boost_program_options
|
<library>/boost/program_options//boost_program_options
|
||||||
# <library>ssl
|
|
||||||
# <library>crypto
|
|
||||||
<define>BOOST_ALL_NO_LIB=1
|
<define>BOOST_ALL_NO_LIB=1
|
||||||
<define>BOOST_SYSTEM_NO_DEPRECATED=1
|
|
||||||
<threading>multi
|
<threading>multi
|
||||||
<link>static
|
|
||||||
<runtime-link>shared
|
<runtime-link>shared
|
||||||
<debug-symbols>on
|
<debug-symbols>on
|
||||||
<toolset>gcc:<cxxflags>-std=c++11
|
<toolset>gcc:<cxxflags>-std=c++11
|
||||||
<toolset>gcc:<cxxflags>-Wno-unused-variable
|
<toolset>gcc:<cxxflags>-Wno-unused-parameter
|
||||||
<toolset>clang:<cxxflags>-std=c++11
|
<toolset>clang:<cxxflags>-std=c++11
|
||||||
|
<toolset>clang:<cxxflags>-Wno-unused-parameter
|
||||||
|
<toolset>gcc:<cxxflags>-Wno-unused-variable # Temporary until we can figure out -isystem
|
||||||
|
<toolset>clang:<cxxflags>-Wno-unused-variable # Temporary until we can figure out -isystem
|
||||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||||
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
||||||
<toolset>msvc:<cxxflags>-bigobj
|
<toolset>msvc:<cxxflags>"/wd4100 /bigobj"
|
||||||
|
<toolset>msvc,<variant>release:<cxxflags>"/Ob2 /Oi /Ot"
|
||||||
<os>LINUX:<define>_XOPEN_SOURCE=600
|
<os>LINUX:<define>_XOPEN_SOURCE=600
|
||||||
<os>LINUX:<define>_GNU_SOURCE=1
|
<os>LINUX:<define>_GNU_SOURCE=1
|
||||||
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
||||||
@@ -113,12 +113,7 @@ project beast
|
|||||||
<os>NT,<toolset>gcc:<library>ws2_32
|
<os>NT,<toolset>gcc:<library>ws2_32
|
||||||
<os>NT,<toolset>gcc:<library>mswsock
|
<os>NT,<toolset>gcc:<library>mswsock
|
||||||
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
|
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
|
||||||
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
|
|
||||||
<os>HPUX:<library>ipv6
|
|
||||||
<os>QNXNTO:<library>socket
|
|
||||||
<os>HAIKU:<library>network
|
|
||||||
: usage-requirements
|
: usage-requirements
|
||||||
<include>.
|
|
||||||
:
|
:
|
||||||
build-dir bin
|
build-dir bin
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -12,16 +12,15 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## CppCon 2016
|
## Beast at CppCon 2016
|
||||||
|
|
||||||
I will be giving a lightning talk on Beast at CppCon 2016 in Bellevue,
|
Presentation
|
||||||
Washington from September 18 to September 22. If you'd like to meet me
|
(slides: <a href="https://raw.githubusercontent.com/vinniefalco/Beast/master/doc/images/CppCon2016.pdf">CppCon2016.pdf</a>)
|
||||||
and hear the talk or ask questions about Beast feel free to approach
|
|
||||||
me in person or send me an email at vinnie.falco@gmail.com to schedule
|
|
||||||
some time.
|
|
||||||
|
|
||||||
About CppCon 2016:
|
<a href="https://www.youtube.com/watch?v=uJZgRcvPFwI">
|
||||||
http://cppcon.org
|
<img width="320" height = "180" alt = "Beast"
|
||||||
|
src="https://raw.githubusercontent.com/vinniefalco/Beast/master/doc/images/CppCon2016.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -96,7 +95,7 @@ using the `git subtree` or `git submodule` commands). Then, edit your
|
|||||||
build scripts to add the `include/` directory to the list of paths checked
|
build scripts to add the `include/` directory to the list of paths checked
|
||||||
by the C++ compiler when searching for includes. Beast `#include` lines
|
by the C++ compiler when searching for includes. Beast `#include` lines
|
||||||
will look like this:
|
will look like this:
|
||||||
```
|
```C++
|
||||||
#include <beast/http.hpp>
|
#include <beast/http.hpp>
|
||||||
#include <beast/websocket.hpp>
|
#include <beast/websocket.hpp>
|
||||||
```
|
```
|
||||||
@@ -137,6 +136,7 @@ The files in the repository are laid out thusly:
|
|||||||
./
|
./
|
||||||
bin/ Holds executables and project files
|
bin/ Holds executables and project files
|
||||||
bin64/ Holds 64-bit Windows executables and project files
|
bin64/ Holds 64-bit Windows executables and project files
|
||||||
|
doc/ Source code and scripts for the documentation
|
||||||
include/ Add this to your compiler includes
|
include/ Add this to your compiler includes
|
||||||
beast/
|
beast/
|
||||||
extras/ Additional APIs, may change
|
extras/ Additional APIs, may change
|
||||||
@@ -171,14 +171,14 @@ int main()
|
|||||||
// WebSocket connect and send message using beast
|
// WebSocket connect and send message using beast
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
ws.handshake(host, "/");
|
ws.handshake(host, "/");
|
||||||
ws.write(boost::asio::buffer("Hello, world!"));
|
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||||
|
|
||||||
// Receive WebSocket message, print and close using beast
|
// Receive WebSocket message, print and close using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
beast::websocket::opcode op;
|
beast::websocket::opcode op;
|
||||||
ws.read(op, sb);
|
ws.read(op, sb);
|
||||||
ws.close(beast::websocket::close_code::normal);
|
ws.close(beast::websocket::close_code::normal);
|
||||||
std::cout << to_string(sb.data()) << "\n";
|
std::cout << beast::to_string(sb.data()) << "\n";
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -186,6 +186,7 @@ Example HTTP program:
|
|||||||
```C++
|
```C++
|
||||||
#include <beast/http.hpp>
|
#include <beast/http.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -200,18 +201,19 @@ int main()
|
|||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
// Send HTTP request using beast
|
// Send HTTP request using beast
|
||||||
beast::http::request_v1<beast::http::empty_body> req;
|
beast::http::request<beast::http::empty_body> req;
|
||||||
req.method = "GET";
|
req.method = "GET";
|
||||||
req.url = "/";
|
req.url = "/";
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
req.fields.replace("Host", host + ":" +
|
||||||
req.headers.replace("User-Agent", "Beast");
|
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||||
|
req.fields.replace("User-Agent", "Beast");
|
||||||
beast::http::prepare(req);
|
beast::http::prepare(req);
|
||||||
beast::http::write(sock, req);
|
beast::http::write(sock, req);
|
||||||
|
|
||||||
// Receive and print HTTP response using beast
|
// Receive and print HTTP response using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
beast::http::response<beast::http::streambuf_body> resp;
|
||||||
beast::http::read(sock, sb, resp);
|
beast::http::read(sock, sb, resp);
|
||||||
std::cout << resp;
|
std::cout << resp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ Core:
|
|||||||
* Complete allocator testing in basic_streambuf
|
* Complete allocator testing in basic_streambuf
|
||||||
|
|
||||||
WebSocket:
|
WebSocket:
|
||||||
|
* Minimize sizeof(websocket::stream)
|
||||||
|
* Move check for message size limit to account for compression
|
||||||
* more invokable unit test coverage
|
* more invokable unit test coverage
|
||||||
* More control over the HTTP request and response during handshakes
|
* More control over the HTTP request and response during handshakes
|
||||||
* optimized versions of key/masking, choose prepared_key size
|
* optimized versions of key/masking, choose prepared_key size
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ using boostbook ;
|
|||||||
using quickbook ;
|
using quickbook ;
|
||||||
using doxygen ;
|
using doxygen ;
|
||||||
|
|
||||||
xml beast_boostbook : master.qbk ;
|
import quickbook ;
|
||||||
|
|
||||||
path-constant out : . ;
|
path-constant here : . ;
|
||||||
|
|
||||||
install stylesheets
|
install stylesheets
|
||||||
:
|
:
|
||||||
$(broot)/doc/src/boostbook.css
|
$(broot)/doc/src/boostbook.css
|
||||||
:
|
:
|
||||||
<location>$(out)/html
|
<location>$(here)/html
|
||||||
;
|
;
|
||||||
|
|
||||||
explicit stylesheets ;
|
explicit stylesheets ;
|
||||||
@@ -35,7 +35,7 @@ install images
|
|||||||
images/body.png
|
images/body.png
|
||||||
images/message.png
|
images/message.png
|
||||||
:
|
:
|
||||||
<location>$(out)/html/images
|
<location>$(here)/html/images
|
||||||
;
|
;
|
||||||
|
|
||||||
explicit images ;
|
explicit images ;
|
||||||
@@ -44,40 +44,54 @@ install callouts
|
|||||||
:
|
:
|
||||||
[ glob $(broot)/doc/src/images/callouts/*.png ]
|
[ glob $(broot)/doc/src/images/callouts/*.png ]
|
||||||
:
|
:
|
||||||
<location>$(out)/html/images/callouts
|
<location>$(here)/html/images/callouts
|
||||||
;
|
;
|
||||||
|
|
||||||
explicit callout ;
|
explicit callout ;
|
||||||
|
|
||||||
boostbook doc
|
install examples
|
||||||
:
|
:
|
||||||
beast_boostbook
|
[ glob
|
||||||
|
../examples/*.cpp
|
||||||
|
../examples/*.hpp
|
||||||
|
../examples/ssl/*.cpp
|
||||||
|
../examples/ssl/*.hpp
|
||||||
|
]
|
||||||
:
|
:
|
||||||
<xsl:param>chapter.autolabel=0
|
<location>$(here)/html/examples
|
||||||
<xsl:param>boost.image.src=images/beast.png
|
|
||||||
<xsl:param>boost.image.alt="Beast Logo"
|
|
||||||
<xsl:param>boost.image.w=2400
|
|
||||||
<xsl:param>boost.image.h=80
|
|
||||||
<xsl:param>boost.root=$(broot)
|
|
||||||
<xsl:param>chapter.autolabel=0
|
|
||||||
<xsl:param>chunk.first.sections=1 # Chunk the first top-level section?
|
|
||||||
<xsl:param>chunk.section.depth=8 # Depth to which sections should be chunked
|
|
||||||
<xsl:param>generate.section.toc.level=1 # Control depth of TOC generation in sections
|
|
||||||
<xsl:param>toc.max.depth=2 # How many levels should be created for each TOC?
|
|
||||||
<xsl:param>toc.section.depth=2 # How deep should recursive sections appear in the TOC?
|
|
||||||
:
|
|
||||||
<location>temp
|
|
||||||
<dependency>stylesheets
|
|
||||||
<dependency>images
|
|
||||||
;
|
;
|
||||||
|
|
||||||
#explicit doc ;
|
explicit examples ;
|
||||||
# <xsl:param>nav.layout=none
|
|
||||||
# <format>html:<xsl:param>location=../bin/doc/html
|
|
||||||
# <xsl:param>generate.toc="chapter nop section nop"
|
|
||||||
# <xsl:param>root.filename=index
|
|
||||||
# <xsl:param>output-root="../bin/html"
|
|
||||||
|
|
||||||
|
xml doc
|
||||||
|
:
|
||||||
|
master.qbk
|
||||||
|
:
|
||||||
|
<location>temp
|
||||||
|
<include>$(broot)/tools/boostbook/dtd
|
||||||
|
;
|
||||||
|
|
||||||
|
boostbook boostdoc
|
||||||
|
:
|
||||||
|
doc
|
||||||
|
:
|
||||||
|
<xsl:param>boost.root=$(broot)
|
||||||
|
<xsl:param>boost.image.src=images/beast.png
|
||||||
|
<xsl:param>boost.image.alt="Beast Logo"
|
||||||
|
<xsl:param>boost.image.w=1330
|
||||||
|
<xsl:param>boost.image.h=80
|
||||||
|
<xsl:param>chapter.autolabel=0
|
||||||
|
<xsl:param>chunk.section.depth=8 # Depth to which sections should be chunked
|
||||||
|
<xsl:param>chunk.first.sections=1 # Chunk the first top-level section?
|
||||||
|
<xsl:param>toc.section.depth=8 # How deep should recursive sections appear in the TOC?
|
||||||
|
<xsl:param>toc.max.depth=8 # How many levels should be created for each TOC?
|
||||||
|
<xsl:param>generate.section.toc.level=8 # Control depth of TOC generation in sections
|
||||||
|
<xsl:param>generate.toc="chapter nop section nop"
|
||||||
|
<include>$(broot)/tools/boostbook/dtd
|
||||||
|
:
|
||||||
|
<location>temp
|
||||||
|
<dependency>examples
|
||||||
|
<dependency>images
|
||||||
|
<dependency>stylesheets
|
||||||
|
;
|
||||||
|
|
||||||
#[include reference.qbk]
|
|
||||||
#[xinclude index.xml]
|
|
||||||
@@ -5,44 +5,52 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:design Design choices]
|
[section:design Design Choices]
|
||||||
|
|
||||||
|
[block '''
|
||||||
|
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||||
|
<member><link linkend="beast.design.http">HTTP FAQ</link></member>
|
||||||
|
<member><link linkend="beast.design.websocket">WebSocket FAQ</link></member>
|
||||||
|
<member><link linkend="beast.design.websocketpp">Comparison to Zaphoyd Studios WebSocket++</link></member>
|
||||||
|
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||||
|
''']
|
||||||
|
|
||||||
The implementations are driven by business needs of cryptocurrency server
|
The implementations are driven by business needs of cryptocurrency server
|
||||||
applications (e.g. [@https://ripple.com Ripple]) written in C++. These
|
applications (e.g. [@https://ripple.com Ripple]) written in C++. These
|
||||||
needs were not met by existing solutions so Beast was written from scratch
|
needs were not met by existing solutions so Beast was written from scratch
|
||||||
as a solution. Beast's design philosophy avoid flaws exhibited by other
|
as a solution. Beast's design philosophy avoids flaws exhibited by other
|
||||||
libraries:
|
libraries:
|
||||||
|
|
||||||
|
* Don't try to do too much.
|
||||||
|
|
||||||
* Don't sacrifice performance.
|
* Don't sacrifice performance.
|
||||||
|
|
||||||
* Don't do too much, otherwise interfaces become rigid.
|
* Mimic Boost.Asio; familiarity breeds confidence.
|
||||||
|
|
||||||
* Symmetric interfaces (client and server the same, or close to it).
|
* Role-symmetric interfaces; client and server the same (or close to it).
|
||||||
|
|
||||||
* Emulate Boost.Asio interfaces as much as possible, since Asio is
|
* Leave important decisions to the user, such as allocating memory or
|
||||||
proven and it is familiar to users.
|
managing flow control.
|
||||||
|
|
||||||
* Let library users make the important decisions such as how to
|
Beast uses the __DynamicBuffer__ concept presented in the Networking TS
|
||||||
allocate memory or how to leverage flow control.
|
(__N4588__), and relies heavily on the Boost.Asio __ConstBufferSequence__
|
||||||
|
and __MutableBufferSequence__ concepts for passing buffers to functions.
|
||||||
Beast uses the [link beast.types.DynamicBuffer [*`DynamicBuffer`]] concept
|
The authors have found the dynamic buffer and buffer sequence interfaces to
|
||||||
presented in the Netwoking TS, and relies heavily on the Boost.Asio
|
be optimal for interacting with Asio, and for other tasks such as incremental
|
||||||
[*`ConstBufferSequence`] and [*`MutableBufferSequence`] concepts for passing
|
parsing of data in buffers (for example, parsing websocket frames stored
|
||||||
buffers to functions. The authors have found the dynamic buffer and buffer
|
in a [link beast.ref.static_streambuf `static_streambuf`]).
|
||||||
sequence interfaces to be optimal for interacting with Asio, and for other
|
|
||||||
tasks such as incremental parsing of data in buffers (for example, parsing
|
|
||||||
websocket frames stored in a [link beast.ref.static_streambuf `static_streambuf`]).
|
|
||||||
|
|
||||||
During the development of Beast the authors have studied other software
|
During the development of Beast the authors have studied other software
|
||||||
packages and in particular the comments left during the Boost Review process
|
packages and in particular the comments left during the Boost Review process
|
||||||
of other packages offering similar functionality. In this section we attempt
|
of other packages offering similar functionality. In this section and the
|
||||||
to address those issues.
|
FAQs that follow we attempt to answer those questions that are also applicable
|
||||||
|
to Beast.
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
[[
|
[[
|
||||||
"I would also like to see instances of this library being used
|
"I would also like to see instances of this library being used
|
||||||
in production. That would give some evidence that the design
|
in production. That would give some evidence that the design
|
||||||
works in practice.""
|
works in practice."
|
||||||
][
|
][
|
||||||
Beast.HTTP and Beast.WebSocket are production ready and currently
|
Beast.HTTP and Beast.WebSocket are production ready and currently
|
||||||
running on public servers receiving traffic and handling millions of
|
running on public servers receiving traffic and handling millions of
|
||||||
@@ -56,25 +64,26 @@ to address those issues.
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[section:http HTTP]
|
|
||||||
|
|
||||||
For HTTP we to model the message to maximize flexibility of implementation
|
[section:http HTTP FAQ]
|
||||||
|
|
||||||
|
For HTTP we model the message to maximize flexibility of implementation
|
||||||
strategies while allowing familiar verbs such as [*`read`] and [*`write`].
|
strategies while allowing familiar verbs such as [*`read`] and [*`write`].
|
||||||
The HTTP interface is further driven by the needs of the WebSocket module,
|
The HTTP interface is further driven by the needs of the WebSocket module,
|
||||||
as a WebSocket session requires a HTTP Upgrade handshake exchange at the
|
as a WebSocket session requires a HTTP Upgrade handshake exchange at the
|
||||||
start. Other design goals:
|
start. Other design goals:
|
||||||
|
|
||||||
* Don't try to invent a complete web server or client
|
* Keep it simple.
|
||||||
|
|
||||||
* Have simple free functions to send and receive messages.
|
* Stay low level; don't invent a whole web server or client.
|
||||||
|
|
||||||
* Allow the message object to be customized,
|
* Allow for customizations, if the user needs it.
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
[[
|
[[
|
||||||
"Some more advanced examples, e.g. including TLS with client/server
|
"Some more advanced examples, e.g. including TLS with client/server
|
||||||
certificates would help.""
|
certificates would help."
|
||||||
][
|
][
|
||||||
The HTTP interface doesn't try to reinvent the wheel, it just uses
|
The HTTP interface doesn't try to reinvent the wheel, it just uses
|
||||||
the `boost::asio::ip::tcp::socket` or `boost::asio::ssl::stream` that
|
the `boost::asio::ip::tcp::socket` or `boost::asio::ssl::stream` that
|
||||||
@@ -94,7 +103,7 @@ start. Other design goals:
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
[[
|
[[
|
||||||
"Cookies? Forms/File Uploads?""
|
"Cookies? Forms/File Uploads?"
|
||||||
][
|
][
|
||||||
Cookies, or managing these types of HTTP headers in general, is the
|
Cookies, or managing these types of HTTP headers in general, is the
|
||||||
responsibility of higher levels. Beast.HTTP just tries to get complete
|
responsibility of higher levels. Beast.HTTP just tries to get complete
|
||||||
@@ -107,7 +116,7 @@ start. Other design goals:
|
|||||||
|
|
||||||
[[
|
[[
|
||||||
"...supporting TLS (is this a feature? If not this would be a show-stopper),
|
"...supporting TLS (is this a feature? If not this would be a show-stopper),
|
||||||
etc.
|
etc."
|
||||||
][
|
][
|
||||||
Beast.HTTP does not provide direct facilities for implementing TLS
|
Beast.HTTP does not provide direct facilities for implementing TLS
|
||||||
connections; however, the interfaces already existing on the
|
connections; however, the interfaces already existing on the
|
||||||
@@ -126,17 +135,24 @@ start. Other design goals:
|
|||||||
over Asio. Such an implementation should serve as a building block upon
|
over Asio. Such an implementation should serve as a building block upon
|
||||||
which higher abstractions such as the aforementioned HTTP service or
|
which higher abstractions such as the aforementioned HTTP service or
|
||||||
cgi-gateway can be built.
|
cgi-gateway can be built.
|
||||||
|
|
||||||
|
One of the example programs implements a simple HTTP server that
|
||||||
|
delivers files from the filesystem.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
[[
|
[[
|
||||||
"You should send a 100-continue to ask for the rest of the body if required."
|
"You should send a 100-continue to ask for the rest of the body if required."
|
||||||
][
|
][
|
||||||
These behaviors are best left to the calling software. A future library
|
The Beast interface needs to support this functionality (by allowing this
|
||||||
can build on Beast.HTTP to provide these behaviors.
|
special case of partial message parsing and serialization). Specifically,
|
||||||
|
it should let callers read the request up to just before the body,
|
||||||
|
and let callers write the request up to just before the body. However,
|
||||||
|
making use of this behavior should be up to callers (since Beast is low
|
||||||
|
level).
|
||||||
]]
|
]]
|
||||||
|
|
||||||
[[
|
[[
|
||||||
"What about HTTP/2?""
|
"What about HTTP/2?"
|
||||||
][
|
][
|
||||||
Many reviewers feel that HTTP/2 support is an essential feature of
|
Many reviewers feel that HTTP/2 support is an essential feature of
|
||||||
a HTTP library. The authors agree that HTTP/2 is important but also
|
a HTTP library. The authors agree that HTTP/2 is important but also
|
||||||
@@ -145,13 +161,13 @@ start. Other design goals:
|
|||||||
and 1.1.
|
and 1.1.
|
||||||
|
|
||||||
The Beast.HTTP message model is suitable for HTTP/2 and can be re-used.
|
The Beast.HTTP message model is suitable for HTTP/2 and can be re-used.
|
||||||
The IEFT HTTP Working Group adopted message compatiblity with HTTP/1.x
|
The IETF HTTP Working Group adopted message compatiblity with HTTP/1.x
|
||||||
as an explicit goal. A parser can simply emit full headers after
|
as an explicit goal. A parser can simply emit full headers after
|
||||||
decoding the compressed HTTP/2 headers. The stream ID is not logicaly
|
decoding the compressed HTTP/2 headers. The stream ID is not logically
|
||||||
part of the message but rather message metadata and should be
|
part of the message but rather message metadata and should be
|
||||||
communicated out-of-band (see below). HTTP/2 sessions begin with a
|
communicated out-of-band (see below). HTTP/2 sessions begin with a
|
||||||
traditional HTTP/1.1 Upgrade similar in fashion to the WebSocket
|
traditional HTTP/1.1 Upgrade similar in fashion to the WebSocket
|
||||||
upgrade. A HTTP/2 implementation can use existing Beast.HTTP primitives
|
upgrade. An HTTP/2 implementation can use existing Beast.HTTP primitives
|
||||||
to perform this handshake.
|
to perform this handshake.
|
||||||
|
|
||||||
Free functions for HTTP/2 sessions are not possible because of the
|
Free functions for HTTP/2 sessions are not possible because of the
|
||||||
@@ -167,10 +183,55 @@ start. Other design goals:
|
|||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[section:websocket WebSocket FAQ]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[
|
||||||
|
What about message compression?
|
||||||
|
][
|
||||||
|
The author is currently porting ZLib 1.2.8 to modern, header-only C++11
|
||||||
|
that does not use macros or try to support ancient architectures. This
|
||||||
|
deflate implementation will be available as its own individually
|
||||||
|
usable interface, and also will be used to power Beast WebSocket's
|
||||||
|
permessage-deflate implementation, due Q1 of 2017.
|
||||||
|
|
||||||
|
However, Beast currently has sufficient functionality that users can
|
||||||
|
begin taking advantage of the WebSocket protocol using this library
|
||||||
|
immediately.
|
||||||
|
]]
|
||||||
|
|
||||||
|
[[
|
||||||
|
Where is the TLS/SSL interface?
|
||||||
|
][
|
||||||
|
The `websocket::stream` wraps the socket or stream that you provide
|
||||||
|
(for example, a `boost::asio::ip::tcp::socket` or a
|
||||||
|
`boost::asio::ssl::stream`). You establish your TLS connection using the
|
||||||
|
interface on `ssl::stream` like shown in all of the Asio examples, then
|
||||||
|
construct your `websocket::stream` around it. It works perfectly fine;
|
||||||
|
Beast.WebSocket doesn't try to reinvent the wheel or put a fresh coat of
|
||||||
|
interface paint on the `ssl::stream`.
|
||||||
|
|
||||||
|
The WebSocket implementation [*does] provide support for shutting down
|
||||||
|
the TLS connection through the use of the ADL compile-time virtual functions
|
||||||
|
[link beast.ref.websocket__teardown `teardown`] and
|
||||||
|
[link beast.ref.websocket__async_teardown `async_teardown`]. These will
|
||||||
|
properly close the connection as per rfc6455 and overloads are available
|
||||||
|
for TLS streams. Callers may provide their own overloads of these functions
|
||||||
|
for user-defined next layer types.
|
||||||
|
]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section:websocket WebSocket]
|
|
||||||
|
|
||||||
|
[section:websocketpp Comparison to Zaphoyd Studios WebSocket++]
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
@@ -208,21 +269,19 @@ start. Other design goals:
|
|||||||
To get an idea of the complexity involved with implementing a transport,
|
To get an idea of the complexity involved with implementing a transport,
|
||||||
compare the asio transport to the
|
compare the asio transport to the
|
||||||
[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport]
|
[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport]
|
||||||
(a layer that allows websocket communication over a std iostream).
|
(a layer that allows websocket communication over a `std::iostream`).
|
||||||
|
|
||||||
In contrast, Beast abstracts the transport by defining just one [*`NextLayer`]
|
In contrast, Beast abstracts the transport by defining just one [*`NextLayer`]
|
||||||
template argument The type requirements for [*`NextLayer`] are
|
template argument The type requirements for [*`NextLayer`] are
|
||||||
already familiar to users as they are documented in Asio:
|
already familiar to users as they are documented in Asio:
|
||||||
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html SyncReadStream],
|
__AsyncReadStream__, __AsyncWriteStream__, __SyncReadStream__, __SyncWriteStream__.
|
||||||
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html SyncWriteStream],
|
|
||||||
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html AsyncReadStream], and
|
|
||||||
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html AsyncWriteStream].
|
|
||||||
The type requirements for instantiating `beast::websocket::stream` versus
|
The type requirements for instantiating `beast::websocket::stream` versus
|
||||||
`websocketpp::connection` with user defined types are vastly reduced
|
`websocketpp::connection` with user defined types are vastly reduced
|
||||||
(18 functions versus 2). Note that websocketpp connections are passed by
|
(18 functions versus 2). Note that websocketpp connections are passed by
|
||||||
`shared_ptr`. Beast does not use `shared_ptr` anywhere in its public interface.
|
`shared_ptr`. Beast does not use `shared_ptr` anywhere in its public interface.
|
||||||
A `beast::websocket::stream` is constructible and movable in a manner identical
|
A `beast::websocket::stream` is constructible and movable in a manner identical
|
||||||
`to a boost::asio::ip::tcp::socket`. Callers can put such objects in a
|
to a `boost::asio::ip::tcp::socket`. Callers can put such objects in a
|
||||||
`shared_ptr` if they want to, but there is no requirement to do so.
|
`shared_ptr` if they want to, but there is no requirement to do so.
|
||||||
|
|
||||||
[table
|
[table
|
||||||
@@ -283,8 +342,7 @@ start. Other design goals:
|
|||||||
implementation. Instead, it follows the Asio pattern. Calls to
|
implementation. Instead, it follows the Asio pattern. Calls to
|
||||||
asynchronous initiation functions use the same method to invoke
|
asynchronous initiation functions use the same method to invoke
|
||||||
intermediate handlers as the method used to invoke the final handler,
|
intermediate handlers as the method used to invoke the final handler,
|
||||||
through the
|
through the __asio_handler_invoke__ mechanism.
|
||||||
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/asio_handler_invoke.html asio_handler_invoke] mechanism.
|
|
||||||
|
|
||||||
The only requirement in Beast is that calls to asynchronous initiation
|
The only requirement in Beast is that calls to asynchronous initiation
|
||||||
functions are made from the same implicit or explicit strand. For
|
functions are made from the same implicit or explicit strand. For
|
||||||
@@ -314,7 +372,7 @@ start. Other design goals:
|
|||||||
|
|
||||||
websocketpp requires a one-time call to set the handler for each event
|
websocketpp requires a one-time call to set the handler for each event
|
||||||
in its interface (for example, upon message receipt). The handler is
|
in its interface (for example, upon message receipt). The handler is
|
||||||
represented by a `std::function equivalent`. Its important to recognize
|
represented by a `std::function` equivalent. Its important to recognize
|
||||||
that the websocketpp interface performs type-erasure on this handler.
|
that the websocketpp interface performs type-erasure on this handler.
|
||||||
|
|
||||||
In comparison, Beast handlers are specified in a manner identical to
|
In comparison, Beast handlers are specified in a manner identical to
|
||||||
@@ -378,29 +436,27 @@ start. Other design goals:
|
|||||||
|
|
||||||
websocketpp defines a message buffer, passed in arguments by
|
websocketpp defines a message buffer, passed in arguments by
|
||||||
`shared_ptr`, and an associated message manager which permits
|
`shared_ptr`, and an associated message manager which permits
|
||||||
aggregation and memory reuse of memory. The implementation of
|
aggregation and reuse of memory. The implementation of
|
||||||
`websocketpp::message` uses a `std::string` to hold the payload. If an
|
`websocketpp::message` uses a `std::string` to hold the payload. If an
|
||||||
incoming message is broken up into multiple frames, the string may be
|
incoming message is broken up into multiple frames, the string may be
|
||||||
reallocated for each continuation frame. The std::string always uses
|
reallocated for each continuation frame. The `std::string` always uses
|
||||||
the standard allocator, it is not possible to customize the choice of
|
the standard allocator, it is not possible to customize the choice of
|
||||||
allocator.
|
allocator.
|
||||||
|
|
||||||
Beast allows callers to specify the object for receiving the message
|
Beast allows callers to specify the object for receiving the message
|
||||||
or frame data, which is of any type meeting the requirements of
|
or frame data, which is of any type meeting the requirements of
|
||||||
[@http://vinniefalco.github.io/beast/beast/types/DynamicBuffer.html [*DynamicBuffer]]
|
__DynamicBuffer__ (modeled after `boost::asio::streambuf`).
|
||||||
(modeled after `boost::asio::streambuf`).
|
|
||||||
|
|
||||||
Beast comes with the class `beast::basic_streambuf`, an efficient
|
Beast comes with the class __basic_streambuf__, an efficient
|
||||||
implementation of the [*DynamicBuffer] concept which makes use of multiple
|
implementation of the __DynamicBuffer__ concept which makes use of multiple
|
||||||
allocated octet arrays. If an incoming message is broken up into
|
allocated octet arrays. If an incoming message is broken up into
|
||||||
multiple pieces, no reallocation occurs. Instead, new allocations are
|
multiple pieces, no reallocation occurs. Instead, new allocations are
|
||||||
appended to the sequence when existing allocations are filled. Beast
|
appended to the sequence when existing allocations are filled. Beast
|
||||||
does not impose any particular memory management model on callers. The
|
does not impose any particular memory management model on callers. The
|
||||||
`basic_streambuf` provided by beast supports standard allocators through
|
__basic_streambuf__ provided by beast supports standard allocators through
|
||||||
a template argument. Use the [*DynamicBuffer] that comes with beast,
|
a template argument. Use the __DynamicBuffer__ that comes with beast,
|
||||||
customize the allocator if you desire, or provide your own type that
|
customize the allocator if you desire, or provide your own type that
|
||||||
meets the
|
meets the requirements.
|
||||||
[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/basic_streambuf.hpp#L21 concept requirements].
|
|
||||||
|
|
||||||
[table
|
[table
|
||||||
[
|
[
|
||||||
@@ -596,44 +652,8 @@ start. Other design goals:
|
|||||||
]
|
]
|
||||||
]]
|
]]
|
||||||
|
|
||||||
[[
|
|
||||||
What about message compression?
|
|
||||||
][
|
|
||||||
The author is currently porting ZLib 1.2.8 to modern, header-only C++11
|
|
||||||
that does not use macros or try to support ancient architectures. This
|
|
||||||
deflate implementation will be available as its own individually
|
|
||||||
usable interface, and also will be used to power Beast WebSocket's
|
|
||||||
permessage-deflate implementation, due Q4 of 2016.
|
|
||||||
|
|
||||||
However, Beast currently has sufficient functionality that users can
|
|
||||||
begin taking advantage of the WebSocket protocol using this library
|
|
||||||
immediately.
|
|
||||||
]]
|
|
||||||
|
|
||||||
[[
|
|
||||||
Where is the TLS/SSL interface?
|
|
||||||
][
|
|
||||||
The `websocket::stream` wraps the socket or stream that you provide
|
|
||||||
(for example, a `boost::asio::ip::tcp::socket` or a
|
|
||||||
`boost::asio::ssl::stream`). You establish your TLS connection using the
|
|
||||||
interface on `ssl::stream` like shown in all of the Asio examples, they
|
|
||||||
construct your `websocket::stream` around it. It works perfectly fine;
|
|
||||||
Beast.WebSocket doesn't try to reinvent the wheel or put a fresh coat of
|
|
||||||
interface paint on the `ssl::stream`.
|
|
||||||
|
|
||||||
The WebSocket implementation [*does] provides support for shutting down
|
|
||||||
the TLS connection through the use of the ADL compile-time virtual functions
|
|
||||||
[link beast.ref.websocket__teardown `teardown`] and
|
|
||||||
[link beast.ref.websocket__async_teardown `async_teardown`]. These will
|
|
||||||
properly close the connection as per rfc6455 and overloads are available
|
|
||||||
for TLS streams. Callers may provide their own overloads of these functions
|
|
||||||
for user-defined next layer types.
|
|
||||||
]]
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|||||||
127
src/beast/doc/examples.qbk
Normal file
127
src/beast/doc/examples.qbk
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
[/
|
||||||
|
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)
|
||||||
|
]
|
||||||
|
|
||||||
|
[section:example Examples]
|
||||||
|
|
||||||
|
These usage examples are intended to quickly impress upon readers the
|
||||||
|
flavor of the library. They are complete programs which may be built
|
||||||
|
and run. Source code and build scripts for these programs may be found
|
||||||
|
in the examples directory.
|
||||||
|
|
||||||
|
[heading HTTP GET]
|
||||||
|
|
||||||
|
Use HTTP to request the root page from a website and print the response:
|
||||||
|
|
||||||
|
```
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Normal boost::asio setup
|
||||||
|
std::string const host = "boost.org";
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
|
boost::asio::connect(sock,
|
||||||
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
|
// Send HTTP request using beast
|
||||||
|
beast::http::request<beast::http::empty_body> req;
|
||||||
|
req.method = "GET";
|
||||||
|
req.url = "/";
|
||||||
|
req.version = 11;
|
||||||
|
req.fields.replace("Host", host + ":" +
|
||||||
|
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||||
|
req.fields.replace("User-Agent", "Beast");
|
||||||
|
beast::http::prepare(req);
|
||||||
|
beast::http::write(sock, req);
|
||||||
|
|
||||||
|
// Receive and print HTTP response using beast
|
||||||
|
beast::streambuf sb;
|
||||||
|
beast::http::response<beast::http::streambuf_body> resp;
|
||||||
|
beast::http::read(sock, sb, resp);
|
||||||
|
std::cout << resp;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
[heading WebSocket]
|
||||||
|
|
||||||
|
Establish a WebSocket connection, send a message and receive the reply:
|
||||||
|
```
|
||||||
|
#include <beast/core/to_string.hpp>
|
||||||
|
#include <beast/websocket.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Normal boost::asio setup
|
||||||
|
std::string const host = "echo.websocket.org";
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
|
boost::asio::connect(sock,
|
||||||
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||||
|
|
||||||
|
// WebSocket connect and send message using beast
|
||||||
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
|
ws.handshake(host, "/");
|
||||||
|
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||||
|
|
||||||
|
// Receive WebSocket message, print and close using beast
|
||||||
|
beast::streambuf sb;
|
||||||
|
beast::websocket::opcode op;
|
||||||
|
ws.read(op, sb);
|
||||||
|
ws.close(beast::websocket::close_code::normal);
|
||||||
|
std::cout << beast::to_string(sb.data()) << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[heading Secure WebSocket]
|
||||||
|
|
||||||
|
Establish a WebSocket connection over an encrypted TLS connection,
|
||||||
|
send a message and receive the reply. Requires OpenSSL to build.
|
||||||
|
|
||||||
|
* [@examples/websocket_ssl_example.cpp]
|
||||||
|
|
||||||
|
[heading HTTPS GET]
|
||||||
|
|
||||||
|
This example demonstrates sending and receiving HTTP messages
|
||||||
|
over a TLS connection. Requires OpenSSL to build.
|
||||||
|
|
||||||
|
* [@examples/http_ssl_example.cpp]
|
||||||
|
|
||||||
|
[heading HTTP Crawl]
|
||||||
|
|
||||||
|
This example retrieves the page at each of the most popular domains
|
||||||
|
as measured by Alexa.
|
||||||
|
|
||||||
|
* [@examples/http_crawl.cpp]
|
||||||
|
|
||||||
|
[heading HTTP Server]
|
||||||
|
|
||||||
|
This example demonstrates both synchronous and asynchronous server
|
||||||
|
implementations. It also provides an example of implementing a [*Body]
|
||||||
|
type, in `file_body`.
|
||||||
|
|
||||||
|
* [@examples/file_body.hpp]
|
||||||
|
* [@examples/http_async_server.hpp]
|
||||||
|
* [@examples/http_sync_server.hpp]
|
||||||
|
* [@examples/http_server.cpp]
|
||||||
|
|
||||||
|
[heading Listings]
|
||||||
|
|
||||||
|
These are stand-alone listings of the HTTP and WebSocket examples.
|
||||||
|
|
||||||
|
* [@examples/http_example.cpp]
|
||||||
|
* [@examples/websocket_example.cpp]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
@@ -5,138 +5,203 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:http HTTP]
|
[/
|
||||||
|
ideas:
|
||||||
|
- complete send request walkthrough (client)
|
||||||
|
- complete receive response walkthrough (client)
|
||||||
|
- complete receive request walkthrough (server)
|
||||||
|
- complete send response walkthrough (server)
|
||||||
|
|
||||||
Beast.HTTP offers programmers simple and performant models of HTTP messages and
|
- Introduce concepts from simple to complex
|
||||||
|
- Smooth progression of new ideas building on the previous ideas
|
||||||
|
|
||||||
|
- do we show a simplified message with collapsed fields?
|
||||||
|
- do we introduce `header` or `message` first?
|
||||||
|
|
||||||
|
|
||||||
|
contents:
|
||||||
|
Message (and header, fields)
|
||||||
|
Create request
|
||||||
|
Create response
|
||||||
|
Algorithms
|
||||||
|
Write
|
||||||
|
Read
|
||||||
|
Parse
|
||||||
|
Examples
|
||||||
|
Send Request
|
||||||
|
Receive Response
|
||||||
|
Receive Request
|
||||||
|
Send Response
|
||||||
|
Advanced
|
||||||
|
Responding to HEAD
|
||||||
|
Expect: 100-continue
|
||||||
|
Body (user defined)
|
||||||
|
|
||||||
|
|
||||||
|
section beast.http.examples Examples
|
||||||
|
|
||||||
|
note
|
||||||
|
In the example code which follows, `socket` refers to an object of type
|
||||||
|
`boost::asio::ip::tcp::socket` which is currently connected to a remote peer.
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[section:http Using HTTP]
|
||||||
|
|
||||||
|
[block '''
|
||||||
|
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||||
|
<member><link linkend="beast.http.message">Message</link></member>
|
||||||
|
<member><link linkend="beast.http.fields">Fields</link></member>
|
||||||
|
<member><link linkend="beast.http.body">Body</link></member>
|
||||||
|
<member><link linkend="beast.http.algorithms">Algorithms</link></member>
|
||||||
|
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||||
|
''']
|
||||||
|
|
||||||
|
Beast offers programmers simple and performant models of HTTP messages and
|
||||||
their associated operations including synchronous and asynchronous reading and
|
their associated operations including synchronous and asynchronous reading and
|
||||||
writing of messages in the HTTP/1 wire format using Boost.Asio.
|
writing of messages and headers in the HTTP/1 wire format using Boost.Asio.
|
||||||
|
|
||||||
The HTTP protocol is described fully in
|
|
||||||
[@https://tools.ietf.org/html/rfc7230 rfc7230]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:motivation Motivation]
|
|
||||||
|
|
||||||
The HTTP protocol is pervasive in network applications. As C++ is a logical
|
|
||||||
choice for high performance network servers, there is great utility in solid
|
|
||||||
building blocks for manipulating, sending, and receiving HTTP messages
|
|
||||||
compliant with the Hypertext Transfer Protocol and the supplements that
|
|
||||||
follow. Unfortunately reliable implementations or industry standards do not
|
|
||||||
exist in C++.
|
|
||||||
|
|
||||||
Beast.HTTP is built on Boost.Asio and uses its own robust header-only HTTP/1
|
|
||||||
message parser modeled after the nodejs http-parser (written in C). A proposal
|
|
||||||
to add networking functionality to the C++ standard library, based on
|
|
||||||
Boost.Asio, is under consideration by the standards committee. Since the final
|
|
||||||
approved networking interface for the C++ standard library will likely closely
|
|
||||||
resemble the current interface of Boost.Asio, it is logical for Beast.HTTP to
|
|
||||||
use Boost.Asio as its network transport.
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:scope Scope]
|
|
||||||
|
|
||||||
This library is designed to be a building block for creating higher level
|
|
||||||
libraries. It is not designed to be end-user facing. There is no convenient
|
|
||||||
class that implements the core of a web server, nor is there a convenient
|
|
||||||
class to quickly perform common operations such as fetching a file or
|
|
||||||
connecting and retrieving a document from a secure connection. These
|
|
||||||
use-cases are important, but this library does not try to do that. Instead,
|
|
||||||
it offers primitives that can be used to build those user-facing algorithms.
|
|
||||||
|
|
||||||
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. `http::message` models both requests and responses.
|
|
||||||
Beast aims to offer this functionality:
|
|
||||||
|
|
||||||
* [*Model]: Provide a universal HTTP message class model.
|
|
||||||
|
|
||||||
* [*Build]: Construct a new message and manipulate its contents.
|
|
||||||
|
|
||||||
* [*Parse]: Deserialize a message from a network or memory stream in HTTP/1 wire format.
|
|
||||||
|
|
||||||
* [*Serialize]: Serialize a message into a network or memory stream in HTTP/1 wire format.
|
|
||||||
|
|
||||||
[note The documentation which follows assumes familiarity with
|
|
||||||
both Boost.Asio and the HTTP protocol specification described in
|
|
||||||
[@https://tools.ietf.org/html/rfc7230 rfc7230] ]
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:usage Usage]
|
|
||||||
|
|
||||||
[note
|
[note
|
||||||
Sample code and identifiers mentioned in this section are written
|
The following documentation assumes familiarity with both Boost.Asio
|
||||||
as if the following declarations are in effect:
|
and the HTTP protocol specification described in __rfc7230__. Sample code
|
||||||
|
and identifiers mentioned in this section are written as if the following
|
||||||
|
declarations are in effect:
|
||||||
```
|
```
|
||||||
|
#include <beast/core.hpp>
|
||||||
#include <beast/http.hpp>
|
#include <beast/http.hpp>
|
||||||
using namespace beast;
|
using namespace beast;
|
||||||
|
using namespace beast::http;
|
||||||
```
|
```
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In the paragraphs that follow we describe the available interfaces for
|
|
||||||
performing typical operations such as interacting with a HTTP server
|
|
||||||
or handling simple requests. Subsequent sections cover the message model
|
|
||||||
and its customization points in more depth, for advanced applications.
|
|
||||||
|
|
||||||
[heading Declarations]
|
|
||||||
|
|
||||||
To do anything, a message must be declared. The message class template
|
[section:message Message]
|
||||||
requires at minimum, a value indicating whether the message is a request
|
|
||||||
(versus a response), and a `Body` type. The choice of `Body` determines the
|
The HTTP protocol defines the client and server roles: clients send messages
|
||||||
kind of container used to represent the message body. Here we will
|
called requests and servers send back messages called responses. A HTTP message
|
||||||
declare a HTTP/1 request that has a `std::string` for the body container:
|
(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:
|
||||||
```
|
```
|
||||||
http::message_v1<true, http::string_body> req;
|
using request_header = header<true, fields>;
|
||||||
|
using response_header = header<false, fields>;
|
||||||
|
|
||||||
|
template<class Body, class Fields = fields>
|
||||||
|
using request = message<true, Body, Fields>;
|
||||||
|
|
||||||
|
template<class Body, class Fields = fields>
|
||||||
|
using response = message<false, Body, Fields>;
|
||||||
```
|
```
|
||||||
|
|
||||||
Two type aliases are provided for notational convenience when declaring
|
The code examples below show how to create and fill in a request and response
|
||||||
HTTP/1 messages. These two statements declare a request and a response
|
object:
|
||||||
respectively:
|
|
||||||
```
|
|
||||||
http::request_v1<http::string_body> req;
|
|
||||||
http::response_v1<http::string_body> resp;
|
|
||||||
```
|
|
||||||
|
|
||||||
[heading Members]
|
[table Create Message
|
||||||
|
[[HTTP Request] [HTTP Response]]
|
||||||
Message objects are default constructible, with public access to data members.
|
[[
|
||||||
Request and response objects have some common members, and some members unique
|
```
|
||||||
to the message type. These statements set all the members in each message:
|
request<empty_body> req;
|
||||||
```
|
|
||||||
http::request_v1<http::string_body> req;
|
|
||||||
req.method = "GET";
|
|
||||||
req.url = "/index.html";
|
|
||||||
req.version = 11; // HTTP/1.1
|
req.version = 11; // HTTP/1.1
|
||||||
req.headers.insert("User-Agent", "hello_world");
|
req.method = "GET";
|
||||||
req.body = "";
|
req.url = "/index.htm"
|
||||||
|
req.fields.insert("Accept", "text/html");
|
||||||
|
req.fields.insert("Connection", "keep-alive");
|
||||||
|
req.fields.insert("User-Agent", "Beast");
|
||||||
|
```
|
||||||
|
][
|
||||||
|
```
|
||||||
|
response<string_body> res;
|
||||||
|
res.version = 11; // HTTP/1.1
|
||||||
|
res.status = 200;
|
||||||
|
res.reason = "OK";
|
||||||
|
res.fields.insert("Sever", "Beast");
|
||||||
|
res.fields.insert("Content-Length", 4);
|
||||||
|
res.body = "****";
|
||||||
|
```
|
||||||
|
]]]
|
||||||
|
|
||||||
http::response_v1<http::string_body> resp;
|
In the serialized format of a HTTP message, the header is represented as a
|
||||||
resp.status = 404;
|
series of text lines ending in CRLF (`"\r\n"`). The end of the header is
|
||||||
resp.reason = "Not Found";
|
indicated by a line containing only CRLF. Here are examples of serialized HTTP
|
||||||
resp.version = 10; // HTTP/1.0
|
request and response objects. The objects created above will produce these
|
||||||
resp.headers.insert("Server", "Beast.HTTP");
|
results when serialized. Note that only the response has a body:
|
||||||
resp.body = "The requested resource was not found.";
|
|
||||||
```
|
|
||||||
|
|
||||||
[heading Headers]
|
[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
|
||||||
|
****
|
||||||
|
```
|
||||||
|
]]]
|
||||||
|
|
||||||
The `message::headers` member is a container for setting the field/value
|
|
||||||
pairs in the message. These statements change the values of the headers
|
|
||||||
in the message passed:
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[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.
|
||||||
|
|
||||||
|
These statements change the values of the headers in the message passed:
|
||||||
```
|
```
|
||||||
template<class Body>
|
template<class Body>
|
||||||
void set_fields(http::request_v1<Body>& req)
|
void set_fields(request<Body>& req)
|
||||||
{
|
{
|
||||||
if(! req.exists("User-Agent"))
|
if(! req.exists("User-Agent"))
|
||||||
req.insert("User-Agent", "myWebClient");
|
req.insert("User-Agent", "myWebClient");
|
||||||
@@ -148,17 +213,24 @@ in the message passed:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[heading Body]
|
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.
|
||||||
|
|
||||||
The `message::body` member represents the message body. Depending on the
|
[endsect]
|
||||||
`Body` template argument type, this could be a writable container. The
|
|
||||||
following types, provided by the library, are suitable choices for the
|
|
||||||
`Body` type:
|
|
||||||
|
[section:body Body]
|
||||||
|
|
||||||
|
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.
|
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
|
||||||
Used in GET requests where there is no message body. Example:
|
Used in GET requests where there is no message body. Example:
|
||||||
```
|
```
|
||||||
http::request_v1<http::empty_body> req;
|
request<empty_body> req;
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.method = "GET";
|
req.method = "GET";
|
||||||
req.url = "/index.html";
|
req.url = "/index.html";
|
||||||
@@ -170,36 +242,77 @@ or response with simple text in the message body (such as an error message).
|
|||||||
Has the same insertion complexity of `std::string`. This is the type of body
|
Has the same insertion complexity of `std::string`. This is the type of body
|
||||||
used in the examples:
|
used in the examples:
|
||||||
```
|
```
|
||||||
http::response_v1<http::string_body> resp;
|
response<string_body> res;
|
||||||
static_assert(std::is_same<decltype(resp.body), std::string>::value);
|
static_assert(std::is_same<decltype(res.body), std::string>::value);
|
||||||
resp.body = "Here is the data you requested";
|
res.body = "Here is the data you requested";
|
||||||
```
|
```
|
||||||
|
|
||||||
* [link beast.ref.http__streambuf_body [*`streambuf_body`:]] A body with a
|
* [link beast.ref.http__streambuf_body [*`streambuf_body`:]] A body with a
|
||||||
`value_type` of [link beast.ref.streambuf `streambuf`]: an efficient storage
|
`value_type` of [link beast.ref.streambuf `streambuf`]: an efficient storage
|
||||||
object which uses multiple octet arrays of varying lengths to represent data.
|
object which uses multiple octet arrays of varying lengths to represent data.
|
||||||
|
|
||||||
[heading Sockets]
|
[heading Advanced]
|
||||||
|
|
||||||
The library provides simple free functions modeled after Boost.Asio to
|
User-defined types are possible for the message body, where the type meets the
|
||||||
send and receive messages on TCP/IP sockets, SSL streams, or any object
|
[link beast.ref.Body [*`Body`]] requirements. This simplified class declaration
|
||||||
which meets the Boost.Asio type requirements (SyncReadStream, SyncWriteStream,
|
shows the customization points available to user-defined body types:
|
||||||
AsyncReadStream, and AsyncWriteStream depending on the types of operations
|
|
||||||
performed). To send messages synchronously, use one of the `http:write`
|
[$images/body.png [width 510px] [height 210px]]
|
||||||
functions:
|
|
||||||
|
* [*`value_type`]: Determines the type of the
|
||||||
|
[link beast.ref.http__message.body `message::body`] member. If this
|
||||||
|
type defines default construction, move, copy, or swap, then message objects
|
||||||
|
declared with this [*`Body`] will have those operations defined.
|
||||||
|
|
||||||
|
* [*`reader`]: An optional nested type meeting the requirements of
|
||||||
|
[link beast.ref.Reader [*`Reader`]]. If present, this defines the algorithm
|
||||||
|
used for parsing bodies of this type.
|
||||||
|
|
||||||
|
* [*`writer`]: An optional nested type meeting the requirements of
|
||||||
|
[link beast.ref.Writer [*`Writer`]]. If present, this defines the algorithm
|
||||||
|
used for serializing bodies of this type.
|
||||||
|
|
||||||
|
The examples included with this library provide a Body implementation that
|
||||||
|
serializing message bodies that come from a file.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[section:algorithms Algorithms]
|
||||||
|
|
||||||
|
Algorithms are provided to serialize and deserialize HTTP/1 messages on
|
||||||
|
streams.
|
||||||
|
|
||||||
|
* [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]]: 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.
|
||||||
|
|
||||||
|
[heading Using Sockets]
|
||||||
|
|
||||||
|
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)
|
void send_request(boost::asio::ip::tcp::socket& sock)
|
||||||
{
|
{
|
||||||
http::request<http::empty_body> req;
|
request<empty_body> req;
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.method = "GET";
|
req.method = "GET";
|
||||||
req.url = "/index.html";
|
req.url = "/index.html";
|
||||||
...
|
...
|
||||||
http::write(sock, req); // Throws exception on error
|
write(sock, req); // Throws exception on error
|
||||||
...
|
...
|
||||||
// Alternatively
|
// Alternatively
|
||||||
boost::system::error:code ec;
|
boost::system::error:code ec;
|
||||||
http::write(sock, req, ec);
|
write(sock, req, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
std::cerr << "error writing http message: " << ec.message();
|
std::cerr << "error writing http message: " << ec.message();
|
||||||
}
|
}
|
||||||
@@ -209,27 +322,27 @@ An asynchronous interface is available:
|
|||||||
```
|
```
|
||||||
void handle_write(boost::system::error_code);
|
void handle_write(boost::system::error_code);
|
||||||
...
|
...
|
||||||
http::request_v1<http::empty_body> req;
|
request<empty_body> req;
|
||||||
...
|
...
|
||||||
http::async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
|
async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
|
||||||
```
|
```
|
||||||
|
|
||||||
When the implementation reads messages from a socket, it can read bytes lying
|
When the implementation reads messages from a socket, it can read bytes lying
|
||||||
after the end of the message if they are present (the alternative is to read
|
after the end of the message if they are present (the alternative is to read
|
||||||
a single byte at a time which is unsuitable for performance reasons). To
|
a single byte at a time which is unsuitable for performance reasons). To
|
||||||
store and re-use these extra bytes on subsequent messages, the read interface
|
store and re-use these extra bytes on subsequent messages, the read interface
|
||||||
requires an additional parameter: a [link beast.types.DynamicBuffer [*`DynamicBuffer`]]
|
requires an additional parameter: a [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]
|
||||||
object. This example reads a message from the socket, with the extra bytes
|
object. This example reads a message from the socket, with the extra bytes
|
||||||
stored in the streambuf parameter for use in a subsequent call to read:
|
stored in the streambuf parameter for use in a subsequent call to read:
|
||||||
```
|
```
|
||||||
boost::asio::streambuf sb;
|
boost::asio::streambuf sb;
|
||||||
...
|
...
|
||||||
http::response_v1<http::string_body> resp;
|
response<string_body> res;
|
||||||
http::read(sock, sb, resp); // Throws exception on error
|
read(sock, sb, res); // Throws exception on error
|
||||||
...
|
...
|
||||||
// Alternatively
|
// Alternatively
|
||||||
boost::system::error:code ec;
|
boost::system::error:code ec;
|
||||||
http::read(sock, sb, resp, ec);
|
read(sock, sb, res, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
std::cerr << "error reading http message: " << ec.message();
|
std::cerr << "error reading http message: " << ec.message();
|
||||||
```
|
```
|
||||||
@@ -241,116 +354,28 @@ called:
|
|||||||
void handle_read(boost::system::error_code);
|
void handle_read(boost::system::error_code);
|
||||||
...
|
...
|
||||||
boost::asio::streambuf sb;
|
boost::asio::streambuf sb;
|
||||||
http::response_v1<http::string_body> resp;
|
response<string_body> res;
|
||||||
...
|
...
|
||||||
http::async_read(sock, resp, std::bind(&handle_read, std::placeholders::_1));
|
async_read(sock, res, std::bind(&handle_read, std::placeholders::_1));
|
||||||
```
|
```
|
||||||
|
|
||||||
An alternative to using a `boost::asio::streambuf` is to use a
|
An alternative to using a `boost::asio::streambuf` is to use a
|
||||||
[link beast.ref.streambuf `beast::streambuf`], which meets the requirements of
|
__streambuf__, which meets the requirements of __DynamicBuffer__ and
|
||||||
[*`DynamicBuffer`] and is optimized for performance:
|
is optimized for performance:
|
||||||
```
|
```
|
||||||
void handle_read(boost::system::error_code);
|
void handle_read(boost::system::error_code);
|
||||||
...
|
...
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
http::response_v1<http::string_body> resp;
|
response<string_body> res;
|
||||||
http::read(sock, sb, resp);
|
read(sock, sb, res);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `read` implementation can use any object meeting the requirements of
|
The `read` implementation can use any object meeting the requirements of
|
||||||
[link beast.types.DynamicBuffer [*`DynamicBuffer`]], allowing callers to define custom
|
__DynamicBuffer__, allowing callers to define custom
|
||||||
memory management strategies used by the implementation.
|
memory management strategies used by the implementation.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:advanced Advanced]
|
|
||||||
|
|
||||||
The spectrum of hardware and software platforms which perform these typical
|
|
||||||
HTTP operations is vast, ranging from powerful servers in large datacenters
|
|
||||||
to tiny resource-limited embedded devices. No single concrete implementation
|
|
||||||
of a class intended to model messages can efficiently serve all needs.
|
|
||||||
For example, an object that minimizes resources during parsing may not be
|
|
||||||
able to edit and change headers dynamically. A message that represents the
|
|
||||||
message body as a disk file may support sending but not parsing. Many efficient
|
|
||||||
and correct models of messages exist, supporting some or all of the
|
|
||||||
operations listed above.
|
|
||||||
|
|
||||||
[heading Message model]
|
|
||||||
|
|
||||||
The message class template and provided Body types are suitable for casual
|
|
||||||
library users. This section explains the message model for advanced users
|
|
||||||
who wish to take control over aspects of the implementation. We introduce
|
|
||||||
customization points for the header and body via class template arguments.
|
|
||||||
This illustration shows more detail about the
|
|
||||||
[link beast.ref.http__message [*`message`]] class template (boilerplate
|
|
||||||
present in the actual declaration has been removed for clarity):
|
|
||||||
|
|
||||||
[$images/message.png [width 580px] [height 225px]]
|
|
||||||
|
|
||||||
The default constructor, move special members, and copy special members are
|
|
||||||
all defaulted. A message is movable, copyable, or default constructible based
|
|
||||||
on the capabilities of its template arguments.
|
|
||||||
|
|
||||||
Messages modeled in this fashion are ['complete], containing all of the
|
|
||||||
information required to perform the supported set of operations. They are
|
|
||||||
['first-class types], returnable from functions and composable. HTTP
|
|
||||||
requests and responses are distinct types, allowing functions to be
|
|
||||||
overloaded on the type of message.
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:headers Headers Type]
|
|
||||||
|
|
||||||
The `Headers` type represents the field/value pairs present in every HTTP
|
|
||||||
message. These types implement the
|
|
||||||
[link beast.types.FieldSequence [*`FieldSequence`]]
|
|
||||||
concept. The value type of a field sequence is an object meeting the
|
|
||||||
requirements of [link beast.types.Field [*`Field`]]. The implementation can
|
|
||||||
serialize any instance of `Headers` that meets the field sequence requirements.
|
|
||||||
This example shows a function which returns `true` if the specified field
|
|
||||||
sequence has a connect field:
|
|
||||||
```
|
|
||||||
template<class FieldSequence>
|
|
||||||
bool
|
|
||||||
has_connect(FieldSequence const& fs)
|
|
||||||
{
|
|
||||||
return std::find_if(fs.begin(), fs.end(),
|
|
||||||
[&](auto const& field)
|
|
||||||
{
|
|
||||||
return ci_equal(field.name(), "Connect");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:body Body Type]
|
|
||||||
|
|
||||||
The `Body` template argument in the `message` class must meet the
|
|
||||||
[link beast.types.Body [*`Body`] requirements]. It provides customization
|
|
||||||
of the data member in the message, the algorithm for parsing, and the
|
|
||||||
algorithm for serialization:
|
|
||||||
|
|
||||||
[$images/body.png [width 510px] [height 210px]]
|
|
||||||
|
|
||||||
Instances of the optional nested types `writer` and `reader` perform
|
|
||||||
serialization and deserialization of the message body. If either or
|
|
||||||
both of these types are present, the message becomes serializable, parsable,
|
|
||||||
or both. They model [link beast.types.Reader [*`Reader`]] and
|
|
||||||
[link beast.types.Writer [*`Writer`]] respectively.
|
|
||||||
|
|
||||||
For specialized applications, users may implement their own types which
|
|
||||||
meet the requirements. The examples included with this library provide a
|
|
||||||
Body implementation used to serve files in a HTTP server.
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|||||||
BIN
src/beast/doc/images/CppCon2016.pdf
Normal file
BIN
src/beast/doc/images/CppCon2016.pdf
Normal file
Binary file not shown.
BIN
src/beast/doc/images/CppCon2016.png
Normal file
BIN
src/beast/doc/images/CppCon2016.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 145 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 30 KiB |
Binary file not shown.
@@ -8,6 +8,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<section id="index">
|
<section id="beast.index">
|
||||||
|
<title>Index</title>
|
||||||
<index/>
|
<index/>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
2
src/beast/doc/makeqbk.sh
Normal file → Executable file
2
src/beast/doc/makeqbk.sh
Normal file → Executable file
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
[library Beast
|
[library Beast
|
||||||
[quickbook 1.6]
|
[quickbook 1.6]
|
||||||
[copyright 2013 - 2016 Vinnie Falco]
|
[copyright 2013 - 2016 Vinnie Falco]
|
||||||
[purpose C++ Library]
|
[purpose Networking Protocol Library]
|
||||||
[license
|
[license
|
||||||
Distributed under the Boost Software License, Version 1.0.
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
(See accompanying file LICENSE_1_0.txt or copy at
|
(See accompanying file LICENSE_1_0.txt or copy at
|
||||||
@@ -22,174 +22,85 @@
|
|||||||
[template mdash[] '''— ''']
|
[template mdash[] '''— ''']
|
||||||
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
|
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
|
||||||
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
|
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
|
||||||
[def __POSIX__ /POSIX/]
|
|
||||||
[def __Windows__ /Windows/]
|
|
||||||
[def __accept__ [@http://www.opengroup.org/onlinepubs/000095399/functions/accept.html `accept()`]]
|
|
||||||
[def __connect__ [@http://www.opengroup.org/onlinepubs/000095399/functions/connect.html `connect()`]]
|
|
||||||
[def __getpeername__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getpeername.html `getpeername()`]]
|
|
||||||
[def __getsockname__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getsockname.html `getsockname()`]]
|
|
||||||
[def __getsockopt__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getsockopt.html `getsockopt()`]]
|
|
||||||
[def __ioctl__ [@http://www.opengroup.org/onlinepubs/000095399/functions/ioctl.html `ioctl()`]]
|
|
||||||
[def __recvfrom__ [@http://www.opengroup.org/onlinepubs/000095399/functions/recvfrom.html `recvfrom()`]]
|
|
||||||
[def __sendto__ [@http://www.opengroup.org/onlinepubs/000095399/functions/sendto.html `sendto()`]]
|
|
||||||
[def __setsockopt__ [@http://www.opengroup.org/onlinepubs/000095399/functions/setsockopt.html `setsockopt()`]]
|
|
||||||
[def __socket__ [@http://www.opengroup.org/onlinepubs/000095399/functions/socket.html `socket()`]]
|
|
||||||
|
|
||||||
|
[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 __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]]]
|
||||||
|
|
||||||
[section:intro Introduction]
|
[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]]]
|
||||||
|
|
||||||
Beast is a header-only, cross-platform C++ library built on Boost.Asio and
|
[def __Body__ [link beast.ref.Body [*`Body`]]]
|
||||||
Boost, containing two modules implementing widely used network protocols.
|
[def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]]
|
||||||
Beast.HTTP offers a universal model for describing, sending, and receiving
|
[def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]]
|
||||||
HTTP messages while Beast.WebSocket provides a complete implementation of
|
[def __Parser__ [link beast.ref.Parser [*`Parser`]]]
|
||||||
the WebSocket protocol. Their design achieves these goals:
|
|
||||||
|
|
||||||
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
|
[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]]
|
||||||
used to build clients, servers, or both.
|
[def __fields__ [link beast.ref.http__fields `fields`]]
|
||||||
|
[def __header__ [link beast.ref.http__header `header`]]
|
||||||
* [*Ease of Use.] HTTP messages are modeled using simple, readily
|
[def __message__ [link beast.ref.http__message `message`]]
|
||||||
accessible objects. Functions and classes used to send and receive HTTP
|
[def __streambuf__ [link beast.ref.streambuf `streambuf`]]
|
||||||
or WebSocket messages are designed to resemble Boost.Asio as closely as
|
[def __basic_streambuf__ [link beast.ref.basic_streambuf `basic_streambuf`]]
|
||||||
possible. Users familiar with Boost.Asio will be immediately comfortable
|
|
||||||
using this library.
|
|
||||||
|
|
||||||
* [*Flexibility.] Interfaces do not mandate specific implementation
|
|
||||||
strategies; important decisions such as buffer or thread management are
|
|
||||||
left to users of the library.
|
|
||||||
|
|
||||||
* [*Performance.] The implementation performs competitively, making it a
|
|
||||||
realistic choice for building high performance network servers.
|
|
||||||
|
|
||||||
* [*Scalability.] Development of network applications that scale to thousands
|
|
||||||
of concurrent connections is possible with the implementation.
|
|
||||||
|
|
||||||
* [*Basis for further abstraction.] The interfaces facilitate the
|
|
||||||
development of other libraries that provide higher levels of abstraction.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:requirements Requirements]
|
|
||||||
|
|
||||||
Beast requires:
|
|
||||||
|
|
||||||
* [*C++11.] A minimum of C++11 is needed.
|
|
||||||
* [*Boost.] Beast is built on Boost, especially Boost.Asio.
|
|
||||||
* [*OpenSSL.] If using TLS/Secure sockets (optional).
|
|
||||||
|
|
||||||
[note Tested compilers: msvc-14+, gcc 5+, clang 3.6+]
|
|
||||||
|
|
||||||
The library is [*header-only]. It is not necessary to add any .cpp files,
|
|
||||||
or to edit your existing build script or project file except to provide
|
|
||||||
that the include/ directory for beast is searched for include files.
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:example Examples]
|
|
||||||
|
|
||||||
These usage examples are intended to quickly impress upon readers the
|
|
||||||
flavor of the library. They are complete programs which may be built
|
|
||||||
and run. Source code and build scripts for these programs may be found
|
|
||||||
in the examples directory.
|
|
||||||
|
|
||||||
Use HTTP to request the root page from a website and print the response:
|
|
||||||
```
|
|
||||||
#include <beast/http.hpp>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
// Normal boost::asio setup
|
|
||||||
std::string const host = "boost.org";
|
|
||||||
boost::asio::io_service ios;
|
|
||||||
boost::asio::ip::tcp::resolver r{ios};
|
|
||||||
boost::asio::ip::tcp::socket sock{ios};
|
|
||||||
boost::asio::connect(sock,
|
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
|
||||||
|
|
||||||
// Send HTTP request using beast
|
|
||||||
beast::http::request_v1<beast::http::empty_body> req;
|
|
||||||
req.method = "GET";
|
|
||||||
req.url = "/";
|
|
||||||
req.version = 11;
|
|
||||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
|
||||||
req.headers.replace("User-Agent", "Beast");
|
|
||||||
beast::http::prepare(req);
|
|
||||||
beast::http::write(sock, req);
|
|
||||||
|
|
||||||
// Receive and print HTTP response using beast
|
|
||||||
beast::streambuf sb;
|
|
||||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
|
||||||
beast::http::read(sock, sb, resp);
|
|
||||||
std::cout << resp;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Establish a WebSocket connection, send a message and receive the reply:
|
|
||||||
```
|
|
||||||
#include <beast/core/to_string.hpp>
|
|
||||||
#include <beast/websocket.hpp>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
// Normal boost::asio setup
|
|
||||||
std::string const host = "echo.websocket.org";
|
|
||||||
boost::asio::io_service ios;
|
|
||||||
boost::asio::ip::tcp::resolver r{ios};
|
|
||||||
boost::asio::ip::tcp::socket sock{ios};
|
|
||||||
boost::asio::connect(sock,
|
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
|
||||||
|
|
||||||
// WebSocket connect and send message using beast
|
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
|
||||||
ws.handshake(host, "/");
|
|
||||||
ws.write(boost::asio::buffer("Hello, world!"));
|
|
||||||
|
|
||||||
// Receive WebSocket message, print and close using beast
|
|
||||||
beast::streambuf sb;
|
|
||||||
beast::websocket::opcode op;
|
|
||||||
ws.read(op, sb);
|
|
||||||
ws.close(beast::websocket::close_code::normal);
|
|
||||||
std::cout << to_string(sb.data()) << "\n";
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:credits Credits]
|
|
||||||
|
|
||||||
Boost.Asio is the inspiration behind which all of the interfaces and
|
|
||||||
implementation strategies are built. Some parts of the documentation are
|
|
||||||
written to closely resemble the wording and presentation of Boost.Asio
|
|
||||||
documentation. Credit goes to Christopher Kohloff for the wonderful
|
|
||||||
Asio library and the ideas upon which Beast is built.
|
|
||||||
|
|
||||||
Beast would not be possible without the considerable time and patience
|
|
||||||
contributed by David Schwartz, Edward Hennis, Howard Hinnant, Miguel Portilla,
|
|
||||||
Nikolaos Bougalis, Scott Determan, Scott Schurr, and Ripple Labs for
|
|
||||||
supporting its development.
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
Beast is a cross-platform, header-only C++ library built on Boost.Asio that
|
||||||
|
provides implementations of the HTTP and WebSocket protocols.
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
[[
|
||||||
|
[link beast.overview Overview]
|
||||||
|
][
|
||||||
|
An introduction with features, requirements, and credits.
|
||||||
|
]]
|
||||||
|
[[
|
||||||
|
[link beast.http Using HTTP]
|
||||||
|
][
|
||||||
|
How to use Beast's HTTP interfaces in your applications.
|
||||||
|
]]
|
||||||
|
[[
|
||||||
|
[link beast.websocket Using WebSocket]
|
||||||
|
][
|
||||||
|
How to use Beast's WebSocket interfaces in your applications.
|
||||||
|
]]
|
||||||
|
[[
|
||||||
|
[link beast.example Examples]
|
||||||
|
][
|
||||||
|
Examples that illustrate the use of Beast in more complex applications.
|
||||||
|
]]
|
||||||
|
[[
|
||||||
|
[link beast.design Design]
|
||||||
|
][
|
||||||
|
Design rationale, answers to review questions, and
|
||||||
|
other library comparisons.
|
||||||
|
]]
|
||||||
|
[[
|
||||||
|
[link beast.ref Reference]
|
||||||
|
][
|
||||||
|
Detailed class and function reference.
|
||||||
|
]]
|
||||||
|
[[
|
||||||
|
[link beast.index Index]
|
||||||
|
][
|
||||||
|
Book-style text index of Beast documentation.
|
||||||
|
]]
|
||||||
|
]
|
||||||
|
|
||||||
|
[include overview.qbk]
|
||||||
[include http.qbk]
|
[include http.qbk]
|
||||||
[include websocket.qbk]
|
[include websocket.qbk]
|
||||||
|
[include examples.qbk]
|
||||||
|
[include design.qbk]
|
||||||
|
|
||||||
[section:types Type Requirements]
|
[section:ref Reference]
|
||||||
|
[xinclude quickref.xml]
|
||||||
[include types/Body.qbk]
|
[include types/Body.qbk]
|
||||||
[include types/BufferSequence.qbk]
|
[include types/BufferSequence.qbk]
|
||||||
[include types/DynamicBuffer.qbk]
|
[include types/DynamicBuffer.qbk]
|
||||||
@@ -199,13 +110,7 @@ supporting its development.
|
|||||||
[include types/Reader.qbk]
|
[include types/Reader.qbk]
|
||||||
[include types/Streams.qbk]
|
[include types/Streams.qbk]
|
||||||
[include types/Writer.qbk]
|
[include types/Writer.qbk]
|
||||||
|
[include reference.qbk]
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[include design.qbk]
|
|
||||||
[section:quickref Quick Reference]
|
|
||||||
[xinclude quickref.xml]
|
|
||||||
[endsect]
|
|
||||||
[include reference.qbk]
|
|
||||||
[section:idx Index]
|
|
||||||
[xinclude index.xml]
|
[xinclude index.xml]
|
||||||
[endsect]
|
|
||||||
|
|||||||
114
src/beast/doc/overview.qbk
Normal file
114
src/beast/doc/overview.qbk
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
[/
|
||||||
|
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)
|
||||||
|
]
|
||||||
|
|
||||||
|
[section:overview Introduction]
|
||||||
|
|
||||||
|
Beast is a header-only, cross-platform C++ library built on Boost.Asio and
|
||||||
|
parts of Boost, containing two modules implementing widely used network
|
||||||
|
protocols. Beast offers a universal HTTP message model, plus algorithms for
|
||||||
|
parsing and serializing HTTP/1 messages. Beast.WebSocket provides a complete
|
||||||
|
implementation of the WebSocket protocol. Their design achieves these goals:
|
||||||
|
|
||||||
|
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
|
||||||
|
used to build clients, servers, or both.
|
||||||
|
|
||||||
|
* [*Ease of Use.] HTTP messages are modeled using simple, readily
|
||||||
|
accessible objects. Functions and classes used to send and receive HTTP
|
||||||
|
or WebSocket messages are designed to resemble Boost.Asio as closely as
|
||||||
|
possible. Users familiar with Boost.Asio will be immediately comfortable
|
||||||
|
using this library.
|
||||||
|
|
||||||
|
* [*Flexibility.] Interfaces do not mandate specific implementation
|
||||||
|
strategies; important decisions such as buffer or thread management are
|
||||||
|
left to users of the library.
|
||||||
|
|
||||||
|
* [*Performance.] The implementation performs competitively, making it a
|
||||||
|
realistic choice for building high performance network servers.
|
||||||
|
|
||||||
|
* [*Scalability.] Development of network applications that scale to thousands
|
||||||
|
of concurrent connections is possible with the implementation.
|
||||||
|
|
||||||
|
* [*Basis for further abstraction.] The interfaces facilitate the
|
||||||
|
development of other libraries that provide higher levels of abstraction.
|
||||||
|
|
||||||
|
The HTTP portion of Beast is designed to be a low-level building block for
|
||||||
|
creating higher level libraries. It implements only the HTTP protocol, and
|
||||||
|
does not handle domain specific features (for example: cookies, redirects, or
|
||||||
|
deflate content encodings).
|
||||||
|
|
||||||
|
[heading Requirements]
|
||||||
|
|
||||||
|
Beast requires:
|
||||||
|
|
||||||
|
* [*C++11.] A minimum of C++11 is needed.
|
||||||
|
* [*Boost.] Beast is built on Boost, especially Boost.Asio.
|
||||||
|
* [*OpenSSL.] If using TLS/Secure sockets (optional).
|
||||||
|
|
||||||
|
[note Tested compilers: msvc-14+, gcc 5+, clang 3.6+]
|
||||||
|
|
||||||
|
The library is [*header-only]. It is not necessary to add any .cpp files,
|
||||||
|
or to add commands to your build script for building Beast. To link your
|
||||||
|
program successfully, you'll need to add the Boost.System library to link
|
||||||
|
with. If you use coroutines you'll also need the Boost.Coroutine library.
|
||||||
|
Please visit the Boost documentation for instructions on how to do this for
|
||||||
|
your particular build system.
|
||||||
|
|
||||||
|
[heading Motivation]
|
||||||
|
|
||||||
|
Beast is built on Boost.Asio A proposal to add networking functionality to the
|
||||||
|
C++ standard library, based on Boost.Asio, is under consideration by the
|
||||||
|
committee and on track for standardization. Since the final approved networking
|
||||||
|
interface for the C++ standard library will likely closely resemble the current
|
||||||
|
interface of Boost.Asio, the choice of Boost.Asio as the network transport
|
||||||
|
layer is prudent.
|
||||||
|
|
||||||
|
The HTTP protocol is pervasive in network applications. As C++ is a logical
|
||||||
|
choice for high performance network servers, there is great utility in solid
|
||||||
|
building blocks for manipulating, sending, and receiving HTTP messages
|
||||||
|
compliant with the Hypertext Transfer Protocol and the supplements that
|
||||||
|
follow. Unfortunately reliable implementations or industry standards do not
|
||||||
|
exist in C++. The development of higher level libraries is stymied by the
|
||||||
|
lack of a common set of low-level algorithms and types for interacting with
|
||||||
|
the HTTP protocol.
|
||||||
|
|
||||||
|
Today's web applications increasingly rely on alternatives to standard HTTP
|
||||||
|
to achieve performance and/or responsiveness. While WebSocket implementations
|
||||||
|
are widely available in common web development languages such as Javascript,
|
||||||
|
good implementations in C++ are scarce. A survey of existing C++ WebSocket
|
||||||
|
solutions reveals interfaces which lack symmetry, impose performance penalties,
|
||||||
|
and needlessly restrict implementation strategies.
|
||||||
|
|
||||||
|
Beast.WebSocket takes advantage of Boost.Asio's extensible asynchronous
|
||||||
|
model, handler allocation, and handler invocation hooks. Calls to
|
||||||
|
Beast.WebSocket asynchronous initiation functions allow callers the choice
|
||||||
|
of using a completion handler, stackful or stackless coroutines, futures,
|
||||||
|
or user defined customizations (for example, Boost.Fiber). The
|
||||||
|
implementation uses handler invocation hooks (__asio_handler_invoke__),
|
||||||
|
providing execution guarantees on composed operations in a manner identical
|
||||||
|
to Boost.Asio. The implementation also uses handler allocation hooks
|
||||||
|
(__asio_handler_allocate__) when allocating memory internally for composed
|
||||||
|
operations.
|
||||||
|
|
||||||
|
There is no need for inheritance or virtual members in a
|
||||||
|
[link beast.ref.websocket__stream `websocket::stream`].
|
||||||
|
All operations are templated and transparent to the compiler, allowing for
|
||||||
|
maximum inlining and optimization.
|
||||||
|
|
||||||
|
[heading Credits]
|
||||||
|
|
||||||
|
Boost.Asio is the inspiration behind which all of the interfaces and
|
||||||
|
implementation strategies are built. Some parts of the documentation are
|
||||||
|
written to closely resemble the wording and presentation of Boost.Asio
|
||||||
|
documentation. Credit goes to Christopher Kohlhoff for the wonderful
|
||||||
|
Asio library and the ideas upon which Beast is built.
|
||||||
|
|
||||||
|
Beast would not be possible without the considerable time and patience
|
||||||
|
contributed by David Schwartz, Edward Hennis, Howard Hinnant, Miguel Portilla,
|
||||||
|
Nikolaos Bougalis, Scott Determan, Scott Schurr, and Ripple Labs for
|
||||||
|
supporting its development.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
<colspec colname="d"/>
|
<colspec colname="d"/>
|
||||||
<thead>
|
<thead>
|
||||||
<row>
|
<row>
|
||||||
<entry valign="center" namest="a" nameend="b">
|
<entry valign="center" namest="a" nameend="c">
|
||||||
<bridgehead renderas="sect2">HTTP</bridgehead>
|
<bridgehead renderas="sect2">HTTP</bridgehead>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="center" namest="c" nameend="d">
|
<entry valign="center" namest="d" nameend="d">
|
||||||
<bridgehead renderas="sect2">WebSocket</bridgehead>
|
<bridgehead renderas="sect2">WebSocket</bridgehead>
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
@@ -30,53 +30,82 @@
|
|||||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.http__basic_dynabuf_body">basic_dynabuf_body</link></member>
|
<member><link linkend="beast.ref.http__basic_dynabuf_body">basic_dynabuf_body</link></member>
|
||||||
<member><link linkend="beast.ref.http__basic_headers">basic_headers</link></member>
|
<member><link linkend="beast.ref.http__basic_fields">basic_fields</link></member>
|
||||||
<member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member>
|
<member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member>
|
||||||
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
|
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
|
||||||
<member><link linkend="beast.ref.http__headers">headers</link></member>
|
<member><link linkend="beast.ref.http__fields">fields</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__header">header</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__header_parser_v1">header_parser_v1</link></member>
|
||||||
<member><link linkend="beast.ref.http__message">message</link></member>
|
<member><link linkend="beast.ref.http__message">message</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__parser_v1">parser_v1</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__request">request</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__request_header">request_header</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__response">response</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__response_header">response_header</link></member>
|
||||||
<member><link linkend="beast.ref.http__resume_context">resume_context</link></member>
|
<member><link linkend="beast.ref.http__resume_context">resume_context</link></member>
|
||||||
<member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member>
|
<member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member>
|
||||||
<member><link linkend="beast.ref.http__string_body">string_body</link></member>
|
<member><link linkend="beast.ref.http__string_body">string_body</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Options</bridgehead>
|
<bridgehead renderas="sect3">rfc7230</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
|
||||||
<member><link linkend="beast.ref.http__headers_max_size">headers_max_size</link></member>
|
<member><link linkend="beast.ref.http__ext_list">ext_list</link></member>
|
||||||
<member><link linkend="beast.ref.http__skip_body">skip_body</link></member>
|
<member><link linkend="beast.ref.http__param_list">param_list</link></member>
|
||||||
</simplelist>
|
<member><link linkend="beast.ref.http__token_list">token_list</link></member>
|
||||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
|
||||||
<simplelist type="vert" columns="1">
|
|
||||||
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
|
|
||||||
<member><link linkend="beast.ref.http__is_Parser">is_Parser</link></member>
|
|
||||||
<member><link linkend="beast.ref.http__is_ReadableBody">is_ReadableBody</link></member>
|
|
||||||
<member><link linkend="beast.ref.http__is_WritableBody">is_WritableBody</link></member>
|
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
|
|
||||||
<member><link linkend="beast.ref.http__async_read">async_read</link></member>
|
<member><link linkend="beast.ref.http__async_read">async_read</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
|
||||||
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
|
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__chunk_encode">chunk_encode</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__chunk_encode_final">chunk_encode_final</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__swap">swap</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__is_keep_alive">is_keep_alive</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__is_upgrade">is_upgrade</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__operator_ls_">operator<<</link></member>
|
||||||
<member><link linkend="beast.ref.http__parse">parse</link></member>
|
<member><link linkend="beast.ref.http__parse">parse</link></member>
|
||||||
<member><link linkend="beast.ref.http__prepare">prepare</link></member>
|
<member><link linkend="beast.ref.http__prepare">prepare</link></member>
|
||||||
<member><link linkend="beast.ref.http__read">read</link></member>
|
<member><link linkend="beast.ref.http__read">read</link></member>
|
||||||
<member><link linkend="beast.ref.http__swap">swap</link></member>
|
<member><link linkend="beast.ref.http__reason_string">reason_string</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__with_body">with_body</link></member>
|
||||||
<member><link linkend="beast.ref.http__write">write</link></member>
|
<member><link linkend="beast.ref.http__write">write</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__is_Parser">is_Parser</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__is_Reader">is_Reader</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__is_Writer">is_Writer</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__has_reader">has_reader</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__has_writer">has_writer</link></member>
|
||||||
|
</simplelist>
|
||||||
|
</entry>
|
||||||
|
<entry valign="top">
|
||||||
|
<bridgehead renderas="sect3">Options</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.http__header_max_size">header_max_size</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__skip_body">skip_body</link></member>
|
||||||
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.http__body_what">body_what</link></member>
|
||||||
<member><link linkend="beast.ref.http__connection">connection</link></member>
|
<member><link linkend="beast.ref.http__connection">connection</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__no_content_length">no_content_length</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__parse_error">parse_error</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__parse_flag">parse_flag</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.types.Body">Body</link></member>
|
<member><link linkend="beast.ref.Body">Body</link></member>
|
||||||
<member><link linkend="beast.types.Field">Field</link></member>
|
<member><link linkend="beast.ref.Field">Field</link></member>
|
||||||
<member><link linkend="beast.types.FieldSequence">FieldSequence</link></member>
|
<member><link linkend="beast.ref.FieldSequence">FieldSequence</link></member>
|
||||||
<member><link linkend="beast.types.Parser">Parser</link></member>
|
<member><link linkend="beast.ref.Parser">Parser</link></member>
|
||||||
<member><link linkend="beast.types.Reader">Reader</link></member>
|
<member><link linkend="beast.ref.Reader">Reader</link></member>
|
||||||
<member><link linkend="beast.types.Writer">Writer</link></member>
|
<member><link linkend="beast.ref.Writer">Writer</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
@@ -88,24 +117,22 @@
|
|||||||
<member><link linkend="beast.ref.websocket__reason_string">reason_string</link></member>
|
<member><link linkend="beast.ref.websocket__reason_string">reason_string</link></member>
|
||||||
<member><link linkend="beast.ref.websocket__teardown_tag">teardown_tag</link></member>
|
<member><link linkend="beast.ref.websocket__teardown_tag">teardown_tag</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Options</bridgehead>
|
|
||||||
<simplelist type="vert" columns="1">
|
|
||||||
<member><link linkend="beast.ref.websocket__auto_fragment_size">auto_fragment_size</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__decorate">decorate</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__mask_buffer_size">mask_buffer_size</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__message_type">message_type</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__pong_callback">pong_callback</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__read_buffer_size">read_buffer_size</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__read_message_max">read_message_max</link></member>
|
|
||||||
</simplelist>
|
|
||||||
</entry>
|
|
||||||
<entry valign="top">
|
|
||||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.websocket__async_teardown">async_teardown</link></member>
|
<member><link linkend="beast.ref.websocket__async_teardown">async_teardown</link></member>
|
||||||
<member><link linkend="beast.ref.websocket__teardown">teardown</link></member>
|
<member><link linkend="beast.ref.websocket__teardown">teardown</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Options</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.websocket__auto_fragment">auto_fragment</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__decorate">decorate</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__message_type">message_type</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__pong_callback">pong_callback</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__read_buffer_size">read_buffer_size</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__read_message_max">read_message_max</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__write_buffer_size">write_buffer_size</link></member>
|
||||||
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.websocket__close_code">close_code</link></member>
|
<member><link linkend="beast.ref.websocket__close_code">close_code</link></member>
|
||||||
@@ -121,11 +148,15 @@
|
|||||||
<colspec colname="b"/>
|
<colspec colname="b"/>
|
||||||
<colspec colname="c"/>
|
<colspec colname="c"/>
|
||||||
<colspec colname="d"/>
|
<colspec colname="d"/>
|
||||||
|
<colspec colname="e"/>
|
||||||
<thead>
|
<thead>
|
||||||
<row>
|
<row>
|
||||||
<entry valign="center" namest="a" nameend="d">
|
<entry valign="center" namest="a" nameend="d">
|
||||||
<bridgehead renderas="sect2">Core</bridgehead>
|
<bridgehead renderas="sect2">Core</bridgehead>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry valign="center" namest="e" nameend="e">
|
||||||
|
<bridgehead renderas="sect2">ZLib</bridgehead>
|
||||||
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -138,9 +169,12 @@
|
|||||||
<member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member>
|
<member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member>
|
||||||
<member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member>
|
<member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member>
|
||||||
<member><link linkend="beast.ref.dynabuf_readstream">dynabuf_readstream</link></member>
|
<member><link linkend="beast.ref.dynabuf_readstream">dynabuf_readstream</link></member>
|
||||||
|
<member><link linkend="beast.ref.errc">errc</link></member>
|
||||||
|
<member><link linkend="beast.ref.error_category">error_category</link></member>
|
||||||
<member><link linkend="beast.ref.error_code">error_code</link></member>
|
<member><link linkend="beast.ref.error_code">error_code</link></member>
|
||||||
|
<member><link linkend="beast.ref.error_condition">error_condition</link></member>
|
||||||
<member><link linkend="beast.ref.handler_alloc">handler_alloc</link></member>
|
<member><link linkend="beast.ref.handler_alloc">handler_alloc</link></member>
|
||||||
<member><link linkend="beast.ref.prepared_buffers">prepared_buffers</link></member>
|
<member><link linkend="beast.ref.handler_ptr">handler_ptr</link></member>
|
||||||
<member><link linkend="beast.ref.static_streambuf">static_streambuf</link></member>
|
<member><link linkend="beast.ref.static_streambuf">static_streambuf</link></member>
|
||||||
<member><link linkend="beast.ref.static_streambuf_n">static_streambuf_n</link></member>
|
<member><link linkend="beast.ref.static_streambuf_n">static_streambuf_n</link></member>
|
||||||
<member><link linkend="beast.ref.static_string">static_string</link></member>
|
<member><link linkend="beast.ref.static_string">static_string</link></member>
|
||||||
@@ -153,18 +187,15 @@
|
|||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.bind_handler">bind_handler</link></member>
|
<member><link linkend="beast.ref.bind_handler">bind_handler</link></member>
|
||||||
<member><link linkend="beast.ref.buffer_cat">buffer_cat</link></member>
|
<member><link linkend="beast.ref.buffer_cat">buffer_cat</link></member>
|
||||||
<member><link linkend="beast.ref.consumed_buffers">consumed_buffers</link></member>
|
|
||||||
<member><link linkend="beast.ref.prepare_buffer">prepare_buffer</link></member>
|
<member><link linkend="beast.ref.prepare_buffer">prepare_buffer</link></member>
|
||||||
<member><link linkend="beast.ref.prepare_buffers">prepare_buffers</link></member>
|
<member><link linkend="beast.ref.prepare_buffers">prepare_buffers</link></member>
|
||||||
<member><link linkend="beast.ref.to_string">to_string</link></member>
|
<member><link linkend="beast.ref.to_string">to_string</link></member>
|
||||||
|
|
||||||
<member><link linkend="beast.ref.write">write</link></member>
|
<member><link linkend="beast.ref.write">write</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
|
|
||||||
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
|
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
|
||||||
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
|
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
|
||||||
<member><link linkend="beast.ref.is_AsyncStream">is_AsyncStream</link></member>
|
<member><link linkend="beast.ref.is_AsyncStream">is_AsyncStream</link></member>
|
||||||
@@ -181,11 +212,29 @@
|
|||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.types.streams.AsyncStream">AsyncStream</link></member>
|
<member><link linkend="beast.ref.streams.AsyncStream">AsyncStream</link></member>
|
||||||
<member><link linkend="beast.types.BufferSequence">BufferSequence</link></member>
|
<member><link linkend="beast.ref.BufferSequence">BufferSequence</link></member>
|
||||||
<member><link linkend="beast.types.DynamicBuffer">DynamicBuffer</link></member>
|
<member><link linkend="beast.ref.DynamicBuffer">DynamicBuffer</link></member>
|
||||||
<member><link linkend="beast.types.streams.Stream">Stream</link></member>
|
<member><link linkend="beast.ref.streams.Stream">Stream</link></member>
|
||||||
<member><link linkend="beast.types.streams.SyncStream">SyncStream</link></member>
|
<member><link linkend="beast.ref.streams.SyncStream">SyncStream</link></member>
|
||||||
|
</simplelist>
|
||||||
|
</entry>
|
||||||
|
<entry valign="top">
|
||||||
|
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.zlib__deflate_stream">deflate_stream</link></member>
|
||||||
|
<member><link linkend="beast.ref.zlib__inflate_stream">inflate_stream</link></member>
|
||||||
|
<member><link linkend="beast.ref.zlib__z_params">z_params</link></member>
|
||||||
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.zlib__deflate_upper_bound">deflate_upper_bound</link></member>
|
||||||
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.zlib__error">error</link></member>
|
||||||
|
<member><link linkend="beast.ref.zlib__Flush">Flush</link></member>
|
||||||
|
<member><link linkend="beast.ref.zlib__Strategy">Strategy</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|||||||
@@ -31,8 +31,6 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:ref Reference]
|
|
||||||
|
|
||||||
</xsl:text>
|
</xsl:text>
|
||||||
<xsl:for-each select="
|
<xsl:for-each select="
|
||||||
compounddef[@kind = 'class' or @kind = 'struct'] |
|
compounddef[@kind = 'class' or @kind = 'struct'] |
|
||||||
@@ -59,7 +57,6 @@
|
|||||||
</xsl:otherwise>
|
</xsl:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
</xsl:for-each>
|
</xsl:for-each>
|
||||||
<xsl:text>
[endsect]</xsl:text>
|
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<!--========== Utilities ==========-->
|
<!--========== Utilities ==========-->
|
||||||
@@ -165,7 +162,7 @@
|
|||||||
<xsl:text>``['implementation-defined]``</xsl:text>
|
<xsl:text>``['implementation-defined]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="$type='void_or_deduced'">
|
<xsl:when test="$type='void_or_deduced'">
|
||||||
<xsl:text>``[@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]]``</xsl:text>
|
<xsl:text>__void_or_deduced__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:otherwise>
|
<xsl:otherwise>
|
||||||
<xsl:value-of select="$type"/>
|
<xsl:value-of select="$type"/>
|
||||||
@@ -198,6 +195,18 @@
|
|||||||
select="concat(substring-before($name, '::'), '__', substring-after($name, '::'))"/>
|
select="concat(substring-before($name, '::'), '__', substring-after($name, '::'))"/>
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
<xsl:when test="substring($name, string-length($name) - 1) = '<<'">
|
||||||
|
<xsl:call-template name="make-id">
|
||||||
|
<xsl:with-param name="name"
|
||||||
|
select="concat(substring-before($name, '<<'), '_ls_')"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:when test="substring($name, string-length($name) - 1) = '>>'">
|
||||||
|
<xsl:call-template name="make-id">
|
||||||
|
<xsl:with-param name="name"
|
||||||
|
select="concat(substring-before($name, '>>'), '_rs_')"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
<xsl:when test="contains($name, '=')">
|
<xsl:when test="contains($name, '=')">
|
||||||
<xsl:call-template name="make-id">
|
<xsl:call-template name="make-id">
|
||||||
<xsl:with-param name="name"
|
<xsl:with-param name="name"
|
||||||
@@ -270,10 +279,10 @@
|
|||||||
select="concat(substring-before($name, '*'), '_star_', substring-after($name, '*'))"/>
|
select="concat(substring-before($name, '*'), '_star_', substring-after($name, '*'))"/>
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="contains($name, '~')">
|
<xsl:when test="starts-with($name, '~')">
|
||||||
<xsl:call-template name="make-id">
|
<xsl:call-template name="make-id">
|
||||||
<xsl:with-param name="name"
|
<xsl:with-param name="name"
|
||||||
select="concat(substring-before($name, '~'), '_', substring-after($name, '~'))"/>
|
select="concat(substring-after($name, '~'), '_dtor_')"/>
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="contains($name, ' ')">
|
<xsl:when test="contains($name, ' ')">
|
||||||
@@ -1055,10 +1064,26 @@
|
|||||||
</xsl:for-each>
|
</xsl:for-each>
|
||||||
<xsl:text>]
</xsl:text>
|
<xsl:text>]
</xsl:text>
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
<xsl:if test="count(sectiondef[@kind='public-attrib' or @kind='public-static-attrib']) > 0">
|
<xsl:if test="count(sectiondef[@kind='public-static-attrib']) > 0">
|
||||||
|
<xsl:text>[heading Static Data Members]
</xsl:text>
|
||||||
|
<xsl:text>[table
 [[Name][Description]]
</xsl:text>
|
||||||
|
<xsl:for-each select="sectiondef[@kind='public-static-attrib']/memberdef" mode="class-table">
|
||||||
|
<xsl:sort select="name"/>
|
||||||
|
<xsl:text> [
</xsl:text>
|
||||||
|
<xsl:text> [[link beast.ref.</xsl:text>
|
||||||
|
<xsl:value-of select="$class-id"/>.<xsl:value-of select="name"/>
|
||||||
|
<xsl:text> [*</xsl:text>
|
||||||
|
<xsl:value-of select="name"/>
|
||||||
|
<xsl:text>]]]
 [
 </xsl:text>
|
||||||
|
<xsl:value-of select="briefdescription"/>
|
||||||
|
<xsl:text>
 ]
 ]
</xsl:text>
|
||||||
|
</xsl:for-each>
|
||||||
|
<xsl:text>]
</xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test="count(sectiondef[@kind='public-attrib']) > 0">
|
||||||
<xsl:text>[heading Data Members]
</xsl:text>
|
<xsl:text>[heading Data Members]
</xsl:text>
|
||||||
<xsl:text>[table
 [[Name][Description]]
</xsl:text>
|
<xsl:text>[table
 [[Name][Description]]
</xsl:text>
|
||||||
<xsl:for-each select="sectiondef[@kind='public-attrib' or @kind='public-static-attrib']/memberdef" mode="class-table">
|
<xsl:for-each select="sectiondef[@kind='public-attrib']/memberdef" mode="class-table">
|
||||||
<xsl:sort select="name"/>
|
<xsl:sort select="name"/>
|
||||||
<xsl:text> [
</xsl:text>
|
<xsl:text> [
</xsl:text>
|
||||||
<xsl:text> [[link beast.ref.</xsl:text>
|
<xsl:text> [[link beast.ref.</xsl:text>
|
||||||
@@ -1528,47 +1553,50 @@
|
|||||||
<xsl:text> </xsl:text>
|
<xsl:text> </xsl:text>
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
<xsl:when test="type = 'class AsyncStream'">
|
<xsl:when test="type = 'class AsyncStream'">
|
||||||
<xsl:text>class ``[link beast.types.streams.AsyncStream [*AsyncStream]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.streams.AsyncStream [*AsyncStream]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="type = 'class AsyncReadStream'">
|
<xsl:when test="type = 'class AsyncReadStream'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]``</xsl:text>
|
<xsl:text>class __AsyncReadStream__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="type = 'class AsyncWriteStream'">
|
<xsl:when test="type = 'class AsyncWriteStream'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]``</xsl:text>
|
<xsl:text>class __AsyncWriteStream__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="type = 'class Body'">
|
<xsl:when test="type = 'class Body'">
|
||||||
<xsl:text>class ``[link beast.types.Body [*Body]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.Body [*Body]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="type = 'class BufferSequence'">
|
<xsl:when test="type = 'class BufferSequence'">
|
||||||
<xsl:text>class ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="(type = 'class' or type = 'class...') and declname = 'BufferSequence'">
|
<xsl:when test="(type = 'class' or type = 'class...') and declname = 'BufferSequence'">
|
||||||
<xsl:value-of select="type"/>
|
<xsl:value-of select="type"/>
|
||||||
<xsl:text> ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
|
<xsl:text> ``[link beast.ref.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'CompletionHandler' or type = 'class CompletionHandler'">
|
<xsl:when test="declname = 'CompletionHandler' or type = 'class CompletionHandler'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]``</xsl:text>
|
<xsl:text>class __CompletionHandler__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'ConstBufferSequence' or type = 'class ConstBufferSequence'">
|
<xsl:when test="declname = 'ConstBufferSequence' or type = 'class ConstBufferSequence'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]``</xsl:text>
|
<xsl:text>class __ConstBufferSequence__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'DynamicBuffer' or type = 'class DynamicBuffer'">
|
<xsl:when test="declname = 'DynamicBuffer' or type = 'class DynamicBuffer'">
|
||||||
<xsl:text>class ``[link beast.types.DynamicBuffer [*DynamicBuffer]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.DynamicBuffer [*DynamicBuffer]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'MutableBufferSequence' or type = 'class MutableBufferSequence'">
|
<xsl:when test="declname = 'MutableBufferSequence' or type = 'class MutableBufferSequence'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]``</xsl:text>
|
<xsl:text>class __MutableBufferSequence__</xsl:text>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:when test="declname = 'Parser' or type = 'class Parser'">
|
||||||
|
<xsl:text>class ``[link beast.ref.Parser [*Parser]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'Stream' or type = 'class Stream'">
|
<xsl:when test="declname = 'Stream' or type = 'class Stream'">
|
||||||
<xsl:text>class ``[link beast.types.streams.Stream [*Stream]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.streams.Stream [*Stream]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="type = 'class SyncStream'">
|
<xsl:when test="type = 'class SyncStream'">
|
||||||
<xsl:text>class ``[link beast.types.streams.SyncStream [*SyncStream]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.streams.SyncStream [*SyncStream]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'SyncReadStream' or type = 'class SyncReadStream'">
|
<xsl:when test="declname = 'SyncReadStream' or type = 'class SyncReadStream'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]``</xsl:text>
|
<xsl:text>class __SyncReadStream__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'SyncWriteStream' or type = 'class SyncWriteStream'">
|
<xsl:when test="declname = 'SyncWriteStream' or type = 'class SyncWriteStream'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]``</xsl:text>
|
<xsl:text>class __SyncWriteStream__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
|
||||||
<xsl:when test="declname = 'T'">
|
<xsl:when test="declname = 'T'">
|
||||||
@@ -1682,6 +1710,14 @@
|
|||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
<xsl:text>```
</xsl:text>
|
<xsl:text>```
</xsl:text>
|
||||||
<xsl:for-each select="../memberdef[name = $unqualified-name]">
|
<xsl:for-each select="../memberdef[name = $unqualified-name]">
|
||||||
|
<xsl:if test="position() > 1">
|
||||||
|
<xsl:text>
</xsl:text>
|
||||||
|
<xsl:if test=" not(briefdescription = preceding-sibling::*/briefdescription)">
|
||||||
|
<xsl:text>```
</xsl:text>
|
||||||
|
<xsl:apply-templates select="briefdescription" mode="markup"/>
|
||||||
|
<xsl:text>```
</xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:if>
|
||||||
<xsl:variable name="stripped-type">
|
<xsl:variable name="stripped-type">
|
||||||
<xsl:call-template name="cleanup-type">
|
<xsl:call-template name="cleanup-type">
|
||||||
<xsl:with-param name="name" select="type"/>
|
<xsl:with-param name="name" select="type"/>
|
||||||
|
|||||||
@@ -107,52 +107,8 @@ INPUT = \
|
|||||||
../include/beast/core \
|
../include/beast/core \
|
||||||
../include/beast/http \
|
../include/beast/http \
|
||||||
../include/beast/websocket \
|
../include/beast/websocket \
|
||||||
../include/beast/doc_debug.hpp \
|
../include/beast/zlib \
|
||||||
|
../extras/beast/doc_debug.hpp
|
||||||
../include/beast/async_completion.hpp \
|
|
||||||
../include/beast/basic_streambuf.hpp \
|
|
||||||
../include/beast/bind_handler.hpp \
|
|
||||||
../include/beast/buffer_cat.hpp \
|
|
||||||
../include/beast/buffers_adapter.hpp \
|
|
||||||
../include/beast/consuming_buffers.hpp \
|
|
||||||
../include/beast/handler_alloc.hpp \
|
|
||||||
../include/beast/http.hpp \
|
|
||||||
../include/beast/placeholders.hpp \
|
|
||||||
../include/beast/prepare_buffers.hpp \
|
|
||||||
../include/beast/static_streambuf.hpp \
|
|
||||||
../include/beast/streambuf.hpp \
|
|
||||||
../include/beast/streambuf_readstream.hpp \
|
|
||||||
../include/beast/to_string.hpp \
|
|
||||||
../include/beast/type_check.hpp \
|
|
||||||
../include/beast/websocket.hpp \
|
|
||||||
../include/beast/write_streambuf.hpp \
|
|
||||||
../include/beast/http/basic_headers.hpp \
|
|
||||||
../include/beast/http/basic_parser_v1.hpp \
|
|
||||||
../include/beast/http/body_writer.hpp \
|
|
||||||
../include/beast/http/chunk_encode.hpp \
|
|
||||||
../include/beast/http/empty_body.hpp \
|
|
||||||
../include/beast/http/error.hpp \
|
|
||||||
../include/beast/http/fields.hpp \
|
|
||||||
../include/beast/http/headers.hpp \
|
|
||||||
../include/beast/http/message.hpp \
|
|
||||||
../include/beast/http/message_v1.hpp \
|
|
||||||
../include/beast/http/method.hpp \
|
|
||||||
../include/beast/http/parse_error.hpp \
|
|
||||||
../include/beast/http/parser.hpp \
|
|
||||||
../include/beast/http/read.hpp \
|
|
||||||
../include/beast/http/resume_context.hpp \
|
|
||||||
../include/beast/http/rfc2616.hpp \
|
|
||||||
../include/beast/http/streambuf_body.hpp \
|
|
||||||
../include/beast/http/string_body.hpp \
|
|
||||||
../include/beast/http/type_check.hpp \
|
|
||||||
../include/beast/http/write.hpp \
|
|
||||||
../include/beast/websocket/error.hpp \
|
|
||||||
../include/beast/websocket/option.hpp \
|
|
||||||
../include/beast/websocket/rfc6455.hpp \
|
|
||||||
../include/beast/websocket/ssl.hpp \
|
|
||||||
../include/beast/websocket/static_string.hpp \
|
|
||||||
../include/beast/websocket/stream.hpp \
|
|
||||||
../include/beast/websocket/teardown.hpp \
|
|
||||||
|
|
||||||
INPUT_ENCODING = UTF-8
|
INPUT_ENCODING = UTF-8
|
||||||
FILE_PATTERNS =
|
FILE_PATTERNS =
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:Body Body]
|
[section:Body Body requirements]
|
||||||
|
|
||||||
|
A [*Body] type is supplied as a template argument to the __message__ class. It
|
||||||
|
controls both the type of the data member of the resulting message object, and
|
||||||
|
the algorithms used during parsing and serialization.
|
||||||
|
|
||||||
In this table:
|
In this table:
|
||||||
|
|
||||||
@@ -22,17 +26,12 @@ In this table:
|
|||||||
will be not movable or not copyable.
|
will be not movable or not copyable.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
|
||||||
[`X:value_type{}`]
|
|
||||||
[]
|
|
||||||
[`DefaultConstructible`]
|
|
||||||
]
|
|
||||||
[
|
[
|
||||||
[`Body::reader`]
|
[`Body::reader`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
If present, a type meeting the requirements of
|
If present, a type meeting the requirements of
|
||||||
[link beast.types.Reader [*`Reader`]].
|
[link beast.ref.Reader [*`Reader`]].
|
||||||
Provides an implementation to parse the body.
|
Provides an implementation to parse the body.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@@ -41,7 +40,7 @@ In this table:
|
|||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
If present, a type meeting the requirements of
|
If present, a type meeting the requirements of
|
||||||
[link beast.types.Writer [*`Writer`]].
|
[link beast.ref.Writer [*`Writer`]].
|
||||||
Provides an implementation to serialize the body.
|
Provides an implementation to serialize the body.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:BufferSequence BufferSequence]
|
[section:BufferSequence BufferSequence requirements]
|
||||||
|
|
||||||
A `BufferSequence` is a type meeting either of the following requirements:
|
A `BufferSequence` is a type meeting either of the following requirements:
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:DynamicBuffer DynamicBuffer]
|
[section:DynamicBuffer DynamicBuffer requirements]
|
||||||
|
|
||||||
A dynamic buffer encapsulates memory storage that may be automatically resized
|
A dynamic buffer encapsulates memory storage that may be automatically resized
|
||||||
as required, where the memory is divided into an input sequence followed by an
|
as required, where the memory is divided into an input sequence followed by an
|
||||||
@@ -27,7 +27,7 @@ implementation strategies:
|
|||||||
|
|
||||||
* A sequence of one or more octet arrays of varying sizes. Additional octet
|
* A sequence of one or more octet arrays of varying sizes. Additional octet
|
||||||
array objects are appended to the sequence to accommodate changes in the
|
array objects are appended to the sequence to accommodate changes in the
|
||||||
size of the character sequence. This is the implementation approached
|
size of the character sequence. This is the implementation approach
|
||||||
currently offered by [link beast.ref.basic_streambuf `basic_streambuf`].
|
currently offered by [link beast.ref.basic_streambuf `basic_streambuf`].
|
||||||
|
|
||||||
In the table below:
|
In the table below:
|
||||||
@@ -88,7 +88,7 @@ In the table below:
|
|||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.prepare(n)`]
|
[`a.prepare(n)`]
|
||||||
[`X:mutable_buffers_type`]
|
[`X::mutable_buffers_type`]
|
||||||
[
|
[
|
||||||
Returns a mutable buffer sequence u representing the output sequence,
|
Returns a mutable buffer sequence u representing the output sequence,
|
||||||
and where `buffer_size(u) == n`. The dynamic buffer reallocates memory
|
and where `buffer_size(u) == n`. The dynamic buffer reallocates memory
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:Field Field]
|
[section:Field Field requirements]
|
||||||
|
|
||||||
A [*`Field`] represents a single HTTP header field/value pair.
|
A [*`Field`] represents a single HTTP header field/value pair.
|
||||||
|
|
||||||
|
|||||||
@@ -5,16 +5,17 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:FieldSequence FieldSequence]
|
[section:FieldSequence FieldSequence requirements]
|
||||||
|
|
||||||
A [*`FieldSequence`] is an iterable container whose value type meets
|
A [*FieldSequence] is an iterable container whose value type meets
|
||||||
the requirements of [link beast.types.Field [*`Field`]].
|
the requirements of [link beast.ref.Field [*Field]]. Objects that meet
|
||||||
|
these requirements become serializable by the implementation.
|
||||||
|
|
||||||
In this table:
|
In this table:
|
||||||
|
|
||||||
* `X` denotes a type that meets the requirements of [*`FieldSequence`].
|
* `X` denotes a type that meets the requirements of [*FieldSequence].
|
||||||
|
|
||||||
* `a` is a value of type `X`.
|
* `c` is a value of type `X const`.
|
||||||
|
|
||||||
[table FieldSequence requirements
|
[table FieldSequence requirements
|
||||||
[[operation][type][semantics, pre/post-conditions]]
|
[[operation][type][semantics, pre/post-conditions]]
|
||||||
@@ -22,25 +23,33 @@ In this table:
|
|||||||
[`X::value_type`]
|
[`X::value_type`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
A type that meets the requirements of `Field`.
|
A type that meets the requirements of [link beast.ref.Field [*Field]].
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`X::const_iterator`]
|
[`X::const_iterator`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
A type that meets the requirements of `ForwardIterator`.
|
An iterator type whose `reference` type meets the
|
||||||
|
requirements of [link beast.ref.Field [*Field]], and which
|
||||||
|
satisfies all the requirements of [*ForwardIterator],
|
||||||
|
except that:
|
||||||
|
|
||||||
|
[ordered_list
|
||||||
|
[there is no requirement that `operator->` is provided, and]
|
||||||
|
[there is no requirement that `reference` be a reference type.]
|
||||||
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.begin()`]
|
[`c.begin()`]
|
||||||
[`X::const_iterator`]
|
[`X::const_iterator`]
|
||||||
[
|
[
|
||||||
Returns an iterator to the beginning of the field sequence.
|
Returns an iterator to the beginning of the field sequence.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.end()`]
|
[`c.end()`]
|
||||||
[`X::const_iterator`]
|
[`X::const_iterator`]
|
||||||
[
|
[
|
||||||
Returns an iterator to the end of the field sequence.
|
Returns an iterator to the end of the field sequence.
|
||||||
|
|||||||
@@ -5,19 +5,22 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:Parser Parser]
|
[section:Parser Parser requirements]
|
||||||
|
|
||||||
A [*`Parser`] is used to deserialize HTTP/1 messages from [link beast.types.streams streams].
|
A [*Parser] is used to deserialize objects from
|
||||||
Objects of this type are used with [link beast.ref.http__parse http::parse] and
|
[link beast.ref.streams streams]. Objects of this type are used with
|
||||||
[link beast.ref.http__async_parse http::async_parse].
|
[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:
|
In this table:
|
||||||
|
|
||||||
* `X` denotes a type meeting the requirements of [*`Parser`].
|
* `X` denotes a type meeting the requirements of [*Parser].
|
||||||
|
|
||||||
* `a` denotes a value of type `X`.
|
* `a` denotes a value of type `X`.
|
||||||
|
|
||||||
* `b` is a value meeting the requirements of [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConvertibleToConstBuffer.html [*`ConvertibleToConstBuffer`]].
|
* `b` is a value meeting the requirements of __ConstBufferSequence__.
|
||||||
|
|
||||||
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
||||||
|
|
||||||
@@ -27,18 +30,18 @@ In this table:
|
|||||||
[`a.complete()`]
|
[`a.complete()`]
|
||||||
[`bool`]
|
[`bool`]
|
||||||
[
|
[
|
||||||
Returns `true` when a complete HTTP/1 message has been parsed.
|
Returns `true` when parsing is complete.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.write(b, ec)`]
|
[`a.write(b, ec)`]
|
||||||
[`std::size_t`]
|
[`std::size_t`]
|
||||||
[
|
[
|
||||||
Parses the octets in the specified input buffer sequentially until
|
Sequentially parses the octets in the specified input buffer sequence
|
||||||
an error occurs, the end of the buffer is reached, or a complete
|
until an error occurs, the end of the buffer is reached, or parsing is
|
||||||
HTTP/1 message has been parsed. If an error occurs, `ec` is set
|
complete. Upon success, this function returns the number of bytes used
|
||||||
to the error code and parsing stops. This function returns the
|
from the input. If an error occurs, `ec` is set to the error code and
|
||||||
number of bytes consumed from the input buffer.
|
parsing stops.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
@@ -48,9 +51,9 @@ In this table:
|
|||||||
Indicates to the parser that no more octets will be available.
|
Indicates to the parser that no more octets will be available.
|
||||||
Typically this function is called when the end of stream is reached.
|
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`
|
For example, if a call to `boost::asio::ip::tcp::socket::read_some`
|
||||||
generates a `boost::asio::error::eof` error. Some HTTP/1 messages
|
generates a `boost::asio::error::eof` error. Some objects, such as
|
||||||
determine the end of the message body by an end of file marker or
|
certain HTTP/1 messages, determine the end of the message body by
|
||||||
closing of the connection.
|
an end of file marker or closing of the connection.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:Reader Reader]
|
[section:Reader Reader requirements]
|
||||||
|
|
||||||
Parser implementations will construct the corresponding `reader` object
|
Parsers provided by the implementation will construct the corresponding
|
||||||
during the parse. This customization point allows the Body to determine
|
`reader` object during parsing. This customization point allows the
|
||||||
the strategy for storing incoming message body data.
|
Body to determine the strategy for storing incoming message body data.
|
||||||
|
|
||||||
In this table:
|
In this table:
|
||||||
|
|
||||||
@@ -17,15 +17,14 @@ In this table:
|
|||||||
|
|
||||||
* `a` denotes a value of type `X`.
|
* `a` denotes a value of type `X`.
|
||||||
|
|
||||||
* `p` is any pointer.
|
|
||||||
|
|
||||||
* `n` is a value convertible to `std::size_t`.
|
* `n` is a value convertible to `std::size_t`.
|
||||||
|
|
||||||
* `ec` is a value of type `error_code&`.
|
* `p` is a `void const*` to valid memory of at least `n` bytes.
|
||||||
|
|
||||||
* `m` denotes a value of type `message const&` where
|
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
||||||
`std::is_same<decltype(m.body), Body::value_type>:value == true`
|
|
||||||
|
|
||||||
|
* `m` denotes a value of type `message&` where
|
||||||
|
`std::is_same<decltype(m.body), Body::value_type>::value == true`.
|
||||||
|
|
||||||
[table Reader requirements
|
[table Reader requirements
|
||||||
[[operation] [type] [semantics, pre/post-conditions]]
|
[[operation] [type] [semantics, pre/post-conditions]]
|
||||||
@@ -33,22 +32,38 @@ In this table:
|
|||||||
[`X a(m);`]
|
[`X a(m);`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
`a` is constructible from `m`. The lifetime of `m` is
|
`a` is constructible from `m`. The lifetime of `m` is guaranteed
|
||||||
guaranteed to end no earlier than after `a` is destroyed.
|
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`.
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[
|
||||||
|
[`a.init(ec)`]
|
||||||
|
[`void`]
|
||||||
|
[
|
||||||
|
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`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.write(p, n, ec)`]
|
[`a.write(p, n, ec)`]
|
||||||
[`void`]
|
[`void`]
|
||||||
[
|
[
|
||||||
Deserializes the input sequence into the body.
|
Deserializes the input sequence into the body. If `ec` is set,
|
||||||
If `ec` is set, the deserialization is aborted and the error
|
the deserialization is aborted and the error is propagated to
|
||||||
is returned to the caller.
|
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`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
[note Definitions for required `Reader` member functions should be declared
|
[note
|
||||||
inline so the generated code becomes part of the implementation. ]
|
Definitions for required `Reader` member functions should be declared
|
||||||
|
inline so the generated code can become part of the implementation.
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:streams Streams]
|
[section:streams Streams requirements]
|
||||||
|
|
||||||
Stream types represent objects capable of performing synchronous or
|
Stream types represent objects capable of performing synchronous or
|
||||||
asynchronous I/O. They are based on concepts from `boost::asio`.
|
asynchronous I/O. They are based on concepts from `boost::asio`.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:Writer Writer]
|
[section:Writer Writer requirements]
|
||||||
|
|
||||||
A `Writer` serializes the message body. The implementation creates an instance
|
A `Writer` serializes the message body. The implementation creates an instance
|
||||||
of this type when serializing a message, and calls into it zero or more times
|
of this type when serializing a message, and calls into it zero or more times
|
||||||
@@ -28,13 +28,13 @@ In this table:
|
|||||||
* `m` denotes a value of type `message const&` where
|
* `m` denotes a value of type `message const&` where
|
||||||
`std::is_same<decltype(m.body), Body::value_type>:value == true`.
|
`std::is_same<decltype(m.body), Body::value_type>:value == true`.
|
||||||
|
|
||||||
* `rc` is an object of type [link beast.ref.http__resume_context resume_context].
|
* `rc` is an object of type [link beast.ref.http__resume_context `resume_context`].
|
||||||
|
|
||||||
* `ec` is a value of type `error_code&`.
|
* `ec` is a value of type [link beast.ref.error_code `error_code&`]
|
||||||
|
|
||||||
* `wf` is a [*write function]: a function object of unspecified type provided
|
* `wf` is a [*write function]: a function object of unspecified type provided
|
||||||
by the implementation which accepts any value meeting the requirements
|
by the implementation which accepts any value meeting the requirements
|
||||||
of `ConstBufferSequence` as its single parameter.
|
of __ConstBufferSequence__ as its single parameter.
|
||||||
|
|
||||||
[table Writer requirements
|
[table Writer requirements
|
||||||
[[operation] [type] [semantics, pre/post-conditions]]
|
[[operation] [type] [semantics, pre/post-conditions]]
|
||||||
@@ -42,17 +42,18 @@ In this table:
|
|||||||
[`X a(m);`]
|
[`X a(m);`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
`a` is constructible from `m`. The lifetime of `m` is
|
`a` is constructible from `m`. The lifetime of `m` is guaranteed
|
||||||
guaranteed to end no earlier than after `a` is destroyed.
|
to end no earlier than after `a` is destroyed. This function must
|
||||||
|
be `noexcept`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.init(ec)`]
|
[`a.init(ec)`]
|
||||||
[`void`]
|
[`void`]
|
||||||
[
|
[
|
||||||
Called immediately after construction.
|
Called immediately after construction. If the function sets an
|
||||||
If `ec` is set, the serialization is aborted and the error
|
error code in `ec`, the serialization is aborted and the error
|
||||||
is propagated to the caller.
|
is propagated to the caller. This function must be `noexcept`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
@@ -67,31 +68,33 @@ In this table:
|
|||||||
the serialized message body will be sent unmodified, with the
|
the serialized message body will be sent unmodified, with the
|
||||||
error `boost::asio::error::eof` returned to the caller, to notify
|
error `boost::asio::error::eof` returned to the caller, to notify
|
||||||
they should close the connection to indicate the end of the message.
|
they should close the connection to indicate the end of the message.
|
||||||
|
This function must be `noexcept`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a(rc, ec, wf)`]
|
[`a.write(rc, ec, wf)`]
|
||||||
[`boost::tribool`]
|
[`boost::tribool`]
|
||||||
[
|
[
|
||||||
Called repeatedly after `init` succeeds.
|
Called repeatedly after `init` succeeds. `wf` is a function object
|
||||||
`wf` is a function object which takes as its single parameter,
|
which takes as its single parameter any value meeting the requirements
|
||||||
any value meeting the requirements of `ConstBufferSequence`.
|
of __ConstBufferSequence__. Buffers provided to this write function
|
||||||
Buffers provided by the `writer` to this [*write function] must
|
must remain valid until the next member function of `writer` is
|
||||||
remain valid until the next member function of `writer` is
|
|
||||||
invoked (which may be the destructor). This function returns `true`
|
invoked (which may be the destructor). This function returns `true`
|
||||||
to indicate all message body data has been written, or `false`
|
to indicate all message body data has been written, or `false` if
|
||||||
if there is more body data. If the return value is
|
there is more body data. If the return value is `boost::indeterminate`,
|
||||||
`boost::indeterminate`, the implementation will suspend the operation
|
the implementation will suspend the operation until the writer invokes
|
||||||
until the writer invokes `rc`. It is the writers responsibility when
|
`rc`. It is the writers responsibility when returning
|
||||||
returning `boost::indeterminate`, to acquire ownership of the
|
`boost::indeterminate`, to acquire ownership of `rc` via move
|
||||||
`resume_context` via move construction and eventually call it or else
|
construction and eventually call it or else undefined behavior
|
||||||
undefined behavior results.
|
results. This function must be `noexcept`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
[note Definitions for required `Writer` member functions should be declared
|
[note
|
||||||
inline so the generated code becomes part of the implementation. ]
|
Definitions for required `Writer` member functions should be declared
|
||||||
|
inline so the generated code can become part of the implementation.
|
||||||
|
]
|
||||||
|
|
||||||
Exemplar:
|
Exemplar:
|
||||||
```
|
```
|
||||||
@@ -109,7 +112,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<bool isRequest, class Body, class Headers>
|
template<bool isRequest, class Body, class Headers>
|
||||||
explicit
|
explicit
|
||||||
writer(message<isRequest, Body, Headers> const& msg);
|
writer(message<isRequest, Body, Headers> const& msg) noexcept;
|
||||||
|
|
||||||
/** Initialize the writer.
|
/** Initialize the writer.
|
||||||
|
|
||||||
@@ -119,7 +122,7 @@ public:
|
|||||||
@param ec Contains the error code if any errors occur.
|
@param ec Contains the error code if any errors occur.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
init(error_code& ec);
|
init(error_code& ec) noexcept;
|
||||||
|
|
||||||
/** Returns the content length.
|
/** Returns the content length.
|
||||||
|
|
||||||
@@ -128,8 +131,8 @@ public:
|
|||||||
use chunk-encoding or terminate the connection to indicate the end
|
use chunk-encoding or terminate the connection to indicate the end
|
||||||
of the message.
|
of the message.
|
||||||
*/
|
*/
|
||||||
std::size_t
|
std::uint64_t
|
||||||
content_length() const;
|
content_length() noexcept;
|
||||||
|
|
||||||
/** Write zero or one buffer representing the message body.
|
/** Write zero or one buffer representing the message body.
|
||||||
|
|
||||||
@@ -172,7 +175,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<class WriteFunction>
|
template<class WriteFunction>
|
||||||
boost::tribool
|
boost::tribool
|
||||||
operator()(resume_context&&, error_code&, WriteFunction&& write);
|
write(
|
||||||
|
resume_context&&,
|
||||||
|
error_code&,
|
||||||
|
WriteFunction&& wf) noexcept;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,21 @@
|
|||||||
|
|
||||||
[section:websocket WebSocket]
|
[section:websocket WebSocket]
|
||||||
|
|
||||||
|
[block '''
|
||||||
|
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||||
|
<member><link linkend="beast.websocket.creation">Creation</link></member>
|
||||||
|
<member><link linkend="beast.websocket.connections">Making connections</link></member>
|
||||||
|
<member><link linkend="beast.websocket.handshaking">Handshaking</link></member>
|
||||||
|
<member><link linkend="beast.websocket.messages">Messages</link></member>
|
||||||
|
<member><link linkend="beast.websocket.frames">Frames</link></member>
|
||||||
|
<member><link linkend="beast.websocket.control">Control Frames</link></member>
|
||||||
|
<member><link linkend="beast.websocket.buffers">Buffers</link></member>
|
||||||
|
<member><link linkend="beast.websocket.async">Asynchronous interface</link></member>
|
||||||
|
<member><link linkend="beast.websocket.io_service">The io_service</link></member>
|
||||||
|
<member><link linkend="beast.websocket.threads">Thread Safety</link></member>
|
||||||
|
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||||
|
''']
|
||||||
|
|
||||||
The WebSocket Protocol enables two-way communication between a client
|
The WebSocket Protocol enables two-way communication between a client
|
||||||
running untrusted code in a controlled environment to a remote host that has
|
running untrusted code in a controlled environment to a remote host that has
|
||||||
opted-in to communications from that code. The protocol consists of an opening
|
opted-in to communications from that code. The protocol consists of an opening
|
||||||
@@ -22,48 +37,12 @@ C++ approach.
|
|||||||
The WebSocket protocol is described fully in
|
The WebSocket protocol is described fully in
|
||||||
[@https://tools.ietf.org/html/rfc6455 rfc6455]
|
[@https://tools.ietf.org/html/rfc6455 rfc6455]
|
||||||
|
|
||||||
|
[note
|
||||||
|
The following documentation assumes familiarity with both
|
||||||
|
Boost.Asio and the WebSocket protocol specification described in __rfc6455__.
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
[section:motivation Motivation]
|
|
||||||
|
|
||||||
Today's web applications increasingly rely on alternatives to standard HTTP
|
|
||||||
to achieve performance and/or responsiveness. While WebSocket implementations
|
|
||||||
are widely available in common web development languages such as Javascript,
|
|
||||||
good implementations in C++ are scarce. A survey of existing C++ WebSocket
|
|
||||||
solutions reveals interfaces which lack symmetry, impose performance penalties,
|
|
||||||
and needlessly restrict implementation strategies.
|
|
||||||
|
|
||||||
Beast.WebSocket is built on Boost.Asio, a robust cross platform networking
|
|
||||||
framework that is part of Boost and also offered as a standalone library.
|
|
||||||
A proposal to add networking functionality to the C++ standard library,
|
|
||||||
based on Boost.Asio, is under consideration by the standards committee.
|
|
||||||
Since the final approved networking interface for the C++ standard library
|
|
||||||
will likely closely resemble the current interface of Boost.Asio, it is
|
|
||||||
logical for Beast.WebSocket to use Boost.Asio as its network transport.
|
|
||||||
|
|
||||||
Beast.WebSocket takes advantage of Boost.Asio's extensible asynchronous
|
|
||||||
model, handler allocation, and handler invocation hooks. Calls to
|
|
||||||
Beast.WebSocket asynchronous initiation functions allow callers the choice
|
|
||||||
of using a completion handler, stackful or stackless coroutines, futures,
|
|
||||||
or user defined customizations (for example, Boost.Fiber). The
|
|
||||||
implementation uses handler invocation hooks
|
|
||||||
([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]),
|
|
||||||
providing execution guarantees on composed operations in a manner
|
|
||||||
identical to Boost.Asio. The implementation also uses handler allocation hooks
|
|
||||||
([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`])
|
|
||||||
when allocating memory internally for composed operations.
|
|
||||||
|
|
||||||
There is no need for inheritance or virtual members in a
|
|
||||||
[link beast.ref.websocket__stream `beast::websocket::stream`].
|
|
||||||
All operations are templated and transparent to the compiler, allowing for
|
|
||||||
maximum inlining and optimization.
|
|
||||||
|
|
||||||
[note The documentation which follows assumes familiarity with
|
|
||||||
both Boost.Asio and the WebSocket protocol specification described in
|
|
||||||
[@https://tools.ietf.org/html/rfc6455 rfc6455] ]
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:creation Creation]
|
[section:creation Creation]
|
||||||
@@ -71,15 +50,15 @@ both Boost.Asio and the WebSocket protocol specification described in
|
|||||||
The interface to Beast's WebSocket implementation is a single template
|
The interface to Beast's WebSocket implementation is a single template
|
||||||
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
|
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
|
||||||
wraps a "next layer" object. The next layer object must meet the requirements
|
wraps a "next layer" object. The next layer object must meet the requirements
|
||||||
of [link beast.types.streams.SyncStream [*`SyncReadStream`]] if synchronous
|
of [link beast.ref.streams.SyncStream [*`SyncReadStream`]] if synchronous
|
||||||
operations are performed, or
|
operations are performed, or
|
||||||
[link beast.types.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
[link beast.ref.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
||||||
operations are performed, or both. Arguments supplied during construction are
|
operations are performed, or both. Arguments supplied during construction are
|
||||||
passed to next layer's constructor. Here we declare a websocket stream over
|
passed to next layer's constructor. Here we declare a websocket stream over
|
||||||
a TCP/IP socket with ownership of the socket:
|
a TCP/IP socket with ownership of the socket:
|
||||||
```
|
```
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||||
```
|
```
|
||||||
|
|
||||||
[heading Using SSL]
|
[heading Using SSL]
|
||||||
@@ -92,8 +71,8 @@ argument when constructing the stream.
|
|||||||
#include <boost/asio/ssl.hpp>
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
|
||||||
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ws(ios, ctx);
|
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ws{ios, ctx};
|
||||||
```
|
```
|
||||||
|
|
||||||
[note
|
[note
|
||||||
@@ -108,7 +87,7 @@ to wrap an object that already exists. This socket can be moved in:
|
|||||||
```
|
```
|
||||||
boost::asio::ip::tcp::socket&& sock;
|
boost::asio::ip::tcp::socket&& sock;
|
||||||
...
|
...
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(std::move(sock));
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{std::move(sock)};
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, the wrapper can be constructed with a non-owning reference. In
|
Or, the wrapper can be constructed with a non-owning reference. In
|
||||||
@@ -117,35 +96,37 @@ underlying socket being wrapped:
|
|||||||
```
|
```
|
||||||
boost::asio::ip::tcp::socket sock;
|
boost::asio::ip::tcp::socket sock;
|
||||||
...
|
...
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
```
|
```
|
||||||
|
|
||||||
The layer being wrapped can be accessed through the websocket's "next layer",
|
The layer being wrapped can be accessed through the websocket's "next layer",
|
||||||
permitting callers to interact directly with its interface.
|
permitting callers to interact directly with its interface.
|
||||||
```
|
```
|
||||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
|
||||||
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws(ios, ctx);
|
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws{ios, ctx};
|
||||||
...
|
...
|
||||||
ws.next_layer().shutdown(); // ssl::stream shutdown
|
ws.next_layer().shutdown(); // ssl::stream shutdown
|
||||||
```
|
```
|
||||||
|
|
||||||
[important Initiating read and write operations on the next layer while
|
[warning
|
||||||
websocket operations are being performed can break invariants, and
|
Initiating read and write operations on the next layer while
|
||||||
result in undefined behavior. ]
|
stream operations are being performed can break invariants, and
|
||||||
|
result in undefined behavior.
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:connecting Making connections]
|
[section:connections Making connections]
|
||||||
|
|
||||||
Connections are established by using the interfaces which already exist
|
Connections are established by using the interfaces which already exist
|
||||||
for the next layer. For example, making an outgoing connection:
|
for the next layer. For example, making an outgoing connection:
|
||||||
```
|
```
|
||||||
std::string const host = "mywebapp.com";
|
std::string const host = "mywebapp.com";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||||
boost::asio::connect(ws.next_layer(),
|
boost::asio::connect(ws.next_layer(),
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"}));
|
||||||
```
|
```
|
||||||
@@ -154,12 +135,14 @@ Accepting an incoming connection:
|
|||||||
```
|
```
|
||||||
void do_accept(boost::asio::ip::tcp::acceptor& acceptor)
|
void do_accept(boost::asio::ip::tcp::acceptor& acceptor)
|
||||||
{
|
{
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(acceptor.get_io_service());
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{acceptor.get_io_service()};
|
||||||
acceptor.accept(ws.next_layer());
|
acceptor.accept(ws.next_layer());
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[note Examples use synchronous interfaces for clarity of exposition. ]
|
[note
|
||||||
|
Examples use synchronous interfaces for clarity of exposition.
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -171,16 +154,17 @@ A WebSocket session begins when one side sends the HTTP Upgrade request
|
|||||||
for websocket, and the other side sends an appropriate HTTP response
|
for websocket, and the other side sends an appropriate HTTP response
|
||||||
indicating that the request was accepted and that the connection has
|
indicating that the request was accepted and that the connection has
|
||||||
been upgraded. The HTTP Upgrade request must include the Host HTTP field,
|
been upgraded. The HTTP Upgrade request must include the Host HTTP field,
|
||||||
and the URI of the resource to request. `handshake` is used to send the
|
and the URI of the resource to request.
|
||||||
|
[link beast.ref.websocket__stream.handshake `handshake`] is used to send the
|
||||||
request with the required host and resource strings.
|
request with the required host and resource strings.
|
||||||
```
|
```
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||||
...
|
...
|
||||||
ws.set_option(beast::websocket::keep_alive(true));
|
ws.set_option(beast::websocket::keep_alive(true));
|
||||||
ws.handshake("ws.example.com:80", "/cgi-bin/bitcoin-prices");
|
ws.handshake("ws.example.com:80", "/cgi-bin/bitcoin-prices");
|
||||||
```
|
```
|
||||||
|
|
||||||
The [link beast.ref.websocket__stream `beast::websocket::stream`] automatically
|
The [link beast.ref.websocket__stream `stream`] automatically
|
||||||
handles receiving and processing the HTTP response to the handshake request.
|
handles receiving and processing the HTTP response to the handshake request.
|
||||||
The call to handshake is successful if a HTTP response is received with the
|
The call to handshake is successful if a HTTP response is received with the
|
||||||
101 "Switching Protocols" status code. On failure, an error is returned or an
|
101 "Switching Protocols" status code. On failure, an error is returned or an
|
||||||
@@ -190,7 +174,7 @@ open for a subsequent handshake attempt
|
|||||||
Performing a handshake for an incoming websocket upgrade request operates
|
Performing a handshake for an incoming websocket upgrade request operates
|
||||||
similarly. If the handshake fails, an error is returned or exception thrown:
|
similarly. If the handshake fails, an error is returned or exception thrown:
|
||||||
```
|
```
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||||
...
|
...
|
||||||
ws.accept();
|
ws.accept();
|
||||||
```
|
```
|
||||||
@@ -205,7 +189,7 @@ void do_accept(boost::asio::ip::tcp::socket& sock)
|
|||||||
boost::asio::streambuf sb;
|
boost::asio::streambuf sb;
|
||||||
boost::asio::read_until(sock, sb, "\r\n\r\n");
|
boost::asio::read_until(sock, sb, "\r\n\r\n");
|
||||||
...
|
...
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
ws.accept(sb.data());
|
ws.accept(sb.data());
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
@@ -218,10 +202,10 @@ void do_accept(boost::asio::ip::tcp::socket& sock)
|
|||||||
{
|
{
|
||||||
boost::asio::streambuf sb;
|
boost::asio::streambuf sb;
|
||||||
beast::http::request<http::empty_body> request;
|
beast::http::request<http::empty_body> request;
|
||||||
beast::http::read(sock, request);
|
beast::http::read(sock, sb, request);
|
||||||
if(beast::http::is_upgrade(request))
|
if(beast::http::is_upgrade(request))
|
||||||
{
|
{
|
||||||
websocket::stream<ip::tcp::socket&> ws(sock);
|
websocket::stream<ip::tcp::socket&> ws{sock};
|
||||||
ws.accept(request);
|
ws.accept(request);
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
@@ -242,17 +226,19 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
|||||||
{
|
{
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
beast::websocket::opcode::value op;
|
beast::websocket::opcode::value op;
|
||||||
ws.read(sb);
|
ws.read(op, sb);
|
||||||
|
|
||||||
ws.set_option(beast::websocket::message_type(op));
|
ws.set_option(beast::websocket::message_type{op});
|
||||||
ws.write(sb.data());
|
ws.write(sb.data());
|
||||||
sb.consume(sb.size());
|
sb.consume(sb.size());
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[important Calls to [link beast.ref.websocket__stream.set_option `set_option`]
|
[important
|
||||||
must be made from the same implicit or explicit strand as that used to perform
|
Calls to [link beast.ref.websocket__stream.set_option `set_option`]
|
||||||
other operations. ]
|
must be made from the same implicit or explicit strand as that used
|
||||||
|
to perform other operations.
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -280,9 +266,9 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
|||||||
if(fi.fin)
|
if(fi.fin)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ws.set_option(beast::websocket::message_type(fi.op));
|
ws.set_option(beast::websocket::message_type{fi.op});
|
||||||
beast::consuming_buffers<
|
beast::consuming_buffers<
|
||||||
beast::streambuf::const_buffers_type> cb(sb.data());
|
beast::streambuf::const_buffers_type> cb{sb.data()};
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
@@ -305,46 +291,49 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:controlframes Control frames]
|
[section:control Control Frames]
|
||||||
|
|
||||||
During read operations, the implementation automatically reads and processes
|
Control frames are small (less than 128 bytes) messages entirely contained
|
||||||
WebSocket control frames such as ping, pong, and close. Pings are replied
|
in an individual WebSocket frame. They may be sent at any time by either
|
||||||
to as soon as possible, pongs are delivered to the pong callback. The receipt
|
peer on an established connection, and can appear in between continuation
|
||||||
of a close frame initiates the WebSocket close procedure, eventually resulting
|
frames for a message. There are three types of control frames: ping, pong,
|
||||||
in the error code [link beast.ref.websocket__error `error::closed`] being
|
and close.
|
||||||
delivered to the caller in a subsequent read operation, assuming no other error
|
|
||||||
|
A sent ping indicates a request that the sender wants to receive a pong. A
|
||||||
|
pong is a response to a ping. Pongs may be sent unsolicited, at any time.
|
||||||
|
One use for an unsolicited pong is to inform the remote peer that the
|
||||||
|
session is still active after a long period of inactivity. A close frame
|
||||||
|
indicates that the remote peer wishes to close the WebSocket connection.
|
||||||
|
The connection is considered gracefully closed when each side has sent
|
||||||
|
and received a close frame.
|
||||||
|
|
||||||
|
During read operations, Beast automatically reads and processes control
|
||||||
|
frames. Pings are replied to as soon as possible with a pong, received
|
||||||
|
pongs are delivered to the pong callback. The receipt of a close frame
|
||||||
|
initiates the WebSocket close procedure, eventually resulting in the error
|
||||||
|
code [link beast.ref.websocket__error `error::closed`] being delivered
|
||||||
|
to the caller in a subsequent read operation, assuming no other error
|
||||||
takes place.
|
takes place.
|
||||||
|
|
||||||
To ensure timely delivery of control frames, large messages are broken up
|
A consequence of this automatic behavior is that caller-initiated read
|
||||||
into smaller sized frames. The implementation chooses the size and number
|
operations can cause socket writes. However, these writes will not
|
||||||
of the frames making up the message. The automatic fragment size option
|
compete with caller-initiated write operations. For the purposes of
|
||||||
gives callers control over the size of these frames:
|
correctness with respect to the stream invariants, caller-initiated
|
||||||
```
|
read operations still only count as a read. This means that callers can
|
||||||
...
|
have a simultaneous active read and write operation in progress, while
|
||||||
ws.set_option(beast::websocket::auto_fragment_size(8192));
|
the implementation also automatically handles control frames.
|
||||||
```
|
|
||||||
|
|
||||||
The WebSocket protocol defines a procedure and control message for initiating
|
[heading Ping and Pong Frames]
|
||||||
a close of the session. Handling of close initiated by the remote end of the
|
|
||||||
connection is performed automatically. To manually initiate a close, use
|
|
||||||
[link beast.ref.websocket__stream.close `close`]:
|
|
||||||
```
|
|
||||||
ws.close();
|
|
||||||
```
|
|
||||||
|
|
||||||
[note To receive the [link beast.ref.websocket__error `error::closed`]
|
Ping and pong messages are control frames which may be sent at any time
|
||||||
error, a read operation is required. ]
|
by either peer on an established WebSocket connection. They are sent
|
||||||
|
using the functions
|
||||||
[endsect]
|
[link beast.ref.websocket__stream.ping `ping`] and
|
||||||
|
[link beast.ref.websocket__stream.pong `pong`].
|
||||||
|
|
||||||
|
|
||||||
[section:pongs Pong messages]
|
|
||||||
|
|
||||||
To receive pong control frames, callers may register a "pong callback" using
|
To receive pong control frames, callers may register a "pong callback" using
|
||||||
[link beast.ref.websocket__stream.set_option `set_option`]:
|
[link beast.ref.websocket__stream.set_option `set_option`]. The object provided
|
||||||
|
with this option should be callable with the following signature:
|
||||||
the following signature:
|
|
||||||
```
|
```
|
||||||
void on_pong(ping_data const& payload);
|
void on_pong(ping_data const& payload);
|
||||||
...
|
...
|
||||||
@@ -361,9 +350,47 @@ reset when a pong is received. The same callback is used for both synchronous
|
|||||||
and asynchronous reads. The pong callback is passive; in order to receive
|
and asynchronous reads. The pong callback is passive; in order to receive
|
||||||
pongs, a synchronous or asynchronous stream read function must be active.
|
pongs, a synchronous or asynchronous stream read function must be active.
|
||||||
|
|
||||||
[note When an asynchronous read function receives a pong, the the pong callback
|
[note
|
||||||
is invoked in the same manner as that used to invoke the final completion
|
When an asynchronous read function receives a pong, the the pong
|
||||||
handler of the corresponding read function.]
|
callback is invoked in the same manner as that used to invoke the
|
||||||
|
final completion handler of the corresponding read function.
|
||||||
|
]
|
||||||
|
|
||||||
|
[heading Close Frames]
|
||||||
|
|
||||||
|
The WebSocket protocol defines a procedure and control message for initiating
|
||||||
|
a close of the session. Handling of close initiated by the remote end of the
|
||||||
|
connection is performed automatically. To manually initiate a close, use
|
||||||
|
the [link beast.ref.websocket__stream.close `close`] function:
|
||||||
|
```
|
||||||
|
ws.close();
|
||||||
|
```
|
||||||
|
|
||||||
|
When the remote peer initiates a close by sending a close frame, Beast
|
||||||
|
will handle it for you by causing the next read to return `error::closed`.
|
||||||
|
When this error code is delivered, it indicates to the application that
|
||||||
|
the WebSocket connection has been closed cleanly, and that the TCP/IP
|
||||||
|
connection has been closed. After initiating a close, it is necessary to
|
||||||
|
continue reading messages until receiving the error `error::closed`. This
|
||||||
|
is because the remote peer may still be sending message and control frames
|
||||||
|
before it receives and responds to the close frame.
|
||||||
|
|
||||||
|
[important
|
||||||
|
To receive the [link beast.ref.websocket__error `error::closed`]
|
||||||
|
error, a read operation is required.
|
||||||
|
]
|
||||||
|
|
||||||
|
[heading Auto-fragment]
|
||||||
|
|
||||||
|
To ensure timely delivery of control frames, large messages can be broken up
|
||||||
|
into smaller sized frames. The automatic fragment option turns on this
|
||||||
|
feature, and the write buffer size option determines the maximum size of
|
||||||
|
the fragments:
|
||||||
|
```
|
||||||
|
...
|
||||||
|
ws.set_option(beast::websocket::auto_fragment{true});
|
||||||
|
ws.set_option(beast::websocket::write_buffer_size{16384});
|
||||||
|
```
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -373,7 +400,7 @@ handler of the corresponding read function.]
|
|||||||
|
|
||||||
Because calls to read data may return a variable amount of bytes, the
|
Because calls to read data may return a variable amount of bytes, the
|
||||||
interface to calls that read data require an object that meets the requirements
|
interface to calls that read data require an object that meets the requirements
|
||||||
of [link beast.types.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on
|
of [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on
|
||||||
[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
|
[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
|
||||||
|
|
||||||
The implementation does not perform queueing or buffering of messages. If
|
The implementation does not perform queueing or buffering of messages. If
|
||||||
@@ -429,7 +456,7 @@ use or require threads.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:safety Thread Safety]
|
[section:threads Thread Safety]
|
||||||
|
|
||||||
Like a regular asio socket, a [link beast.ref.websocket__stream `stream`] is
|
Like a regular asio socket, a [link beast.ref.websocket__stream `stream`] is
|
||||||
not thread safe. Callers are responsible for synchronizing operations on the
|
not thread safe. Callers are responsible for synchronizing operations on the
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
#
|
#
|
||||||
|
|
||||||
import os ;
|
|
||||||
|
|
||||||
exe http-crawl :
|
exe http-crawl :
|
||||||
http_crawl.cpp
|
http_crawl.cpp
|
||||||
urls_large_data.cpp
|
urls_large_data.cpp
|
||||||
@@ -23,4 +21,3 @@ exe http-example :
|
|||||||
exe websocket-example :
|
exe websocket-example :
|
||||||
websocket_example.cpp
|
websocket_example.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -8,9 +8,12 @@
|
|||||||
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||||
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/http/body_type.hpp>
|
#include <beast/core/error.hpp>
|
||||||
|
#include <beast/http/message.hpp>
|
||||||
|
#include <beast/http/resume_context.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/logic/tribool.hpp>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@@ -34,8 +37,8 @@ struct file_body
|
|||||||
writer(writer const&) = delete;
|
writer(writer const&) = delete;
|
||||||
writer& operator=(writer const&) = delete;
|
writer& operator=(writer const&) = delete;
|
||||||
|
|
||||||
template<bool isRequest, class Headers>
|
template<bool isRequest, class Fields>
|
||||||
writer(message<isRequest, file_body, Headers> const& m) noexcept
|
writer(message<isRequest, file_body, Fields> const& m) noexcept
|
||||||
: path_(m.body)
|
: path_(m.body)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -58,14 +61,15 @@ struct file_body
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t
|
std::uint64_t
|
||||||
content_length() const
|
content_length() const noexcept
|
||||||
{
|
{
|
||||||
return size_;
|
return size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Write>
|
template<class WriteFunction>
|
||||||
boost::tribool
|
boost::tribool
|
||||||
operator()(resume_context&&, error_code&, Write&& write)
|
write(resume_context&&, error_code&,
|
||||||
|
WriteFunction&& wf) noexcept
|
||||||
{
|
{
|
||||||
if(size_ - offset_ < sizeof(buf_))
|
if(size_ - offset_ < sizeof(buf_))
|
||||||
buf_len_ = static_cast<std::size_t>(
|
buf_len_ = static_cast<std::size_t>(
|
||||||
@@ -75,7 +79,7 @@ struct file_body
|
|||||||
auto const nread = fread(buf_, 1, sizeof(buf_), file_);
|
auto const nread = fread(buf_, 1, sizeof(buf_), file_);
|
||||||
(void)nread;
|
(void)nread;
|
||||||
offset_ += buf_len_;
|
offset_ += buf_len_;
|
||||||
write(boost::asio::buffer(buf_, buf_len_));
|
wf(boost::asio::buffer(buf_, buf_len_));
|
||||||
return offset_ >= size_;
|
return offset_ >= size_;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
#include "mime_type.hpp"
|
#include "mime_type.hpp"
|
||||||
|
|
||||||
#include <beast/http.hpp>
|
#include <beast/http.hpp>
|
||||||
|
#include <beast/core/handler_helpers.hpp>
|
||||||
|
#include <beast/core/handler_ptr.hpp>
|
||||||
#include <beast/core/placeholders.hpp>
|
#include <beast/core/placeholders.hpp>
|
||||||
#include <beast/core/streambuf.hpp>
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
@@ -32,8 +34,8 @@ class http_async_server
|
|||||||
using address_type = boost::asio::ip::address;
|
using address_type = boost::asio::ip::address;
|
||||||
using socket_type = boost::asio::ip::tcp::socket;
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
using req_type = request_v1<string_body>;
|
using req_type = request<string_body>;
|
||||||
using resp_type = response_v1<file_body>;
|
using resp_type = response<file_body>;
|
||||||
|
|
||||||
std::mutex m_;
|
std::mutex m_;
|
||||||
bool log_ = true;
|
bool log_ = true;
|
||||||
@@ -85,32 +87,26 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template<class Stream, class Handler,
|
template<class Stream, class Handler,
|
||||||
bool isRequest, class Body, class Headers>
|
bool isRequest, class Body, class Fields>
|
||||||
class write_op
|
class write_op
|
||||||
{
|
{
|
||||||
using alloc_type =
|
|
||||||
handler_alloc<char, Handler>;
|
|
||||||
|
|
||||||
struct data
|
struct data
|
||||||
{
|
{
|
||||||
Stream& s;
|
|
||||||
message_v1<isRequest, Body, Headers> m;
|
|
||||||
Handler h;
|
|
||||||
bool cont;
|
bool cont;
|
||||||
|
Stream& s;
|
||||||
|
message<isRequest, Body, Fields> m;
|
||||||
|
|
||||||
template<class DeducedHandler>
|
data(Handler& handler, Stream& s_,
|
||||||
data(DeducedHandler&& h_, Stream& s_,
|
message<isRequest, Body, Fields>&& m_)
|
||||||
message_v1<isRequest, Body, Headers>&& m_)
|
: cont(beast_asio_helpers::
|
||||||
: s(s_)
|
is_continuation(handler))
|
||||||
|
, s(s_)
|
||||||
, m(std::move(m_))
|
, m(std::move(m_))
|
||||||
, h(std::forward<DeducedHandler>(h_))
|
|
||||||
, cont(boost_asio_handler_cont_helpers::
|
|
||||||
is_continuation(h))
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<data> d_;
|
handler_ptr<data, Handler> d_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
write_op(write_op&&) = default;
|
write_op(write_op&&) = default;
|
||||||
@@ -118,7 +114,7 @@ private:
|
|||||||
|
|
||||||
template<class DeducedHandler, class... Args>
|
template<class DeducedHandler, class... Args>
|
||||||
write_op(DeducedHandler&& h, Stream& s, Args&&... args)
|
write_op(DeducedHandler&& h, Stream& s, Args&&... args)
|
||||||
: d_(std::allocate_shared<data>(alloc_type{h},
|
: d_(make_handler_ptr<data, Handler>(
|
||||||
std::forward<DeducedHandler>(h), s,
|
std::forward<DeducedHandler>(h), s,
|
||||||
std::forward<Args>(args)...))
|
std::forward<Args>(args)...))
|
||||||
{
|
{
|
||||||
@@ -135,23 +131,23 @@ private:
|
|||||||
beast::http::async_write(d.s, d.m, std::move(*this));
|
beast::http::async_write(d.s, d.m, std::move(*this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
d.h(ec);
|
d_.invoke(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
void* asio_handler_allocate(
|
void* asio_handler_allocate(
|
||||||
std::size_t size, write_op* op)
|
std::size_t size, write_op* op)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_alloc_helpers::
|
return beast_asio_helpers::
|
||||||
allocate(size, op->d_->h);
|
allocate(size, op->d_.handler());
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
void asio_handler_deallocate(
|
void asio_handler_deallocate(
|
||||||
void* p, std::size_t size, write_op* op)
|
void* p, std::size_t size, write_op* op)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_alloc_helpers::
|
return beast_asio_helpers::
|
||||||
deallocate(p, size, op->d_->h);
|
deallocate(p, size, op->d_.handler());
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
@@ -164,22 +160,22 @@ private:
|
|||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, write_op* op)
|
void asio_handler_invoke(Function&& f, write_op* op)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_invoke_helpers::
|
return beast_asio_helpers::
|
||||||
invoke(f, op->d_->h);
|
invoke(f, op->d_.handler());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Stream,
|
template<class Stream,
|
||||||
bool isRequest, class Body, class Headers,
|
bool isRequest, class Body, class Fields,
|
||||||
class DeducedHandler>
|
class DeducedHandler>
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
async_write(Stream& stream, message_v1<
|
async_write(Stream& stream, message<
|
||||||
isRequest, Body, Headers>&& msg,
|
isRequest, Body, Fields>&& msg,
|
||||||
DeducedHandler&& handler)
|
DeducedHandler&& handler)
|
||||||
{
|
{
|
||||||
write_op<Stream, typename std::decay<DeducedHandler>::type,
|
write_op<Stream, typename std::decay<DeducedHandler>::type,
|
||||||
isRequest, Body, Headers>{std::forward<DeducedHandler>(
|
isRequest, Body, Fields>{std::forward<DeducedHandler>(
|
||||||
handler), stream, std::move(msg)};
|
handler), stream, std::move(msg)};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,12 +232,12 @@ private:
|
|||||||
path = server_.root_ + path;
|
path = server_.root_ + path;
|
||||||
if(! boost::filesystem::exists(path))
|
if(! boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
response_v1<string_body> res;
|
response<string_body> res;
|
||||||
res.status = 404;
|
res.status = 404;
|
||||||
res.reason = "Not Found";
|
res.reason = "Not Found";
|
||||||
res.version = req_.version;
|
res.version = req_.version;
|
||||||
res.headers.insert("Server", "http_async_server");
|
res.fields.insert("Server", "http_async_server");
|
||||||
res.headers.insert("Content-Type", "text/html");
|
res.fields.insert("Content-Type", "text/html");
|
||||||
res.body = "The file '" + path + "' was not found";
|
res.body = "The file '" + path + "' was not found";
|
||||||
prepare(res);
|
prepare(res);
|
||||||
async_write(sock_, std::move(res),
|
async_write(sock_, std::move(res),
|
||||||
@@ -249,33 +245,36 @@ private:
|
|||||||
asio::placeholders::error));
|
asio::placeholders::error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
resp_type res;
|
resp_type res;
|
||||||
res.status = 200;
|
res.status = 200;
|
||||||
res.reason = "OK";
|
res.reason = "OK";
|
||||||
res.version = req_.version;
|
res.version = req_.version;
|
||||||
res.headers.insert("Server", "http_async_server");
|
res.fields.insert("Server", "http_async_server");
|
||||||
res.headers.insert("Content-Type", mime_type(path));
|
res.fields.insert("Content-Type", mime_type(path));
|
||||||
res.body = path;
|
res.body = path;
|
||||||
try
|
|
||||||
{
|
|
||||||
prepare(res);
|
prepare(res);
|
||||||
}
|
|
||||||
catch(std::exception const& e)
|
|
||||||
{
|
|
||||||
res = {};
|
|
||||||
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.body =
|
|
||||||
std::string{"An internal error occurred"} + e.what();
|
|
||||||
prepare(res);
|
|
||||||
}
|
|
||||||
async_write(sock_, std::move(res),
|
async_write(sock_, std::move(res),
|
||||||
std::bind(&peer::on_write, shared_from_this(),
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
asio::placeholders::error));
|
asio::placeholders::error));
|
||||||
}
|
}
|
||||||
|
catch(std::exception const& e)
|
||||||
|
{
|
||||||
|
response<string_body> res;
|
||||||
|
res.status = 500;
|
||||||
|
res.reason = "Internal Error";
|
||||||
|
res.version = req_.version;
|
||||||
|
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);
|
||||||
|
async_write(sock_, std::move(res),
|
||||||
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
|
asio::placeholders::error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void on_write(error_code ec)
|
void on_write(error_code ec)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <beast/core/streambuf.hpp>
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <beast/http.hpp>
|
#include <beast/http.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace beast::http;
|
using namespace beast::http;
|
||||||
@@ -35,21 +36,21 @@ int main(int, char const*[])
|
|||||||
ip::tcp::socket sock(ios);
|
ip::tcp::socket sock(ios);
|
||||||
connect(sock, it);
|
connect(sock, it);
|
||||||
auto ep = sock.remote_endpoint();
|
auto ep = sock.remote_endpoint();
|
||||||
request_v1<empty_body> req;
|
request<empty_body> req;
|
||||||
req.method = "GET";
|
req.method = "GET";
|
||||||
req.url = "/";
|
req.url = "/";
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.headers.insert("Host", host +
|
req.fields.insert("Host", host + std::string(":") +
|
||||||
std::string(":") + std::to_string(ep.port()));
|
boost::lexical_cast<std::string>(ep.port()));
|
||||||
req.headers.insert("User-Agent", "beast/http");
|
req.fields.insert("User-Agent", "beast/http");
|
||||||
prepare(req);
|
prepare(req);
|
||||||
write(sock, req);
|
write(sock, req);
|
||||||
response_v1<string_body> res;
|
response<string_body> res;
|
||||||
streambuf sb;
|
streambuf sb;
|
||||||
beast::http::read(sock, sb, res);
|
beast::http::read(sock, sb, res);
|
||||||
std::cout << res;
|
std::cout << res;
|
||||||
}
|
}
|
||||||
catch(boost::system::system_error const& ec)
|
catch(beast::system_error const& ec)
|
||||||
{
|
{
|
||||||
std::cerr << host << ": " << ec.what();
|
std::cerr << host << ": " << ec.what();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <beast/http.hpp>
|
#include <beast/http.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -21,18 +22,19 @@ int main()
|
|||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
// Send HTTP request using beast
|
// Send HTTP request using beast
|
||||||
beast::http::request_v1<beast::http::empty_body> req;
|
beast::http::request<beast::http::empty_body> req;
|
||||||
req.method = "GET";
|
req.method = "GET";
|
||||||
req.url = "/";
|
req.url = "/";
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
req.fields.replace("Host", host + ":" +
|
||||||
req.headers.replace("User-Agent", "Beast");
|
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||||
|
req.fields.replace("User-Agent", "Beast");
|
||||||
beast::http::prepare(req);
|
beast::http::prepare(req);
|
||||||
beast::http::write(sock, req);
|
beast::http::write(sock, req);
|
||||||
|
|
||||||
// Receive and print HTTP response using beast
|
// Receive and print HTTP response using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
beast::http::response<beast::http::streambuf_body> resp;
|
||||||
beast::http::read(sock, sb, resp);
|
beast::http::read(sock, sb, resp);
|
||||||
std::cout << resp;
|
std::cout << resp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,34 +20,26 @@ int main(int ac, char const* av[])
|
|||||||
po::options_description desc("Options");
|
po::options_description desc("Options");
|
||||||
|
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
("root,r", po::value<std::string>()->implicit_value("."),
|
("root,r", po::value<std::string>()->default_value("."),
|
||||||
"Set the root directory for serving files")
|
"Set the root directory for serving files")
|
||||||
("port,p", po::value<std::uint16_t>()->implicit_value(8080),
|
("port,p", po::value<std::uint16_t>()->default_value(8080),
|
||||||
"Set the port number for the server")
|
"Set the port number for the server")
|
||||||
("ip", po::value<std::string>()->implicit_value("0.0.0.0"),
|
("ip", po::value<std::string>()->default_value("0.0.0.0"),
|
||||||
"Set the IP address to bind to, \"0.0.0.0\" for all")
|
"Set the IP address to bind to, \"0.0.0.0\" for all")
|
||||||
("threads,n", po::value<std::size_t>()->implicit_value(4),
|
("threads,n", po::value<std::size_t>()->default_value(4),
|
||||||
"Set the number of threads to use")
|
"Set the number of threads to use")
|
||||||
("sync,s", "Launch a synchronous server")
|
("sync,s", "Launch a synchronous server")
|
||||||
;
|
;
|
||||||
po::variables_map vm;
|
po::variables_map vm;
|
||||||
po::store(po::parse_command_line(ac, av, desc), vm);
|
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||||
|
|
||||||
std::string root = ".";
|
std::string root = vm["root"].as<std::string>();
|
||||||
if(vm.count("root"))
|
|
||||||
root = vm["root"].as<std::string>();
|
|
||||||
|
|
||||||
std::uint16_t port = 8080;
|
std::uint16_t port = vm["port"].as<std::uint16_t>();
|
||||||
if(vm.count("port"))
|
|
||||||
port = vm["port"].as<std::uint16_t>();
|
|
||||||
|
|
||||||
std::string ip = "0.0.0.0";
|
std::string ip = vm["ip"].as<std::string>();
|
||||||
if(vm.count("ip"))
|
|
||||||
ip = vm["ip"].as<std::string>();
|
|
||||||
|
|
||||||
std::size_t threads = 4;
|
std::size_t threads = vm["threads"].as<std::size_t>();
|
||||||
if(vm.count("threads"))
|
|
||||||
threads = vm["threads"].as<std::size_t>();
|
|
||||||
|
|
||||||
bool sync = vm.count("sync") > 0;
|
bool sync = vm.count("sync") > 0;
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
#include "file_body.hpp"
|
#include "file_body.hpp"
|
||||||
#include "mime_type.hpp"
|
#include "mime_type.hpp"
|
||||||
|
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
#include <beast/core/placeholders.hpp>
|
||||||
#include <beast/core/streambuf.hpp>
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -19,6 +21,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -32,8 +35,8 @@ class http_sync_server
|
|||||||
using address_type = boost::asio::ip::address;
|
using address_type = boost::asio::ip::address;
|
||||||
using socket_type = boost::asio::ip::tcp::socket;
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
using req_type = request_v1<string_body>;
|
using req_type = request<string_body>;
|
||||||
using resp_type = response_v1<file_body>;
|
using resp_type = response<file_body>;
|
||||||
|
|
||||||
bool log_ = true;
|
bool log_ = true;
|
||||||
std::mutex m_;
|
std::mutex m_;
|
||||||
@@ -161,45 +164,49 @@ private:
|
|||||||
path = root_ + path;
|
path = root_ + path;
|
||||||
if(! boost::filesystem::exists(path))
|
if(! boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
response_v1<string_body> res;
|
response<string_body> res;
|
||||||
res.status = 404;
|
res.status = 404;
|
||||||
res.reason = "Not Found";
|
res.reason = "Not Found";
|
||||||
res.version = req.version;
|
res.version = req.version;
|
||||||
res.headers.insert("Server", "http_sync_server");
|
res.fields.insert("Server", "http_sync_server");
|
||||||
res.headers.insert("Content-Type", "text/html");
|
res.fields.insert("Content-Type", "text/html");
|
||||||
res.body = "The file '" + path + "' was not found";
|
res.body = "The file '" + path + "' was not found";
|
||||||
prepare(res);
|
prepare(res);
|
||||||
write(sock, res, ec);
|
write(sock, res, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
resp_type res;
|
resp_type res;
|
||||||
res.status = 200;
|
res.status = 200;
|
||||||
res.reason = "OK";
|
res.reason = "OK";
|
||||||
res.version = req.version;
|
res.version = req.version;
|
||||||
res.headers.insert("Server", "http_sync_server");
|
res.fields.insert("Server", "http_sync_server");
|
||||||
res.headers.insert("Content-Type", mime_type(path));
|
res.fields.insert("Content-Type", mime_type(path));
|
||||||
res.body = path;
|
res.body = path;
|
||||||
try
|
|
||||||
{
|
|
||||||
prepare(res);
|
prepare(res);
|
||||||
}
|
|
||||||
catch(std::exception const& e)
|
|
||||||
{
|
|
||||||
res = {};
|
|
||||||
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.body =
|
|
||||||
std::string{"An internal error occurred"} + e.what();
|
|
||||||
prepare(res);
|
|
||||||
}
|
|
||||||
write(sock, res, ec);
|
write(sock, res, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
catch(std::exception const& e)
|
||||||
|
{
|
||||||
|
response<string_body> res;
|
||||||
|
res.status = 500;
|
||||||
|
res.reason = "Internal Error";
|
||||||
|
res.version = req.version;
|
||||||
|
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);
|
||||||
|
write(sock, res, ec);
|
||||||
|
if(ec)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
fail(id, ec);
|
fail(id, ec);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
32
src/beast/examples/ssl/CMakeLists.txt
Normal file
32
src/beast/examples/ssl/CMakeLists.txt
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Part of Beast
|
||||||
|
|
||||||
|
GroupSources(extras/beast extras)
|
||||||
|
GroupSources(include/beast beast)
|
||||||
|
|
||||||
|
GroupSources(examples/ssl "/")
|
||||||
|
|
||||||
|
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||||
|
|
||||||
|
add_executable (http-ssl-example
|
||||||
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
|
http_ssl_example.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(http-ssl-example ${OPENSSL_LIBRARIES})
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
target_link_libraries(http-ssl-example ${Boost_LIBRARIES} Threads::Threads)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable (websocket-ssl-example
|
||||||
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
|
websocket_ssl_example.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(websocket-ssl-example ${OPENSSL_LIBRARIES})
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
target_link_libraries(websocket-ssl-example ${Boost_LIBRARIES} Threads::Threads)
|
||||||
|
endif()
|
||||||
54
src/beast/examples/ssl/Jamfile.v2
Normal file
54
src/beast/examples/ssl/Jamfile.v2
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#
|
||||||
|
# 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)
|
||||||
|
#
|
||||||
|
|
||||||
|
import os ;
|
||||||
|
|
||||||
|
if [ os.name ] = SOLARIS
|
||||||
|
{
|
||||||
|
lib socket ;
|
||||||
|
lib nsl ;
|
||||||
|
}
|
||||||
|
else if [ os.name ] = NT
|
||||||
|
{
|
||||||
|
lib ws2_32 ;
|
||||||
|
lib mswsock ;
|
||||||
|
}
|
||||||
|
else if [ os.name ] = HPUX
|
||||||
|
{
|
||||||
|
lib ipv6 ;
|
||||||
|
}
|
||||||
|
else if [ os.name ] = HAIKU
|
||||||
|
{
|
||||||
|
lib network ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ os.name ] = NT
|
||||||
|
{
|
||||||
|
lib ssl : : <name>ssleay32 ;
|
||||||
|
lib crypto : : <name>libeay32 ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lib ssl ;
|
||||||
|
lib crypto ;
|
||||||
|
}
|
||||||
|
|
||||||
|
project
|
||||||
|
: requirements
|
||||||
|
<library>ssl
|
||||||
|
<library>crypto
|
||||||
|
;
|
||||||
|
|
||||||
|
exe http-ssl-example
|
||||||
|
:
|
||||||
|
http_ssl_example.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
exe websocket-ssl-example
|
||||||
|
:
|
||||||
|
websocket_ssl_example.cpp
|
||||||
|
;
|
||||||
58
src/beast/examples/ssl/http_ssl_example.cpp
Normal file
58
src/beast/examples/ssl/http_ssl_example.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::asio::connect;
|
||||||
|
using socket = boost::asio::ip::tcp::socket;
|
||||||
|
using resolver = boost::asio::ip::tcp::resolver;
|
||||||
|
using io_service = boost::asio::io_service;
|
||||||
|
namespace ssl = boost::asio::ssl;
|
||||||
|
|
||||||
|
// Normal boost::asio setup
|
||||||
|
std::string const host = "github.com";
|
||||||
|
io_service ios;
|
||||||
|
resolver r{ios};
|
||||||
|
socket sock{ios};
|
||||||
|
connect(sock, r.resolve(resolver::query{host, "https"}));
|
||||||
|
|
||||||
|
// Perform SSL handshaking
|
||||||
|
ssl::context ctx{ssl::context::sslv23};
|
||||||
|
ssl::stream<socket&> stream{sock, ctx};
|
||||||
|
stream.set_verify_mode(ssl::verify_none);
|
||||||
|
stream.handshake(ssl::stream_base::client);
|
||||||
|
|
||||||
|
// Send HTTP request over SSL using Beast
|
||||||
|
beast::http::request<beast::http::empty_body> req;
|
||||||
|
req.method = "GET";
|
||||||
|
req.url = "/";
|
||||||
|
req.version = 11;
|
||||||
|
req.fields.insert("Host", host + ":" +
|
||||||
|
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||||
|
req.fields.insert("User-Agent", "Beast");
|
||||||
|
beast::http::prepare(req);
|
||||||
|
beast::http::write(stream, req);
|
||||||
|
|
||||||
|
// Receive and print HTTP response using Beast
|
||||||
|
beast::streambuf sb;
|
||||||
|
beast::http::response<beast::http::streambuf_body> resp;
|
||||||
|
beast::http::read(stream, sb, resp);
|
||||||
|
std::cout << resp;
|
||||||
|
|
||||||
|
// Shut down SSL on the stream
|
||||||
|
boost::system::error_code ec;
|
||||||
|
stream.shutdown(ec);
|
||||||
|
if(ec && ec != boost::asio::error::eof)
|
||||||
|
std::cout << "error: " << ec.message();
|
||||||
|
}
|
||||||
49
src/beast/examples/ssl/websocket_ssl_example.cpp
Normal file
49
src/beast/examples/ssl/websocket_ssl_example.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <beast/core/to_string.hpp>
|
||||||
|
#include <beast/websocket.hpp>
|
||||||
|
#include <beast/websocket/ssl.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::asio::connect;
|
||||||
|
using socket = boost::asio::ip::tcp::socket;
|
||||||
|
using resolver = boost::asio::ip::tcp::resolver;
|
||||||
|
using io_service = boost::asio::io_service;
|
||||||
|
namespace ssl = boost::asio::ssl;
|
||||||
|
|
||||||
|
// Normal boost::asio setup
|
||||||
|
std::string const host = "echo.websocket.org";
|
||||||
|
io_service ios;
|
||||||
|
resolver r{ios};
|
||||||
|
socket sock{ios};
|
||||||
|
connect(sock, r.resolve(resolver::query{host, "https"}));
|
||||||
|
|
||||||
|
// Perform SSL handshaking
|
||||||
|
using stream_type = ssl::stream<socket&>;
|
||||||
|
ssl::context ctx{ssl::context::sslv23};
|
||||||
|
stream_type stream{sock, ctx};
|
||||||
|
stream.set_verify_mode(ssl::verify_none);
|
||||||
|
stream.handshake(ssl::stream_base::client);
|
||||||
|
|
||||||
|
// Secure WebSocket connect and send message using Beast
|
||||||
|
beast::websocket::stream<stream_type&> ws{stream};
|
||||||
|
ws.handshake(host, "/");
|
||||||
|
ws.write(boost::asio::buffer("Hello, world!"));
|
||||||
|
|
||||||
|
// Receive Secure WebSocket message, print and close using Beast
|
||||||
|
beast::streambuf sb;
|
||||||
|
beast::websocket::opcode op;
|
||||||
|
ws.read(op, sb);
|
||||||
|
ws.close(beast::websocket::close_code::normal);
|
||||||
|
std::cout << to_string(sb.data()) << "\n";
|
||||||
|
}
|
||||||
@@ -24,12 +24,12 @@ int main()
|
|||||||
// WebSocket connect and send message using beast
|
// WebSocket connect and send message using beast
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
ws.handshake(host, "/");
|
ws.handshake(host, "/");
|
||||||
ws.write(boost::asio::buffer("Hello, world!"));
|
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||||
|
|
||||||
// Receive WebSocket message, print and close using beast
|
// Receive WebSocket message, print and close using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
beast::websocket::opcode op;
|
beast::websocket::opcode op;
|
||||||
ws.read(op, sb);
|
ws.read(op, sb);
|
||||||
ws.close(beast::websocket::close_code::normal);
|
ws.close(beast::websocket::close_code::normal);
|
||||||
std::cout << to_string(sb.data()) << "\n";
|
std::cout << beast::to_string(sb.data()) << "\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,9 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
enum error
|
enum class error
|
||||||
{
|
{
|
||||||
success = 0,
|
fail_error = 1
|
||||||
|
|
||||||
fail_error
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@@ -79,14 +77,15 @@ inline
|
|||||||
error_code
|
error_code
|
||||||
make_error_code(error ev)
|
make_error_code(error ev)
|
||||||
{
|
{
|
||||||
return error_code{static_cast<int>(ev),
|
return error_code{
|
||||||
|
static_cast<std::underlying_type<error>::type>(ev),
|
||||||
detail::get_error_category()};
|
detail::get_error_category()};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A countdown to simulated failure.
|
/** A countdown to simulated failure.
|
||||||
|
|
||||||
On the Nth operation, the class will fail with the specified
|
On the Nth operation, the class will fail with the specified
|
||||||
error code, or the default error code of @ref fail_error.
|
error code, or the default error code of @ref error::fail_error.
|
||||||
*/
|
*/
|
||||||
class fail_counter
|
class fail_counter
|
||||||
{
|
{
|
||||||
@@ -102,7 +101,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
explicit
|
explicit
|
||||||
fail_counter(std::size_t n,
|
fail_counter(std::size_t n,
|
||||||
error_code ev = make_error_code(fail_error))
|
error_code ev = make_error_code(error::fail_error))
|
||||||
: n_(n)
|
: n_(n)
|
||||||
, ec_(ev)
|
, ec_(ev)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#ifndef BEAST_TEST_STRING_STREAM_HPP
|
#ifndef BEAST_TEST_STRING_STREAM_HPP
|
||||||
#define BEAST_TEST_STRING_STREAM_HPP
|
#define BEAST_TEST_STRING_STREAM_HPP
|
||||||
|
|
||||||
|
#include <beast/core/async_completion.hpp>
|
||||||
#include <beast/core/bind_handler.hpp>
|
#include <beast/core/bind_handler.hpp>
|
||||||
#include <beast/core/error.hpp>
|
#include <beast/core/error.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <beast/unit_test/amount.hpp>
|
#include <beast/unit_test/amount.hpp>
|
||||||
#include <beast/unit_test/recorder.hpp>
|
#include <beast/unit_test/recorder.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -214,7 +215,8 @@ reporter<_>::fmtdur(typename clock_type::duration const& d)
|
|||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
auto const ms = duration_cast<milliseconds>(d);
|
auto const ms = duration_cast<milliseconds>(d);
|
||||||
if(ms < seconds{1})
|
if(ms < seconds{1})
|
||||||
return std::to_string(ms.count()) + "ms";
|
return boost::lexical_cast<std::string>(
|
||||||
|
ms.count()) + "ms";
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << std::fixed << std::setprecision(1) <<
|
ss << std::fixed << std::setprecision(1) <<
|
||||||
(ms.count()/1000.) << "s";
|
(ms.count()/1000.) << "s";
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#define BEAST_UNIT_TEST_RUNNER_H_INCLUDED
|
#define BEAST_UNIT_TEST_RUNNER_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/unit_test/suite_info.hpp>
|
#include <beast/unit_test/suite_info.hpp>
|
||||||
#include <cassert>
|
#include <boost/assert.hpp>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -185,7 +185,7 @@ runner::run(suite_info const& s)
|
|||||||
on_suite_begin(s);
|
on_suite_begin(s);
|
||||||
s.run(*this);
|
s.run(*this);
|
||||||
// Forgot to call pass or fail.
|
// Forgot to call pass or fail.
|
||||||
assert(cond_);
|
BOOST_ASSERT(cond_);
|
||||||
on_case_end();
|
on_case_end();
|
||||||
on_suite_end();
|
on_suite_end();
|
||||||
return failed_;
|
return failed_;
|
||||||
@@ -239,9 +239,9 @@ runner::testcase(std::string const& name)
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||||
// Name may not be empty
|
// Name may not be empty
|
||||||
assert(default_ || ! name.empty());
|
BOOST_ASSERT(default_ || ! name.empty());
|
||||||
// Forgot to call pass or fail
|
// Forgot to call pass or fail
|
||||||
assert(default_ || cond_);
|
BOOST_ASSERT(default_ || cond_);
|
||||||
if(! default_)
|
if(! default_)
|
||||||
on_case_end();
|
on_case_end();
|
||||||
default_ = false;
|
default_ = false;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <beast/unit_test/runner.hpp>
|
#include <beast/unit_test/runner.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -17,6 +18,27 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace unit_test {
|
namespace unit_test {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class String>
|
||||||
|
static
|
||||||
|
std::string
|
||||||
|
make_reason(String const& reason,
|
||||||
|
char const* file, int line)
|
||||||
|
{
|
||||||
|
std::string s(reason);
|
||||||
|
if(! s.empty())
|
||||||
|
s.append(": ");
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
s.append(fs::path{file}.filename().string());
|
||||||
|
s.append("(");
|
||||||
|
s.append(boost::lexical_cast<std::string>(line));
|
||||||
|
s.append(")");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
class thread;
|
class thread;
|
||||||
|
|
||||||
enum abort_t
|
enum abort_t
|
||||||
@@ -178,11 +200,21 @@ public:
|
|||||||
|
|
||||||
/** Record a failure.
|
/** Record a failure.
|
||||||
|
|
||||||
@param reason
|
@param reason Optional text added to the output on a failure.
|
||||||
|
|
||||||
|
@param file The source code file where the test failed.
|
||||||
|
|
||||||
|
@param line The source code line number where the test failed.
|
||||||
*/
|
*/
|
||||||
|
/** @{ */
|
||||||
|
template<class String>
|
||||||
|
void
|
||||||
|
fail(String const& reason, char const* file, int line);
|
||||||
|
|
||||||
template<class = void>
|
template<class = void>
|
||||||
void
|
void
|
||||||
fail(std::string const& reason = "");
|
fail(std::string const& reason = "");
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/** Evaluate a test condition.
|
/** Evaluate a test condition.
|
||||||
|
|
||||||
@@ -206,25 +238,25 @@ public:
|
|||||||
bool
|
bool
|
||||||
expect(Condition const& shouldBeTrue)
|
expect(Condition const& shouldBeTrue)
|
||||||
{
|
{
|
||||||
return expect(shouldBeTrue, {});
|
return expect(shouldBeTrue, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Condition>
|
template<class Condition, class String>
|
||||||
bool
|
bool
|
||||||
expect(Condition const& shouldBeTrue, std::string const& reason);
|
expect(Condition const& shouldBeTrue, String const& reason);
|
||||||
|
|
||||||
template<class Condition>
|
template<class Condition>
|
||||||
bool
|
bool
|
||||||
expect(Condition const& shouldBeTrue,
|
expect(Condition const& shouldBeTrue,
|
||||||
char const* file, int line)
|
char const* file, int line)
|
||||||
{
|
{
|
||||||
return expect(shouldBeTrue, {}, file, line);
|
return expect(shouldBeTrue, "", file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Condition>
|
template<class Condition, class String>
|
||||||
bool
|
bool
|
||||||
expect(Condition const& shouldBeTrue,
|
expect(Condition const& shouldBeTrue,
|
||||||
std::string const& reason, char const* file, int line);
|
String const& reason, char const* file, int line);
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -402,11 +434,11 @@ operator()(runner& r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Condition>
|
template<class Condition, class String>
|
||||||
bool
|
bool
|
||||||
suite::
|
suite::
|
||||||
expect(
|
expect(
|
||||||
Condition const& shouldBeTrue, std::string const& reason)
|
Condition const& shouldBeTrue, String const& reason)
|
||||||
{
|
{
|
||||||
if(shouldBeTrue)
|
if(shouldBeTrue)
|
||||||
{
|
{
|
||||||
@@ -417,26 +449,18 @@ expect(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Condition>
|
template<class Condition, class String>
|
||||||
bool
|
bool
|
||||||
suite::
|
suite::
|
||||||
expect(Condition const& shouldBeTrue,
|
expect(Condition const& shouldBeTrue,
|
||||||
std::string const& reason, char const* file, int line)
|
String const& reason, char const* file, int line)
|
||||||
{
|
{
|
||||||
if(shouldBeTrue)
|
if(shouldBeTrue)
|
||||||
{
|
{
|
||||||
pass();
|
pass();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
std::string s;
|
fail(detail::make_reason(reason, file, line));
|
||||||
if(! reason.empty())
|
|
||||||
{
|
|
||||||
s += reason;
|
|
||||||
s += " ";
|
|
||||||
}
|
|
||||||
s += boost::filesystem::path{file}.filename().string() +
|
|
||||||
"(" + std::to_string(line) + ")";
|
|
||||||
fail(s);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -535,6 +559,14 @@ fail(std::string const& reason)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class String>
|
||||||
|
void
|
||||||
|
suite::
|
||||||
|
fail(String const& reason, char const* file, int line)
|
||||||
|
{
|
||||||
|
fail(detail::make_reason(reason, file, line));
|
||||||
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
suite::
|
suite::
|
||||||
@@ -583,7 +615,8 @@ run(runner& r)
|
|||||||
|
|
||||||
If the condition is false, the file and line number are reported.
|
If the condition is false, the file and line number are reported.
|
||||||
*/
|
*/
|
||||||
#define BEAST_EXPECTS(cond, reason) expect(cond, reason, __FILE__, __LINE__)
|
#define BEAST_EXPECTS(cond, reason) ((cond) ? (pass(), true) : \
|
||||||
|
(fail((reason), __FILE__, __LINE__), false))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // unit_test
|
} // unit_test
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include <beast/unit_test/suite_info.hpp>
|
#include <beast/unit_test/suite_info.hpp>
|
||||||
#include <beast/unit_test/detail/const_container.hpp>
|
#include <beast/unit_test/detail/const_container.hpp>
|
||||||
#include <cassert>
|
#include <boost/assert.hpp>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
@@ -57,13 +57,13 @@ suite_list::insert(
|
|||||||
std::string s;
|
std::string s;
|
||||||
s = std::string(library) + "." + module + "." + name;
|
s = std::string(library) + "." + module + "." + name;
|
||||||
auto const result(names_.insert(s));
|
auto const result(names_.insert(s));
|
||||||
assert(result.second); // Duplicate name
|
BOOST_ASSERT(result.second); // Duplicate name
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto const result(classes_.insert(
|
auto const result(classes_.insert(
|
||||||
std::type_index(typeid(Suite))));
|
std::type_index(typeid(Suite))));
|
||||||
assert(result.second); // Duplicate type
|
BOOST_ASSERT(result.second); // Duplicate type
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
cont().emplace(make_suite_info<Suite>(
|
cont().emplace(make_suite_info<Suite>(
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include <beast/core/error.hpp>
|
#include <beast/core/error.hpp>
|
||||||
#include <beast/core/handler_alloc.hpp>
|
#include <beast/core/handler_alloc.hpp>
|
||||||
#include <beast/core/handler_concepts.hpp>
|
#include <beast/core/handler_concepts.hpp>
|
||||||
|
#include <beast/core/handler_helpers.hpp>
|
||||||
|
#include <beast/core/handler_ptr.hpp>
|
||||||
#include <beast/core/placeholders.hpp>
|
#include <beast/core/placeholders.hpp>
|
||||||
#include <beast/core/prepare_buffers.hpp>
|
#include <beast/core/prepare_buffers.hpp>
|
||||||
#include <beast/core/static_streambuf.hpp>
|
#include <beast/core/static_streambuf.hpp>
|
||||||
|
|||||||
@@ -34,11 +34,11 @@ namespace beast {
|
|||||||
...
|
...
|
||||||
template<class CompletionHandler>
|
template<class CompletionHandler>
|
||||||
typename async_completion<CompletionHandler,
|
typename async_completion<CompletionHandler,
|
||||||
void(boost::system::error_code)>::result_type
|
void(error_code)>::result_type
|
||||||
async_initfn(..., CompletionHandler&& handler)
|
async_initfn(..., CompletionHandler&& handler)
|
||||||
{
|
{
|
||||||
async_completion<CompletionHandler,
|
async_completion<CompletionHandler,
|
||||||
void(boost::system::error_code)> completion(handler);
|
void(error_code)> completion(handler);
|
||||||
...
|
...
|
||||||
return completion.result.get();
|
return completion.result.get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace beast {
|
|||||||
the sequence to accommodate changes in the size of the character
|
the sequence to accommodate changes in the size of the character
|
||||||
sequence.
|
sequence.
|
||||||
|
|
||||||
@note Meets the requirements of @b `DynamicBuffer`.
|
@note Meets the requirements of @b DynamicBuffer.
|
||||||
|
|
||||||
@tparam Allocator The allocator to use for managing memory.
|
@tparam Allocator The allocator to use for managing memory.
|
||||||
*/
|
*/
|
||||||
@@ -209,6 +209,36 @@ public:
|
|||||||
return this->member();
|
return this->member();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the default allocation size.
|
||||||
|
|
||||||
|
This is the smallest size that the stream buffer will allocate.
|
||||||
|
The size of the allocation can influence capacity, which will
|
||||||
|
affect algorithms that use capacity to efficiently read from
|
||||||
|
streams.
|
||||||
|
*/
|
||||||
|
std::size_t
|
||||||
|
alloc_size() const
|
||||||
|
{
|
||||||
|
return alloc_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the default allocation size.
|
||||||
|
|
||||||
|
This is the smallest size that the stream buffer will allocate.
|
||||||
|
The size of the allocation can influence capacity, which will
|
||||||
|
affect algorithms that use capacity to efficiently read from
|
||||||
|
streams.
|
||||||
|
|
||||||
|
@note This will not affect any already-existing allocations.
|
||||||
|
|
||||||
|
@param n The number of bytes.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
alloc_size(std::size_t n)
|
||||||
|
{
|
||||||
|
alloc_size_ = n;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the size of the input sequence.
|
/// Returns the size of the input sequence.
|
||||||
size_type
|
size_type
|
||||||
size() const
|
size() const
|
||||||
@@ -220,7 +250,7 @@ public:
|
|||||||
size_type
|
size_type
|
||||||
max_size() const
|
max_size() const
|
||||||
{
|
{
|
||||||
return std::numeric_limits<std::size_t>::max();
|
return (std::numeric_limits<std::size_t>::max)();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
|
/// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
|
||||||
|
|||||||
@@ -19,18 +19,21 @@
|
|||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
/** Concatenate 2 or more buffer sequences to form a `ConstBufferSequence`.
|
/** Concatenate 2 or more buffer sequences.
|
||||||
|
|
||||||
This function returns a @b `ConstBufferSequence` that when iterated,
|
This function returns a constant or mutable buffer sequence which,
|
||||||
efficiently concatenates the input buffer sequences. Copies of the
|
when iterated, efficiently concatenates the input buffer sequences.
|
||||||
arguments passed will be made; however, the returned object does
|
Copies of the arguments passed will be made; however, the returned
|
||||||
not take ownership of the underlying memory. The application is still
|
object does not take ownership of the underlying memory. The application
|
||||||
responsible for managing the lifetime of the referenced memory.
|
is still responsible for managing the lifetime of the referenced memory.
|
||||||
|
|
||||||
@param buffers The list of buffer sequences to concatenate.
|
@param buffers The list of buffer sequences to concatenate.
|
||||||
|
|
||||||
@return A new @b `ConstBufferSequence` that represents the
|
@return A new buffer sequence that represents the concatenation of
|
||||||
concatenation of the input buffer sequences.
|
the input buffer sequences. This buffer sequence will be a
|
||||||
|
@b MutableBufferSequence if each of the passed buffer sequences is
|
||||||
|
also a @b MutableBufferSequence, else the returned buffer sequence
|
||||||
|
will be a @b ConstBufferSequence.
|
||||||
*/
|
*/
|
||||||
#if GENERATING_DOCS
|
#if GENERATING_DOCS
|
||||||
template<class... BufferSequence>
|
template<class... BufferSequence>
|
||||||
@@ -38,14 +41,15 @@ implementation_defined
|
|||||||
buffer_cat(BufferSequence const&... buffers)
|
buffer_cat(BufferSequence const&... buffers)
|
||||||
#else
|
#else
|
||||||
template<class B1, class B2, class... Bn>
|
template<class B1, class B2, class... Bn>
|
||||||
detail::buffer_cat_helper<
|
detail::buffer_cat_helper<B1, B2, Bn...>
|
||||||
boost::asio::const_buffer, B1, B2, Bn...>
|
|
||||||
buffer_cat(B1 const& b1, B2 const& b2, Bn const&... bn)
|
buffer_cat(B1 const& b1, B2 const& b2, Bn const&... bn)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
static_assert(
|
||||||
|
detail::is_all_ConstBufferSequence<B1, B2, Bn...>::value,
|
||||||
|
"BufferSequence requirements not met");
|
||||||
return detail::buffer_cat_helper<
|
return detail::buffer_cat_helper<
|
||||||
boost::asio::const_buffer,
|
B1, B2, Bn...>{b1, b2, bn...};
|
||||||
B1, B2, Bn...>(b1, b2, bn...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|||||||
@@ -37,20 +37,12 @@ namespace beast {
|
|||||||
consumable `ConstBufferSequence`. Violations of buffer const safety
|
consumable `ConstBufferSequence`. Violations of buffer const safety
|
||||||
are not permitted, and will result in a compile error.
|
are not permitted, and will result in a compile error.
|
||||||
*/
|
*/
|
||||||
template<class BufferSequence,
|
template<class BufferSequence>
|
||||||
class ValueType = typename BufferSequence::value_type>
|
|
||||||
class consuming_buffers
|
class consuming_buffers
|
||||||
{
|
{
|
||||||
using iter_type =
|
using iter_type =
|
||||||
typename BufferSequence::const_iterator;
|
typename BufferSequence::const_iterator;
|
||||||
|
|
||||||
static_assert(is_BufferSequence<BufferSequence, ValueType>::value,
|
|
||||||
"BufferSequence requirements not met");
|
|
||||||
|
|
||||||
static_assert(std::is_constructible<ValueType,
|
|
||||||
typename std::iterator_traits<iter_type>::value_type>::value,
|
|
||||||
"ValueType requirements not met");
|
|
||||||
|
|
||||||
BufferSequence bs_;
|
BufferSequence bs_;
|
||||||
iter_type begin_;
|
iter_type begin_;
|
||||||
std::size_t skip_ = 0;
|
std::size_t skip_ = 0;
|
||||||
@@ -65,7 +57,12 @@ class consuming_buffers
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// The type for each element in the list of buffers.
|
/// The type for each element in the list of buffers.
|
||||||
using value_type = ValueType;
|
using value_type = typename std::conditional<
|
||||||
|
std::is_convertible<typename
|
||||||
|
std::iterator_traits<iter_type>::value_type,
|
||||||
|
boost::asio::mutable_buffer>::value,
|
||||||
|
boost::asio::mutable_buffer,
|
||||||
|
boost::asio::const_buffer>::type;
|
||||||
|
|
||||||
#if GENERATING_DOCS
|
#if GENERATING_DOCS
|
||||||
/// A bidirectional iterator type that may be used to read elements.
|
/// A bidirectional iterator type that may be used to read elements.
|
||||||
@@ -100,7 +97,7 @@ public:
|
|||||||
const_iterator
|
const_iterator
|
||||||
begin() const;
|
begin() const;
|
||||||
|
|
||||||
/// Get a bidirectional iterator for one past the last element.
|
/// Get a bidirectional iterator to one past the last element.
|
||||||
const_iterator
|
const_iterator
|
||||||
end() const;
|
end() const;
|
||||||
|
|
||||||
@@ -114,25 +111,6 @@ public:
|
|||||||
consume(std::size_t n);
|
consume(std::size_t n);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Returns a new, consumed buffer sequence.
|
|
||||||
|
|
||||||
This function returns a new buffer sequence which when iterated,
|
|
||||||
efficiently represents the portion of the original buffer sequence
|
|
||||||
with `n` bytes removed from the beginning.
|
|
||||||
|
|
||||||
Copies will be made of the buffer sequence passed, but ownership
|
|
||||||
of the underlying memory is not transferred.
|
|
||||||
|
|
||||||
@param buffers The buffer sequence to consume.
|
|
||||||
|
|
||||||
@param n The number of bytes to remove from the front. If this is
|
|
||||||
larger than the size of the buffer sequence, an empty buffer sequence
|
|
||||||
is returned.
|
|
||||||
*/
|
|
||||||
template<class BufferSequence>
|
|
||||||
consuming_buffers<BufferSequence, typename BufferSequence::value_type>
|
|
||||||
consumed_buffers(BufferSequence const& buffers, std::size_t n);
|
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#include <beast/core/impl/consuming_buffers.ipp>
|
#include <beast/core/impl/consuming_buffers.ipp>
|
||||||
|
|||||||
@@ -8,10 +8,8 @@
|
|||||||
#ifndef BEAST_BIND_DETAIL_HANDLER_HPP
|
#ifndef BEAST_BIND_DETAIL_HANDLER_HPP
|
||||||
#define BEAST_BIND_DETAIL_HANDLER_HPP
|
#define BEAST_BIND_DETAIL_HANDLER_HPP
|
||||||
|
|
||||||
|
#include <beast/core/handler_helpers.hpp>
|
||||||
#include <beast/core/detail/integer_sequence.hpp>
|
#include <beast/core/detail/integer_sequence.hpp>
|
||||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
|
||||||
#include <boost/asio/detail/handler_cont_helpers.hpp>
|
|
||||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
@@ -69,7 +67,7 @@ public:
|
|||||||
asio_handler_allocate(
|
asio_handler_allocate(
|
||||||
std::size_t size, bound_handler* h)
|
std::size_t size, bound_handler* h)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_alloc_helpers::
|
return beast_asio_helpers::
|
||||||
allocate(size, h->h_);
|
allocate(size, h->h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +76,7 @@ public:
|
|||||||
asio_handler_deallocate(
|
asio_handler_deallocate(
|
||||||
void* p, std::size_t size, bound_handler* h)
|
void* p, std::size_t size, bound_handler* h)
|
||||||
{
|
{
|
||||||
boost_asio_handler_alloc_helpers::
|
beast_asio_helpers::
|
||||||
deallocate(p, size, h->h_);
|
deallocate(p, size, h->h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +84,7 @@ public:
|
|||||||
bool
|
bool
|
||||||
asio_handler_is_continuation(bound_handler* h)
|
asio_handler_is_continuation(bound_handler* h)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_cont_helpers::
|
return beast_asio_helpers::
|
||||||
is_continuation (h->h_);
|
is_continuation (h->h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +93,7 @@ public:
|
|||||||
void
|
void
|
||||||
asio_handler_invoke(F&& f, bound_handler* h)
|
asio_handler_invoke(F&& f, bound_handler* h)
|
||||||
{
|
{
|
||||||
boost_asio_handler_invoke_helpers::
|
beast_asio_helpers::
|
||||||
invoke(f, h->h_);
|
invoke(f, h->h_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#ifndef BEAST_DETAIL_BUFFER_CAT_HPP
|
#ifndef BEAST_DETAIL_BUFFER_CAT_HPP
|
||||||
#define BEAST_DETAIL_BUFFER_CAT_HPP
|
#define BEAST_DETAIL_BUFFER_CAT_HPP
|
||||||
|
|
||||||
|
#include <beast/core/buffer_concepts.hpp>
|
||||||
|
#include <beast/core/detail/type_traits.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
@@ -19,24 +21,36 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
|
struct common_buffers_type
|
||||||
|
{
|
||||||
|
using type = typename std::conditional<
|
||||||
|
std::is_convertible<std::tuple<Bn...>,
|
||||||
|
typename repeat_tuple<sizeof...(Bn),
|
||||||
|
boost::asio::mutable_buffer>::type>::value,
|
||||||
|
boost::asio::mutable_buffer,
|
||||||
|
boost::asio::const_buffer>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class... Bn>
|
||||||
class buffer_cat_helper
|
class buffer_cat_helper
|
||||||
{
|
{
|
||||||
std::tuple<Bs...> bs_;
|
std::tuple<Bn...> bn_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = ValueType;
|
using value_type = typename
|
||||||
|
common_buffers_type<Bn...>::type;
|
||||||
|
|
||||||
class const_iterator;
|
class const_iterator;
|
||||||
|
|
||||||
buffer_cat_helper(buffer_cat_helper&&) = default;
|
buffer_cat_helper(buffer_cat_helper&&) = default;
|
||||||
buffer_cat_helper(buffer_cat_helper const&) = default;
|
buffer_cat_helper(buffer_cat_helper const&) = default;
|
||||||
buffer_cat_helper& operator=(buffer_cat_helper&&) = default;
|
buffer_cat_helper& operator=(buffer_cat_helper&&) = delete;
|
||||||
buffer_cat_helper& operator=(buffer_cat_helper const&) = default;
|
buffer_cat_helper& operator=(buffer_cat_helper const&) = delete;
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
buffer_cat_helper(Bs const&... bs)
|
buffer_cat_helper(Bn const&... bn)
|
||||||
: bs_(bs...)
|
: bn_(bn...)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,39 +61,22 @@ public:
|
|||||||
end() const;
|
end() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class U>
|
template<class... Bn>
|
||||||
std::size_t constexpr
|
class buffer_cat_helper<Bn...>::const_iterator
|
||||||
max_sizeof()
|
|
||||||
{
|
|
||||||
return sizeof(U);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class U0, class U1, class... Us>
|
|
||||||
std::size_t constexpr
|
|
||||||
max_sizeof()
|
|
||||||
{
|
|
||||||
return
|
|
||||||
max_sizeof<U0>() > max_sizeof<U1, Us...>() ?
|
|
||||||
max_sizeof<U0>() : max_sizeof<U1, Us...>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
|
||||||
class buffer_cat_helper<
|
|
||||||
ValueType, Bs...>::const_iterator
|
|
||||||
{
|
{
|
||||||
std::size_t n_;
|
std::size_t n_;
|
||||||
std::tuple<Bs...> const* bs_;
|
std::tuple<Bn...> const* bn_;
|
||||||
std::array<std::uint8_t,
|
std::array<std::uint8_t,
|
||||||
max_sizeof<typename Bs::const_iterator...>()> buf_;
|
max_sizeof<typename Bn::const_iterator...>()> buf_;
|
||||||
|
|
||||||
friend class buffer_cat_helper<ValueType, Bs...>;
|
friend class buffer_cat_helper<Bn...>;
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
using C = std::integral_constant<std::size_t, I>;
|
using C = std::integral_constant<std::size_t, I>;
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
using iter_t = typename std::tuple_element<
|
using iter_t = typename std::tuple_element<
|
||||||
I, std::tuple<Bs...>>::type::const_iterator;
|
I, std::tuple<Bn...>>::type::const_iterator;
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
iter_t<I>&
|
iter_t<I>&
|
||||||
@@ -98,7 +95,8 @@ class buffer_cat_helper<
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = ValueType;
|
using value_type = typename
|
||||||
|
common_buffers_type<Bn...>::type;
|
||||||
using pointer = value_type const*;
|
using pointer = value_type const*;
|
||||||
using reference = value_type;
|
using reference = value_type;
|
||||||
using difference_type = std::ptrdiff_t;
|
using difference_type = std::ptrdiff_t;
|
||||||
@@ -151,39 +149,39 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const_iterator(
|
const_iterator(
|
||||||
std::tuple<Bs...> const& bs, bool at_end);
|
std::tuple<Bn...> const& bn, bool at_end);
|
||||||
|
|
||||||
void
|
void
|
||||||
construct(C<sizeof...(Bs)>)
|
construct(C<sizeof...(Bn)> const&)
|
||||||
{
|
{
|
||||||
auto constexpr I = sizeof...(Bs);
|
auto constexpr I = sizeof...(Bn);
|
||||||
n_ = I;
|
n_ = I;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
void
|
void
|
||||||
construct(C<I>)
|
construct(C<I> const&)
|
||||||
{
|
{
|
||||||
if(std::get<I>(*bs_).begin() !=
|
if(std::get<I>(*bn_).begin() !=
|
||||||
std::get<I>(*bs_).end())
|
std::get<I>(*bn_).end())
|
||||||
{
|
{
|
||||||
n_ = I;
|
n_ = I;
|
||||||
new(buf_.data()) iter_t<I>{
|
new(buf_.data()) iter_t<I>{
|
||||||
std::get<I>(*bs_).begin()};
|
std::get<I>(*bn_).begin()};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
construct(C<I+1>{});
|
construct(C<I+1>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
destroy(C<sizeof...(Bs)>)
|
destroy(C<sizeof...(Bn)> const&)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
void
|
void
|
||||||
destroy(C<I>)
|
destroy(C<I> const&)
|
||||||
{
|
{
|
||||||
if(n_ == I)
|
if(n_ == I)
|
||||||
{
|
{
|
||||||
@@ -195,13 +193,15 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
move(C<sizeof...(Bs)>, const_iterator&&)
|
move(const_iterator&&,
|
||||||
|
C<sizeof...(Bn)> const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
void
|
void
|
||||||
move(C<I>, const_iterator&& other)
|
move(const_iterator&& other,
|
||||||
|
C<I> const&)
|
||||||
{
|
{
|
||||||
if(n_ == I)
|
if(n_ == I)
|
||||||
{
|
{
|
||||||
@@ -209,17 +209,19 @@ private:
|
|||||||
std::move(other.iter<I>())};
|
std::move(other.iter<I>())};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
move(C<I+1>{}, std::move(other));
|
move(std::move(other), C<I+1>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
copy(C<sizeof...(Bs)>, const_iterator const&)
|
copy(const_iterator const&,
|
||||||
|
C<sizeof...(Bn)> const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
void
|
void
|
||||||
copy(C<I>, const_iterator const& other)
|
copy(const_iterator const& other,
|
||||||
|
C<I> const&)
|
||||||
{
|
{
|
||||||
if(n_ == I)
|
if(n_ == I)
|
||||||
{
|
{
|
||||||
@@ -227,35 +229,36 @@ private:
|
|||||||
other.iter<I>()};
|
other.iter<I>()};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
copy(C<I+1>{}, other);
|
copy(other, C<I+1>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
equal(C<sizeof...(Bs)>,
|
equal(const_iterator const&,
|
||||||
const_iterator const&) const
|
C<sizeof...(Bn)> const&) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
bool
|
bool
|
||||||
equal(C<I>, const_iterator const& other) const
|
equal(const_iterator const& other,
|
||||||
|
C<I> const&) const
|
||||||
{
|
{
|
||||||
if(n_ == I)
|
if(n_ == I)
|
||||||
return iter<I>() == other.iter<I>();
|
return iter<I>() == other.iter<I>();
|
||||||
return equal(C<I+1>{}, other);
|
return equal(other, C<I+1>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
reference
|
reference
|
||||||
dereference(C<sizeof...(Bs)>) const
|
dereference(C<sizeof...(Bn)> const&) const
|
||||||
{
|
{
|
||||||
throw std::logic_error("invalid iterator");
|
throw std::logic_error("invalid iterator");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
reference
|
reference
|
||||||
dereference(C<I>) const
|
dereference(C<I> const&) const
|
||||||
{
|
{
|
||||||
if(n_ == I)
|
if(n_ == I)
|
||||||
return *iter<I>();
|
return *iter<I>();
|
||||||
@@ -264,19 +267,19 @@ private:
|
|||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void
|
void
|
||||||
increment(C<sizeof...(Bs)>)
|
increment(C<sizeof...(Bn)> const&)
|
||||||
{
|
{
|
||||||
throw std::logic_error("invalid iterator");
|
throw std::logic_error("invalid iterator");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
void
|
void
|
||||||
increment(C<I>)
|
increment(C<I> const&)
|
||||||
{
|
{
|
||||||
if(n_ == I)
|
if(n_ == I)
|
||||||
{
|
{
|
||||||
if(++iter<I>() !=
|
if(++iter<I>() !=
|
||||||
std::get<I>(*bs_).end())
|
std::get<I>(*bn_).end())
|
||||||
return;
|
return;
|
||||||
using Iter = iter_t<I>;
|
using Iter = iter_t<I>;
|
||||||
iter<I>().~Iter();
|
iter<I>().~Iter();
|
||||||
@@ -286,23 +289,23 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
decrement(C<sizeof...(Bs)>)
|
decrement(C<sizeof...(Bn)> const&)
|
||||||
{
|
{
|
||||||
auto constexpr I = sizeof...(Bs);
|
auto constexpr I = sizeof...(Bn);
|
||||||
if(n_ == I)
|
if(n_ == I)
|
||||||
{
|
{
|
||||||
--n_;
|
--n_;
|
||||||
new(buf_.data()) iter_t<I-1>{
|
new(buf_.data()) iter_t<I-1>{
|
||||||
std::get<I-1>(*bs_).end()};
|
std::get<I-1>(*bn_).end()};
|
||||||
}
|
}
|
||||||
decrement(C<I-1>{});
|
decrement(C<I-1>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
decrement(C<0>)
|
decrement(C<0> const&)
|
||||||
{
|
{
|
||||||
auto constexpr I = 0;
|
auto constexpr I = 0;
|
||||||
if(iter<I>() != std::get<I>(*bs_).begin())
|
if(iter<I>() != std::get<I>(*bn_).begin())
|
||||||
{
|
{
|
||||||
--iter<I>();
|
--iter<I>();
|
||||||
return;
|
return;
|
||||||
@@ -312,11 +315,11 @@ private:
|
|||||||
|
|
||||||
template<std::size_t I>
|
template<std::size_t I>
|
||||||
void
|
void
|
||||||
decrement(C<I>)
|
decrement(C<I> const&)
|
||||||
{
|
{
|
||||||
if(n_ == I)
|
if(n_ == I)
|
||||||
{
|
{
|
||||||
if(iter<I>() != std::get<I>(*bs_).begin())
|
if(iter<I>() != std::get<I>(*bn_).begin())
|
||||||
{
|
{
|
||||||
--iter<I>();
|
--iter<I>();
|
||||||
return;
|
return;
|
||||||
@@ -325,7 +328,7 @@ private:
|
|||||||
using Iter = iter_t<I>;
|
using Iter = iter_t<I>;
|
||||||
iter<I>().~Iter();
|
iter<I>().~Iter();
|
||||||
new(buf_.data()) iter_t<I-1>{
|
new(buf_.data()) iter_t<I-1>{
|
||||||
std::get<I-1>(*bs_).end()};
|
std::get<I-1>(*bn_).end()};
|
||||||
}
|
}
|
||||||
decrement(C<I-1>{});
|
decrement(C<I-1>{});
|
||||||
}
|
}
|
||||||
@@ -333,54 +336,54 @@ private:
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::~const_iterator()
|
const_iterator::~const_iterator()
|
||||||
{
|
{
|
||||||
destroy(C<0>{});
|
destroy(C<0>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::const_iterator()
|
const_iterator::const_iterator()
|
||||||
: n_(sizeof...(Bs))
|
: n_(sizeof...(Bn))
|
||||||
, bs_(nullptr)
|
, bn_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::const_iterator(
|
const_iterator::const_iterator(
|
||||||
std::tuple<Bs...> const& bs, bool at_end)
|
std::tuple<Bn...> const& bn, bool at_end)
|
||||||
: bs_(&bs)
|
: bn_(&bn)
|
||||||
{
|
{
|
||||||
if(at_end)
|
if(at_end)
|
||||||
n_ = sizeof...(Bs);
|
n_ = sizeof...(Bn);
|
||||||
else
|
else
|
||||||
construct(C<0>{});
|
construct(C<0>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::const_iterator(const_iterator&& other)
|
const_iterator::const_iterator(const_iterator&& other)
|
||||||
: n_(other.n_)
|
: n_(other.n_)
|
||||||
, bs_(other.bs_)
|
, bn_(other.bn_)
|
||||||
{
|
{
|
||||||
move(C<0>{}, std::move(other));
|
move(std::move(other), C<0>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::const_iterator(const_iterator const& other)
|
const_iterator::const_iterator(const_iterator const& other)
|
||||||
: n_(other.n_)
|
: n_(other.n_)
|
||||||
, bs_(other.bs_)
|
, bn_(other.bn_)
|
||||||
{
|
{
|
||||||
copy(C<0>{}, other);
|
copy(other, C<0>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
auto
|
auto
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::operator=(const_iterator&& other) ->
|
const_iterator::operator=(const_iterator&& other) ->
|
||||||
const_iterator&
|
const_iterator&
|
||||||
{
|
{
|
||||||
@@ -388,14 +391,14 @@ const_iterator::operator=(const_iterator&& other) ->
|
|||||||
return *this;
|
return *this;
|
||||||
destroy(C<0>{});
|
destroy(C<0>{});
|
||||||
n_ = other.n_;
|
n_ = other.n_;
|
||||||
bs_ = other.bs_;
|
bn_ = other.bn_;
|
||||||
move(C<0>{}, std::move(other));
|
move(std::move(other), C<0>{});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
auto
|
auto
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::operator=(const_iterator const& other) ->
|
const_iterator::operator=(const_iterator const& other) ->
|
||||||
const_iterator&
|
const_iterator&
|
||||||
{
|
{
|
||||||
@@ -403,35 +406,35 @@ const_iterator&
|
|||||||
return *this;
|
return *this;
|
||||||
destroy(C<0>{});
|
destroy(C<0>{});
|
||||||
n_ = other.n_;
|
n_ = other.n_;
|
||||||
bs_ = other.bs_;
|
bn_ = other.bn_;
|
||||||
copy(C<0>{}, other);
|
copy(other, C<0>{});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
bool
|
bool
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::operator==(const_iterator const& other) const
|
const_iterator::operator==(const_iterator const& other) const
|
||||||
{
|
{
|
||||||
if(bs_ != other.bs_)
|
if(bn_ != other.bn_)
|
||||||
return false;
|
return false;
|
||||||
if(n_ != other.n_)
|
if(n_ != other.n_)
|
||||||
return false;
|
return false;
|
||||||
return equal(C<0>{}, other);
|
return equal(other, C<0>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
auto
|
auto
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::operator*() const ->
|
const_iterator::operator*() const ->
|
||||||
reference
|
reference
|
||||||
{
|
{
|
||||||
return dereference(C<0>{});
|
return dereference(C<0>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
auto
|
auto
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::operator++() ->
|
const_iterator::operator++() ->
|
||||||
const_iterator&
|
const_iterator&
|
||||||
{
|
{
|
||||||
@@ -439,30 +442,32 @@ const_iterator::operator++() ->
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
auto
|
auto
|
||||||
buffer_cat_helper<ValueType, Bs...>::
|
buffer_cat_helper<Bn...>::
|
||||||
const_iterator::operator--() ->
|
const_iterator::operator--() ->
|
||||||
const_iterator&
|
const_iterator&
|
||||||
{
|
{
|
||||||
decrement(C<sizeof...(Bs)>{});
|
decrement(C<sizeof...(Bn)>{});
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
|
inline
|
||||||
auto
|
auto
|
||||||
buffer_cat_helper<ValueType, Bs...>::begin() const ->
|
buffer_cat_helper<Bn...>::begin() const ->
|
||||||
const_iterator
|
const_iterator
|
||||||
{
|
{
|
||||||
return const_iterator(bs_, false);
|
return const_iterator{bn_, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueType, class... Bs>
|
template<class... Bn>
|
||||||
|
inline
|
||||||
auto
|
auto
|
||||||
buffer_cat_helper<ValueType, Bs...>::end() const ->
|
buffer_cat_helper<Bn...>::end() const ->
|
||||||
const_iterator
|
const_iterator
|
||||||
{
|
{
|
||||||
return const_iterator(bs_, true);
|
return const_iterator{bn_, true};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|||||||
@@ -85,53 +85,93 @@ public:
|
|||||||
type3::value && type4::value>;
|
type3::value && type4::value>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class B1, class... Bn>
|
||||||
|
struct is_all_ConstBufferSequence
|
||||||
|
: std::integral_constant<bool,
|
||||||
|
is_BufferSequence<B1, boost::asio::const_buffer>::type::value &&
|
||||||
|
is_all_ConstBufferSequence<Bn...>::value>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class B1>
|
||||||
|
struct is_all_ConstBufferSequence<B1>
|
||||||
|
: is_BufferSequence<B1, boost::asio::const_buffer>::type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class is_DynamicBuffer
|
class is_DynamicBuffer
|
||||||
{
|
{
|
||||||
template<class U, class R = std::integral_constant<
|
// size()
|
||||||
bool, is_BufferSequence<decltype(
|
template<class U, class R = std::is_convertible<decltype(
|
||||||
std::declval<U>().prepare(1)),
|
std::declval<U const>().size()), std::size_t>>
|
||||||
boost::asio::mutable_buffer>::type::value>>
|
|
||||||
static R check1(int);
|
static R check1(int);
|
||||||
template<class>
|
template<class>
|
||||||
static std::false_type check1(...);
|
static std::false_type check1(...);
|
||||||
using type1 = decltype(check1<T>(0));
|
using type1 = decltype(check1<T>(0));
|
||||||
|
|
||||||
template<class U, class R = std::integral_constant<
|
// max_size()
|
||||||
bool, is_BufferSequence<decltype(
|
template<class U, class R = std::is_convertible<decltype(
|
||||||
std::declval<U>().data()),
|
std::declval<U const>().max_size()), std::size_t>>
|
||||||
boost::asio::const_buffer>::type::value>>
|
|
||||||
static R check2(int);
|
static R check2(int);
|
||||||
template<class>
|
template<class>
|
||||||
static std::false_type check2(...);
|
static std::false_type check2(...);
|
||||||
using type2 = decltype(check2<T>(0));
|
using type2 = decltype(check2<T>(0));
|
||||||
|
|
||||||
template<class U, class R = decltype(
|
// capacity()
|
||||||
std::declval<U>().commit(1), std::true_type{})>
|
template<class U, class R = std::is_convertible<decltype(
|
||||||
|
std::declval<U const>().capacity()), std::size_t>>
|
||||||
static R check3(int);
|
static R check3(int);
|
||||||
template<class>
|
template<class>
|
||||||
static std::false_type check3(...);
|
static std::false_type check3(...);
|
||||||
using type3 = decltype(check3<T>(0));
|
using type3 = decltype(check3<T>(0));
|
||||||
|
|
||||||
template<class U, class R = decltype(
|
// data()
|
||||||
std::declval<U>().consume(1), std::true_type{})>
|
template<class U, class R = std::integral_constant<
|
||||||
|
bool, is_BufferSequence<decltype(
|
||||||
|
std::declval<U const>().data()),
|
||||||
|
boost::asio::const_buffer>::type::value>>
|
||||||
static R check4(int);
|
static R check4(int);
|
||||||
template<class>
|
template<class>
|
||||||
static std::false_type check4(...);
|
static std::false_type check4(...);
|
||||||
using type4 = decltype(check4<T>(0));
|
using type4 = decltype(check4<T>(0));
|
||||||
|
|
||||||
template<class U, class R = std::is_same<decltype(
|
// prepare()
|
||||||
std::declval<U>().size()), std::size_t>>
|
template<class U, class R = std::integral_constant<
|
||||||
|
bool, is_BufferSequence<decltype(
|
||||||
|
std::declval<U>().prepare(1)),
|
||||||
|
boost::asio::mutable_buffer>::type::value>>
|
||||||
static R check5(int);
|
static R check5(int);
|
||||||
template<class>
|
template<class>
|
||||||
static std::false_type check5(...);
|
static std::false_type check5(...);
|
||||||
using type5 = decltype(check5<T>(0));
|
using type5 = decltype(check5<T>(0));
|
||||||
|
|
||||||
|
// commit()
|
||||||
|
template<class U, class R = decltype(
|
||||||
|
std::declval<U>().commit(1), std::true_type{})>
|
||||||
|
static R check6(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check6(...);
|
||||||
|
using type6 = decltype(check6<T>(0));
|
||||||
|
|
||||||
|
// consume
|
||||||
|
template<class U, class R = decltype(
|
||||||
|
std::declval<U>().consume(1), std::true_type{})>
|
||||||
|
static R check7(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check7(...);
|
||||||
|
using type7 = decltype(check7<T>(0));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using type = std::integral_constant<bool,
|
using type = std::integral_constant<bool,
|
||||||
type1::value && type2::value &&
|
type1::value
|
||||||
type3::value && type4::value &&
|
&& type2::value
|
||||||
type5::value>;
|
//&& type3::value // Networking TS
|
||||||
|
&& type4::value
|
||||||
|
&& type5::value
|
||||||
|
&& type6::value
|
||||||
|
&& type7::value
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|||||||
40
src/beast/include/beast/core/detail/clamp.hpp
Normal file
40
src/beast/include/beast/core/detail/clamp.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// 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_CORE_DETAIL_CLAMP_HPP
|
||||||
|
#define BEAST_CORE_DETAIL_CLAMP_HPP
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class UInt>
|
||||||
|
static
|
||||||
|
std::size_t
|
||||||
|
clamp(UInt x)
|
||||||
|
{
|
||||||
|
if(x >= (std::numeric_limits<std::size_t>::max)())
|
||||||
|
return (std::numeric_limits<std::size_t>::max)();
|
||||||
|
return static_cast<std::size_t>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class UInt>
|
||||||
|
static
|
||||||
|
std::size_t
|
||||||
|
clamp(UInt x, std::size_t limit)
|
||||||
|
{
|
||||||
|
if(x >= limit)
|
||||||
|
return limit;
|
||||||
|
return static_cast<std::size_t>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -61,6 +61,8 @@ struct is_call_possible_udt3
|
|||||||
int operator()(int);
|
int operator()(int);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef __INTELLISENSE__
|
||||||
|
// VFALCO Fails to compile with Intellisense
|
||||||
static_assert(is_call_possible<
|
static_assert(is_call_possible<
|
||||||
is_call_possible_udt1, void(int)>::value, "");
|
is_call_possible_udt1, void(int)>::value, "");
|
||||||
|
|
||||||
@@ -81,6 +83,7 @@ static_assert(is_call_possible<
|
|||||||
|
|
||||||
static_assert(! is_call_possible<
|
static_assert(! is_call_possible<
|
||||||
is_call_possible_udt3 const, int(int)>::value, "");
|
is_call_possible_udt3 const, int(int)>::value, "");
|
||||||
|
#endif
|
||||||
|
|
||||||
} // test
|
} // test
|
||||||
|
|
||||||
|
|||||||
@@ -5,38 +5,104 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef BEAST_IMPL_PREPARE_BUFFERS_IPP
|
#ifndef BEAST_DETAIL_PREPARED_BUFFERS_HPP
|
||||||
#define BEAST_IMPL_PREPARE_BUFFERS_IPP
|
#define BEAST_DETAIL_PREPARED_BUFFERS_HPP
|
||||||
|
|
||||||
|
#include <beast/core/prepare_buffer.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
/** A buffer sequence adapter that shortens the sequence size.
|
||||||
|
|
||||||
|
The class adapts a buffer sequence to efficiently represent
|
||||||
|
a shorter subset of the original list of buffers starting
|
||||||
|
with the first byte of the original sequence.
|
||||||
|
|
||||||
|
@tparam BufferSequence The buffer sequence to adapt.
|
||||||
|
*/
|
||||||
template<class BufferSequence>
|
template<class BufferSequence>
|
||||||
void
|
class prepared_buffers
|
||||||
prepared_buffers<BufferSequence>::
|
|
||||||
setup(std::size_t n)
|
|
||||||
{
|
{
|
||||||
for(end_ = bs_.begin(); end_ != bs_.end(); ++end_)
|
using iter_type =
|
||||||
|
typename BufferSequence::const_iterator;
|
||||||
|
|
||||||
|
BufferSequence bs_;
|
||||||
|
iter_type back_;
|
||||||
|
iter_type end_;
|
||||||
|
std::size_t size_;
|
||||||
|
|
||||||
|
template<class Deduced>
|
||||||
|
prepared_buffers(Deduced&& other,
|
||||||
|
std::size_t nback, std::size_t nend)
|
||||||
|
: bs_(std::forward<Deduced>(other).bs_)
|
||||||
|
, back_(std::next(bs_.begin(), nback))
|
||||||
|
, end_(std::next(bs_.begin(), nend))
|
||||||
|
, size_(other.size_)
|
||||||
{
|
{
|
||||||
auto const len =
|
|
||||||
boost::asio::buffer_size(*end_);
|
|
||||||
if(n <= len)
|
|
||||||
{
|
|
||||||
size_ = n;
|
|
||||||
back_ = end_++;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
n -= len;
|
|
||||||
}
|
void
|
||||||
size_ = 0;
|
setup(std::size_t n);
|
||||||
back_ = end_;
|
|
||||||
}
|
public:
|
||||||
|
/// The type for each element in the list of buffers.
|
||||||
|
using value_type = typename std::conditional<
|
||||||
|
std::is_convertible<typename
|
||||||
|
std::iterator_traits<iter_type>::value_type,
|
||||||
|
boost::asio::mutable_buffer>::value,
|
||||||
|
boost::asio::mutable_buffer,
|
||||||
|
boost::asio::const_buffer>::type;
|
||||||
|
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
/// A bidirectional iterator type that may be used to read elements.
|
||||||
|
using const_iterator = implementation_defined;
|
||||||
|
|
||||||
|
#else
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Move constructor.
|
||||||
|
prepared_buffers(prepared_buffers&&);
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
prepared_buffers(prepared_buffers const&);
|
||||||
|
|
||||||
|
/// Move assignment.
|
||||||
|
prepared_buffers& operator=(prepared_buffers&&);
|
||||||
|
|
||||||
|
/// Copy assignment.
|
||||||
|
prepared_buffers& operator=(prepared_buffers const&);
|
||||||
|
|
||||||
|
/** Construct a shortened buffer sequence.
|
||||||
|
|
||||||
|
@param n The maximum number of bytes in the wrapped
|
||||||
|
sequence. If this is larger than the size of passed,
|
||||||
|
buffers, the resulting sequence will represent the
|
||||||
|
entire input sequence.
|
||||||
|
|
||||||
|
@param buffers The buffer sequence to adapt. A copy of
|
||||||
|
the sequence will be made, but ownership of the underlying
|
||||||
|
memory is not transferred.
|
||||||
|
*/
|
||||||
|
prepared_buffers(std::size_t n, BufferSequence const& buffers);
|
||||||
|
|
||||||
|
/// Get a bidirectional iterator to the first element.
|
||||||
|
const_iterator
|
||||||
|
begin() const;
|
||||||
|
|
||||||
|
/// Get a bidirectional iterator to one past the last element.
|
||||||
|
const_iterator
|
||||||
|
end() const;
|
||||||
|
};
|
||||||
|
|
||||||
template<class BufferSequence>
|
template<class BufferSequence>
|
||||||
class prepared_buffers<BufferSequence>::const_iterator
|
class prepared_buffers<BufferSequence>::const_iterator
|
||||||
@@ -50,8 +116,12 @@ class prepared_buffers<BufferSequence>::const_iterator
|
|||||||
typename BufferSequence::const_iterator it_;
|
typename BufferSequence::const_iterator it_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type =
|
using value_type = typename std::conditional<
|
||||||
typename std::iterator_traits<iter_type>::value_type;
|
std::is_convertible<typename
|
||||||
|
std::iterator_traits<iter_type>::value_type,
|
||||||
|
boost::asio::mutable_buffer>::value,
|
||||||
|
boost::asio::mutable_buffer,
|
||||||
|
boost::asio::const_buffer>::type;
|
||||||
using pointer = value_type const*;
|
using pointer = value_type const*;
|
||||||
using reference = value_type;
|
using reference = value_type;
|
||||||
using difference_type = std::ptrdiff_t;
|
using difference_type = std::ptrdiff_t;
|
||||||
@@ -59,10 +129,10 @@ public:
|
|||||||
std::bidirectional_iterator_tag;
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
const_iterator() = default;
|
const_iterator() = default;
|
||||||
const_iterator(const_iterator&& other) = default;
|
const_iterator(const_iterator&& other);
|
||||||
const_iterator(const_iterator const& other) = default;
|
const_iterator(const_iterator const& other);
|
||||||
const_iterator& operator=(const_iterator&& other) = default;
|
const_iterator& operator=(const_iterator&& other);
|
||||||
const_iterator& operator=(const_iterator const& other) = default;
|
const_iterator& operator=(const_iterator const& other);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
operator==(const_iterator const& other) const
|
operator==(const_iterator const& other) const
|
||||||
@@ -126,6 +196,67 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
void
|
||||||
|
prepared_buffers<BufferSequence>::
|
||||||
|
setup(std::size_t n)
|
||||||
|
{
|
||||||
|
for(end_ = bs_.begin(); end_ != bs_.end(); ++end_)
|
||||||
|
{
|
||||||
|
auto const len =
|
||||||
|
boost::asio::buffer_size(*end_);
|
||||||
|
if(n <= len)
|
||||||
|
{
|
||||||
|
size_ = n;
|
||||||
|
back_ = end_++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
n -= len;
|
||||||
|
}
|
||||||
|
size_ = 0;
|
||||||
|
back_ = end_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
prepared_buffers<BufferSequence>::const_iterator::
|
||||||
|
const_iterator(const_iterator&& other)
|
||||||
|
: b_(other.b_)
|
||||||
|
, it_(std::move(other.it_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
prepared_buffers<BufferSequence>::const_iterator::
|
||||||
|
const_iterator(const_iterator const& other)
|
||||||
|
: b_(other.b_)
|
||||||
|
, it_(other.it_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
auto
|
||||||
|
prepared_buffers<BufferSequence>::const_iterator::
|
||||||
|
operator=(const_iterator&& other) ->
|
||||||
|
const_iterator&
|
||||||
|
{
|
||||||
|
b_ = other.b_;
|
||||||
|
it_ = std::move(other.it_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class BufferSequence>
|
||||||
|
auto
|
||||||
|
prepared_buffers<BufferSequence>::const_iterator::
|
||||||
|
operator=(const_iterator const& other) ->
|
||||||
|
const_iterator&
|
||||||
|
{
|
||||||
|
if(&other == this)
|
||||||
|
return *this;
|
||||||
|
b_ = other.b_;
|
||||||
|
it_ = other.it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template<class BufferSequence>
|
template<class BufferSequence>
|
||||||
prepared_buffers<BufferSequence>::
|
prepared_buffers<BufferSequence>::
|
||||||
prepared_buffers(prepared_buffers&& other)
|
prepared_buffers(prepared_buffers&& other)
|
||||||
@@ -187,6 +318,7 @@ prepared_buffers(std::size_t n, BufferSequence const& bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence>
|
template<class BufferSequence>
|
||||||
|
inline
|
||||||
auto
|
auto
|
||||||
prepared_buffers<BufferSequence>::begin() const ->
|
prepared_buffers<BufferSequence>::begin() const ->
|
||||||
const_iterator
|
const_iterator
|
||||||
@@ -195,6 +327,7 @@ prepared_buffers<BufferSequence>::begin() const ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence>
|
template<class BufferSequence>
|
||||||
|
inline
|
||||||
auto
|
auto
|
||||||
prepared_buffers<BufferSequence>::end() const ->
|
prepared_buffers<BufferSequence>::end() const ->
|
||||||
const_iterator
|
const_iterator
|
||||||
@@ -202,14 +335,7 @@ prepared_buffers<BufferSequence>::end() const ->
|
|||||||
return const_iterator{*this, true};
|
return const_iterator{*this, true};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence>
|
} // detail
|
||||||
inline
|
|
||||||
prepared_buffers<BufferSequence>
|
|
||||||
prepare_buffers(std::size_t n, BufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
return prepared_buffers<BufferSequence>(n, buffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -249,7 +249,7 @@ update(sha1_context& ctx,
|
|||||||
std::uint8_t const*>(message);
|
std::uint8_t const*>(message);
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
auto const n = std::min(
|
auto const n = (std::min)(
|
||||||
size, sizeof(ctx.buf) - ctx.buflen);
|
size, sizeof(ctx.buf) - ctx.buflen);
|
||||||
std::memcpy(ctx.buf + ctx.buflen, p, n);
|
std::memcpy(ctx.buf + ctx.buflen, p, n);
|
||||||
ctx.buflen += n;
|
ctx.buflen += n;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
#define BEAST_DETAIL_STREAM_CONCEPTS_HPP
|
#define BEAST_DETAIL_STREAM_CONCEPTS_HPP
|
||||||
|
|
||||||
#include <beast/core/buffer_concepts.hpp>
|
#include <beast/core/buffer_concepts.hpp>
|
||||||
|
#include <beast/core/error.hpp>
|
||||||
#include <boost/asio/io_service.hpp>
|
#include <boost/asio/io_service.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ namespace detail {
|
|||||||
struct StreamHandler
|
struct StreamHandler
|
||||||
{
|
{
|
||||||
StreamHandler(StreamHandler const&) = default;
|
StreamHandler(StreamHandler const&) = default;
|
||||||
void operator()(boost::system::error_code ec, std::size_t);
|
void operator()(error_code ec, std::size_t);
|
||||||
};
|
};
|
||||||
using ReadHandler = StreamHandler;
|
using ReadHandler = StreamHandler;
|
||||||
using WriteHandler = StreamHandler;
|
using WriteHandler = StreamHandler;
|
||||||
@@ -79,9 +79,6 @@ public:
|
|||||||
template<class T>
|
template<class T>
|
||||||
class is_SyncReadStream
|
class is_SyncReadStream
|
||||||
{
|
{
|
||||||
using error_code =
|
|
||||||
boost::system::error_code;
|
|
||||||
|
|
||||||
template<class U, class R = std::is_same<decltype(
|
template<class U, class R = std::is_same<decltype(
|
||||||
std::declval<U>().read_some(
|
std::declval<U>().read_some(
|
||||||
std::declval<MutableBufferSequence>())),
|
std::declval<MutableBufferSequence>())),
|
||||||
@@ -108,9 +105,6 @@ public:
|
|||||||
template<class T>
|
template<class T>
|
||||||
class is_SyncWriteStream
|
class is_SyncWriteStream
|
||||||
{
|
{
|
||||||
using error_code =
|
|
||||||
boost::system::error_code;
|
|
||||||
|
|
||||||
template<class U, class R = std::is_same<decltype(
|
template<class U, class R = std::is_same<decltype(
|
||||||
std::declval<U>().write_some(
|
std::declval<U>().write_some(
|
||||||
std::declval<ConstBufferSequence>())),
|
std::declval<ConstBufferSequence>())),
|
||||||
|
|||||||
93
src/beast/include/beast/core/detail/sync_ostream.hpp
Normal file
93
src/beast/include/beast/core/detail/sync_ostream.hpp
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
//
|
||||||
|
// 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_DETAIL_SYNC_OSTREAM_HPP
|
||||||
|
#define BEAST_DETAIL_SYNC_OSTREAM_HPP
|
||||||
|
|
||||||
|
#include <beast/core/buffer_concepts.hpp>
|
||||||
|
#include <beast/core/error.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
/** A SyncWriteStream which outputs to a `std::ostream`
|
||||||
|
|
||||||
|
Objects of this type meet the requirements of @b SyncWriteStream.
|
||||||
|
*/
|
||||||
|
class sync_ostream
|
||||||
|
{
|
||||||
|
std::ostream& os_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Construct the stream.
|
||||||
|
|
||||||
|
@param os The associated `std::ostream`. All buffers
|
||||||
|
written will be passed to the associated output stream.
|
||||||
|
*/
|
||||||
|
sync_ostream(std::ostream& os)
|
||||||
|
: os_(os)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_some(ConstBufferSequence const& buffers);
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_some(ConstBufferSequence const& buffers,
|
||||||
|
error_code& ec);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
sync_ostream::
|
||||||
|
write_some(ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
is_ConstBufferSequence<ConstBufferSequence>::value,
|
||||||
|
"ConstBufferSequence requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
auto const n = write_some(buffers, ec);
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
sync_ostream::
|
||||||
|
write_some(ConstBufferSequence const& buffers,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
is_ConstBufferSequence<ConstBufferSequence>::value,
|
||||||
|
"ConstBufferSequence requirements not met");
|
||||||
|
std::size_t n = 0;
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
for(auto const& buffer : buffers)
|
||||||
|
{
|
||||||
|
os_.write(buffer_cast<char const*>(buffer),
|
||||||
|
buffer_size(buffer));
|
||||||
|
if(os_.fail())
|
||||||
|
{
|
||||||
|
ec = errc::make_error_code(
|
||||||
|
errc::no_stream_resources);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n += buffer_size(buffer);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
84
src/beast/include/beast/core/detail/type_traits.hpp
Normal file
84
src/beast/include/beast/core/detail/type_traits.hpp
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// 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_DETAIL_TYPE_TRAITS_HPP
|
||||||
|
#define BEAST_DETAIL_TYPE_TRAITS_HPP
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class... Ts>
|
||||||
|
struct make_void
|
||||||
|
{
|
||||||
|
using type = void;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class... Ts>
|
||||||
|
using void_t = typename make_void<Ts...>::type;
|
||||||
|
|
||||||
|
template<class... Ts>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
ignore_unused(Ts const& ...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Ts>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
ignore_unused()
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
std::size_t constexpr
|
||||||
|
max_sizeof()
|
||||||
|
{
|
||||||
|
return sizeof(U);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U0, class U1, class... Us>
|
||||||
|
std::size_t constexpr
|
||||||
|
max_sizeof()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
max_sizeof<U0>() > max_sizeof<U1, Us...>() ?
|
||||||
|
max_sizeof<U0>() : max_sizeof<U1, Us...>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned N, class T, class... Tn>
|
||||||
|
struct repeat_tuple_impl
|
||||||
|
{
|
||||||
|
using type = typename repeat_tuple_impl<
|
||||||
|
N - 1, T, T, Tn...>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class... Tn>
|
||||||
|
struct repeat_tuple_impl<0, T, Tn...>
|
||||||
|
{
|
||||||
|
using type = std::tuple<T, Tn...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<unsigned N, class T>
|
||||||
|
struct repeat_tuple
|
||||||
|
{
|
||||||
|
using type =
|
||||||
|
typename repeat_tuple_impl<N-1, T>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct repeat_tuple<0, T>
|
||||||
|
{
|
||||||
|
using type = std::tuple<>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
#include <beast/core/detail/get_lowest_layer.hpp>
|
#include <beast/core/detail/get_lowest_layer.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/asio/io_service.hpp>
|
#include <boost/asio/io_service.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -47,7 +46,7 @@ namespace beast {
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
@code
|
@code
|
||||||
// Process the next HTTP headers on the stream,
|
// Process the next HTTP header on the stream,
|
||||||
// leaving excess bytes behind for the next call.
|
// leaving excess bytes behind for the next call.
|
||||||
//
|
//
|
||||||
template<class DynamicBuffer>
|
template<class DynamicBuffer>
|
||||||
@@ -55,7 +54,7 @@ namespace beast {
|
|||||||
dynabuf_readstream<DynamicBuffer>& stream)
|
dynabuf_readstream<DynamicBuffer>& stream)
|
||||||
{
|
{
|
||||||
// Read up to and including the end of the HTTP
|
// Read up to and including the end of the HTTP
|
||||||
// headers, leaving the sequence in the stream's
|
// header, leaving the sequence in the stream's
|
||||||
// buffer. read_until may read past the end of the
|
// buffer. read_until may read past the end of the
|
||||||
// headers; the return value will include only the
|
// headers; the return value will include only the
|
||||||
// part up to the end of the delimiter.
|
// part up to the end of the delimiter.
|
||||||
|
|||||||
@@ -19,6 +19,18 @@ using error_code = boost::system::error_code;
|
|||||||
/// The type of system error thrown by the library
|
/// The type of system error thrown by the library
|
||||||
using system_error = boost::system::system_error;
|
using system_error = boost::system::system_error;
|
||||||
|
|
||||||
|
/// The type of error category used by the library
|
||||||
|
using error_category = boost::system::error_category;
|
||||||
|
|
||||||
|
/// The type of error condition used by the library
|
||||||
|
using error_condition = boost::system::error_condition;
|
||||||
|
|
||||||
|
/// The set of constants used for cross-platform error codes
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
enum errc{};
|
||||||
|
#else
|
||||||
|
namespace errc = boost::system::errc;
|
||||||
|
#endif
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#ifndef BEAST_HANDLER_ALLOC_HPP
|
#ifndef BEAST_HANDLER_ALLOC_HPP
|
||||||
#define BEAST_HANDLER_ALLOC_HPP
|
#define BEAST_HANDLER_ALLOC_HPP
|
||||||
|
|
||||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
#include <beast/core/handler_helpers.hpp>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@@ -23,15 +23,15 @@ namespace beast {
|
|||||||
|
|
||||||
This allocator uses the handler customizations `asio_handler_allocate`
|
This allocator uses the handler customizations `asio_handler_allocate`
|
||||||
and `asio_handler_deallocate` to manage memory. It meets the requirements
|
and `asio_handler_deallocate` to manage memory. It meets the requirements
|
||||||
of `Allocator` and can be used anywhere a `std::allocator` is
|
of @b Allocator and can be used anywhere a `std::allocator` is
|
||||||
accepted.
|
accepted.
|
||||||
|
|
||||||
@tparam T The type of objects allocated by the allocator.
|
@tparam T The type of objects allocated by the allocator.
|
||||||
|
|
||||||
@tparam CompletionHandler The type of handler.
|
@tparam CompletionHandler The type of handler.
|
||||||
|
|
||||||
@note Allocated memory is only valid until the handler is called. The
|
@note Memory allocated by this allocator must be freed before
|
||||||
caller is still responsible for freeing memory.
|
the handler is invoked or undefined behavior results.
|
||||||
*/
|
*/
|
||||||
#if GENERATING_DOCS
|
#if GENERATING_DOCS
|
||||||
template<class T, class CompletionHandler>
|
template<class T, class CompletionHandler>
|
||||||
@@ -49,12 +49,18 @@ private:
|
|||||||
template<class U, class H>
|
template<class U, class H>
|
||||||
friend class handler_alloc;
|
friend class handler_alloc;
|
||||||
|
|
||||||
CompletionHandler h_;
|
CompletionHandler& h_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using is_always_equal = std::true_type;
|
using is_always_equal = std::true_type;
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
using other = handler_alloc<U, CompletionHandler>;
|
||||||
|
};
|
||||||
|
|
||||||
handler_alloc() = delete;
|
handler_alloc() = delete;
|
||||||
handler_alloc(handler_alloc&&) = default;
|
handler_alloc(handler_alloc&&) = default;
|
||||||
handler_alloc(handler_alloc const&) = default;
|
handler_alloc(handler_alloc const&) = default;
|
||||||
@@ -63,31 +69,16 @@ public:
|
|||||||
|
|
||||||
/** Construct the allocator.
|
/** Construct the allocator.
|
||||||
|
|
||||||
The handler is moved or copied into the allocator.
|
A reference of the handler is stored. The handler must
|
||||||
|
remain valid for at least the lifetime of the allocator.
|
||||||
*/
|
*/
|
||||||
explicit
|
explicit
|
||||||
handler_alloc(CompletionHandler&& h)
|
handler_alloc(CompletionHandler& h)
|
||||||
: h_(std::move(h))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Construct the allocator.
|
|
||||||
|
|
||||||
A copy of the handler is made.
|
|
||||||
*/
|
|
||||||
explicit
|
|
||||||
handler_alloc(CompletionHandler const& h)
|
|
||||||
: h_(h)
|
: h_(h)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U>
|
/// Copy constructor
|
||||||
handler_alloc(
|
|
||||||
handler_alloc<U, CompletionHandler>&& other)
|
|
||||||
: h_(std::move(other.h_))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
handler_alloc(
|
handler_alloc(
|
||||||
handler_alloc<U, CompletionHandler> const& other)
|
handler_alloc<U, CompletionHandler> const& other)
|
||||||
@@ -100,7 +91,7 @@ public:
|
|||||||
{
|
{
|
||||||
auto const size = n * sizeof(T);
|
auto const size = n * sizeof(T);
|
||||||
return static_cast<value_type*>(
|
return static_cast<value_type*>(
|
||||||
boost_asio_handler_alloc_helpers::allocate(
|
beast_asio_helpers::allocate(
|
||||||
size, h_));
|
size, h_));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +99,7 @@ public:
|
|||||||
deallocate(value_type* p, std::ptrdiff_t n)
|
deallocate(value_type* p, std::ptrdiff_t n)
|
||||||
{
|
{
|
||||||
auto const size = n * sizeof(T);
|
auto const size = n * sizeof(T);
|
||||||
boost_asio_handler_alloc_helpers::deallocate(
|
beast_asio_helpers::deallocate(
|
||||||
p, size, h_);
|
p, size, h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
104
src/beast/include/beast/core/handler_helpers.hpp
Normal file
104
src/beast/include/beast/core/handler_helpers.hpp
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
//
|
||||||
|
// 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_HANDLER_HELPERS_HPP
|
||||||
|
#define BEAST_HANDLER_HELPERS_HPP
|
||||||
|
|
||||||
|
#include <boost/asio/handler_alloc_hook.hpp>
|
||||||
|
#include <boost/asio/handler_continuation_hook.hpp>
|
||||||
|
#include <boost/asio/handler_invoke_hook.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
/* Calls to:
|
||||||
|
|
||||||
|
* asio_handler_allocate
|
||||||
|
* asio_handler_deallocate
|
||||||
|
* asio_handler_invoke
|
||||||
|
* asio_handler_is_continuation
|
||||||
|
|
||||||
|
must be made from a namespace that does not
|
||||||
|
contain overloads of this function. The beast_asio_helpers
|
||||||
|
namespace is defined here for that purpose.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace beast_asio_helpers {
|
||||||
|
|
||||||
|
/// Allocation function for handlers.
|
||||||
|
template <class Handler>
|
||||||
|
inline
|
||||||
|
void*
|
||||||
|
allocate(std::size_t s, Handler& handler)
|
||||||
|
{
|
||||||
|
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
|
||||||
|
return ::operator new(s);
|
||||||
|
#else
|
||||||
|
using boost::asio::asio_handler_allocate;
|
||||||
|
return asio_handler_allocate(s, std::addressof(handler));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deallocation function for handlers.
|
||||||
|
template<class Handler>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
deallocate(void* p, std::size_t s, Handler& handler)
|
||||||
|
{
|
||||||
|
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
|
||||||
|
::operator delete(p);
|
||||||
|
#else
|
||||||
|
using boost::asio::asio_handler_deallocate;
|
||||||
|
asio_handler_deallocate(p, s, std::addressof(handler));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invoke function for handlers.
|
||||||
|
template<class Function, class Handler>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
invoke(Function& function, Handler& handler)
|
||||||
|
{
|
||||||
|
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
|
||||||
|
Function tmp(function);
|
||||||
|
tmp();
|
||||||
|
#else
|
||||||
|
using boost::asio::asio_handler_invoke;
|
||||||
|
asio_handler_invoke(function, std::addressof(handler));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invoke function for handlers.
|
||||||
|
template<class Function, class Handler>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
invoke(Function const& function, Handler& handler)
|
||||||
|
{
|
||||||
|
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
|
||||||
|
Function tmp(function);
|
||||||
|
tmp();
|
||||||
|
#else
|
||||||
|
using boost::asio::asio_handler_invoke;
|
||||||
|
asio_handler_invoke(function, std::addressof(handler));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if handler represents a continuation of the asynchronous operation
|
||||||
|
template<class Handler>
|
||||||
|
inline
|
||||||
|
bool
|
||||||
|
is_continuation(Handler& handler)
|
||||||
|
{
|
||||||
|
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
using boost::asio::asio_handler_is_continuation;
|
||||||
|
return asio_handler_is_continuation(std::addressof(handler));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast_asio_helpers
|
||||||
|
|
||||||
|
#endif
|
||||||
173
src/beast/include/beast/core/handler_ptr.hpp
Normal file
173
src/beast/include/beast/core/handler_ptr.hpp
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
//
|
||||||
|
// 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_HANDLER_PTR_HPP
|
||||||
|
#define BEAST_HANDLER_PTR_HPP
|
||||||
|
|
||||||
|
#include <beast/core/detail/type_traits.hpp>
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/** A smart pointer container.
|
||||||
|
|
||||||
|
This is a smart pointer that retains shared ownership of an
|
||||||
|
object through a pointer. Memory is managed using the allocation
|
||||||
|
and deallocation functions associated with a completion handler,
|
||||||
|
which is also stored in the object. The object is destroyed and
|
||||||
|
its memory deallocated when one of the following happens:
|
||||||
|
|
||||||
|
@li The function @ref invoke is called.
|
||||||
|
|
||||||
|
@li The function @ref release_handler is called
|
||||||
|
|
||||||
|
@li The last remaining container owning the object is destroyed
|
||||||
|
|
||||||
|
Objects of this type are used in the implementation of
|
||||||
|
composed operations. Typically the composed operation's shared
|
||||||
|
state is managed by the @ref handler_ptr and an allocator
|
||||||
|
associated with the final handler is used to create the managed
|
||||||
|
object.
|
||||||
|
|
||||||
|
@note The reference count is stored using a 16 bit unsigned
|
||||||
|
integer. Making more than 2^16 copies of one object results
|
||||||
|
in undefined behavior.
|
||||||
|
*/
|
||||||
|
template<class T, class Handler>
|
||||||
|
class handler_ptr
|
||||||
|
{
|
||||||
|
struct P
|
||||||
|
{
|
||||||
|
T* t;
|
||||||
|
std::atomic<std::uint16_t> n;
|
||||||
|
|
||||||
|
// There's no way to put the handler anywhere else
|
||||||
|
// without exposing ourselves to race conditions
|
||||||
|
// and all sorts of ugliness.
|
||||||
|
// See:
|
||||||
|
// https://github.com/vinniefalco/Beast/issues/215
|
||||||
|
Handler handler;
|
||||||
|
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
P(DeducedHandler&& handler, Args&&... args);
|
||||||
|
};
|
||||||
|
|
||||||
|
P* p_;
|
||||||
|
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
handler_ptr(int, DeducedHandler&& handler, Args&&... args);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The type of handler this object stores
|
||||||
|
using handler_type = Handler;
|
||||||
|
|
||||||
|
/// Copy assignment (disallowed).
|
||||||
|
handler_ptr& operator=(handler_ptr const&) = delete;
|
||||||
|
|
||||||
|
/** Destructs the owned object if no more @ref handler_ptr link to it.
|
||||||
|
|
||||||
|
If `*this` owns an object and it is the last @ref handler_ptr
|
||||||
|
owning it, the object is destroyed and the memory deallocated
|
||||||
|
using the associated deallocator.
|
||||||
|
*/
|
||||||
|
~handler_ptr();
|
||||||
|
|
||||||
|
/** Move constructor.
|
||||||
|
|
||||||
|
When this call returns, the moved-from container
|
||||||
|
will have no owned object.
|
||||||
|
*/
|
||||||
|
handler_ptr(handler_ptr&& other);
|
||||||
|
|
||||||
|
/// Copy constructor
|
||||||
|
handler_ptr(handler_ptr const& other);
|
||||||
|
|
||||||
|
/// Returns a reference to the handler
|
||||||
|
handler_type&
|
||||||
|
handler() const
|
||||||
|
{
|
||||||
|
return p_->handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a pointer to the owned object
|
||||||
|
T*
|
||||||
|
get() const
|
||||||
|
{
|
||||||
|
return p_->t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a reference to the owned object.
|
||||||
|
T&
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
return *get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a pointer to the owned object.
|
||||||
|
T*
|
||||||
|
operator->() const
|
||||||
|
{
|
||||||
|
return get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Release ownership of the handler
|
||||||
|
|
||||||
|
If `*this` owns an object, it is first destroyed.
|
||||||
|
|
||||||
|
@return The released handler.
|
||||||
|
*/
|
||||||
|
handler_type
|
||||||
|
release_handler();
|
||||||
|
|
||||||
|
/** Invoke the handler in the owned object.
|
||||||
|
|
||||||
|
This function invokes the handler in the owned object
|
||||||
|
with a forwarded argument list. Before the invocation,
|
||||||
|
the owned object is destroyed, satisfying the
|
||||||
|
deallocation-before-invocation Asio guarantee. All
|
||||||
|
instances of @ref handler_ptr which refer to the
|
||||||
|
same owned object will be reset, including this instance.
|
||||||
|
*/
|
||||||
|
template<class... Args>
|
||||||
|
void
|
||||||
|
invoke(Args&&... args);
|
||||||
|
|
||||||
|
// VFALCO The free function interface works around
|
||||||
|
// a horrible Visual Studio 15 Update 3 bug
|
||||||
|
|
||||||
|
/** Construct a new `handler_ptr`.
|
||||||
|
|
||||||
|
@param handler The handler. The allocator associated with
|
||||||
|
the handler will be used to allocate memory for the owned
|
||||||
|
object. This argument will be forwarded to the owned object's
|
||||||
|
constructor.
|
||||||
|
|
||||||
|
@param args Optional arguments forwarded to
|
||||||
|
the owned object's constructor.
|
||||||
|
*/
|
||||||
|
/** @{ */
|
||||||
|
template<class U, class CompletionHandler, class... Args>
|
||||||
|
friend
|
||||||
|
handler_ptr<U, CompletionHandler>
|
||||||
|
make_handler_ptr(
|
||||||
|
CompletionHandler&& handler, Args&&... args);
|
||||||
|
|
||||||
|
template<class U, class CompletionHandler, class... Args>
|
||||||
|
friend
|
||||||
|
handler_ptr<U, CompletionHandler>
|
||||||
|
make_handler_ptr(
|
||||||
|
CompletionHandler const& handler, Args&&... args);
|
||||||
|
/** @} */
|
||||||
|
};
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/core/impl/handler_ptr.ipp>
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,9 +8,10 @@
|
|||||||
#ifndef BEAST_IMPL_BASIC_STREAMBUF_IPP
|
#ifndef BEAST_IMPL_BASIC_STREAMBUF_IPP
|
||||||
#define BEAST_IMPL_BASIC_STREAMBUF_IPP
|
#define BEAST_IMPL_BASIC_STREAMBUF_IPP
|
||||||
|
|
||||||
|
#include <beast/core/detail/type_traits.hpp>
|
||||||
#include <beast/core/detail/write_dynabuf.hpp>
|
#include <beast/core/detail/write_dynabuf.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -533,7 +534,7 @@ basic_streambuf<Allocator>::capacity() const
|
|||||||
{
|
{
|
||||||
auto pos = out_;
|
auto pos = out_;
|
||||||
if(pos == list_.end())
|
if(pos == list_.end())
|
||||||
return 0;
|
return in_size_;
|
||||||
auto n = pos->size() - out_pos_;
|
auto n = pos->size() - out_pos_;
|
||||||
while(++pos != list_.end())
|
while(++pos != list_.end())
|
||||||
n += pos->size();
|
n += pos->size();
|
||||||
@@ -656,7 +657,7 @@ basic_streambuf<Allocator>::commit(size_type n)
|
|||||||
debug_check();
|
debug_check();
|
||||||
}
|
}
|
||||||
|
|
||||||
n = std::min(n, out_end_ - out_pos_);
|
n = (std::min)(n, out_end_ - out_pos_);
|
||||||
out_pos_ += n;
|
out_pos_ += n;
|
||||||
in_size_ += n;
|
in_size_ += n;
|
||||||
if(out_pos_ == out_->size())
|
if(out_pos_ == out_->size())
|
||||||
@@ -786,6 +787,7 @@ void
|
|||||||
basic_streambuf<Allocator>::
|
basic_streambuf<Allocator>::
|
||||||
copy_assign(basic_streambuf const& other, std::false_type)
|
copy_assign(basic_streambuf const& other, std::false_type)
|
||||||
{
|
{
|
||||||
|
beast::detail::ignore_unused(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
@@ -816,36 +818,36 @@ basic_streambuf<Allocator>::debug_check() const
|
|||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
assert(buffer_size(data()) == in_size_);
|
BOOST_ASSERT(buffer_size(data()) == in_size_);
|
||||||
if(list_.empty())
|
if(list_.empty())
|
||||||
{
|
{
|
||||||
assert(in_pos_ == 0);
|
BOOST_ASSERT(in_pos_ == 0);
|
||||||
assert(in_size_ == 0);
|
BOOST_ASSERT(in_size_ == 0);
|
||||||
assert(out_pos_ == 0);
|
BOOST_ASSERT(out_pos_ == 0);
|
||||||
assert(out_end_ == 0);
|
BOOST_ASSERT(out_end_ == 0);
|
||||||
assert(out_ == list_.end());
|
BOOST_ASSERT(out_ == list_.end());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const& front = list_.front();
|
auto const& front = list_.front();
|
||||||
|
|
||||||
assert(in_pos_ < front.size());
|
BOOST_ASSERT(in_pos_ < front.size());
|
||||||
|
|
||||||
if(out_ == list_.end())
|
if(out_ == list_.end())
|
||||||
{
|
{
|
||||||
assert(out_pos_ == 0);
|
BOOST_ASSERT(out_pos_ == 0);
|
||||||
assert(out_end_ == 0);
|
BOOST_ASSERT(out_end_ == 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto const& out = *out_;
|
auto const& out = *out_;
|
||||||
auto const& back = list_.back();
|
auto const& back = list_.back();
|
||||||
|
|
||||||
assert(out_end_ <= back.size());
|
BOOST_ASSERT(out_end_ <= back.size());
|
||||||
assert(out_pos_ < out.size());
|
BOOST_ASSERT(out_pos_ < out.size());
|
||||||
assert(&out != &front || out_pos_ >= in_pos_);
|
BOOST_ASSERT(&out != &front || out_pos_ >= in_pos_);
|
||||||
assert(&out != &front || out_pos_ - in_pos_ == in_size_);
|
BOOST_ASSERT(&out != &front || out_pos_ - in_pos_ == in_size_);
|
||||||
assert(&out != &back || out_pos_ <= out_end_);
|
BOOST_ASSERT(&out != &back || out_pos_ <= out_end_);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -855,11 +857,18 @@ std::size_t
|
|||||||
read_size_helper(basic_streambuf<
|
read_size_helper(basic_streambuf<
|
||||||
Allocator> const& streambuf, std::size_t max_size)
|
Allocator> const& streambuf, std::size_t max_size)
|
||||||
{
|
{
|
||||||
|
BOOST_ASSERT(max_size >= 1);
|
||||||
|
// If we already have an allocated
|
||||||
|
// buffer, try to fill that up first
|
||||||
auto const avail = streambuf.capacity() - streambuf.size();
|
auto const avail = streambuf.capacity() - streambuf.size();
|
||||||
if(avail == 0)
|
if (avail > 0)
|
||||||
return std::min(max_size,
|
return (std::min)(avail, max_size);
|
||||||
std::max<std::size_t>(512, streambuf.alloc_size_));
|
// Try to have just one new block allocated
|
||||||
return std::min(max_size, avail);
|
constexpr std::size_t low = 512;
|
||||||
|
if (streambuf.alloc_size_ > low)
|
||||||
|
return (std::min)(max_size, streambuf.alloc_size_);
|
||||||
|
// ...but enforce a 512 byte minimum.
|
||||||
|
return (std::min)(max_size, low);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Alloc, class T>
|
template<class Alloc, class T>
|
||||||
|
|||||||
@@ -444,7 +444,7 @@ buffers_adapter<MutableBufferSequence>::commit(std::size_t n)
|
|||||||
max_size_ -= avail;
|
max_size_ -= avail;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = std::min(n, out_end_ - out_pos_);
|
n = (std::min)(n, out_end_ - out_pos_);
|
||||||
out_pos_ += n;
|
out_pos_ += n;
|
||||||
in_size_ += n;
|
in_size_ += n;
|
||||||
max_size_ -= n;
|
max_size_ -= n;
|
||||||
|
|||||||
@@ -18,10 +18,10 @@
|
|||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
template<class BufferSequence, class ValueType>
|
template<class BufferSequence>
|
||||||
class consuming_buffers<BufferSequence, ValueType>::const_iterator
|
class consuming_buffers<BufferSequence>::const_iterator
|
||||||
{
|
{
|
||||||
friend class consuming_buffers<BufferSequence, ValueType>;
|
friend class consuming_buffers<BufferSequence>;
|
||||||
|
|
||||||
using iter_type =
|
using iter_type =
|
||||||
typename BufferSequence::const_iterator;
|
typename BufferSequence::const_iterator;
|
||||||
@@ -30,8 +30,12 @@ class consuming_buffers<BufferSequence, ValueType>::const_iterator
|
|||||||
consuming_buffers const* b_ = nullptr;
|
consuming_buffers const* b_ = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type =
|
using value_type = typename std::conditional<
|
||||||
typename std::iterator_traits<iter_type>::value_type;
|
std::is_convertible<typename
|
||||||
|
std::iterator_traits<iter_type>::value_type,
|
||||||
|
boost::asio::mutable_buffer>::value,
|
||||||
|
boost::asio::mutable_buffer,
|
||||||
|
boost::asio::const_buffer>::type;
|
||||||
using pointer = value_type const*;
|
using pointer = value_type const*;
|
||||||
using reference = value_type;
|
using reference = value_type;
|
||||||
using difference_type = std::ptrdiff_t;
|
using difference_type = std::ptrdiff_t;
|
||||||
@@ -59,8 +63,9 @@ public:
|
|||||||
reference
|
reference
|
||||||
operator*() const
|
operator*() const
|
||||||
{
|
{
|
||||||
return it_ == b_->begin_ ?
|
return it_ == b_->begin_
|
||||||
*it_ + b_->skip_ : *it_;
|
? value_type{*it_} + b_->skip_
|
||||||
|
: *it_;
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer
|
pointer
|
||||||
@@ -105,8 +110,8 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class BufferSequence, class ValueType>
|
template<class BufferSequence>
|
||||||
consuming_buffers<BufferSequence, ValueType>::
|
consuming_buffers<BufferSequence>::
|
||||||
consuming_buffers(consuming_buffers&& other)
|
consuming_buffers(consuming_buffers&& other)
|
||||||
: consuming_buffers(std::move(other),
|
: consuming_buffers(std::move(other),
|
||||||
std::distance<iter_type>(
|
std::distance<iter_type>(
|
||||||
@@ -114,8 +119,8 @@ consuming_buffers(consuming_buffers&& other)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence, class ValueType>
|
template<class BufferSequence>
|
||||||
consuming_buffers<BufferSequence, ValueType>::
|
consuming_buffers<BufferSequence>::
|
||||||
consuming_buffers(consuming_buffers const& other)
|
consuming_buffers(consuming_buffers const& other)
|
||||||
: consuming_buffers(other,
|
: consuming_buffers(other,
|
||||||
std::distance<iter_type>(
|
std::distance<iter_type>(
|
||||||
@@ -123,9 +128,9 @@ consuming_buffers(consuming_buffers const& other)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence, class ValueType>
|
template<class BufferSequence>
|
||||||
auto
|
auto
|
||||||
consuming_buffers<BufferSequence, ValueType>::
|
consuming_buffers<BufferSequence>::
|
||||||
operator=(consuming_buffers&& other) ->
|
operator=(consuming_buffers&& other) ->
|
||||||
consuming_buffers&
|
consuming_buffers&
|
||||||
{
|
{
|
||||||
@@ -137,9 +142,9 @@ operator=(consuming_buffers&& other) ->
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence, class ValueType>
|
template<class BufferSequence>
|
||||||
auto
|
auto
|
||||||
consuming_buffers<BufferSequence, ValueType>::
|
consuming_buffers<BufferSequence>::
|
||||||
operator=(consuming_buffers const& other) ->
|
operator=(consuming_buffers const& other) ->
|
||||||
consuming_buffers&
|
consuming_buffers&
|
||||||
{
|
{
|
||||||
@@ -151,35 +156,41 @@ operator=(consuming_buffers const& other) ->
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence, class ValueType>
|
template<class BufferSequence>
|
||||||
consuming_buffers<BufferSequence, ValueType>::
|
consuming_buffers<BufferSequence>::
|
||||||
consuming_buffers(BufferSequence const& bs)
|
consuming_buffers(BufferSequence const& bs)
|
||||||
: bs_(bs)
|
: bs_(bs)
|
||||||
, begin_(bs_.begin())
|
, begin_(bs_.begin())
|
||||||
{
|
{
|
||||||
static_assert(is_BufferSequence<BufferSequence, ValueType>::value,
|
static_assert(
|
||||||
|
is_BufferSequence<BufferSequence, value_type>::value,
|
||||||
"BufferSequence requirements not met");
|
"BufferSequence requirements not met");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence, class ValueType>
|
template<class BufferSequence>
|
||||||
|
inline
|
||||||
auto
|
auto
|
||||||
consuming_buffers<BufferSequence, ValueType>::begin() const ->
|
consuming_buffers<BufferSequence>::
|
||||||
|
begin() const ->
|
||||||
const_iterator
|
const_iterator
|
||||||
{
|
{
|
||||||
return const_iterator{*this, begin_};
|
return const_iterator{*this, begin_};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence, class ValueType>
|
template<class BufferSequence>
|
||||||
|
inline
|
||||||
auto
|
auto
|
||||||
consuming_buffers<BufferSequence, ValueType>::end() const ->
|
consuming_buffers<BufferSequence>::
|
||||||
|
end() const ->
|
||||||
const_iterator
|
const_iterator
|
||||||
{
|
{
|
||||||
return const_iterator{*this, bs_.end()};
|
return const_iterator{*this, bs_.end()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence, class ValueType>
|
template<class BufferSequence>
|
||||||
void
|
void
|
||||||
consuming_buffers<BufferSequence, ValueType>::consume(std::size_t n)
|
consuming_buffers<BufferSequence>::
|
||||||
|
consume(std::size_t n)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
for(;n > 0 && begin_ != bs_.end(); ++begin_)
|
for(;n > 0 && begin_ != bs_.end(); ++begin_)
|
||||||
@@ -196,15 +207,6 @@ consuming_buffers<BufferSequence, ValueType>::consume(std::size_t n)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BufferSequence>
|
|
||||||
consuming_buffers<BufferSequence, typename BufferSequence::value_type>
|
|
||||||
consumed_buffers(BufferSequence const& bs, std::size_t n)
|
|
||||||
{
|
|
||||||
consuming_buffers<BufferSequence> cb(bs);
|
|
||||||
cb.consume(n);
|
|
||||||
return cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
#define BEAST_IMPL_DYNABUF_READSTREAM_HPP
|
#define BEAST_IMPL_DYNABUF_READSTREAM_HPP
|
||||||
|
|
||||||
#include <beast/core/bind_handler.hpp>
|
#include <beast/core/bind_handler.hpp>
|
||||||
|
#include <beast/core/error.hpp>
|
||||||
#include <beast/core/handler_concepts.hpp>
|
#include <beast/core/handler_concepts.hpp>
|
||||||
#include <beast/core/handler_alloc.hpp>
|
#include <beast/core/handler_helpers.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
#include <beast/core/handler_ptr.hpp>
|
||||||
#include <boost/system/system_error.hpp>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
@@ -21,28 +21,22 @@ template<class MutableBufferSequence, class Handler>
|
|||||||
class dynabuf_readstream<
|
class dynabuf_readstream<
|
||||||
Stream, DynamicBuffer>::read_some_op
|
Stream, DynamicBuffer>::read_some_op
|
||||||
{
|
{
|
||||||
using alloc_type =
|
// VFALCO What about bool cont for is_continuation?
|
||||||
handler_alloc<char, Handler>;
|
|
||||||
|
|
||||||
struct data
|
struct data
|
||||||
{
|
{
|
||||||
dynabuf_readstream& srs;
|
dynabuf_readstream& srs;
|
||||||
MutableBufferSequence bs;
|
MutableBufferSequence bs;
|
||||||
Handler h;
|
|
||||||
int state = 0;
|
int state = 0;
|
||||||
|
|
||||||
template<class DeducedHandler>
|
data(Handler&, dynabuf_readstream& srs_,
|
||||||
data(DeducedHandler&& h_,
|
|
||||||
dynabuf_readstream& srs_,
|
|
||||||
MutableBufferSequence const& bs_)
|
MutableBufferSequence const& bs_)
|
||||||
: srs(srs_)
|
: srs(srs_)
|
||||||
, bs(bs_)
|
, bs(bs_)
|
||||||
, h(std::forward<DeducedHandler>(h_))
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<data> d_;
|
handler_ptr<data, Handler> d_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
read_some_op(read_some_op&&) = default;
|
read_some_op(read_some_op&&) = default;
|
||||||
@@ -51,7 +45,7 @@ public:
|
|||||||
template<class DeducedHandler, class... Args>
|
template<class DeducedHandler, class... Args>
|
||||||
read_some_op(DeducedHandler&& h,
|
read_some_op(DeducedHandler&& h,
|
||||||
dynabuf_readstream& srs, Args&&... args)
|
dynabuf_readstream& srs, Args&&... args)
|
||||||
: d_(std::allocate_shared<data>(alloc_type{h},
|
: d_(make_handler_ptr<data, Handler>(
|
||||||
std::forward<DeducedHandler>(h), srs,
|
std::forward<DeducedHandler>(h), srs,
|
||||||
std::forward<Args>(args)...))
|
std::forward<Args>(args)...))
|
||||||
{
|
{
|
||||||
@@ -66,31 +60,31 @@ public:
|
|||||||
void* asio_handler_allocate(
|
void* asio_handler_allocate(
|
||||||
std::size_t size, read_some_op* op)
|
std::size_t size, read_some_op* op)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_alloc_helpers::
|
return beast_asio_helpers::
|
||||||
allocate(size, op->d_->h);
|
allocate(size, op->d_.handler());
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
void asio_handler_deallocate(
|
void asio_handler_deallocate(
|
||||||
void* p, std::size_t size, read_some_op* op)
|
void* p, std::size_t size, read_some_op* op)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_alloc_helpers::
|
return beast_asio_helpers::
|
||||||
deallocate(p, size, op->d_->h);
|
deallocate(p, size, op->d_.handler());
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
bool asio_handler_is_continuation(read_some_op* op)
|
bool asio_handler_is_continuation(read_some_op* op)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_cont_helpers::
|
return beast_asio_helpers::
|
||||||
is_continuation(op->d_->h);
|
is_continuation(op->d_.handler());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, read_some_op* op)
|
void asio_handler_invoke(Function&& f, read_some_op* op)
|
||||||
{
|
{
|
||||||
return boost_asio_handler_invoke_helpers::
|
return beast_asio_helpers::
|
||||||
invoke(f, op->d_->h);
|
invoke(f, op->d_.handler());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -150,7 +144,7 @@ read_some_op<MutableBufferSequence, Handler>::operator()(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.h(ec, bytes_transferred);
|
d_.invoke(ec, bytes_transferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
138
src/beast/include/beast/core/impl/handler_ptr.ipp
Normal file
138
src/beast/include/beast/core/impl/handler_ptr.ipp
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BEAST_IMPL_HANDLER_PTR_HPP
|
||||||
|
#define BEAST_IMPL_HANDLER_PTR_HPP
|
||||||
|
|
||||||
|
#include <beast/core/handler_helpers.hpp>
|
||||||
|
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
template<class T, class Handler>
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
inline
|
||||||
|
handler_ptr<T, Handler>::P::
|
||||||
|
P(DeducedHandler&& h, Args&&... args)
|
||||||
|
: n(1)
|
||||||
|
, handler(std::forward<DeducedHandler>(h))
|
||||||
|
{
|
||||||
|
t = reinterpret_cast<T*>(
|
||||||
|
beast_asio_helpers::
|
||||||
|
allocate(sizeof(T), handler));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
t = new(t) T{handler,
|
||||||
|
std::forward<Args>(args)...};
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
beast_asio_helpers::
|
||||||
|
deallocate(t, sizeof(T), handler);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class Handler>
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
handler_ptr<T, Handler>::
|
||||||
|
handler_ptr(int, DeducedHandler&& handler, Args&&... args)
|
||||||
|
: p_(new P(std::forward<DeducedHandler>(handler),
|
||||||
|
std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class Handler>
|
||||||
|
handler_ptr<T, Handler>::
|
||||||
|
~handler_ptr()
|
||||||
|
{
|
||||||
|
if(! p_)
|
||||||
|
return;
|
||||||
|
if(--p_->n)
|
||||||
|
return;
|
||||||
|
if(p_->t)
|
||||||
|
{
|
||||||
|
p_->t->~T();
|
||||||
|
beast_asio_helpers::
|
||||||
|
deallocate(p_->t, sizeof(T), p_->handler);
|
||||||
|
}
|
||||||
|
delete p_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class Handler>
|
||||||
|
handler_ptr<T, Handler>::
|
||||||
|
handler_ptr(handler_ptr&& other)
|
||||||
|
: p_(other.p_)
|
||||||
|
{
|
||||||
|
other.p_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class Handler>
|
||||||
|
handler_ptr<T, Handler>::
|
||||||
|
handler_ptr(handler_ptr const& other)
|
||||||
|
: p_(other.p_)
|
||||||
|
{
|
||||||
|
if(p_)
|
||||||
|
++p_->n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class Handler>
|
||||||
|
auto
|
||||||
|
handler_ptr<T, Handler>::
|
||||||
|
release_handler() ->
|
||||||
|
handler_type
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(p_);
|
||||||
|
BOOST_ASSERT(p_->t);
|
||||||
|
p_->t->~T();
|
||||||
|
beast_asio_helpers::
|
||||||
|
deallocate(p_->t, sizeof(T), p_->handler);
|
||||||
|
p_->t = nullptr;
|
||||||
|
return std::move(p_->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class Handler>
|
||||||
|
template<class... Args>
|
||||||
|
void
|
||||||
|
handler_ptr<T, Handler>::
|
||||||
|
invoke(Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(p_);
|
||||||
|
BOOST_ASSERT(p_->t);
|
||||||
|
p_->t->~T();
|
||||||
|
beast_asio_helpers::
|
||||||
|
deallocate(p_->t, sizeof(T), p_->handler);
|
||||||
|
p_->t = nullptr;
|
||||||
|
p_->handler(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class T, class CompletionHandler, class... Args>
|
||||||
|
handler_ptr<T, CompletionHandler>
|
||||||
|
make_handler_ptr(
|
||||||
|
CompletionHandler&& handler, Args&&... args)
|
||||||
|
{
|
||||||
|
return handler_ptr<T, CompletionHandler>{0,
|
||||||
|
std::move(handler),
|
||||||
|
std::forward<Args>(args)...};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class T, class CompletionHandler, class... Args>
|
||||||
|
handler_ptr<T, CompletionHandler>
|
||||||
|
make_handler_ptr(
|
||||||
|
CompletionHandler const& handler, Args&&... args)
|
||||||
|
{
|
||||||
|
return handler_ptr<T, CompletionHandler>{0,
|
||||||
|
handler, std::forward<Args>(args)...};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -279,6 +279,16 @@ static_streambuf::mutable_buffers_type::end() const ->
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
inline
|
||||||
|
auto
|
||||||
|
static_streambuf::data() const ->
|
||||||
|
const_buffers_type
|
||||||
|
{
|
||||||
|
return const_buffers_type{in_,
|
||||||
|
static_cast<std::size_t>(out_ - in_)};
|
||||||
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
auto
|
auto
|
||||||
static_streambuf::prepare(std::size_t n) ->
|
static_streambuf::prepare(std::size_t n) ->
|
||||||
@@ -290,15 +300,6 @@ static_streambuf::prepare(std::size_t n) ->
|
|||||||
return mutable_buffers_type{out_, n};
|
return mutable_buffers_type{out_, n};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
static_streambuf::data() const ->
|
|
||||||
const_buffers_type
|
|
||||||
{
|
|
||||||
return const_buffers_type{in_,
|
|
||||||
static_cast<std::size_t>(out_ - in_)};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
68
src/beast/include/beast/core/prepare_buffer.hpp
Normal file
68
src/beast/include/beast/core/prepare_buffer.hpp
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// 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_PREPARE_BUFFER_HPP
|
||||||
|
#define BEAST_PREPARE_BUFFER_HPP
|
||||||
|
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
/** Return a shortened buffer.
|
||||||
|
|
||||||
|
The returned buffer points to the same memory as the
|
||||||
|
passed buffer, but with a size that is equal to or less
|
||||||
|
than the size of the original buffer.
|
||||||
|
|
||||||
|
@param n The size of the returned buffer.
|
||||||
|
|
||||||
|
@param buffer The buffer to shorten. Ownership of the
|
||||||
|
underlying memory is not transferred.
|
||||||
|
|
||||||
|
@return A new buffer that points to the first `n` bytes
|
||||||
|
of the original buffer.
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
boost::asio::const_buffer
|
||||||
|
prepare_buffer(std::size_t n,
|
||||||
|
boost::asio::const_buffer buffer)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
return { buffer_cast<void const*>(buffer),
|
||||||
|
(std::min)(n, buffer_size(buffer)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a shortened buffer.
|
||||||
|
|
||||||
|
The returned buffer points to the same memory as the
|
||||||
|
passed buffer, but with a size that is equal to or less
|
||||||
|
than the size of the original buffer.
|
||||||
|
|
||||||
|
@param n The size of the returned buffer.
|
||||||
|
|
||||||
|
@param buffer The buffer to shorten. Ownership of the
|
||||||
|
underlying memory is not transferred.
|
||||||
|
|
||||||
|
@return A new buffer that points to the first `n` bytes
|
||||||
|
of the original buffer.
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
boost::asio::mutable_buffer
|
||||||
|
prepare_buffer(std::size_t n,
|
||||||
|
boost::asio::mutable_buffer buffer)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_cast;
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
return { buffer_cast<void*>(buffer),
|
||||||
|
(std::min)(n, buffer_size(buffer)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,150 +8,45 @@
|
|||||||
#ifndef BEAST_PREPARE_BUFFERS_HPP
|
#ifndef BEAST_PREPARE_BUFFERS_HPP
|
||||||
#define BEAST_PREPARE_BUFFERS_HPP
|
#define BEAST_PREPARE_BUFFERS_HPP
|
||||||
|
|
||||||
|
#include <beast/core/detail/prepare_buffers.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
/** Get a trimmed const buffer.
|
/** Return a shortened buffer sequence.
|
||||||
|
|
||||||
The new buffer starts at the beginning of the passed
|
This function returns a new buffer sequence which adapts the
|
||||||
buffer. Ownership of the underlying memory is not
|
passed buffer sequence and efficiently presents a shorter subset
|
||||||
transferred.
|
of the original list of buffers starting with the first byte of
|
||||||
*/
|
the original sequence.
|
||||||
inline
|
|
||||||
boost::asio::const_buffer
|
|
||||||
prepare_buffer(std::size_t n,
|
|
||||||
boost::asio::const_buffer buffer)
|
|
||||||
{
|
|
||||||
using boost::asio::buffer_cast;
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
return { buffer_cast<void const*>(buffer),
|
|
||||||
std::min(n, buffer_size(buffer)) };
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a trimmed mutable buffer.
|
@param n The maximum number of bytes in the wrapped
|
||||||
|
sequence. If this is larger than the size of passed,
|
||||||
|
buffers, the resulting sequence will represent the
|
||||||
|
entire input sequence.
|
||||||
|
|
||||||
The new buffer starts at the beginning of the passed
|
@param buffers The buffer sequence to adapt. A copy of
|
||||||
buffer. Ownership of the underlying memory is not
|
the sequence will be made, but ownership of the underlying
|
||||||
transferred.
|
memory is not transferred.
|
||||||
*/
|
|
||||||
inline
|
|
||||||
boost::asio::mutable_buffer
|
|
||||||
prepare_buffer(std::size_t n,
|
|
||||||
boost::asio::mutable_buffer buffer)
|
|
||||||
{
|
|
||||||
using boost::asio::buffer_cast;
|
|
||||||
using boost::asio::buffer_size;
|
|
||||||
return { buffer_cast<void*>(buffer),
|
|
||||||
std::min(n, buffer_size(buffer)) };
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Wrapper to produce a trimmed buffer sequence.
|
|
||||||
|
|
||||||
This wraps a buffer sequence to efficiently present a shorter
|
|
||||||
subset of the original list of buffers starting with the first
|
|
||||||
byte of the original sequence.
|
|
||||||
|
|
||||||
@tparam BufferSequence The buffer sequence to wrap.
|
|
||||||
*/
|
*/
|
||||||
template<class BufferSequence>
|
template<class BufferSequence>
|
||||||
class prepared_buffers
|
|
||||||
{
|
|
||||||
using iter_type =
|
|
||||||
typename BufferSequence::const_iterator;
|
|
||||||
|
|
||||||
BufferSequence bs_;
|
|
||||||
iter_type back_;
|
|
||||||
iter_type end_;
|
|
||||||
std::size_t size_;
|
|
||||||
|
|
||||||
template<class Deduced>
|
|
||||||
prepared_buffers(Deduced&& other,
|
|
||||||
std::size_t nback, std::size_t nend)
|
|
||||||
: bs_(std::forward<Deduced>(other).bs_)
|
|
||||||
, back_(std::next(bs_.begin(), nback))
|
|
||||||
, end_(std::next(bs_.begin(), nend))
|
|
||||||
, size_(other.size_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// The type for each element in the list of buffers.
|
|
||||||
using value_type =
|
|
||||||
typename std::iterator_traits<iter_type>::value_type;
|
|
||||||
|
|
||||||
#if GENERATING_DOCS
|
#if GENERATING_DOCS
|
||||||
/// A bidirectional iterator type that may be used to read elements.
|
implementation_defined
|
||||||
using const_iterator = implementation_defined;
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
class const_iterator;
|
inline
|
||||||
|
detail::prepared_buffers<BufferSequence>
|
||||||
#endif
|
#endif
|
||||||
|
prepare_buffers(std::size_t n, BufferSequence const& buffers)
|
||||||
/// Move constructor.
|
{
|
||||||
prepared_buffers(prepared_buffers&&);
|
return detail::prepared_buffers<BufferSequence>(n, buffers);
|
||||||
|
}
|
||||||
/// Copy constructor.
|
|
||||||
prepared_buffers(prepared_buffers const&);
|
|
||||||
|
|
||||||
/// Move assignment.
|
|
||||||
prepared_buffers& operator=(prepared_buffers&&);
|
|
||||||
|
|
||||||
/// Copy assignment.
|
|
||||||
prepared_buffers& operator=(prepared_buffers const&);
|
|
||||||
|
|
||||||
/** Construct a wrapped buffer sequence.
|
|
||||||
|
|
||||||
@param n The maximum number of bytes in the wrapped sequence.
|
|
||||||
If this is larger than the size of buffers, the wrapped
|
|
||||||
sequence will represent the entire input sequence.
|
|
||||||
|
|
||||||
@param buffers The buffer sequence to wrap. A copy of the sequence
|
|
||||||
will be made, but ownership of the underlying memory is not transferred.
|
|
||||||
*/
|
|
||||||
prepared_buffers(std::size_t n, BufferSequence const& buffers);
|
|
||||||
|
|
||||||
/// Get a bidirectional iterator to the first element.
|
|
||||||
const_iterator
|
|
||||||
begin() const;
|
|
||||||
|
|
||||||
/// Get a bidirectional iterator for one past the last element.
|
|
||||||
const_iterator
|
|
||||||
end() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void
|
|
||||||
setup(std::size_t n);
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Return a trimmed, wrapped buffer sequence.
|
|
||||||
|
|
||||||
This function returns a new buffer sequence which wraps the provided
|
|
||||||
buffer sequence and efficiently presents a shorter subset of the
|
|
||||||
original list of buffers starting with the first byte of the original
|
|
||||||
sequence.
|
|
||||||
|
|
||||||
@param n The maximum number of bytes in the wrapped sequence. If this
|
|
||||||
is larger than the size of buffers, the wrapped sequence will represent
|
|
||||||
the entire input sequence.
|
|
||||||
|
|
||||||
@param buffers The buffer sequence to wrap. A copy of the sequence
|
|
||||||
will be made, but ownership of the underlying memory is not transferred.
|
|
||||||
*/
|
|
||||||
template<class BufferSequence>
|
|
||||||
prepared_buffers<BufferSequence>
|
|
||||||
prepare_buffers(std::size_t n, BufferSequence const& buffers);
|
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#include <beast/core/impl/prepare_buffers.ipp>
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ private:
|
|||||||
#else
|
#else
|
||||||
protected:
|
protected:
|
||||||
#endif
|
#endif
|
||||||
|
std::uint8_t* begin_;
|
||||||
std::uint8_t* in_;
|
std::uint8_t* in_;
|
||||||
std::uint8_t* out_;
|
std::uint8_t* out_;
|
||||||
std::uint8_t* last_;
|
std::uint8_t* last_;
|
||||||
@@ -57,21 +58,35 @@ public:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Returns the largest size output sequence possible.
|
/// Return the size of the input sequence.
|
||||||
std::size_t
|
|
||||||
max_size() const
|
|
||||||
{
|
|
||||||
return end_ - in_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the size of the input sequence.
|
|
||||||
std::size_t
|
std::size_t
|
||||||
size() const
|
size() const
|
||||||
{
|
{
|
||||||
return out_ - in_;
|
return out_ - in_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a list of buffers that represents the output sequence, with the given size.
|
/// Return the maximum sum of the input and output sequence sizes.
|
||||||
|
std::size_t
|
||||||
|
max_size() const
|
||||||
|
{
|
||||||
|
return end_ - begin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the maximum sum of input and output sizes that can be held without an allocation.
|
||||||
|
std::size_t
|
||||||
|
capacity() const
|
||||||
|
{
|
||||||
|
return end_ - in_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a list of buffers that represent the input sequence.
|
||||||
|
|
||||||
|
@note These buffers remain valid across subsequent calls to `prepare`.
|
||||||
|
*/
|
||||||
|
const_buffers_type
|
||||||
|
data() const;
|
||||||
|
|
||||||
|
/** Get a list of buffers that represent the output sequence, with the given size.
|
||||||
|
|
||||||
@throws std::length_error if the size would exceed the limit
|
@throws std::length_error if the size would exceed the limit
|
||||||
imposed by the underlying mutable buffer sequence.
|
imposed by the underlying mutable buffer sequence.
|
||||||
@@ -93,13 +108,6 @@ public:
|
|||||||
out_ += std::min<std::size_t>(n, last_ - out_);
|
out_ += std::min<std::size_t>(n, last_ - out_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a list of buffers that represents the input sequence.
|
|
||||||
|
|
||||||
@note These buffers remain valid across subsequent calls to `prepare`.
|
|
||||||
*/
|
|
||||||
const_buffers_type
|
|
||||||
data() const;
|
|
||||||
|
|
||||||
/// Remove bytes from the input sequence.
|
/// Remove bytes from the input sequence.
|
||||||
void
|
void
|
||||||
consume(std::size_t n)
|
consume(std::size_t n)
|
||||||
@@ -120,6 +128,7 @@ protected:
|
|||||||
void
|
void
|
||||||
reset(std::uint8_t* p, std::size_t n)
|
reset(std::uint8_t* p, std::size_t n)
|
||||||
{
|
{
|
||||||
|
begin_ = p;
|
||||||
in_ = p;
|
in_ = p;
|
||||||
out_ = p;
|
out_ = p;
|
||||||
last_ = p;
|
last_ = p;
|
||||||
|
|||||||
@@ -8,13 +8,13 @@
|
|||||||
#ifndef BEAST_HTTP_HPP
|
#ifndef BEAST_HTTP_HPP
|
||||||
#define BEAST_HTTP_HPP
|
#define BEAST_HTTP_HPP
|
||||||
|
|
||||||
#include <beast/http/basic_headers.hpp>
|
#include <beast/http/basic_fields.hpp>
|
||||||
#include <beast/http/basic_parser_v1.hpp>
|
#include <beast/http/basic_parser_v1.hpp>
|
||||||
#include <beast/http/body_type.hpp>
|
#include <beast/http/chunk_encode.hpp>
|
||||||
#include <beast/http/empty_body.hpp>
|
#include <beast/http/empty_body.hpp>
|
||||||
#include <beast/http/headers.hpp>
|
#include <beast/http/fields.hpp>
|
||||||
#include <beast/http/message.hpp>
|
#include <beast/http/message.hpp>
|
||||||
#include <beast/http/message_v1.hpp>
|
#include <beast/http/parse.hpp>
|
||||||
#include <beast/http/parse_error.hpp>
|
#include <beast/http/parse_error.hpp>
|
||||||
#include <beast/http/parser_v1.hpp>
|
#include <beast/http/parser_v1.hpp>
|
||||||
#include <beast/http/read.hpp>
|
#include <beast/http/read.hpp>
|
||||||
|
|||||||
@@ -8,8 +8,12 @@
|
|||||||
#ifndef BEAST_HTTP_BASIC_DYNABUF_BODY_HPP
|
#ifndef BEAST_HTTP_BASIC_DYNABUF_BODY_HPP
|
||||||
#define BEAST_HTTP_BASIC_DYNABUF_BODY_HPP
|
#define BEAST_HTTP_BASIC_DYNABUF_BODY_HPP
|
||||||
|
|
||||||
#include <beast/http/body_type.hpp>
|
#include <beast/core/error.hpp>
|
||||||
|
#include <beast/http/message.hpp>
|
||||||
|
#include <beast/http/resume_context.hpp>
|
||||||
|
#include <beast/core/detail/type_traits.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/logic/tribool.hpp>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
@@ -33,14 +37,19 @@ private:
|
|||||||
value_type& sb_;
|
value_type& sb_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<bool isRequest, class Headers>
|
template<bool isRequest, class Fields>
|
||||||
explicit
|
explicit
|
||||||
reader(message<isRequest,
|
reader(message<isRequest,
|
||||||
basic_dynabuf_body, Headers>& m) noexcept
|
basic_dynabuf_body, Fields>& m) noexcept
|
||||||
: sb_(m.body)
|
: sb_(m.body)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
init(error_code&) noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
write(void const* data,
|
write(void const* data,
|
||||||
std::size_t size, error_code&) noexcept
|
std::size_t size, error_code&) noexcept
|
||||||
@@ -57,33 +66,32 @@ private:
|
|||||||
DynamicBuffer const& body_;
|
DynamicBuffer const& body_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
writer(writer const&) = delete;
|
template<bool isRequest, class Fields>
|
||||||
writer& operator=(writer const&) = delete;
|
|
||||||
|
|
||||||
template<bool isRequest, class Headers>
|
|
||||||
explicit
|
explicit
|
||||||
writer(message<
|
writer(message<
|
||||||
isRequest, basic_dynabuf_body, Headers> const& m)
|
isRequest, basic_dynabuf_body, Fields> const& m) noexcept
|
||||||
: body_(m.body)
|
: body_(m.body)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
init(error_code& ec)
|
init(error_code& ec) noexcept
|
||||||
{
|
{
|
||||||
|
beast::detail::ignore_unused(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t
|
std::uint64_t
|
||||||
content_length() const
|
content_length() const noexcept
|
||||||
{
|
{
|
||||||
return body_.size();
|
return body_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Write>
|
template<class WriteFunction>
|
||||||
boost::tribool
|
boost::tribool
|
||||||
operator()(resume_context&&, error_code&, Write&& write)
|
write(resume_context&&, error_code&,
|
||||||
|
WriteFunction&& wf) noexcept
|
||||||
{
|
{
|
||||||
write(body_.data());
|
wf(body_.data());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
306
src/beast/include/beast/http/basic_fields.hpp
Normal file
306
src/beast/include/beast/http/basic_fields.hpp
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
//
|
||||||
|
// 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_BASIC_FIELDS_HPP
|
||||||
|
#define BEAST_HTTP_BASIC_FIELDS_HPP
|
||||||
|
|
||||||
|
#include <beast/core/detail/empty_base_optimization.hpp>
|
||||||
|
#include <beast/http/detail/basic_fields.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
/** A container for storing HTTP header fields.
|
||||||
|
|
||||||
|
This container is designed to store the field value pairs that make
|
||||||
|
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 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
|
||||||
|
of the field name.
|
||||||
|
|
||||||
|
@note Meets the requirements of @b FieldSequence.
|
||||||
|
*/
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_fields :
|
||||||
|
#if ! GENERATING_DOCS
|
||||||
|
private beast::detail::empty_base_optimization<
|
||||||
|
typename std::allocator_traits<Allocator>::
|
||||||
|
template rebind_alloc<
|
||||||
|
detail::basic_fields_base::element>>,
|
||||||
|
#endif
|
||||||
|
public detail::basic_fields_base
|
||||||
|
{
|
||||||
|
using alloc_type = typename
|
||||||
|
std::allocator_traits<Allocator>::
|
||||||
|
template rebind_alloc<
|
||||||
|
detail::basic_fields_base::element>;
|
||||||
|
|
||||||
|
using alloc_traits =
|
||||||
|
std::allocator_traits<alloc_type>;
|
||||||
|
|
||||||
|
using size_type =
|
||||||
|
typename std::allocator_traits<Allocator>::size_type;
|
||||||
|
|
||||||
|
void
|
||||||
|
delete_all();
|
||||||
|
|
||||||
|
void
|
||||||
|
move_assign(basic_fields&, std::false_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
move_assign(basic_fields&, std::true_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
copy_assign(basic_fields const&, std::false_type);
|
||||||
|
|
||||||
|
void
|
||||||
|
copy_assign(basic_fields const&, std::true_type);
|
||||||
|
|
||||||
|
template<class FieldSequence>
|
||||||
|
void
|
||||||
|
copy_from(FieldSequence const& fs)
|
||||||
|
{
|
||||||
|
for(auto const& e : fs)
|
||||||
|
insert(e.first, e.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The type of allocator used.
|
||||||
|
using allocator_type = Allocator;
|
||||||
|
|
||||||
|
/** The value type of the field sequence.
|
||||||
|
|
||||||
|
Meets the requirements of @b Field.
|
||||||
|
*/
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
using value_type = implementation_defined;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// A const iterator to the field sequence
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
using iterator = implementation_defined;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// A const iterator to the field sequence
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
using const_iterator = implementation_defined;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Default constructor.
|
||||||
|
basic_fields() = default;
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
~basic_fields();
|
||||||
|
|
||||||
|
/** Construct the fields.
|
||||||
|
|
||||||
|
@param alloc The allocator to use.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
basic_fields(Allocator const& alloc);
|
||||||
|
|
||||||
|
/** Move constructor.
|
||||||
|
|
||||||
|
The moved-from object becomes an empty field sequence.
|
||||||
|
|
||||||
|
@param other The object to move from.
|
||||||
|
*/
|
||||||
|
basic_fields(basic_fields&& other);
|
||||||
|
|
||||||
|
/** Move assignment.
|
||||||
|
|
||||||
|
The moved-from object becomes an empty field sequence.
|
||||||
|
|
||||||
|
@param other The object to move from.
|
||||||
|
*/
|
||||||
|
basic_fields& operator=(basic_fields&& other);
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
basic_fields(basic_fields const&);
|
||||||
|
|
||||||
|
/// Copy assignment.
|
||||||
|
basic_fields& operator=(basic_fields const&);
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_fields(basic_fields<OtherAlloc> const&);
|
||||||
|
|
||||||
|
/// Copy assignment.
|
||||||
|
template<class OtherAlloc>
|
||||||
|
basic_fields& operator=(basic_fields<OtherAlloc> const&);
|
||||||
|
|
||||||
|
/// Construct from a field sequence.
|
||||||
|
template<class FwdIt>
|
||||||
|
basic_fields(FwdIt first, FwdIt last);
|
||||||
|
|
||||||
|
/// Returns `true` if the field sequence contains no elements.
|
||||||
|
bool
|
||||||
|
empty() const
|
||||||
|
{
|
||||||
|
return set_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of elements in the field sequence.
|
||||||
|
std::size_t
|
||||||
|
size() const
|
||||||
|
{
|
||||||
|
return set_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a const iterator to the beginning of the field sequence.
|
||||||
|
const_iterator
|
||||||
|
begin() const
|
||||||
|
{
|
||||||
|
return list_.cbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a const iterator to the end of the field sequence.
|
||||||
|
const_iterator
|
||||||
|
end() const
|
||||||
|
{
|
||||||
|
return list_.cend();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a const iterator to the beginning of the field sequence.
|
||||||
|
const_iterator
|
||||||
|
cbegin() const
|
||||||
|
{
|
||||||
|
return list_.cbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a const iterator to the end of the field sequence.
|
||||||
|
const_iterator
|
||||||
|
cend() const
|
||||||
|
{
|
||||||
|
return list_.cend();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the specified field exists.
|
||||||
|
bool
|
||||||
|
exists(boost::string_ref const& name) const
|
||||||
|
{
|
||||||
|
return set_.find(name, less{}) != set_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of values for the specified field.
|
||||||
|
std::size_t
|
||||||
|
count(boost::string_ref const& name) const;
|
||||||
|
|
||||||
|
/** Returns an iterator to the case-insensitive matching field name.
|
||||||
|
|
||||||
|
If more than one field with the specified name exists, the
|
||||||
|
first field defined by insertion order is returned.
|
||||||
|
*/
|
||||||
|
iterator
|
||||||
|
find(boost::string_ref const& name) const;
|
||||||
|
|
||||||
|
/** Returns the value for a case-insensitive matching header, or `""`.
|
||||||
|
|
||||||
|
If more than one field with the specified name exists, the
|
||||||
|
first field defined by insertion order is returned.
|
||||||
|
*/
|
||||||
|
boost::string_ref
|
||||||
|
operator[](boost::string_ref const& name) const;
|
||||||
|
|
||||||
|
/// Clear the contents of the basic_fields.
|
||||||
|
void
|
||||||
|
clear() noexcept;
|
||||||
|
|
||||||
|
/** Remove a field.
|
||||||
|
|
||||||
|
If more than one field with the specified name exists, all
|
||||||
|
matching fields will be removed.
|
||||||
|
|
||||||
|
@param name The name of the field(s) to remove.
|
||||||
|
|
||||||
|
@return The number of fields removed.
|
||||||
|
*/
|
||||||
|
std::size_t
|
||||||
|
erase(boost::string_ref const& name);
|
||||||
|
|
||||||
|
/** Insert a field value.
|
||||||
|
|
||||||
|
If a field with the same name already exists, the
|
||||||
|
existing field is untouched and a new field value pair
|
||||||
|
is inserted into the container.
|
||||||
|
|
||||||
|
@param name The name of the field.
|
||||||
|
|
||||||
|
@param value A string holding the value of the field.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
insert(boost::string_ref const& name, boost::string_ref value);
|
||||||
|
|
||||||
|
/** Insert a field value.
|
||||||
|
|
||||||
|
If a field with the same name already exists, the
|
||||||
|
existing field is untouched and a new field value pair
|
||||||
|
is inserted into the container.
|
||||||
|
|
||||||
|
@param name The name of the field
|
||||||
|
|
||||||
|
@param value The value of the field. The object will be
|
||||||
|
converted to a string using `boost::lexical_cast`.
|
||||||
|
*/
|
||||||
|
template<class T>
|
||||||
|
typename std::enable_if<
|
||||||
|
! std::is_constructible<boost::string_ref, T>::value>::type
|
||||||
|
insert(boost::string_ref name, T const& value)
|
||||||
|
{
|
||||||
|
insert(name, boost::lexical_cast<std::string>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Replace a field value.
|
||||||
|
|
||||||
|
First removes any values with matching field names, then
|
||||||
|
inserts the new field value.
|
||||||
|
|
||||||
|
@param name The name of the field.
|
||||||
|
|
||||||
|
@param value A string holding the value of the field.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
replace(boost::string_ref const& name, boost::string_ref value);
|
||||||
|
|
||||||
|
/** Replace a field value.
|
||||||
|
|
||||||
|
First removes any values with matching field names, then
|
||||||
|
inserts the new field value.
|
||||||
|
|
||||||
|
@param name The name of the field
|
||||||
|
|
||||||
|
@param value The value of the field. The object will be
|
||||||
|
converted to a string using `boost::lexical_cast`.
|
||||||
|
*/
|
||||||
|
template<class T>
|
||||||
|
typename std::enable_if<
|
||||||
|
! std::is_constructible<boost::string_ref, T>::value>::type
|
||||||
|
replace(boost::string_ref const& name, T const& value)
|
||||||
|
{
|
||||||
|
replace(name,
|
||||||
|
boost::lexical_cast<std::string>(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#include <beast/http/impl/basic_fields.ipp>
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,474 +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_BASIC_HEADERS_HPP
|
|
||||||
#define BEAST_HTTP_BASIC_HEADERS_HPP
|
|
||||||
|
|
||||||
#include <beast/core/detail/ci_char_traits.hpp>
|
|
||||||
#include <beast/core/detail/empty_base_optimization.hpp>
|
|
||||||
#include <boost/intrusive/list.hpp>
|
|
||||||
#include <boost/intrusive/set.hpp>
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include <boost/utility/string_ref.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cctype>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace http {
|
|
||||||
|
|
||||||
template<class Allocator>
|
|
||||||
class basic_headers;
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
class basic_headers_base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct value_type
|
|
||||||
{
|
|
||||||
std::string first;
|
|
||||||
std::string second;
|
|
||||||
|
|
||||||
value_type(boost::string_ref const& name_,
|
|
||||||
boost::string_ref const& value_)
|
|
||||||
: first(name_)
|
|
||||||
, second(value_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::string_ref
|
|
||||||
name() const
|
|
||||||
{
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::string_ref
|
|
||||||
value() const
|
|
||||||
{
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
template<class Allocator>
|
|
||||||
friend class beast::http::basic_headers;
|
|
||||||
|
|
||||||
struct element
|
|
||||||
: boost::intrusive::set_base_hook <
|
|
||||||
boost::intrusive::link_mode <
|
|
||||||
boost::intrusive::normal_link>>
|
|
||||||
, boost::intrusive::list_base_hook <
|
|
||||||
boost::intrusive::link_mode <
|
|
||||||
boost::intrusive::normal_link>>
|
|
||||||
{
|
|
||||||
value_type data;
|
|
||||||
|
|
||||||
element(boost::string_ref const& name,
|
|
||||||
boost::string_ref const& value)
|
|
||||||
: data(name, value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct less : private beast::detail::ci_less
|
|
||||||
{
|
|
||||||
template<class String>
|
|
||||||
bool
|
|
||||||
operator()(String const& lhs, element const& rhs) const
|
|
||||||
{
|
|
||||||
return ci_less::operator()(lhs, rhs.data.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class String>
|
|
||||||
bool
|
|
||||||
operator()(element const& lhs, String const& rhs) const
|
|
||||||
{
|
|
||||||
return ci_less::operator()(lhs.data.first, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
operator()(element const& lhs, element const& rhs) const
|
|
||||||
{
|
|
||||||
return ci_less::operator()(
|
|
||||||
lhs.data.first, rhs.data.first);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using list_t = typename boost::intrusive::make_list<
|
|
||||||
element, boost::intrusive::constant_time_size<false>>::type;
|
|
||||||
|
|
||||||
using set_t = typename boost::intrusive::make_multiset<
|
|
||||||
element, boost::intrusive::constant_time_size<true>,
|
|
||||||
boost::intrusive::compare<less>>::type;
|
|
||||||
|
|
||||||
// data
|
|
||||||
set_t set_;
|
|
||||||
list_t list_;
|
|
||||||
|
|
||||||
basic_headers_base(set_t&& set, list_t&& list)
|
|
||||||
: set_(std::move(set))
|
|
||||||
, list_(std::move(list))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
class const_iterator;
|
|
||||||
|
|
||||||
using iterator = const_iterator;
|
|
||||||
|
|
||||||
basic_headers_base() = default;
|
|
||||||
|
|
||||||
/// Returns an iterator to the beginning of the field sequence.
|
|
||||||
iterator
|
|
||||||
begin() const;
|
|
||||||
|
|
||||||
/// Returns an iterator to the end of the field sequence.
|
|
||||||
iterator
|
|
||||||
end() const;
|
|
||||||
|
|
||||||
/// Returns an iterator to the beginning of the field sequence.
|
|
||||||
iterator
|
|
||||||
cbegin() const;
|
|
||||||
|
|
||||||
/// Returns an iterator to the end of the field sequence.
|
|
||||||
iterator
|
|
||||||
cend() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class basic_headers_base::const_iterator
|
|
||||||
{
|
|
||||||
using iter_type = list_t::const_iterator;
|
|
||||||
|
|
||||||
iter_type it_;
|
|
||||||
|
|
||||||
template<class Allocator>
|
|
||||||
friend class beast::http::basic_headers;
|
|
||||||
|
|
||||||
friend class basic_headers_base;
|
|
||||||
|
|
||||||
const_iterator(iter_type it)
|
|
||||||
: it_(it)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using value_type =
|
|
||||||
typename basic_headers_base::value_type;
|
|
||||||
using pointer = value_type const*;
|
|
||||||
using reference = value_type const&;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
using iterator_category =
|
|
||||||
std::bidirectional_iterator_tag;
|
|
||||||
|
|
||||||
const_iterator() = default;
|
|
||||||
const_iterator(const_iterator&& other) = default;
|
|
||||||
const_iterator(const_iterator const& other) = default;
|
|
||||||
const_iterator& operator=(const_iterator&& other) = default;
|
|
||||||
const_iterator& operator=(const_iterator const& other) = default;
|
|
||||||
|
|
||||||
bool
|
|
||||||
operator==(const_iterator const& other) const
|
|
||||||
{
|
|
||||||
return it_ == other.it_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
operator!=(const_iterator const& other) const
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
reference
|
|
||||||
operator*() const
|
|
||||||
{
|
|
||||||
return it_->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer
|
|
||||||
operator->() const
|
|
||||||
{
|
|
||||||
return &**this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator&
|
|
||||||
operator++()
|
|
||||||
{
|
|
||||||
++it_;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator
|
|
||||||
operator++(int)
|
|
||||||
{
|
|
||||||
auto temp = *this;
|
|
||||||
++(*this);
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator&
|
|
||||||
operator--()
|
|
||||||
{
|
|
||||||
--it_;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator
|
|
||||||
operator--(int)
|
|
||||||
{
|
|
||||||
auto temp = *this;
|
|
||||||
--(*this);
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // detail
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** A container for storing HTTP headers.
|
|
||||||
|
|
||||||
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
|
|
||||||
value.
|
|
||||||
|
|
||||||
Field names are stored as-is, but comparison 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
|
|
||||||
of the field name.
|
|
||||||
|
|
||||||
@note Meets the requirements of @b `FieldSequence`.
|
|
||||||
*/
|
|
||||||
template<class Allocator>
|
|
||||||
class basic_headers
|
|
||||||
#if ! GENERATING_DOCS
|
|
||||||
: private beast::detail::empty_base_optimization<
|
|
||||||
typename std::allocator_traits<Allocator>::
|
|
||||||
template rebind_alloc<
|
|
||||||
detail::basic_headers_base::element>>
|
|
||||||
, public detail::basic_headers_base
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
using alloc_type = typename
|
|
||||||
std::allocator_traits<Allocator>::
|
|
||||||
template rebind_alloc<
|
|
||||||
detail::basic_headers_base::element>;
|
|
||||||
|
|
||||||
using alloc_traits =
|
|
||||||
std::allocator_traits<alloc_type>;
|
|
||||||
|
|
||||||
using size_type =
|
|
||||||
typename std::allocator_traits<Allocator>::size_type;
|
|
||||||
|
|
||||||
void
|
|
||||||
delete_all();
|
|
||||||
|
|
||||||
void
|
|
||||||
move_assign(basic_headers&, std::false_type);
|
|
||||||
|
|
||||||
void
|
|
||||||
move_assign(basic_headers&, std::true_type);
|
|
||||||
|
|
||||||
void
|
|
||||||
copy_assign(basic_headers const&, std::false_type);
|
|
||||||
|
|
||||||
void
|
|
||||||
copy_assign(basic_headers const&, std::true_type);
|
|
||||||
|
|
||||||
template<class FieldSequence>
|
|
||||||
void
|
|
||||||
copy_from(FieldSequence const& fs)
|
|
||||||
{
|
|
||||||
for(auto const& e : fs)
|
|
||||||
insert(e.first, e.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// The type of allocator used.
|
|
||||||
using allocator_type = Allocator;
|
|
||||||
|
|
||||||
/// Default constructor.
|
|
||||||
basic_headers() = default;
|
|
||||||
|
|
||||||
/// Destructor
|
|
||||||
~basic_headers();
|
|
||||||
|
|
||||||
/** Construct the headers.
|
|
||||||
|
|
||||||
@param alloc The allocator to use.
|
|
||||||
*/
|
|
||||||
explicit
|
|
||||||
basic_headers(Allocator const& alloc);
|
|
||||||
|
|
||||||
/** Move constructor.
|
|
||||||
|
|
||||||
The moved-from object becomes an empty field sequence.
|
|
||||||
|
|
||||||
@param other The object to move from.
|
|
||||||
*/
|
|
||||||
basic_headers(basic_headers&& other);
|
|
||||||
|
|
||||||
/** Move assignment.
|
|
||||||
|
|
||||||
The moved-from object becomes an empty field sequence.
|
|
||||||
|
|
||||||
@param other The object to move from.
|
|
||||||
*/
|
|
||||||
basic_headers& operator=(basic_headers&& other);
|
|
||||||
|
|
||||||
/// Copy constructor.
|
|
||||||
basic_headers(basic_headers const&);
|
|
||||||
|
|
||||||
/// Copy assignment.
|
|
||||||
basic_headers& operator=(basic_headers const&);
|
|
||||||
|
|
||||||
/// Copy constructor.
|
|
||||||
template<class OtherAlloc>
|
|
||||||
basic_headers(basic_headers<OtherAlloc> const&);
|
|
||||||
|
|
||||||
/// Copy assignment.
|
|
||||||
template<class OtherAlloc>
|
|
||||||
basic_headers& operator=(basic_headers<OtherAlloc> const&);
|
|
||||||
|
|
||||||
/// Construct from a field sequence.
|
|
||||||
template<class FwdIt>
|
|
||||||
basic_headers(FwdIt first, FwdIt last);
|
|
||||||
|
|
||||||
/// Returns `true` if the field sequence contains no elements.
|
|
||||||
bool
|
|
||||||
empty() const
|
|
||||||
{
|
|
||||||
return set_.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of elements in the field sequence.
|
|
||||||
std::size_t
|
|
||||||
size() const
|
|
||||||
{
|
|
||||||
return set_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if the specified field exists.
|
|
||||||
bool
|
|
||||||
exists(boost::string_ref const& name) const
|
|
||||||
{
|
|
||||||
return set_.find(name, less{}) != set_.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of values for the specified field.
|
|
||||||
std::size_t
|
|
||||||
count(boost::string_ref const& name) const;
|
|
||||||
|
|
||||||
/** Returns an iterator to the case-insensitive matching field name.
|
|
||||||
|
|
||||||
If more than one field with the specified name exists, the
|
|
||||||
first field defined by insertion order is returned.
|
|
||||||
*/
|
|
||||||
iterator
|
|
||||||
find(boost::string_ref const& name) const;
|
|
||||||
|
|
||||||
/** Returns the value for a case-insensitive matching header, or `""`.
|
|
||||||
|
|
||||||
If more than one field with the specified name exists, the
|
|
||||||
first field defined by insertion order is returned.
|
|
||||||
*/
|
|
||||||
boost::string_ref
|
|
||||||
operator[](boost::string_ref const& name) const;
|
|
||||||
|
|
||||||
/// Clear the contents of the basic_headers.
|
|
||||||
void
|
|
||||||
clear() noexcept;
|
|
||||||
|
|
||||||
/** Remove a field.
|
|
||||||
|
|
||||||
If more than one field with the specified name exists, all
|
|
||||||
matching fields will be removed.
|
|
||||||
|
|
||||||
@param name The name of the field(s) to remove.
|
|
||||||
|
|
||||||
@return The number of fields removed.
|
|
||||||
*/
|
|
||||||
std::size_t
|
|
||||||
erase(boost::string_ref const& name);
|
|
||||||
|
|
||||||
/** Insert a field value.
|
|
||||||
|
|
||||||
If a field with the same name already exists, the
|
|
||||||
existing field is untouched and a new field value pair
|
|
||||||
is inserted into the container.
|
|
||||||
|
|
||||||
@param name The name of the field.
|
|
||||||
|
|
||||||
@param value A string holding the value of the field.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
insert(boost::string_ref const& name, boost::string_ref value);
|
|
||||||
|
|
||||||
/** Insert a field value.
|
|
||||||
|
|
||||||
If a field with the same name already exists, the
|
|
||||||
existing field is untouched and a new field value pair
|
|
||||||
is inserted into the container.
|
|
||||||
|
|
||||||
@param name The name of the field
|
|
||||||
|
|
||||||
@param value The value of the field. The object will be
|
|
||||||
converted to a string using `boost::lexical_cast`.
|
|
||||||
*/
|
|
||||||
template<class T>
|
|
||||||
typename std::enable_if<
|
|
||||||
! std::is_constructible<boost::string_ref, T>::value>::type
|
|
||||||
insert(boost::string_ref name, T const& value)
|
|
||||||
{
|
|
||||||
insert(name, boost::lexical_cast<std::string>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Replace a field value.
|
|
||||||
|
|
||||||
First removes any values with matching field names, then
|
|
||||||
inserts the new field value.
|
|
||||||
|
|
||||||
@param name The name of the field.
|
|
||||||
|
|
||||||
@param value A string holding the value of the field.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
replace(boost::string_ref const& name, boost::string_ref value);
|
|
||||||
|
|
||||||
/** Replace a field value.
|
|
||||||
|
|
||||||
First removes any values with matching field names, then
|
|
||||||
inserts the new field value.
|
|
||||||
|
|
||||||
@param name The name of the field
|
|
||||||
|
|
||||||
@param value The value of the field. The object will be
|
|
||||||
converted to a string using `boost::lexical_cast`.
|
|
||||||
*/
|
|
||||||
template<class T>
|
|
||||||
typename std::enable_if<
|
|
||||||
! std::is_constructible<boost::string_ref, T>::value>::type
|
|
||||||
replace(boost::string_ref const& name, T const& value)
|
|
||||||
{
|
|
||||||
replace(name,
|
|
||||||
boost::lexical_cast<std::string>(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // http
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#include <beast/http/impl/basic_headers.ipp>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
#include <beast/http/rfc7230.hpp>
|
#include <beast/http/rfc7230.hpp>
|
||||||
#include <beast/http/detail/basic_parser_v1.hpp>
|
#include <beast/http/detail/basic_parser_v1.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@@ -22,8 +22,11 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
|
|
||||||
namespace parse_flag {
|
/** Parse flags
|
||||||
enum values
|
|
||||||
|
The set of parser bit flags are returned by @ref basic_parser_v1::flags.
|
||||||
|
*/
|
||||||
|
enum parse_flag
|
||||||
{
|
{
|
||||||
chunked = 1,
|
chunked = 1,
|
||||||
connection_keep_alive = 2,
|
connection_keep_alive = 2,
|
||||||
@@ -34,28 +37,6 @@ enum values
|
|||||||
skipbody = 64,
|
skipbody = 64,
|
||||||
contentlength = 128
|
contentlength = 128
|
||||||
};
|
};
|
||||||
} // parse_flag
|
|
||||||
|
|
||||||
/** Headers maximum size option.
|
|
||||||
|
|
||||||
Sets the maximum number of cumulative bytes allowed
|
|
||||||
including all header octets. A value of zero indicates
|
|
||||||
no limit on the number of header octets
|
|
||||||
|
|
||||||
The default headers maximum size is 16KB (16,384 bytes).
|
|
||||||
|
|
||||||
@note Objects of this type are passed to @ref set_option.
|
|
||||||
*/
|
|
||||||
struct headers_max_size
|
|
||||||
{
|
|
||||||
std::size_t value;
|
|
||||||
|
|
||||||
explicit
|
|
||||||
headers_max_size(std::size_t v)
|
|
||||||
: value(v)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Body maximum size option.
|
/** Body maximum size option.
|
||||||
|
|
||||||
@@ -67,7 +48,7 @@ struct headers_max_size
|
|||||||
The default body maximum size for requests is 4MB (four
|
The default body maximum size for requests is 4MB (four
|
||||||
megabytes or 4,194,304 bytes) and unlimited for responses.
|
megabytes or 4,194,304 bytes) and unlimited for responses.
|
||||||
|
|
||||||
@note Objects of this type are passed to @ref set_option.
|
@note Objects of this type are used with @ref basic_parser_v1::set_option.
|
||||||
*/
|
*/
|
||||||
struct body_max_size
|
struct body_max_size
|
||||||
{
|
{
|
||||||
@@ -80,9 +61,73 @@ 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_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.
|
/// The value returned when no content length is known or applicable.
|
||||||
static std::uint64_t constexpr no_content_length =
|
static std::uint64_t constexpr no_content_length =
|
||||||
std::numeric_limits<std::uint64_t>::max();
|
(std::numeric_limits<std::uint64_t>::max)();
|
||||||
|
|
||||||
/** A parser for decoding HTTP/1 wire format messages.
|
/** A parser for decoding HTTP/1 wire format messages.
|
||||||
|
|
||||||
@@ -97,86 +142,95 @@ static std::uint64_t constexpr no_content_length =
|
|||||||
more calls to derived class members functions (referred to as
|
more calls to derived class members functions (referred to as
|
||||||
"callbacks" from here on) matching a specific signature.
|
"callbacks" from here on) matching a specific signature.
|
||||||
|
|
||||||
Callbacks are detected through SFINAE. The derived class may
|
Every callback must be provided by the derived class, or else
|
||||||
implement as few or as many of the members as needed.
|
a compilation error will be generated. This exemplar shows
|
||||||
These are the signatures of the callbacks:<br>
|
the signature and description of the callbacks required in
|
||||||
|
the derived class.
|
||||||
|
|
||||||
@li `void on_start(error_code&)`
|
@code
|
||||||
|
template<bool isRequest>
|
||||||
|
struct exemplar : basic_parser_v1<isRequest, exemplar>
|
||||||
|
{
|
||||||
|
// Called when the first valid octet of a new message is received
|
||||||
|
//
|
||||||
|
void on_start(error_code&);
|
||||||
|
|
||||||
Called when the first valid octet of a new message is received
|
// Called for each piece of the Request-Method
|
||||||
|
//
|
||||||
|
void on_method(boost::string_ref const&, error_code&);
|
||||||
|
|
||||||
@li `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 Request-Method
|
// Called for each piece of the reason-phrase
|
||||||
|
//
|
||||||
|
void on_reason(boost::string_ref const&, error_code&);
|
||||||
|
|
||||||
@li `void on_uri(boost::string_ref const&, error_code&)`
|
// Called after the entire Request-Line has been parsed successfully.
|
||||||
|
//
|
||||||
|
void on_request(error_code&);
|
||||||
|
|
||||||
Called for each piece of the Request-URI
|
// Called after the entire Response-Line has been parsed successfully.
|
||||||
|
//
|
||||||
|
void on_response(error_code&);
|
||||||
|
|
||||||
@li `void on_reason(boost::string_ref const&, 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 reason-phrase
|
// Called for each piece of the current header value.
|
||||||
|
//
|
||||||
|
void on_value(boost::string_ref const&, error_code&)
|
||||||
|
|
||||||
@li `void on_request(error_code&)`
|
// Called when the entire header has been parsed successfully.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
on_header(std::uint64_t content_length, error_code&);
|
||||||
|
|
||||||
Called after the entire Request-Line has been parsed successfully.
|
// Called after on_header, before the body is parsed
|
||||||
|
//
|
||||||
|
body_what
|
||||||
|
on_body_what(std::uint64_t content_length, error_code&);
|
||||||
|
|
||||||
@li `void on_response(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 after the entire Response-Line has been parsed successfully.
|
// 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
|
||||||
|
|
||||||
@li `void on_field(boost::string_ref const&, error_code&)`
|
The return value of `on_body_what` is special, it controls
|
||||||
|
whether or not the parser should expect a body. See @ref body_what
|
||||||
Called for each piece of the current header field.
|
for choices of the return value.
|
||||||
|
|
||||||
@li `void on_value(boost::string_ref const&, error_code&)`
|
|
||||||
|
|
||||||
Called for each piece of the current header value.
|
|
||||||
|
|
||||||
@li `int on_headers(std::uint64_t content_length, error_code&)`
|
|
||||||
|
|
||||||
Called when all the headers have been parsed successfully.
|
|
||||||
|
|
||||||
@li `void on_body(boost::string_ref const&, error_code&)`
|
|
||||||
|
|
||||||
Called for each piece of the body. If the headers indicated
|
|
||||||
chunked encoding, the chunk encoding is removed from the
|
|
||||||
buffer before being passed to the callback.
|
|
||||||
|
|
||||||
@li `void on_complete(error_code&)`
|
|
||||||
|
|
||||||
Called when the entire message has been parsed successfully.
|
|
||||||
At this point, @ref basic_parser_v1::complete returns `true`, and
|
|
||||||
the parser is ready to parse another message if keep_alive
|
|
||||||
would return `true`.
|
|
||||||
|
|
||||||
The return value of `on_headers` is special, it controls whether
|
|
||||||
or not the parser should expect a body. These are the return values:
|
|
||||||
|
|
||||||
@li *0* The parser should expect a body
|
|
||||||
|
|
||||||
@li *1* The parser should skip the body. For example, this is
|
|
||||||
used when sending a response to a HEAD request.
|
|
||||||
|
|
||||||
@li *2* The parser should skip ths body, this is an
|
|
||||||
upgrade to a different protocol.
|
|
||||||
|
|
||||||
The parser uses traits to determine if the callback is possible.
|
|
||||||
If the Derived type omits one or more callbacks, they are simply
|
|
||||||
skipped with no compilation error. The default behavior of `on_body`
|
|
||||||
when the derived class does not provide the member, is to specify that
|
|
||||||
the body should not be skipped.
|
|
||||||
|
|
||||||
If a callback sets an error, parsing stops at the current octet
|
If a callback sets an error, parsing stops at the current octet
|
||||||
and the error is returned to the caller.
|
and the error is returned to the caller. Callbacks must not throw
|
||||||
|
exceptions.
|
||||||
|
|
||||||
@tparam isRequest A `bool` indicating whether the parser will be
|
@tparam isRequest A `bool` indicating whether the parser will be
|
||||||
presented with request or response message.
|
presented with request or response message.
|
||||||
|
|
||||||
|
@tparam Derived The derived class type. This is part of the
|
||||||
|
Curiously Recurring Template Pattern interface.
|
||||||
*/
|
*/
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest, class Derived>
|
||||||
class basic_parser_v1 : public detail::parser_base
|
class basic_parser_v1 : public detail::parser_base
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
template<bool, class>
|
||||||
|
friend class basic_parser_v1;
|
||||||
|
|
||||||
using self = basic_parser_v1;
|
using self = basic_parser_v1;
|
||||||
typedef void(self::*pmf_t)(error_code&, boost::string_ref const&);
|
typedef void(self::*pmf_t)(error_code&, boost::string_ref const&);
|
||||||
|
|
||||||
@@ -235,15 +289,19 @@ private:
|
|||||||
bool upgrade_ : 1; // true if parser exited for upgrade
|
bool upgrade_ : 1; // true if parser exited for upgrade
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Copy constructor.
|
|
||||||
basic_parser_v1(basic_parser_v1 const&) = default;
|
|
||||||
|
|
||||||
/// Copy assignment.
|
|
||||||
basic_parser_v1& operator=(basic_parser_v1 const&) = default;
|
|
||||||
|
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
basic_parser_v1();
|
basic_parser_v1();
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
template<class OtherDerived>
|
||||||
|
basic_parser_v1(basic_parser_v1<
|
||||||
|
isRequest, OtherDerived> const& other);
|
||||||
|
|
||||||
|
/// Copy assignment.
|
||||||
|
template<class OtherDerived>
|
||||||
|
basic_parser_v1& operator=(basic_parser_v1<
|
||||||
|
isRequest, OtherDerived> const& other);
|
||||||
|
|
||||||
/** Set options on the parser.
|
/** Set options on the parser.
|
||||||
|
|
||||||
@param args One or more parser options to set.
|
@param args One or more parser options to set.
|
||||||
@@ -263,9 +321,9 @@ public:
|
|||||||
std::forward<An>(an)...);
|
std::forward<An>(an)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the headers maximum size option
|
/// Set the header maximum size option
|
||||||
void
|
void
|
||||||
set_option(headers_max_size const& o)
|
set_option(header_max_size const& o)
|
||||||
{
|
{
|
||||||
h_max_ = o.value;
|
h_max_ = o.value;
|
||||||
h_left_ = h_max_;
|
h_left_ = h_max_;
|
||||||
@@ -373,7 +431,10 @@ public:
|
|||||||
bool
|
bool
|
||||||
complete() const
|
complete() const
|
||||||
{
|
{
|
||||||
return s_ == s_restart || s_ == s_closed_complete;
|
return
|
||||||
|
s_ == s_restart ||
|
||||||
|
s_ == s_closed_complete ||
|
||||||
|
s_ == s_body_pause;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write a sequence of buffers to the parser.
|
/** Write a sequence of buffers to the parser.
|
||||||
@@ -418,6 +479,15 @@ public:
|
|||||||
void
|
void
|
||||||
write_eof(error_code& ec);
|
write_eof(error_code& ec);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Reset the parsing state.
|
||||||
|
|
||||||
|
The state of the parser is reset to expect the beginning of
|
||||||
|
a new request or response. The old state is discarded.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Derived&
|
Derived&
|
||||||
impl()
|
impl()
|
||||||
@@ -437,18 +507,10 @@ private:
|
|||||||
s_ = s_res_start;
|
s_ = s_res_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
reset()
|
|
||||||
{
|
|
||||||
h_left_ = h_max_;
|
|
||||||
b_left_ = b_max_;
|
|
||||||
reset(std::integral_constant<bool, isRequest>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
init(std::true_type)
|
init(std::true_type)
|
||||||
{
|
{
|
||||||
// 16KB max headers, 4MB max body
|
// Request: 16KB max header, 4MB max body
|
||||||
h_max_ = 16 * 1024;
|
h_max_ = 16 * 1024;
|
||||||
b_max_ = 4 * 1024 * 1024;
|
b_max_ = 4 * 1024 * 1024;
|
||||||
}
|
}
|
||||||
@@ -456,7 +518,7 @@ private:
|
|||||||
void
|
void
|
||||||
init(std::false_type)
|
init(std::false_type)
|
||||||
{
|
{
|
||||||
// 16KB max headers, unlimited body
|
// Response: 16KB max header, unlimited body
|
||||||
h_max_ = 16 * 1024;
|
h_max_ = 16 * 1024;
|
||||||
b_max_ = 0;
|
b_max_ = 0;
|
||||||
}
|
}
|
||||||
@@ -474,13 +536,102 @@ private:
|
|||||||
bool
|
bool
|
||||||
needs_eof(std::false_type) const;
|
needs_eof(std::false_type) const;
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct check_on_start : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct check_on_start<T, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().on_start(
|
||||||
|
std::declval<error_code&>())
|
||||||
|
)>> : std::true_type { };
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct check_on_method : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct check_on_method<T, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().on_method(
|
||||||
|
std::declval<boost::string_ref>(),
|
||||||
|
std::declval<error_code&>())
|
||||||
|
)>> : std::true_type {};
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct check_on_uri : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct check_on_uri<T, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().on_uri(
|
||||||
|
std::declval<boost::string_ref>(),
|
||||||
|
std::declval<error_code&>())
|
||||||
|
)>> : std::true_type {};
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct check_on_reason : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct check_on_reason<T, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().on_reason(
|
||||||
|
std::declval<boost::string_ref>(),
|
||||||
|
std::declval<error_code&>())
|
||||||
|
)>> : std::true_type {};
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct check_on_request : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct check_on_request<T, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().on_request(
|
||||||
|
std::declval<error_code&>())
|
||||||
|
)>> : std::true_type {};
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct check_on_response : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct check_on_response<T, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().on_response(
|
||||||
|
std::declval<error_code&>())
|
||||||
|
)>> : std::true_type {};
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct check_on_field : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct check_on_field<T, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().on_field(
|
||||||
|
std::declval<boost::string_ref>(),
|
||||||
|
std::declval<error_code&>())
|
||||||
|
)>> : std::true_type {};
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct check_on_value : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct check_on_value<T, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().on_value(
|
||||||
|
std::declval<boost::string_ref>(),
|
||||||
|
std::declval<error_code&>())
|
||||||
|
)>> : std::true_type {};
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct check_on_headers : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct check_on_headers<T, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().on_header(
|
||||||
|
std::declval<std::uint64_t>(),
|
||||||
|
std::declval<error_code&>())
|
||||||
|
)>> : std::true_type {};
|
||||||
|
|
||||||
|
// VFALCO Can we use std::is_detected? Is C++11 capable?
|
||||||
template<class C>
|
template<class C>
|
||||||
class has_on_start_t
|
class check_on_body_what_t
|
||||||
{
|
{
|
||||||
template<class T, class R =
|
template<class T, class R = std::is_convertible<decltype(
|
||||||
decltype(std::declval<T>().on_start(
|
std::declval<T>().on_body_what(
|
||||||
std::declval<error_code&>()),
|
std::declval<std::uint64_t>(),
|
||||||
std::true_type{})>
|
std::declval<error_code&>())),
|
||||||
|
body_what>>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template<class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
@@ -489,211 +640,46 @@ private:
|
|||||||
static bool const value = type::value;
|
static bool const value = type::value;
|
||||||
};
|
};
|
||||||
template<class C>
|
template<class C>
|
||||||
using has_on_start =
|
using check_on_body_what =
|
||||||
std::integral_constant<bool, has_on_start_t<C>::value>;
|
std::integral_constant<bool, check_on_body_what_t<C>::value>;
|
||||||
|
|
||||||
template<class C>
|
template<class T, class = beast::detail::void_t<>>
|
||||||
class has_on_method_t
|
struct check_on_body : std::false_type {};
|
||||||
{
|
|
||||||
template<class T, class R =
|
|
||||||
decltype(std::declval<T>().on_method(
|
|
||||||
std::declval<boost::string_ref const&>(),
|
|
||||||
std::declval<error_code&>()),
|
|
||||||
std::true_type{})>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<C>(0));
|
|
||||||
public:
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
template<class C>
|
|
||||||
using has_on_method =
|
|
||||||
std::integral_constant<bool, has_on_method_t<C>::value>;
|
|
||||||
|
|
||||||
template<class C>
|
template<class T>
|
||||||
class has_on_uri_t
|
struct check_on_body<T, beast::detail::void_t<decltype(
|
||||||
{
|
std::declval<T>().on_body(
|
||||||
template<class T, class R =
|
std::declval<boost::string_ref>(),
|
||||||
decltype(std::declval<T>().on_uri(
|
std::declval<error_code&>())
|
||||||
std::declval<boost::string_ref const&>(),
|
)>> : std::true_type {};
|
||||||
std::declval<error_code&>()),
|
|
||||||
std::true_type{})>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<C>(0));
|
|
||||||
public:
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
template<class C>
|
|
||||||
using has_on_uri =
|
|
||||||
std::integral_constant<bool, has_on_uri_t<C>::value>;
|
|
||||||
|
|
||||||
template<class C>
|
template<class T, class = beast::detail::void_t<>>
|
||||||
class has_on_reason_t
|
struct check_on_complete : std::false_type {};
|
||||||
{
|
|
||||||
template<class T, class R =
|
|
||||||
decltype(std::declval<T>().on_reason(
|
|
||||||
std::declval<boost::string_ref const&>(),
|
|
||||||
std::declval<error_code&>()),
|
|
||||||
std::true_type{})>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<C>(0));
|
|
||||||
public:
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
template<class C>
|
|
||||||
using has_on_reason =
|
|
||||||
std::integral_constant<bool, has_on_reason_t<C>::value>;
|
|
||||||
|
|
||||||
template<class C>
|
template<class T>
|
||||||
class has_on_request_t
|
struct check_on_complete<T, beast::detail::void_t<decltype(
|
||||||
{
|
std::declval<T>().on_complete(
|
||||||
template<class T, class R =
|
std::declval<error_code&>())
|
||||||
decltype(std::declval<T>().on_request(
|
)>> : std::true_type {};
|
||||||
std::declval<error_code&>()),
|
|
||||||
std::true_type{})>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<C>(0));
|
|
||||||
public:
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
template<class C>
|
|
||||||
using has_on_request =
|
|
||||||
std::integral_constant<bool, has_on_request_t<C>::value>;
|
|
||||||
|
|
||||||
template<class C>
|
|
||||||
class has_on_response_t
|
|
||||||
{
|
|
||||||
template<class T, class R =
|
|
||||||
decltype(std::declval<T>().on_response(
|
|
||||||
std::declval<error_code&>()),
|
|
||||||
std::true_type{})>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<C>(0));
|
|
||||||
public:
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
template<class C>
|
|
||||||
using has_on_response =
|
|
||||||
std::integral_constant<bool, has_on_response_t<C>::value>;
|
|
||||||
|
|
||||||
template<class C>
|
|
||||||
class has_on_field_t
|
|
||||||
{
|
|
||||||
template<class T, class R =
|
|
||||||
decltype(std::declval<T>().on_uri(
|
|
||||||
std::declval<boost::string_ref const&>(),
|
|
||||||
std::declval<error_code&>()),
|
|
||||||
std::true_type{})>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<C>(0));
|
|
||||||
public:
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
template<class C>
|
|
||||||
using has_on_field =
|
|
||||||
std::integral_constant<bool, has_on_field_t<C>::value>;
|
|
||||||
|
|
||||||
template<class C>
|
|
||||||
class has_on_value_t
|
|
||||||
{
|
|
||||||
template<class T, class R =
|
|
||||||
decltype(std::declval<T>().on_uri(
|
|
||||||
std::declval<boost::string_ref const&>(),
|
|
||||||
std::declval<error_code&>()),
|
|
||||||
std::true_type{})>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<C>(0));
|
|
||||||
public:
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
template<class C>
|
|
||||||
using has_on_value =
|
|
||||||
std::integral_constant<bool, has_on_value_t<C>::value>;
|
|
||||||
|
|
||||||
template<class C>
|
|
||||||
class has_on_headers_t
|
|
||||||
{
|
|
||||||
template<class T, class R = std::is_same<int,
|
|
||||||
decltype(std::declval<T>().on_headers(
|
|
||||||
std::declval<std::uint64_t>(), std::declval<error_code&>()))>>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<C>(0));
|
|
||||||
public:
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
template<class C>
|
|
||||||
using has_on_headers =
|
|
||||||
std::integral_constant<bool, has_on_headers_t<C>::value>;
|
|
||||||
|
|
||||||
template<class C>
|
|
||||||
class has_on_body_t
|
|
||||||
{
|
|
||||||
template<class T, class R =
|
|
||||||
decltype(std::declval<T>().on_body(
|
|
||||||
std::declval<boost::string_ref const&>(),
|
|
||||||
std::declval<error_code&>()),
|
|
||||||
std::true_type{})>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<C>(0));
|
|
||||||
public:
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
template<class C>
|
|
||||||
using has_on_body =
|
|
||||||
std::integral_constant<bool, has_on_body_t<C>::value>;
|
|
||||||
|
|
||||||
template<class C>
|
|
||||||
class has_on_complete_t
|
|
||||||
{
|
|
||||||
template<class T, class R =
|
|
||||||
decltype(std::declval<T>().on_complete(
|
|
||||||
std::declval<error_code&>()),
|
|
||||||
std::true_type{})>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<C>(0));
|
|
||||||
public:
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
template<class C>
|
|
||||||
using has_on_complete =
|
|
||||||
std::integral_constant<bool, has_on_complete_t<C>::value>;
|
|
||||||
|
|
||||||
void call_on_start(error_code& ec, std::true_type)
|
|
||||||
{
|
|
||||||
impl().on_start(ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
void call_on_start(error_code& ec, std::false_type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void call_on_start(error_code& ec)
|
void call_on_start(error_code& ec)
|
||||||
{
|
{
|
||||||
call_on_start(ec, has_on_start<Derived>{});
|
static_assert(check_on_start<Derived>::value,
|
||||||
|
"on_start requirements not met");
|
||||||
|
impl().on_start(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_method(error_code& ec,
|
void call_on_method(error_code& ec,
|
||||||
boost::string_ref const& s, std::true_type)
|
boost::string_ref const& s, std::true_type)
|
||||||
{
|
{
|
||||||
|
static_assert(check_on_method<Derived>::value,
|
||||||
|
"on_method requirements not met");
|
||||||
|
if(h_max_ && s.size() > h_left_)
|
||||||
|
{
|
||||||
|
ec = parse_error::header_too_big;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
h_left_ -= s.size();
|
||||||
impl().on_method(s, ec);
|
impl().on_method(s, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,21 +691,21 @@ private:
|
|||||||
void call_on_method(error_code& ec,
|
void call_on_method(error_code& ec,
|
||||||
boost::string_ref const& s)
|
boost::string_ref const& s)
|
||||||
{
|
{
|
||||||
if(! h_max_ || s.size() <= h_left_)
|
call_on_method(ec, s,
|
||||||
{
|
std::integral_constant<bool, isRequest>{});
|
||||||
h_left_ -= s.size();
|
|
||||||
call_on_method(ec, s, std::integral_constant<bool,
|
|
||||||
isRequest && has_on_method<Derived>::value>{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ec = parse_error::headers_too_big;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_uri(error_code& ec,
|
void call_on_uri(error_code& ec,
|
||||||
boost::string_ref const& s, std::true_type)
|
boost::string_ref const& s, std::true_type)
|
||||||
{
|
{
|
||||||
|
static_assert(check_on_uri<Derived>::value,
|
||||||
|
"on_uri requirements not met");
|
||||||
|
if(h_max_ && s.size() > h_left_)
|
||||||
|
{
|
||||||
|
ec = parse_error::header_too_big;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
h_left_ -= s.size();
|
||||||
impl().on_uri(s, ec);
|
impl().on_uri(s, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,23 +714,24 @@ private:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_uri(error_code& ec, boost::string_ref const& s)
|
void call_on_uri(error_code& ec,
|
||||||
|
boost::string_ref const& s)
|
||||||
{
|
{
|
||||||
if(! h_max_ || s.size() <= h_left_)
|
call_on_uri(ec, s,
|
||||||
{
|
std::integral_constant<bool, isRequest>{});
|
||||||
h_left_ -= s.size();
|
|
||||||
call_on_uri(ec, s, std::integral_constant<bool,
|
|
||||||
isRequest && has_on_uri<Derived>::value>{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ec = parse_error::headers_too_big;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_reason(error_code& ec,
|
void call_on_reason(error_code& ec,
|
||||||
boost::string_ref const& s, std::true_type)
|
boost::string_ref const& s, std::true_type)
|
||||||
{
|
{
|
||||||
|
static_assert(check_on_reason<Derived>::value,
|
||||||
|
"on_reason requirements not met");
|
||||||
|
if(h_max_ && s.size() > h_left_)
|
||||||
|
{
|
||||||
|
ec = parse_error::header_too_big;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
h_left_ -= s.size();
|
||||||
impl().on_reason(s, ec);
|
impl().on_reason(s, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,20 +742,14 @@ private:
|
|||||||
|
|
||||||
void call_on_reason(error_code& ec, boost::string_ref const& s)
|
void call_on_reason(error_code& ec, boost::string_ref const& s)
|
||||||
{
|
{
|
||||||
if(! h_max_ || s.size() <= h_left_)
|
call_on_reason(ec, s,
|
||||||
{
|
std::integral_constant<bool, ! isRequest>{});
|
||||||
h_left_ -= s.size();
|
|
||||||
call_on_reason(ec, s, std::integral_constant<bool,
|
|
||||||
! isRequest && has_on_reason<Derived>::value>{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ec = parse_error::headers_too_big;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_request(error_code& ec, std::true_type)
|
void call_on_request(error_code& ec, std::true_type)
|
||||||
{
|
{
|
||||||
|
static_assert(check_on_request<Derived>::value,
|
||||||
|
"on_request requirements not met");
|
||||||
impl().on_request(ec);
|
impl().on_request(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -778,12 +759,14 @@ private:
|
|||||||
|
|
||||||
void call_on_request(error_code& ec)
|
void call_on_request(error_code& ec)
|
||||||
{
|
{
|
||||||
call_on_request(ec, std::integral_constant<bool,
|
call_on_request(ec,
|
||||||
isRequest && has_on_request<Derived>::value>{});
|
std::integral_constant<bool, isRequest>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_response(error_code& ec, std::true_type)
|
void call_on_response(error_code& ec, std::true_type)
|
||||||
{
|
{
|
||||||
|
static_assert(check_on_response<Derived>::value,
|
||||||
|
"on_response requirements not met");
|
||||||
impl().on_response(ec);
|
impl().on_response(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -793,111 +776,73 @@ private:
|
|||||||
|
|
||||||
void call_on_response(error_code& ec)
|
void call_on_response(error_code& ec)
|
||||||
{
|
{
|
||||||
call_on_response(ec, std::integral_constant<bool,
|
call_on_response(ec,
|
||||||
! isRequest && has_on_response<Derived>::value>{});
|
std::integral_constant<bool, ! isRequest>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_field(error_code& ec,
|
void call_on_field(error_code& ec,
|
||||||
boost::string_ref const& s, std::true_type)
|
boost::string_ref const& s)
|
||||||
{
|
{
|
||||||
|
static_assert(check_on_field<Derived>::value,
|
||||||
|
"on_field requirements not met");
|
||||||
|
if(h_max_ && s.size() > h_left_)
|
||||||
|
{
|
||||||
|
ec = parse_error::header_too_big;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
h_left_ -= s.size();
|
||||||
impl().on_field(s, ec);
|
impl().on_field(s, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_field(error_code&,
|
|
||||||
boost::string_ref const&, std::false_type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void call_on_field(error_code& ec, boost::string_ref const& s)
|
|
||||||
{
|
|
||||||
if(! h_max_ || s.size() <= h_left_)
|
|
||||||
{
|
|
||||||
h_left_ -= s.size();
|
|
||||||
call_on_field(ec, s, has_on_field<Derived>{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ec = parse_error::headers_too_big;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void call_on_value(error_code& ec,
|
void call_on_value(error_code& ec,
|
||||||
boost::string_ref const& s, std::true_type)
|
boost::string_ref const& s)
|
||||||
{
|
{
|
||||||
|
static_assert(check_on_value<Derived>::value,
|
||||||
|
"on_value requirements not met");
|
||||||
|
if(h_max_ && s.size() > h_left_)
|
||||||
|
{
|
||||||
|
ec = parse_error::header_too_big;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
h_left_ -= s.size();
|
||||||
impl().on_value(s, ec);
|
impl().on_value(s, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_value(error_code&,
|
void
|
||||||
boost::string_ref const&, std::false_type)
|
call_on_headers(error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(check_on_headers<Derived>::value,
|
||||||
|
"on_header requirements not met");
|
||||||
|
impl().on_header(content_length_, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_value(error_code& ec, boost::string_ref const& s)
|
body_what
|
||||||
|
call_on_body_what(error_code& ec)
|
||||||
{
|
{
|
||||||
if(! h_max_ || s.size() <= h_left_)
|
static_assert(check_on_body_what<Derived>::value,
|
||||||
{
|
"on_body_what requirements not met");
|
||||||
h_left_ -= s.size();
|
return impl().on_body_what(content_length_, ec);
|
||||||
call_on_value(ec, s, has_on_value<Derived>{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ec = parse_error::headers_too_big;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int call_on_headers(error_code& ec,
|
|
||||||
std::uint64_t content_length, std::true_type)
|
|
||||||
{
|
|
||||||
return impl().on_headers(content_length, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
int call_on_headers(error_code& ec, std::uint64_t, std::false_type)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int call_on_headers(error_code& ec)
|
|
||||||
{
|
|
||||||
return call_on_headers(ec, content_length_,
|
|
||||||
has_on_headers<Derived>{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_body(error_code& ec,
|
void call_on_body(error_code& ec,
|
||||||
boost::string_ref const& s, std::true_type)
|
boost::string_ref const& s)
|
||||||
{
|
{
|
||||||
impl().on_body(s, ec);
|
static_assert(check_on_body<Derived>::value,
|
||||||
}
|
"on_body requirements not met");
|
||||||
|
if(b_max_ && s.size() > b_left_)
|
||||||
void call_on_body(error_code&,
|
|
||||||
boost::string_ref const&, std::false_type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void call_on_body(error_code& ec, boost::string_ref const& s)
|
|
||||||
{
|
|
||||||
if(! b_max_ || s.size() <= b_left_)
|
|
||||||
{
|
|
||||||
b_left_ -= s.size();
|
|
||||||
call_on_body(ec, s, has_on_body<Derived>{});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ec = parse_error::body_too_big;
|
ec = parse_error::body_too_big;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
b_left_ -= s.size();
|
||||||
|
impl().on_body(s, ec);
|
||||||
void call_on_complete(error_code& ec, std::true_type)
|
|
||||||
{
|
|
||||||
impl().on_complete(ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
void call_on_complete(error_code&, std::false_type)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_on_complete(error_code& ec)
|
void call_on_complete(error_code& ec)
|
||||||
{
|
{
|
||||||
call_on_complete(ec, has_on_complete<Derived>{});
|
static_assert(check_on_complete<Derived>::value,
|
||||||
|
"on_complete requirements not met");
|
||||||
|
impl().on_complete(ec);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
||||||
//
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BEAST_HTTP_BODY_TYPE_HPP
|
|
||||||
#define BEAST_HTTP_BODY_TYPE_HPP
|
|
||||||
|
|
||||||
// Convenience header to include everything
|
|
||||||
// needed when declarating a user defined Body type.
|
|
||||||
|
|
||||||
#include <beast/core/error.hpp>
|
|
||||||
#include <beast/http/message.hpp>
|
|
||||||
#include <beast/http/resume_context.hpp>
|
|
||||||
#include <boost/logic/tribool.hpp>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
74
src/beast/include/beast/http/chunk_encode.hpp
Normal file
74
src/beast/include/beast/http/chunk_encode.hpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// 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_CHUNK_ENCODE_HPP
|
||||||
|
#define BEAST_HTTP_CHUNK_ENCODE_HPP
|
||||||
|
|
||||||
|
#include <beast/core/buffer_cat.hpp>
|
||||||
|
#include <beast/http/detail/chunk_encode.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
/** Returns a chunk-encoded ConstBufferSequence.
|
||||||
|
|
||||||
|
This returns a buffer sequence representing the
|
||||||
|
first chunk of a chunked transfer coded body.
|
||||||
|
|
||||||
|
@param fin `true` if this is the last chunk.
|
||||||
|
|
||||||
|
@param buffers The input buffer sequence.
|
||||||
|
|
||||||
|
@return A chunk-encoded ConstBufferSequence representing the input.
|
||||||
|
|
||||||
|
@see <a href=https://tools.ietf.org/html/rfc7230#section-4.1.3>rfc7230 section 4.1.3</a>
|
||||||
|
*/
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
implementation_defined
|
||||||
|
#else
|
||||||
|
beast::detail::buffer_cat_helper<
|
||||||
|
detail::chunk_encode_delim,
|
||||||
|
ConstBufferSequence,
|
||||||
|
boost::asio::const_buffers_1>
|
||||||
|
#endif
|
||||||
|
chunk_encode(bool fin, ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
using boost::asio::buffer_size;
|
||||||
|
return buffer_cat(
|
||||||
|
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});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a chunked encoding final chunk.
|
||||||
|
|
||||||
|
@see <a href=https://tools.ietf.org/html/rfc7230#section-4.1.3>rfc7230 section 4.1.3</a>
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
implementation_defined
|
||||||
|
#else
|
||||||
|
boost::asio::const_buffers_1
|
||||||
|
#endif
|
||||||
|
chunk_encode_final()
|
||||||
|
{
|
||||||
|
return boost::asio::const_buffers_1{"0\r\n\r\n", 5};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -9,7 +9,10 @@
|
|||||||
#define BEAST_HTTP_TYPE_CHECK_HPP
|
#define BEAST_HTTP_TYPE_CHECK_HPP
|
||||||
|
|
||||||
#include <beast/core/error.hpp>
|
#include <beast/core/error.hpp>
|
||||||
|
#include <beast/core/detail/type_traits.hpp>
|
||||||
|
#include <beast/http/resume_context.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/logic/tribool.hpp>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -18,65 +21,107 @@ namespace http {
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<class T>
|
struct write_function
|
||||||
class has_value_type
|
|
||||||
{
|
{
|
||||||
template<class U, class R =
|
template<class ConstBufferSequence>
|
||||||
typename U::value_type>
|
void
|
||||||
static std::true_type check(int);
|
operator()(ConstBufferSequence const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct has_value_type : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct has_value_type<T, beast::detail::void_t<
|
||||||
|
typename T::value_type
|
||||||
|
> > : std::true_type {};
|
||||||
|
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct has_content_length : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct has_content_length<T, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().content_length()
|
||||||
|
)> > : std::true_type
|
||||||
|
{
|
||||||
|
static_assert(std::is_convertible<
|
||||||
|
decltype(std::declval<T>().content_length()),
|
||||||
|
std::uint64_t>::value,
|
||||||
|
"Writer::content_length requirements not met");
|
||||||
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
template<class T, class M, class = beast::detail::void_t<>>
|
||||||
|
struct is_Writer : std::false_type {};
|
||||||
|
|
||||||
|
template<class T, class M>
|
||||||
|
struct is_Writer<T, M, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().init(
|
||||||
|
std::declval<error_code&>())
|
||||||
|
// VFALCO This is unfortunate, we have to provide the template
|
||||||
|
// argument type because this is not a deduced context?
|
||||||
|
//
|
||||||
|
,std::declval<T>().template write<detail::write_function>(
|
||||||
|
std::declval<resume_context>(),
|
||||||
|
std::declval<error_code&>(),
|
||||||
|
std::declval<detail::write_function>())
|
||||||
|
)> > : std::integral_constant<bool,
|
||||||
|
std::is_nothrow_constructible<T, M const&>::value &&
|
||||||
|
std::is_convertible<decltype(
|
||||||
|
std::declval<T>().template write<detail::write_function>(
|
||||||
|
std::declval<resume_context>(),
|
||||||
|
std::declval<error_code&>(),
|
||||||
|
std::declval<detail::write_function>())),
|
||||||
|
boost::tribool>::value
|
||||||
|
>
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<
|
||||||
|
typename M::body_type::writer, T>::value,
|
||||||
|
"Mismatched writer and message");
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
template<class T, class M>
|
||||||
|
class is_Writer
|
||||||
|
{
|
||||||
|
template<class U, class R = decltype(
|
||||||
|
std::declval<U>().init(std::declval<error_code&>()),
|
||||||
|
std::true_type{})>
|
||||||
|
static R check1(int);
|
||||||
template<class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check1(...);
|
||||||
using type = decltype(check<T>(0));
|
using type1 = decltype(check1<T>(0));
|
||||||
public:
|
|
||||||
static bool constexpr value = type::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T, bool B = has_value_type<T>::value>
|
// VFALCO This is unfortunate, we have to provide the template
|
||||||
struct extract_value_type
|
// argument type because this is not a deduced context?
|
||||||
{
|
//
|
||||||
using type = void;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct extract_value_type<T, true>
|
|
||||||
{
|
|
||||||
using type = typename T::value_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
class has_reader
|
|
||||||
{
|
|
||||||
template<class U, class R =
|
template<class U, class R =
|
||||||
typename U::reader>
|
std::is_convertible<decltype(
|
||||||
static std::true_type check(int);
|
std::declval<U>().template write<detail::write_function>(
|
||||||
|
std::declval<resume_context>(),
|
||||||
|
std::declval<error_code&>(),
|
||||||
|
std::declval<detail::write_function>()))
|
||||||
|
, boost::tribool>>
|
||||||
|
static R check2(int);
|
||||||
template<class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check2(...);
|
||||||
public:
|
using type2 = decltype(check2<T>(0));
|
||||||
using type = decltype(check<T>(0));
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
class has_writer
|
|
||||||
{
|
|
||||||
template<class U, class R =
|
|
||||||
typename U::writer>
|
|
||||||
static std::true_type check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
public:
|
public:
|
||||||
using type = decltype(check<T>(0));
|
static_assert(std::is_same<
|
||||||
};
|
typename M::body_type::writer, T>::value,
|
||||||
|
"Mismatched writer and message");
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct is_Body
|
|
||||||
{
|
|
||||||
using type = std::integral_constant<bool,
|
using type = std::integral_constant<bool,
|
||||||
has_value_type<T>::value &&
|
std::is_nothrow_constructible<T, M const&>::value
|
||||||
std::is_default_constructible<
|
&& type1::value
|
||||||
typename extract_value_type<T>::type>::value
|
&& type2::value
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class is_Parser
|
class is_Parser
|
||||||
{
|
{
|
||||||
@@ -92,7 +137,7 @@ class is_Parser
|
|||||||
template<class U, class R =
|
template<class U, class R =
|
||||||
std::is_convertible<decltype(
|
std::is_convertible<decltype(
|
||||||
std::declval<U>().write(
|
std::declval<U>().write(
|
||||||
std::declval<boost::asio::const_buffer const&>(),
|
std::declval<boost::asio::const_buffers_1 const&>(),
|
||||||
std::declval<error_code&>())),
|
std::declval<error_code&>())),
|
||||||
std::size_t>>
|
std::size_t>>
|
||||||
static R check2(int);
|
static R check2(int);
|
||||||
@@ -118,31 +163,97 @@ public:
|
|||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
/// Determine if `T` meets the requirements of `Body`.
|
/// Determine if `T` meets the requirements of @b Body.
|
||||||
template<class T>
|
template<class T>
|
||||||
#if GENERATING_DOCS
|
#if GENERATING_DOCS
|
||||||
struct is_Body : std::integral_constant<bool, ...>{};
|
struct is_Body : std::integral_constant<bool, ...>{};
|
||||||
#else
|
#else
|
||||||
using is_Body = typename detail::is_Body<T>::type;
|
using is_Body = detail::has_value_type<T>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Determine if `T` meets the requirements of `ReadableBody`.
|
/** Determine if a @b Body has a nested type `reader`.
|
||||||
template<class T>
|
|
||||||
|
@tparam T The type to check, which must meet the
|
||||||
|
requirements of @b Body.
|
||||||
|
*/
|
||||||
#if GENERATING_DOCS
|
#if GENERATING_DOCS
|
||||||
struct is_ReadableBody : std::integral_constant<bool, ...>{};
|
|
||||||
#else
|
|
||||||
using is_ReadableBody = typename detail::has_reader<T>::type;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Determine if `T` meets the requirements of `WritableBody`.
|
|
||||||
template<class T>
|
template<class T>
|
||||||
#if GENERATING_DOCS
|
struct has_reader : std::integral_constant<bool, ...>{};
|
||||||
struct is_WritableBody : std::integral_constant<bool, ...>{};
|
|
||||||
#else
|
#else
|
||||||
using is_WritableBody = typename detail::has_writer<T>::type;
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct has_reader : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct has_reader<T, beast::detail::void_t<
|
||||||
|
typename T::reader
|
||||||
|
> > : std::true_type {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Determine if `T` meets the requirements of `Parser`.
|
/** Determine if a @b Body has a nested type `writer`.
|
||||||
|
|
||||||
|
@tparam T The type to check, which must meet the
|
||||||
|
requirements of @b Body.
|
||||||
|
*/
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
template<class T>
|
||||||
|
struct has_writer : std::integral_constant<bool, ...>{};
|
||||||
|
#else
|
||||||
|
template<class T, class = beast::detail::void_t<>>
|
||||||
|
struct has_writer : std::false_type {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct has_writer<T, beast::detail::void_t<
|
||||||
|
typename T::writer
|
||||||
|
> > : std::true_type {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Determine if `T` meets the requirements of @b Reader for `M`.
|
||||||
|
|
||||||
|
@tparam T The type to test.
|
||||||
|
|
||||||
|
@tparam M The message type to test with, which must be of
|
||||||
|
type `message`.
|
||||||
|
*/
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
template<class T, class M>
|
||||||
|
struct is_Reader : std::integral_constant<bool, ...> {};
|
||||||
|
#else
|
||||||
|
template<class T, class M, class = beast::detail::void_t<>>
|
||||||
|
struct is_Reader : std::false_type {};
|
||||||
|
|
||||||
|
template<class T, class M>
|
||||||
|
struct is_Reader<T, M, beast::detail::void_t<decltype(
|
||||||
|
std::declval<T>().init(
|
||||||
|
std::declval<error_code&>()),
|
||||||
|
std::declval<T>().write(
|
||||||
|
std::declval<void const*>(),
|
||||||
|
std::declval<std::size_t>(),
|
||||||
|
std::declval<error_code&>())
|
||||||
|
)> > : std::integral_constant<bool,
|
||||||
|
std::is_nothrow_constructible<T, M&>::value
|
||||||
|
>
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<
|
||||||
|
typename M::body_type::reader, T>::value,
|
||||||
|
"Mismatched reader and message");
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Determine if `T` meets the requirements of @b Writer for `M`.
|
||||||
|
|
||||||
|
@tparam T The type to test.
|
||||||
|
|
||||||
|
@tparam M The message type to test with, which must be of
|
||||||
|
type `message`.
|
||||||
|
*/
|
||||||
|
template<class T, class M>
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
struct is_Writer : std::integral_constant<bool, ...> {};
|
||||||
|
#else
|
||||||
|
using is_Writer = typename detail::is_Writer<T, M>::type;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Determine if `T` meets the requirements of @b Parser.
|
||||||
template<class T>
|
template<class T>
|
||||||
#if GENERATING_DOCS
|
#if GENERATING_DOCS
|
||||||
struct is_Parser : std::integral_constant<bool, ...>{};
|
struct is_Parser : std::integral_constant<bool, ...>{};
|
||||||
|
|||||||
214
src/beast/include/beast/http/detail/basic_fields.hpp
Normal file
214
src/beast/include/beast/http/detail/basic_fields.hpp
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
//
|
||||||
|
// 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_BASIC_FIELDS_HPP
|
||||||
|
#define BEAST_HTTP_DETAIL_BASIC_FIELDS_HPP
|
||||||
|
|
||||||
|
#include <beast/core/detail/ci_char_traits.hpp>
|
||||||
|
#include <boost/intrusive/list.hpp>
|
||||||
|
#include <boost/intrusive/set.hpp>
|
||||||
|
#include <boost/utility/string_ref.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
class basic_fields;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
class basic_fields_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct value_type
|
||||||
|
{
|
||||||
|
std::string first;
|
||||||
|
std::string second;
|
||||||
|
|
||||||
|
value_type(boost::string_ref const& name_,
|
||||||
|
boost::string_ref const& value_)
|
||||||
|
: first(name_)
|
||||||
|
, second(value_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::string_ref
|
||||||
|
name() const
|
||||||
|
{
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::string_ref
|
||||||
|
value() const
|
||||||
|
{
|
||||||
|
return second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template<class Allocator>
|
||||||
|
friend class beast::http::basic_fields;
|
||||||
|
|
||||||
|
struct element
|
||||||
|
: boost::intrusive::set_base_hook <
|
||||||
|
boost::intrusive::link_mode <
|
||||||
|
boost::intrusive::normal_link>>
|
||||||
|
, boost::intrusive::list_base_hook <
|
||||||
|
boost::intrusive::link_mode <
|
||||||
|
boost::intrusive::normal_link>>
|
||||||
|
{
|
||||||
|
value_type data;
|
||||||
|
|
||||||
|
element(boost::string_ref const& name,
|
||||||
|
boost::string_ref const& value)
|
||||||
|
: data(name, value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct less : private beast::detail::ci_less
|
||||||
|
{
|
||||||
|
template<class String>
|
||||||
|
bool
|
||||||
|
operator()(String const& lhs, element const& rhs) const
|
||||||
|
{
|
||||||
|
return ci_less::operator()(lhs, rhs.data.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class String>
|
||||||
|
bool
|
||||||
|
operator()(element const& lhs, String const& rhs) const
|
||||||
|
{
|
||||||
|
return ci_less::operator()(lhs.data.first, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator()(element const& lhs, element const& rhs) const
|
||||||
|
{
|
||||||
|
return ci_less::operator()(
|
||||||
|
lhs.data.first, rhs.data.first);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using list_t = typename boost::intrusive::make_list<
|
||||||
|
element, boost::intrusive::constant_time_size<false>>::type;
|
||||||
|
|
||||||
|
using set_t = typename boost::intrusive::make_multiset<
|
||||||
|
element, boost::intrusive::constant_time_size<true>,
|
||||||
|
boost::intrusive::compare<less>>::type;
|
||||||
|
|
||||||
|
// data
|
||||||
|
set_t set_;
|
||||||
|
list_t list_;
|
||||||
|
|
||||||
|
basic_fields_base(set_t&& set, list_t&& list)
|
||||||
|
: set_(std::move(set))
|
||||||
|
, list_(std::move(list))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
class const_iterator;
|
||||||
|
|
||||||
|
using iterator = const_iterator;
|
||||||
|
|
||||||
|
basic_fields_base() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class basic_fields_base::const_iterator
|
||||||
|
{
|
||||||
|
using iter_type = list_t::const_iterator;
|
||||||
|
|
||||||
|
iter_type it_;
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
friend class beast::http::basic_fields;
|
||||||
|
|
||||||
|
friend class basic_fields_base;
|
||||||
|
|
||||||
|
const_iterator(iter_type it)
|
||||||
|
: it_(it)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type =
|
||||||
|
typename basic_fields_base::value_type;
|
||||||
|
using pointer = value_type const*;
|
||||||
|
using reference = value_type const&;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category =
|
||||||
|
std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
const_iterator() = default;
|
||||||
|
const_iterator(const_iterator&& other) = default;
|
||||||
|
const_iterator(const_iterator const& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator&& other) = default;
|
||||||
|
const_iterator& operator=(const_iterator const& other) = default;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return it_ == other.it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(const_iterator const& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
return it_->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const
|
||||||
|
{
|
||||||
|
return &**this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator++(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
++(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator&
|
||||||
|
operator--()
|
||||||
|
{
|
||||||
|
--it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator
|
||||||
|
operator--(int)
|
||||||
|
{
|
||||||
|
auto temp = *this;
|
||||||
|
--(*this);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,9 +8,6 @@
|
|||||||
#ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP
|
#ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP
|
||||||
#define BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP
|
#define BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP
|
||||||
|
|
||||||
#include <boost/system/error_code.hpp>
|
|
||||||
#include <boost/utility/string_ref.hpp>
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
@@ -130,6 +127,7 @@ protected:
|
|||||||
s_chunk_data_cr,
|
s_chunk_data_cr,
|
||||||
s_chunk_data_lf,
|
s_chunk_data_lf,
|
||||||
|
|
||||||
|
s_body_pause,
|
||||||
s_body_identity0,
|
s_body_identity0,
|
||||||
s_body_identity,
|
s_body_identity,
|
||||||
s_body_identity_eof0,
|
s_body_identity_eof0,
|
||||||
|
|||||||
@@ -8,27 +8,30 @@
|
|||||||
#ifndef BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
|
#ifndef BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
|
||||||
#define BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
|
#define BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
|
||||||
|
|
||||||
#include <beast/core/buffer_cat.hpp>
|
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/logic/tribool.hpp>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iterator>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
class chunk_encode_text
|
class chunk_encode_delim
|
||||||
{
|
{
|
||||||
boost::asio::const_buffer cb_;
|
boost::asio::const_buffer cb_;
|
||||||
|
|
||||||
// Storage for the longest hex string we might need, plus delimiters.
|
// Storage for the longest hex string we might need, plus delimiters.
|
||||||
std::array<char, 2 * sizeof(std::size_t) + 2> buf_;
|
std::array<char, 2 * sizeof(std::size_t) + 2> buf_;
|
||||||
|
|
||||||
|
template<class = void>
|
||||||
|
void
|
||||||
|
copy(chunk_encode_delim const& other);
|
||||||
|
|
||||||
|
template<class = void>
|
||||||
|
void
|
||||||
|
setup(std::size_t n);
|
||||||
|
|
||||||
template<class OutIter>
|
template<class OutIter>
|
||||||
static
|
static
|
||||||
OutIter
|
OutIter
|
||||||
@@ -52,24 +55,15 @@ public:
|
|||||||
|
|
||||||
using const_iterator = value_type const*;
|
using const_iterator = value_type const*;
|
||||||
|
|
||||||
chunk_encode_text(chunk_encode_text const& other)
|
chunk_encode_delim(chunk_encode_delim const& other)
|
||||||
{
|
{
|
||||||
auto const n =
|
copy(other);
|
||||||
boost::asio::buffer_size(other.cb_);
|
|
||||||
buf_ = other.buf_;
|
|
||||||
cb_ = boost::asio::const_buffer(
|
|
||||||
&buf_[buf_.size() - n], n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
chunk_encode_text(std::size_t n)
|
chunk_encode_delim(std::size_t n)
|
||||||
{
|
{
|
||||||
buf_[buf_.size() - 2] = '\r';
|
setup(n);
|
||||||
buf_[buf_.size() - 1] = '\n';
|
|
||||||
auto it = to_hex(buf_.end() - 2, n);
|
|
||||||
cb_ = boost::asio::const_buffer{&*it,
|
|
||||||
static_cast<std::size_t>(
|
|
||||||
std::distance(it, buf_.end()))};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const_iterator
|
const_iterator
|
||||||
@@ -85,44 +79,29 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Returns a chunk-encoded ConstBufferSequence.
|
template<class>
|
||||||
|
void
|
||||||
This returns a buffer sequence representing the
|
chunk_encode_delim::
|
||||||
first chunk of a chunked transfer coded body.
|
copy(chunk_encode_delim const& other)
|
||||||
|
|
||||||
@param buffers The input buffer sequence.
|
|
||||||
|
|
||||||
@return A chunk-encoded ConstBufferSequence representing the input.
|
|
||||||
|
|
||||||
@see <a href=https://tools.ietf.org/html/rfc7230#section-4.1.3>rfc7230 section 4.1.3</a>
|
|
||||||
*/
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
#if GENERATING_DOCS
|
|
||||||
implementation_defined
|
|
||||||
#else
|
|
||||||
beast::detail::buffer_cat_helper<boost::asio::const_buffer,
|
|
||||||
chunk_encode_text, ConstBufferSequence, boost::asio::const_buffers_1>
|
|
||||||
#endif
|
|
||||||
chunk_encode(ConstBufferSequence const& buffers)
|
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_size;
|
auto const n =
|
||||||
return buffer_cat(
|
boost::asio::buffer_size(other.cb_);
|
||||||
chunk_encode_text{buffer_size(buffers)},
|
buf_ = other.buf_;
|
||||||
buffers,
|
cb_ = boost::asio::const_buffer(
|
||||||
boost::asio::const_buffers_1{"\r\n", 2});
|
&buf_[buf_.size() - n], n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a chunked encoding final chunk.
|
template<class>
|
||||||
inline
|
void
|
||||||
#if GENERATING_DOCS
|
chunk_encode_delim::
|
||||||
implementation_defined
|
setup(std::size_t n)
|
||||||
#else
|
|
||||||
boost::asio::const_buffers_1
|
|
||||||
#endif
|
|
||||||
chunk_encode_final()
|
|
||||||
{
|
{
|
||||||
return boost::asio::const_buffers_1(
|
buf_[buf_.size() - 2] = '\r';
|
||||||
"0\r\n\r\n", 5);
|
buf_[buf_.size() - 1] = '\n';
|
||||||
|
auto it = to_hex(buf_.end() - 2, n);
|
||||||
|
cb_ = boost::asio::const_buffer{&*it,
|
||||||
|
static_cast<std::size_t>(
|
||||||
|
std::distance(it, buf_.end()))};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|||||||
@@ -1,43 +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_DETAIL_HAS_CONTENT_LENGTH_HPP
|
|
||||||
#define BEAST_HTTP_DETAIL_HAS_CONTENT_LENGTH_HPP
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace http {
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
class has_content_length_value
|
|
||||||
{
|
|
||||||
template<class U, class R = typename std::is_convertible<
|
|
||||||
decltype(std::declval<U>().content_length()),
|
|
||||||
std::uint64_t>>
|
|
||||||
static R check(int);
|
|
||||||
template<class>
|
|
||||||
static std::false_type check(...);
|
|
||||||
using type = decltype(check<T>(0));
|
|
||||||
public:
|
|
||||||
// `true` if `T` meets the requirements.
|
|
||||||
static bool const value = type::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Determines if the writer can provide the content length
|
|
||||||
template<class T>
|
|
||||||
using has_content_length =
|
|
||||||
std::integral_constant<bool,
|
|
||||||
has_content_length_value<T>::value>;
|
|
||||||
|
|
||||||
} // detail
|
|
||||||
} // http
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -233,6 +233,14 @@ skip_ows(FwdIt& it, FwdIt const& end)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class FwdIt>
|
||||||
|
void
|
||||||
|
skip_token(FwdIt& it, FwdIt const& last)
|
||||||
|
{
|
||||||
|
while(it != last && is_tchar(*it))
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
boost::string_ref
|
boost::string_ref
|
||||||
trim(boost::string_ref const& s)
|
trim(boost::string_ref const& s)
|
||||||
@@ -258,14 +266,14 @@ struct param_iter
|
|||||||
using iter_type = boost::string_ref::const_iterator;
|
using iter_type = boost::string_ref::const_iterator;
|
||||||
|
|
||||||
iter_type it;
|
iter_type it;
|
||||||
iter_type begin;
|
iter_type first;
|
||||||
iter_type end;
|
iter_type last;
|
||||||
std::pair<boost::string_ref, boost::string_ref> v;
|
std::pair<boost::string_ref, boost::string_ref> v;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
empty() const
|
empty() const
|
||||||
{
|
{
|
||||||
return begin == it;
|
return first == it;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class = void>
|
template<class = void>
|
||||||
@@ -279,59 +287,48 @@ param_iter::
|
|||||||
increment()
|
increment()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
|
|
||||||
ext = token param-list
|
|
||||||
param-list = *( OWS ";" OWS param )
|
param-list = *( OWS ";" OWS param )
|
||||||
param = token OWS "=" OWS ( token / quoted-string )
|
param = token OWS [ "=" OWS ( token / quoted-string ) ]
|
||||||
|
|
||||||
quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
|
quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
|
||||||
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
|
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
|
||||||
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
||||||
obs-text = %x80-FF
|
obs-text = %x80-FF
|
||||||
|
|
||||||
Example:
|
|
||||||
chunked;a=b;i=j,gzip;windowBits=12
|
|
||||||
x,y
|
|
||||||
*/
|
*/
|
||||||
auto const err =
|
auto const err =
|
||||||
[&]
|
[&]
|
||||||
{
|
{
|
||||||
it = begin;
|
it = first;
|
||||||
};
|
};
|
||||||
v.first.clear();
|
v.first.clear();
|
||||||
v.second.clear();
|
v.second.clear();
|
||||||
detail::skip_ows(it, end);
|
detail::skip_ows(it, last);
|
||||||
begin = it;
|
first = it;
|
||||||
if(it == end)
|
if(it == last)
|
||||||
return err();
|
return err();
|
||||||
if(*it != ';')
|
if(*it != ';')
|
||||||
return err();
|
return err();
|
||||||
++it;
|
++it;
|
||||||
detail::skip_ows(it, end);
|
detail::skip_ows(it, last);
|
||||||
if(it == end)
|
if(it == last)
|
||||||
return err();
|
return err();
|
||||||
// param
|
// param
|
||||||
if(! detail::is_tchar(*it))
|
if(! detail::is_tchar(*it))
|
||||||
return err();
|
return err();
|
||||||
auto const p0 = it;
|
auto const p0 = it;
|
||||||
for(;;)
|
skip_token(++it, last);
|
||||||
{
|
|
||||||
++it;
|
|
||||||
if(it == end)
|
|
||||||
return err();
|
|
||||||
if(! detail::is_tchar(*it))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto const p1 = it;
|
auto const p1 = it;
|
||||||
detail::skip_ows(it, end);
|
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
|
||||||
if(it == end)
|
detail::skip_ows(it, last);
|
||||||
return err();
|
if(it == last)
|
||||||
|
return;
|
||||||
|
if(*it == ';')
|
||||||
|
return;
|
||||||
if(*it != '=')
|
if(*it != '=')
|
||||||
return err();
|
return err();
|
||||||
++it;
|
++it;
|
||||||
detail::skip_ows(it, end);
|
detail::skip_ows(it, last);
|
||||||
if(it == end)
|
if(it == last)
|
||||||
return err();
|
return;
|
||||||
if(*it == '"')
|
if(*it == '"')
|
||||||
{
|
{
|
||||||
// quoted-string
|
// quoted-string
|
||||||
@@ -339,7 +336,7 @@ increment()
|
|||||||
++it;
|
++it;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
if(it == end)
|
if(it == last)
|
||||||
return err();
|
return err();
|
||||||
auto c = *it++;
|
auto c = *it++;
|
||||||
if(c == '"')
|
if(c == '"')
|
||||||
@@ -348,13 +345,12 @@ increment()
|
|||||||
continue;
|
continue;
|
||||||
if(c != '\\')
|
if(c != '\\')
|
||||||
return err();
|
return err();
|
||||||
if(it == end)
|
if(it == last)
|
||||||
return err();
|
return err();
|
||||||
c = *it++;
|
c = *it++;
|
||||||
if(! detail::is_qpchar(c))
|
if(! detail::is_qpchar(c))
|
||||||
return err();
|
return err();
|
||||||
}
|
}
|
||||||
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
|
|
||||||
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -363,15 +359,7 @@ increment()
|
|||||||
if(! detail::is_tchar(*it))
|
if(! detail::is_tchar(*it))
|
||||||
return err();
|
return err();
|
||||||
auto const p2 = it;
|
auto const p2 = it;
|
||||||
for(;;)
|
skip_token(++it, last);
|
||||||
{
|
|
||||||
it++;
|
|
||||||
if(it == end)
|
|
||||||
break;
|
|
||||||
if(! detail::is_tchar(*it))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
|
|
||||||
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,12 @@
|
|||||||
#ifndef BEAST_HTTP_EMPTY_BODY_HPP
|
#ifndef BEAST_HTTP_EMPTY_BODY_HPP
|
||||||
#define BEAST_HTTP_EMPTY_BODY_HPP
|
#define BEAST_HTTP_EMPTY_BODY_HPP
|
||||||
|
|
||||||
#include <beast/http/body_type.hpp>
|
#include <beast/core/error.hpp>
|
||||||
|
#include <beast/http/message.hpp>
|
||||||
|
#include <beast/http/resume_context.hpp>
|
||||||
|
#include <beast/core/detail/type_traits.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/logic/tribool.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -35,31 +39,31 @@ private:
|
|||||||
|
|
||||||
struct writer
|
struct writer
|
||||||
{
|
{
|
||||||
writer(writer const&) = delete;
|
template<bool isRequest, class Fields>
|
||||||
writer& operator=(writer const&) = delete;
|
|
||||||
|
|
||||||
template<bool isRequest, class Headers>
|
|
||||||
explicit
|
explicit
|
||||||
writer(message<isRequest, empty_body, Headers> const& m)
|
writer(message<isRequest, empty_body, Fields> const& m) noexcept
|
||||||
{
|
{
|
||||||
|
beast::detail::ignore_unused(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
init(error_code& ec)
|
init(error_code& ec) noexcept
|
||||||
{
|
{
|
||||||
|
beast::detail::ignore_unused(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t
|
std::uint64_t
|
||||||
content_length() const
|
content_length() const noexcept
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Write>
|
template<class WriteFunction>
|
||||||
boost::tribool
|
boost::tribool
|
||||||
operator()(resume_context&&, error_code&, Write&& write)
|
write(resume_context&&, error_code&,
|
||||||
|
WriteFunction&& wf) noexcept
|
||||||
{
|
{
|
||||||
write(boost::asio::null_buffers{});
|
wf(boost::asio::null_buffers{});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,17 +5,18 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef BEAST_HTTP_HEADERS_HPP
|
#ifndef BEAST_HTTP_FIELDS_HPP
|
||||||
#define BEAST_HTTP_HEADERS_HPP
|
#define BEAST_HTTP_FIELDS_HPP
|
||||||
|
|
||||||
#include <beast/http/basic_headers.hpp>
|
#include <beast/http/basic_fields.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
|
|
||||||
using headers =
|
/// A typical HTTP header fields container
|
||||||
basic_headers<std::allocator<char>>;
|
using fields =
|
||||||
|
basic_fields<std::allocator<char>>;
|
||||||
|
|
||||||
} // http
|
} // http
|
||||||
} // beast
|
} // beast
|
||||||
232
src/beast/include/beast/http/header_parser_v1.hpp
Normal file
232
src/beast/include/beast/http/header_parser_v1.hpp
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
//
|
||||||
|
// 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_HEADERS_PARSER_V1_HPP
|
||||||
|
#define BEAST_HTTP_HEADERS_PARSER_V1_HPP
|
||||||
|
|
||||||
|
#include <beast/http/basic_parser_v1.hpp>
|
||||||
|
#include <beast/http/concepts.hpp>
|
||||||
|
#include <beast/http/message.hpp>
|
||||||
|
#include <beast/core/error.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
struct request_parser_base
|
||||||
|
{
|
||||||
|
std::string method_;
|
||||||
|
std::string uri_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response_parser_base
|
||||||
|
{
|
||||||
|
std::string reason_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
/** 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 request or
|
||||||
|
response @ref header.
|
||||||
|
|
||||||
|
@note A new instance of the parser is required for each message.
|
||||||
|
*/
|
||||||
|
template<bool isRequest, class Fields>
|
||||||
|
class header_parser_v1
|
||||||
|
: public basic_parser_v1<isRequest,
|
||||||
|
header_parser_v1<isRequest, Fields>>
|
||||||
|
, private std::conditional<isRequest,
|
||||||
|
detail::request_parser_base,
|
||||||
|
detail::response_parser_base>::type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// The type of the header this parser produces.
|
||||||
|
using header_type = header<isRequest, Fields>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// VFALCO Check Fields requirements?
|
||||||
|
|
||||||
|
std::string field_;
|
||||||
|
std::string value_;
|
||||||
|
header_type h_;
|
||||||
|
bool flush_ = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Default constructor
|
||||||
|
header_parser_v1() = default;
|
||||||
|
|
||||||
|
/// Move constructor
|
||||||
|
header_parser_v1(header_parser_v1&&) = default;
|
||||||
|
|
||||||
|
/// Copy constructor (disallowed)
|
||||||
|
header_parser_v1(header_parser_v1 const&) = delete;
|
||||||
|
|
||||||
|
/// Move assignment (disallowed)
|
||||||
|
header_parser_v1& operator=(header_parser_v1&&) = delete;
|
||||||
|
|
||||||
|
/// Copy assignment (disallowed)
|
||||||
|
header_parser_v1& operator=(header_parser_v1 const&) = delete;
|
||||||
|
|
||||||
|
/** Construct the parser.
|
||||||
|
|
||||||
|
@param args Forwarded to the header constructor.
|
||||||
|
*/
|
||||||
|
#if GENERATING_DOCS
|
||||||
|
template<class... Args>
|
||||||
|
explicit
|
||||||
|
header_parser_v1(Args&&... args);
|
||||||
|
#else
|
||||||
|
template<class Arg1, class... ArgN,
|
||||||
|
class = typename std::enable_if<! std::is_same<
|
||||||
|
typename std::decay<Arg1>::type, header_parser_v1>::value>>
|
||||||
|
explicit
|
||||||
|
header_parser_v1(Arg1&& arg1, ArgN&&... argn)
|
||||||
|
: h_(std::forward<Arg1>(arg1),
|
||||||
|
std::forward<ArgN>(argn)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Returns the parsed header
|
||||||
|
|
||||||
|
Only valid if @ref complete would return `true`.
|
||||||
|
*/
|
||||||
|
header_type const&
|
||||||
|
get() const
|
||||||
|
{
|
||||||
|
return h_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the parsed header.
|
||||||
|
|
||||||
|
Only valid if @ref complete would return `true`.
|
||||||
|
*/
|
||||||
|
header_type&
|
||||||
|
get()
|
||||||
|
{
|
||||||
|
return h_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns ownership of the parsed header.
|
||||||
|
|
||||||
|
Ownership is transferred to the caller. Only
|
||||||
|
valid if @ref complete would return `true`.
|
||||||
|
|
||||||
|
Requires:
|
||||||
|
@ref header_type is @b MoveConstructible
|
||||||
|
*/
|
||||||
|
header_type
|
||||||
|
release()
|
||||||
|
{
|
||||||
|
static_assert(std::is_move_constructible<decltype(h_)>::value,
|
||||||
|
"MoveConstructible requirements not met");
|
||||||
|
return std::move(h_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class basic_parser_v1<isRequest, header_parser_v1>;
|
||||||
|
|
||||||
|
void flush()
|
||||||
|
{
|
||||||
|
if(! flush_)
|
||||||
|
return;
|
||||||
|
flush_ = false;
|
||||||
|
BOOST_ASSERT(! field_.empty());
|
||||||
|
h_.fields.insert(field_, value_);
|
||||||
|
field_.clear();
|
||||||
|
value_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_start(error_code&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_method(boost::string_ref const& s, error_code&)
|
||||||
|
{
|
||||||
|
this->method_.append(s.data(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_uri(boost::string_ref const& s, error_code&)
|
||||||
|
{
|
||||||
|
this->uri_.append(s.data(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_reason(boost::string_ref const& s, error_code&)
|
||||||
|
{
|
||||||
|
this->reason_.append(s.data(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_request_or_response(std::true_type)
|
||||||
|
{
|
||||||
|
h_.method = std::move(this->method_);
|
||||||
|
h_.url = std::move(this->uri_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_request_or_response(std::false_type)
|
||||||
|
{
|
||||||
|
h_.status = this->status_code();
|
||||||
|
h_.reason = std::move(this->reason_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_request(error_code& ec)
|
||||||
|
{
|
||||||
|
on_request_or_response(
|
||||||
|
std::integral_constant<bool, isRequest>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_response(error_code& ec)
|
||||||
|
{
|
||||||
|
on_request_or_response(
|
||||||
|
std::integral_constant<bool, isRequest>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_field(boost::string_ref const& s, error_code&)
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
field_.append(s.data(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_value(boost::string_ref const& s, error_code&)
|
||||||
|
{
|
||||||
|
value_.append(s.data(), s.size());
|
||||||
|
flush_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_header(std::uint64_t, error_code&)
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
h_.version = 10 * this->http_major() + this->http_minor();
|
||||||
|
}
|
||||||
|
|
||||||
|
body_what
|
||||||
|
on_body_what(std::uint64_t, error_code&)
|
||||||
|
{
|
||||||
|
return body_what::pause;
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_body(boost::string_ref const&, error_code&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_complete(error_code&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
|
#ifndef BEAST_HTTP_IMPL_BASIC_FIELDS_IPP
|
||||||
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
|
#define BEAST_HTTP_IMPL_BASIC_FIELDS_IPP
|
||||||
|
|
||||||
#include <beast/http/detail/rfc7230.hpp>
|
#include <beast/http/detail/rfc7230.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -14,47 +14,9 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
basic_headers_base::begin() const ->
|
|
||||||
const_iterator
|
|
||||||
{
|
|
||||||
return list_.cbegin();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
basic_headers_base::end() const ->
|
|
||||||
const_iterator
|
|
||||||
{
|
|
||||||
return list_.cend();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
basic_headers_base::cbegin() const ->
|
|
||||||
const_iterator
|
|
||||||
{
|
|
||||||
return list_.cbegin();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
basic_headers_base::cend() const ->
|
|
||||||
const_iterator
|
|
||||||
{
|
|
||||||
return list_.cend();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // detail
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
delete_all()
|
delete_all()
|
||||||
{
|
{
|
||||||
for(auto it = list_.begin(); it != list_.end();)
|
for(auto it = list_.begin(); it != list_.end();)
|
||||||
@@ -69,8 +31,8 @@ delete_all()
|
|||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
move_assign(basic_headers& other, std::false_type)
|
move_assign(basic_fields& other, std::false_type)
|
||||||
{
|
{
|
||||||
if(this->member() != other.member())
|
if(this->member() != other.member())
|
||||||
{
|
{
|
||||||
@@ -87,8 +49,8 @@ move_assign(basic_headers& other, std::false_type)
|
|||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
move_assign(basic_headers& other, std::true_type)
|
move_assign(basic_fields& other, std::true_type)
|
||||||
{
|
{
|
||||||
this->member() = std::move(other.member());
|
this->member() = std::move(other.member());
|
||||||
set_ = std::move(other.set_);
|
set_ = std::move(other.set_);
|
||||||
@@ -98,8 +60,8 @@ move_assign(basic_headers& other, std::true_type)
|
|||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
copy_assign(basic_headers const& other, std::false_type)
|
copy_assign(basic_fields const& other, std::false_type)
|
||||||
{
|
{
|
||||||
copy_from(other);
|
copy_from(other);
|
||||||
}
|
}
|
||||||
@@ -107,8 +69,8 @@ copy_assign(basic_headers const& other, std::false_type)
|
|||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
copy_assign(basic_headers const& other, std::true_type)
|
copy_assign(basic_fields const& other, std::true_type)
|
||||||
{
|
{
|
||||||
this->member() = other.member();
|
this->member() = other.member();
|
||||||
copy_from(other);
|
copy_from(other);
|
||||||
@@ -117,35 +79,35 @@ copy_assign(basic_headers const& other, std::true_type)
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
~basic_headers()
|
~basic_fields()
|
||||||
{
|
{
|
||||||
delete_all();
|
delete_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
basic_headers(Allocator const& alloc)
|
basic_fields(Allocator const& alloc)
|
||||||
: beast::detail::empty_base_optimization<
|
: beast::detail::empty_base_optimization<
|
||||||
alloc_type>(alloc)
|
alloc_type>(alloc)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
basic_headers(basic_headers&& other)
|
basic_fields(basic_fields&& other)
|
||||||
: beast::detail::empty_base_optimization<alloc_type>(
|
: beast::detail::empty_base_optimization<alloc_type>(
|
||||||
std::move(other.member()))
|
std::move(other.member()))
|
||||||
, detail::basic_headers_base(
|
, detail::basic_fields_base(
|
||||||
std::move(other.set_), std::move(other.list_))
|
std::move(other.set_), std::move(other.list_))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
auto
|
auto
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
operator=(basic_headers&& other) ->
|
operator=(basic_fields&& other) ->
|
||||||
basic_headers&
|
basic_fields&
|
||||||
{
|
{
|
||||||
if(this == &other)
|
if(this == &other)
|
||||||
return *this;
|
return *this;
|
||||||
@@ -156,9 +118,9 @@ operator=(basic_headers&& other) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
basic_headers(basic_headers const& other)
|
basic_fields(basic_fields const& other)
|
||||||
: basic_headers(alloc_traits::
|
: basic_fields(alloc_traits::
|
||||||
select_on_container_copy_construction(other.member()))
|
select_on_container_copy_construction(other.member()))
|
||||||
{
|
{
|
||||||
copy_from(other);
|
copy_from(other);
|
||||||
@@ -166,9 +128,9 @@ basic_headers(basic_headers const& other)
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
auto
|
auto
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
operator=(basic_headers const& other) ->
|
operator=(basic_fields const& other) ->
|
||||||
basic_headers&
|
basic_fields&
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
copy_assign(other, std::integral_constant<bool,
|
copy_assign(other, std::integral_constant<bool,
|
||||||
@@ -178,8 +140,8 @@ operator=(basic_headers const& other) ->
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
template<class OtherAlloc>
|
template<class OtherAlloc>
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
basic_headers(basic_headers<OtherAlloc> const& other)
|
basic_fields(basic_fields<OtherAlloc> const& other)
|
||||||
{
|
{
|
||||||
copy_from(other);
|
copy_from(other);
|
||||||
}
|
}
|
||||||
@@ -187,9 +149,9 @@ basic_headers(basic_headers<OtherAlloc> const& other)
|
|||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
template<class OtherAlloc>
|
template<class OtherAlloc>
|
||||||
auto
|
auto
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
operator=(basic_headers<OtherAlloc> const& other) ->
|
operator=(basic_fields<OtherAlloc> const& other) ->
|
||||||
basic_headers&
|
basic_fields&
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
copy_from(other);
|
copy_from(other);
|
||||||
@@ -198,8 +160,8 @@ operator=(basic_headers<OtherAlloc> const& other) ->
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
template<class FwdIt>
|
template<class FwdIt>
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
basic_headers(FwdIt first, FwdIt last)
|
basic_fields(FwdIt first, FwdIt last)
|
||||||
{
|
{
|
||||||
for(;first != last; ++first)
|
for(;first != last; ++first)
|
||||||
insert(first->name(), first->value());
|
insert(first->name(), first->value());
|
||||||
@@ -207,7 +169,7 @@ basic_headers(FwdIt first, FwdIt last)
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
std::size_t
|
std::size_t
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
count(boost::string_ref const& name) const
|
count(boost::string_ref const& name) const
|
||||||
{
|
{
|
||||||
auto const it = set_.find(name, less{});
|
auto const it = set_.find(name, less{});
|
||||||
@@ -219,7 +181,7 @@ count(boost::string_ref const& name) const
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
auto
|
auto
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
find(boost::string_ref const& name) const ->
|
find(boost::string_ref const& name) const ->
|
||||||
iterator
|
iterator
|
||||||
{
|
{
|
||||||
@@ -231,7 +193,7 @@ find(boost::string_ref const& name) const ->
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
boost::string_ref
|
boost::string_ref
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
operator[](boost::string_ref const& name) const
|
operator[](boost::string_ref const& name) const
|
||||||
{
|
{
|
||||||
auto const it = find(name);
|
auto const it = find(name);
|
||||||
@@ -242,7 +204,7 @@ operator[](boost::string_ref const& name) const
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
clear() noexcept
|
clear() noexcept
|
||||||
{
|
{
|
||||||
delete_all();
|
delete_all();
|
||||||
@@ -252,7 +214,7 @@ clear() noexcept
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
std::size_t
|
std::size_t
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
erase(boost::string_ref const& name)
|
erase(boost::string_ref const& name)
|
||||||
{
|
{
|
||||||
auto it = set_.find(name, less{});
|
auto it = set_.find(name, less{});
|
||||||
@@ -276,7 +238,7 @@ erase(boost::string_ref const& name)
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
insert(boost::string_ref const& name,
|
insert(boost::string_ref const& name,
|
||||||
boost::string_ref value)
|
boost::string_ref value)
|
||||||
{
|
{
|
||||||
@@ -289,7 +251,7 @@ insert(boost::string_ref const& name,
|
|||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_headers<Allocator>::
|
basic_fields<Allocator>::
|
||||||
replace(boost::string_ref const& name,
|
replace(boost::string_ref const& name,
|
||||||
boost::string_ref value)
|
boost::string_ref value)
|
||||||
{
|
{
|
||||||
@@ -5,6 +5,16 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
|
||||||
|
#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
|
||||||
|
|
||||||
|
#include <beast/http/detail/rfc7230.hpp>
|
||||||
|
#include <beast/core/buffer_concepts.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
|
/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
|
||||||
*
|
*
|
||||||
* Additional changes are licensed under the same terms as NGINX and
|
* Additional changes are licensed under the same terms as NGINX and
|
||||||
@@ -28,21 +38,10 @@
|
|||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
/*
|
/* This code is a modified version of nodejs/http-parser, copyright above:
|
||||||
This code is a modified version of nodejs/http-parser, copyright above:
|
|
||||||
https://github.com/nodejs/http-parser
|
https://github.com/nodejs/http-parser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
|
|
||||||
#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
|
|
||||||
|
|
||||||
#include <beast/http/detail/rfc7230.hpp>
|
|
||||||
#include <beast/core/buffer_concepts.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace http {
|
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest, class Derived>
|
||||||
basic_parser_v1<isRequest, Derived>::
|
basic_parser_v1<isRequest, Derived>::
|
||||||
basic_parser_v1()
|
basic_parser_v1()
|
||||||
@@ -50,6 +49,55 @@ basic_parser_v1()
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Derived>
|
||||||
|
template<class OtherDerived>
|
||||||
|
basic_parser_v1<isRequest, Derived>::
|
||||||
|
basic_parser_v1(basic_parser_v1<
|
||||||
|
isRequest, OtherDerived> const& other)
|
||||||
|
: h_max_(other.h_max_)
|
||||||
|
, h_left_(other.h_left_)
|
||||||
|
, b_max_(other.b_max_)
|
||||||
|
, b_left_(other.b_left_)
|
||||||
|
, content_length_(other.content_length_)
|
||||||
|
, cb_(nullptr)
|
||||||
|
, s_(other.s_)
|
||||||
|
, flags_(other.flags_)
|
||||||
|
, fs_(other.fs_)
|
||||||
|
, pos_(other.pos_)
|
||||||
|
, http_major_(other.http_major_)
|
||||||
|
, http_minor_(other.http_minor_)
|
||||||
|
, status_code_(other.status_code_)
|
||||||
|
, upgrade_(other.upgrade_)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(! other.cb_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Derived>
|
||||||
|
template<class OtherDerived>
|
||||||
|
auto
|
||||||
|
basic_parser_v1<isRequest, Derived>::
|
||||||
|
operator=(basic_parser_v1<
|
||||||
|
isRequest, OtherDerived> const& other) ->
|
||||||
|
basic_parser_v1&
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(! other.cb_);
|
||||||
|
h_max_ = other.h_max_;
|
||||||
|
h_left_ = other.h_left_;
|
||||||
|
b_max_ = other.b_max_;
|
||||||
|
b_left_ = other.b_left_;
|
||||||
|
content_length_ = other.content_length_;
|
||||||
|
cb_ = nullptr;
|
||||||
|
s_ = other.s_;
|
||||||
|
flags_ = other.flags_;
|
||||||
|
fs_ = other.fs_;
|
||||||
|
pos_ = other.pos_;
|
||||||
|
http_major_ = other.http_major_;
|
||||||
|
http_minor_ = other.http_minor_;
|
||||||
|
status_code_ = other.status_code_;
|
||||||
|
upgrade_ = other.upgrade_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest, class Derived>
|
||||||
bool
|
bool
|
||||||
basic_parser_v1<isRequest, Derived>::
|
basic_parser_v1<isRequest, Derived>::
|
||||||
@@ -170,7 +218,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
call_on_start(ec);
|
call_on_start(ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
return errc();
|
return errc();
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
cb(&self::call_on_method);
|
cb(&self::call_on_method);
|
||||||
s_ = s_req_method;
|
s_ = s_req_method;
|
||||||
break;
|
break;
|
||||||
@@ -194,7 +242,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
// VFALCO TODO Better checking for valid URL characters
|
// VFALCO TODO Better checking for valid URL characters
|
||||||
if(! is_text(ch))
|
if(! is_text(ch))
|
||||||
return err(parse_error::bad_uri);
|
return err(parse_error::bad_uri);
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
cb(&self::call_on_uri);
|
cb(&self::call_on_uri);
|
||||||
s_ = s_req_url;
|
s_ = s_req_url;
|
||||||
break;
|
break;
|
||||||
@@ -377,7 +425,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
}
|
}
|
||||||
if(! is_text(ch))
|
if(! is_text(ch))
|
||||||
return err(parse_error::bad_reason);
|
return err(parse_error::bad_reason);
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
cb(&self::call_on_reason);
|
cb(&self::call_on_reason);
|
||||||
s_ = s_res_reason;
|
s_ = s_res_reason;
|
||||||
break;
|
break;
|
||||||
@@ -429,7 +477,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
fs_ = h_general;
|
fs_ = h_general;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
cb(&self::call_on_field);
|
cb(&self::call_on_field);
|
||||||
s_ = s_header_name;
|
s_ = s_header_name;
|
||||||
break;
|
break;
|
||||||
@@ -549,7 +597,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
content_length_ = 0;
|
content_length_ = 0;
|
||||||
flags_ |= parse_flag::contentlength;
|
flags_ |= parse_flag::contentlength;
|
||||||
}
|
}
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
cb(&self::call_on_value);
|
cb(&self::call_on_value);
|
||||||
s_ = s_header_value;
|
s_ = s_header_value;
|
||||||
// fall through
|
// fall through
|
||||||
@@ -801,7 +849,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
return err(parse_error::bad_content_length);
|
return err(parse_error::bad_content_length);
|
||||||
if(fs_ == h_upgrade)
|
if(fs_ == h_upgrade)
|
||||||
flags_ |= parse_flag::upgrade;
|
flags_ |= parse_flag::upgrade;
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
call_on_value(ec, boost::string_ref{"", 0});
|
call_on_value(ec, boost::string_ref{"", 0});
|
||||||
if(ec)
|
if(ec)
|
||||||
return errc();
|
return errc();
|
||||||
@@ -880,7 +928,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
goto redo;
|
goto redo;
|
||||||
|
|
||||||
case s_header_value_unfold:
|
case s_header_value_unfold:
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
cb(&self::call_on_value);
|
cb(&self::call_on_value);
|
||||||
s_ = s_header_value;
|
s_ = s_header_value;
|
||||||
goto redo;
|
goto redo;
|
||||||
@@ -899,30 +947,57 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
return err(parse_error::illegal_content_length);
|
return err(parse_error::illegal_content_length);
|
||||||
upgrade_ = ((flags_ & (parse_flag::upgrade | parse_flag::connection_upgrade)) ==
|
upgrade_ = ((flags_ & (parse_flag::upgrade | parse_flag::connection_upgrade)) ==
|
||||||
(parse_flag::upgrade | parse_flag::connection_upgrade)) /*|| method == "connect"*/;
|
(parse_flag::upgrade | parse_flag::connection_upgrade)) /*|| method == "connect"*/;
|
||||||
auto const maybe_skip = call_on_headers(ec);
|
call_on_headers(ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
return errc();
|
return errc();
|
||||||
switch(maybe_skip)
|
auto const what = call_on_body_what(ec);
|
||||||
|
if(ec)
|
||||||
|
return errc();
|
||||||
|
switch(what)
|
||||||
{
|
{
|
||||||
case 0:
|
case body_what::normal:
|
||||||
break;
|
break;
|
||||||
case 2:
|
case body_what::upgrade:
|
||||||
upgrade_ = true;
|
upgrade_ = true;
|
||||||
// fall through
|
// fall through
|
||||||
case 1:
|
case body_what::skip:
|
||||||
flags_ |= parse_flag::skipbody;
|
flags_ |= parse_flag::skipbody;
|
||||||
break;
|
break;
|
||||||
default:
|
case body_what::pause:
|
||||||
return err(parse_error::bad_on_headers_rv);
|
++p;
|
||||||
|
s_ = s_body_pause;
|
||||||
|
return used();
|
||||||
}
|
}
|
||||||
s_ = s_headers_done;
|
s_ = s_headers_done;
|
||||||
goto redo;
|
goto redo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case s_body_pause:
|
||||||
|
{
|
||||||
|
auto const what = call_on_body_what(ec);
|
||||||
|
if(ec)
|
||||||
|
return errc();
|
||||||
|
switch(what)
|
||||||
|
{
|
||||||
|
case body_what::normal:
|
||||||
|
break;
|
||||||
|
case body_what::upgrade:
|
||||||
|
upgrade_ = true;
|
||||||
|
// fall through
|
||||||
|
case body_what::skip:
|
||||||
|
flags_ |= parse_flag::skipbody;
|
||||||
|
break;
|
||||||
|
case body_what::pause:
|
||||||
|
return used();
|
||||||
|
}
|
||||||
|
--p;
|
||||||
|
s_ = s_headers_done;
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
|
||||||
case s_headers_done:
|
case s_headers_done:
|
||||||
{
|
{
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
call_on_headers(ec);
|
|
||||||
if(ec)
|
if(ec)
|
||||||
return errc();
|
return errc();
|
||||||
bool const hasBody =
|
bool const hasBody =
|
||||||
@@ -959,7 +1034,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case s_body_identity0:
|
case s_body_identity0:
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
cb(&self::call_on_body);
|
cb(&self::call_on_body);
|
||||||
s_ = s_body_identity;
|
s_ = s_body_identity;
|
||||||
// fall through
|
// fall through
|
||||||
@@ -971,7 +1046,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
n = end - p;
|
n = end - p;
|
||||||
else
|
else
|
||||||
n = static_cast<std::size_t>(content_length_);
|
n = static_cast<std::size_t>(content_length_);
|
||||||
assert(content_length_ != 0 && content_length_ != no_content_length);
|
BOOST_ASSERT(content_length_ != 0 && content_length_ != no_content_length);
|
||||||
content_length_ -= n;
|
content_length_ -= n;
|
||||||
if(content_length_ == 0)
|
if(content_length_ == 0)
|
||||||
{
|
{
|
||||||
@@ -984,7 +1059,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case s_body_identity_eof0:
|
case s_body_identity_eof0:
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
cb(&self::call_on_body);
|
cb(&self::call_on_body);
|
||||||
s_ = s_body_identity_eof;
|
s_ = s_body_identity_eof;
|
||||||
// fall through
|
// fall through
|
||||||
@@ -1073,7 +1148,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case s_chunk_data0:
|
case s_chunk_data0:
|
||||||
assert(! cb_);
|
BOOST_ASSERT(! cb_);
|
||||||
cb(&self::call_on_body);
|
cb(&self::call_on_body);
|
||||||
s_ = s_chunk_data;
|
s_ = s_chunk_data;
|
||||||
goto redo; // VFALCO fall through?
|
goto redo; // VFALCO fall through?
|
||||||
@@ -1167,6 +1242,17 @@ write_eof(error_code& ec)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Derived>
|
||||||
|
void
|
||||||
|
basic_parser_v1<isRequest, Derived>::
|
||||||
|
reset()
|
||||||
|
{
|
||||||
|
cb_ = nullptr;
|
||||||
|
h_left_ = h_max_;
|
||||||
|
b_left_ = b_max_;
|
||||||
|
reset(std::integral_constant<bool, isRequest>{});
|
||||||
|
}
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest, class Derived>
|
||||||
bool
|
bool
|
||||||
basic_parser_v1<isRequest, Derived>::
|
basic_parser_v1<isRequest, Derived>::
|
||||||
|
|||||||
264
src/beast/include/beast/http/impl/message.ipp
Normal file
264
src/beast/include/beast/http/impl/message.ipp
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
//
|
||||||
|
// 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_IMPL_MESSAGE_IPP
|
||||||
|
#define BEAST_HTTP_IMPL_MESSAGE_IPP
|
||||||
|
|
||||||
|
#include <beast/core/error.hpp>
|
||||||
|
#include <beast/http/concepts.hpp>
|
||||||
|
#include <beast/http/rfc7230.hpp>
|
||||||
|
#include <beast/core/detail/ci_char_traits.hpp>
|
||||||
|
#include <beast/core/detail/type_traits.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
template<class Fields>
|
||||||
|
void
|
||||||
|
swap(
|
||||||
|
header<true, Fields>& m1,
|
||||||
|
header<true, Fields>& m2)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
swap(m1.version, m2.version);
|
||||||
|
swap(m1.method, m2.method);
|
||||||
|
swap(m1.url, m2.url);
|
||||||
|
swap(m1.fields, m2.fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Fields>
|
||||||
|
void
|
||||||
|
swap(
|
||||||
|
header<false, Fields>& a,
|
||||||
|
header<false, Fields>& b)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
swap(a.version, b.version);
|
||||||
|
swap(a.status, b.status);
|
||||||
|
swap(a.reason, b.reason);
|
||||||
|
swap(a.fields, b.fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Fields>
|
||||||
|
void
|
||||||
|
swap(
|
||||||
|
message<isRequest, Body, Fields>& m1,
|
||||||
|
message<isRequest, Body, Fields>& m2)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
swap(m1.base(), m2.base());
|
||||||
|
swap(m1.body, m2.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Fields>
|
||||||
|
bool
|
||||||
|
is_keep_alive(header<isRequest, Fields> const& msg)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
||||||
|
if(msg.version == 11)
|
||||||
|
{
|
||||||
|
if(token_list{msg.fields["Connection"]}.exists("close"))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(token_list{msg.fields["Connection"]}.exists("keep-alive"))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Fields>
|
||||||
|
bool
|
||||||
|
is_upgrade(header<isRequest, Fields> const& msg)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
||||||
|
if(msg.version == 10)
|
||||||
|
return false;
|
||||||
|
if(token_list{msg.fields["Connection"]}.exists("upgrade"))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
struct prepare_info
|
||||||
|
{
|
||||||
|
boost::optional<connection> connection_value;
|
||||||
|
boost::optional<std::uint64_t> content_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Fields>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
prepare_options(prepare_info& pi,
|
||||||
|
message<isRequest, Body, Fields>& msg)
|
||||||
|
{
|
||||||
|
beast::detail::ignore_unused(pi, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Fields>
|
||||||
|
void
|
||||||
|
prepare_option(prepare_info& pi,
|
||||||
|
message<isRequest, Body, Fields>& msg,
|
||||||
|
connection value)
|
||||||
|
{
|
||||||
|
beast::detail::ignore_unused(msg);
|
||||||
|
pi.connection_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
bool isRequest, class Body, class Fields,
|
||||||
|
class Opt, class... Opts>
|
||||||
|
void
|
||||||
|
prepare_options(prepare_info& pi,
|
||||||
|
message<isRequest, Body, Fields>& msg,
|
||||||
|
Opt&& opt, Opts&&... opts)
|
||||||
|
{
|
||||||
|
prepare_option(pi, msg, opt);
|
||||||
|
prepare_options(pi, msg,
|
||||||
|
std::forward<Opts>(opts)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Fields>
|
||||||
|
void
|
||||||
|
prepare_content_length(prepare_info& pi,
|
||||||
|
message<isRequest, Body, Fields> const& msg,
|
||||||
|
std::true_type)
|
||||||
|
{
|
||||||
|
typename Body::writer w(msg);
|
||||||
|
// VFALCO This is a design problem!
|
||||||
|
error_code ec;
|
||||||
|
w.init(ec);
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
|
pi.content_length = w.content_length();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Fields>
|
||||||
|
void
|
||||||
|
prepare_content_length(prepare_info& pi,
|
||||||
|
message<isRequest, Body, Fields> const& msg,
|
||||||
|
std::false_type)
|
||||||
|
{
|
||||||
|
beast::detail::ignore_unused(msg);
|
||||||
|
pi.content_length = boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
template<
|
||||||
|
bool isRequest, class Body, class Fields,
|
||||||
|
class... Options>
|
||||||
|
void
|
||||||
|
prepare(message<isRequest, Body, Fields>& msg,
|
||||||
|
Options&&... options)
|
||||||
|
{
|
||||||
|
// VFALCO TODO
|
||||||
|
static_assert(is_Body<Body>::value,
|
||||||
|
"Body requirements not met");
|
||||||
|
static_assert(has_writer<Body>::value,
|
||||||
|
"Body has no writer");
|
||||||
|
static_assert(is_Writer<typename Body::writer,
|
||||||
|
message<isRequest, Body, Fields>>::value,
|
||||||
|
"Writer requirements not met");
|
||||||
|
detail::prepare_info pi;
|
||||||
|
detail::prepare_content_length(pi, msg,
|
||||||
|
detail::has_content_length<typename Body::writer>{});
|
||||||
|
detail::prepare_options(pi, msg,
|
||||||
|
std::forward<Options>(options)...);
|
||||||
|
|
||||||
|
if(msg.fields.exists("Connection"))
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"prepare called with Connection field set");
|
||||||
|
|
||||||
|
if(msg.fields.exists("Content-Length"))
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"prepare called with Content-Length field set");
|
||||||
|
|
||||||
|
if(token_list{msg.fields["Transfer-Encoding"]}.exists("chunked"))
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"prepare called with Transfer-Encoding: chunked set");
|
||||||
|
|
||||||
|
if(pi.connection_value != connection::upgrade)
|
||||||
|
{
|
||||||
|
if(pi.content_length)
|
||||||
|
{
|
||||||
|
struct set_field
|
||||||
|
{
|
||||||
|
void
|
||||||
|
operator()(message<true, Body, Fields>& msg,
|
||||||
|
detail::prepare_info const& pi) const
|
||||||
|
{
|
||||||
|
using beast::detail::ci_equal;
|
||||||
|
if(*pi.content_length > 0 ||
|
||||||
|
ci_equal(msg.method, "POST"))
|
||||||
|
{
|
||||||
|
msg.fields.insert(
|
||||||
|
"Content-Length", *pi.content_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(message<false, Body, Fields>& msg,
|
||||||
|
detail::prepare_info const& pi) const
|
||||||
|
{
|
||||||
|
if((msg.status / 100 ) != 1 &&
|
||||||
|
msg.status != 204 &&
|
||||||
|
msg.status != 304)
|
||||||
|
{
|
||||||
|
msg.fields.insert(
|
||||||
|
"Content-Length", *pi.content_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
set_field{}(msg, pi);
|
||||||
|
}
|
||||||
|
else if(msg.version >= 11)
|
||||||
|
{
|
||||||
|
msg.fields.insert("Transfer-Encoding", "chunked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const content_length =
|
||||||
|
msg.fields.exists("Content-Length");
|
||||||
|
|
||||||
|
if(pi.connection_value)
|
||||||
|
{
|
||||||
|
switch(*pi.connection_value)
|
||||||
|
{
|
||||||
|
case connection::upgrade:
|
||||||
|
msg.fields.insert("Connection", "upgrade");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case connection::keep_alive:
|
||||||
|
if(msg.version < 11)
|
||||||
|
{
|
||||||
|
if(content_length)
|
||||||
|
msg.fields.insert("Connection", "keep-alive");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case connection::close:
|
||||||
|
if(msg.version >= 11)
|
||||||
|
msg.fields.insert("Connection", "close");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rfc7230 6.7.
|
||||||
|
if(msg.version < 11 && token_list{
|
||||||
|
msg.fields["Connection"]}.exists("upgrade"))
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"invalid version for Connection: upgrade");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user