mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Merge subtree Beast 1.0.0-b3
Merge commit '47eb7fcc2f30df883b0036d97aac6a0fa90b0e9f'
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
sudo: false
|
||||
language: cpp
|
||||
|
||||
env:
|
||||
@@ -8,55 +7,107 @@ env:
|
||||
# Note that for simplicity, BOOST_ROOT's final
|
||||
# namepart must match the folder name internal
|
||||
# to boost's .tar.gz.
|
||||
- LCOV_ROOT=$HOME/lcov
|
||||
- VALGRIND_ROOT=$HOME/valgrind-install
|
||||
- BOOST_ROOT=$HOME/boost_1_60_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'
|
||||
packages: &gcc5_pkgs
|
||||
- gcc-5
|
||||
- g++-5
|
||||
# - gcc-5-multilib
|
||||
# - g++-5-multilib
|
||||
# - gcc-multilib
|
||||
# - g++-multilib
|
||||
# - libgd2-xpm
|
||||
# - ia32-libs
|
||||
# - ia32-libs-multiarch
|
||||
- python-software-properties
|
||||
- protobuf-compiler
|
||||
- libssl-dev
|
||||
- libffi-dev
|
||||
- libstdc++6
|
||||
- binutils-gold
|
||||
# Provides a backtrace if the unittests crash
|
||||
- gdb
|
||||
# Needed for installing valgrind
|
||||
- subversion
|
||||
- automake
|
||||
- autotools-dev
|
||||
- libc6-dbg
|
||||
|
||||
packages: &clang36_pkgs
|
||||
- clang-3.6
|
||||
- g++-5
|
||||
- python-software-properties
|
||||
- libssl-dev
|
||||
- libffi-dev
|
||||
- libstdc++6
|
||||
- binutils-gold
|
||||
# Provides a backtrace if the unittests crash
|
||||
- gdb
|
||||
# Needed for installing valgrind
|
||||
- subversion
|
||||
- automake
|
||||
- autotools-dev
|
||||
- libc6-dbg
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# GCC/Debug
|
||||
- compiler: gcc
|
||||
env: GCC_VER=5 VARIANT=debug
|
||||
env: GCC_VER=5 VARIANT=debug ADDRESS_MODEL=64
|
||||
addons: &ao_gcc5
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: *gcc5_pkgs
|
||||
|
||||
# - compiler: gcc
|
||||
# env: GCC_VER=5 VARIANT=debug ADDRESS_MODEL=32
|
||||
# addons: *ao_gcc5
|
||||
|
||||
# GCC/Release
|
||||
- compiler: gcc
|
||||
env: GCC_VER=5 VARIANT=release
|
||||
env: GCC_VER=5 VARIANT=release ADDRESS_MODEL=64
|
||||
addons: *ao_gcc5
|
||||
|
||||
# # - compiler: gcc
|
||||
# # env: GCC_VER=5 VARIANT=release ADDRESS_MODEL=32
|
||||
# # addons: *ao_gcc5
|
||||
|
||||
# Clang/Debug
|
||||
- compiler: clang
|
||||
env: GCC_VER=5 VARIANT=debug CLANG_VER=3.6
|
||||
env: GCC_VER=5 VARIANT=debug CLANG_VER=3.6 ADDRESS_MODEL=64
|
||||
addons: &ao_clang36
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6']
|
||||
packages: *clang36_pkgs
|
||||
|
||||
# # - compiler: clang
|
||||
# # env: GCC_VER=5 VARIANT=debug CLANG_VER=3.6 ADDRESS_MODEL=32
|
||||
# # addons: *ao_clang36
|
||||
|
||||
# Clang/Release
|
||||
- compiler: clang
|
||||
env: GCC_VER=5 VARIANT=release CLANG_VER=3.6
|
||||
env: GCC_VER=5 VARIANT=release CLANG_VER=3.6 ADDRESS_MODEL=64
|
||||
addons: *ao_clang36
|
||||
|
||||
# # - compiler: clang
|
||||
# # env: GCC_VER=5 VARIANT=release CLANG_VER=3.6 ADDRESS_MODEL=32
|
||||
# # addons: *ao_clang36
|
||||
|
||||
# Coverage
|
||||
- compiler: gcc
|
||||
env: GCC_VER=5 VARIANT=coverage ADDRESS_MODEL=64
|
||||
addons: *ao_gcc5
|
||||
|
||||
# ASAN
|
||||
- compiler: gcc
|
||||
env: GCC_VER=5 VARIANT=asan ADDRESS_MODEL=64
|
||||
addons: *ao_gcc5
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $BOOST_ROOT
|
||||
- $VALGRIND_ROOT
|
||||
|
||||
before_install:
|
||||
- scripts/install-dependencies.sh
|
||||
@@ -64,6 +115,9 @@ before_install:
|
||||
script:
|
||||
- scripts/build-and-test.sh
|
||||
|
||||
after_script:
|
||||
- cat nohup.out || echo "nohup.out already deleted"
|
||||
|
||||
notifications:
|
||||
email:
|
||||
false
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
# Part of Beast
|
||||
|
||||
cmake_minimum_required (VERSION 3.5)
|
||||
cmake_minimum_required (VERSION 3.2)
|
||||
|
||||
project (Beast)
|
||||
|
||||
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
if (WIN32)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /wd4100 /D_SCL_SECURE_NO_WARNINGS=1 /D_CRT_SECURE_NO_WARNINGS=1")
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4 /wd4100 /D_SCL_SECURE_NO_WARNINGS=1 /D_CRT_SECURE_NO_WARNINGS=1")
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
||||
else()
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
find_package(Boost REQUIRED COMPONENTS filesystem program_options system)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
link_directories(${Boost_LIBRARY_DIR})
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads)
|
||||
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -g -std=c++11 -Wall /Wextra /Wpedantic /Wconversion -Wno-unused-variable")
|
||||
endif()
|
||||
|
||||
message ("cxx Flags: " ${CMAKE_CXX_FLAGS})
|
||||
|
||||
@@ -45,48 +45,65 @@ else
|
||||
lib crypto ;
|
||||
}
|
||||
|
||||
variant coverage
|
||||
:
|
||||
debug
|
||||
:
|
||||
<cxxflags>"-fprofile-arcs -ftest-coverage"
|
||||
<linkflags>"-lgcov"
|
||||
;
|
||||
|
||||
variant asan
|
||||
:
|
||||
release
|
||||
:
|
||||
<cxxflags>"-fsanitize=address -fno-omit-frame-pointer"
|
||||
<linkflags>"-fsanitize=address"
|
||||
;
|
||||
|
||||
project beast
|
||||
: requirements
|
||||
<include>.
|
||||
<include>./include
|
||||
#<use>/boost//headers
|
||||
<library>/boost/system//boost_system
|
||||
<library>/boost/filesystem//boost_filesystem
|
||||
<library>/boost/program_options//boost_program_options
|
||||
: requirements
|
||||
<include>.
|
||||
<include>./include
|
||||
#<use>/boost//headers
|
||||
<library>/boost/system//boost_system
|
||||
<library>/boost/coroutine//boost_coroutine
|
||||
<library>/boost/filesystem//boost_filesystem
|
||||
<library>/boost/program_options//boost_program_options
|
||||
# <library>ssl
|
||||
# <library>crypto
|
||||
<define>BOOST_ALL_NO_LIB=1
|
||||
<define>BOOST_SYSTEM_NO_DEPRECATED=1
|
||||
<threading>multi
|
||||
<link>static
|
||||
<runtime-link>shared
|
||||
<debug-symbols>on
|
||||
<toolset>gcc:<cxxflags>-std=c++11
|
||||
<toolset>gcc:<cxxflags>-Wno-unused-variable
|
||||
<toolset>clang:<cxxflags>-std=c++11
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
||||
<os>LINUX:<define>_XOPEN_SOURCE=600
|
||||
<os>LINUX:<define>_GNU_SOURCE=1
|
||||
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
||||
<os>SOLARIS:<define>__EXTENSIONS__
|
||||
<os>SOLARIS:<library>socket
|
||||
<os>SOLARIS:<library>nsl
|
||||
<os>NT:<define>_WIN32_WINNT=0x0501
|
||||
<os>NT,<toolset>cw:<library>ws2_32
|
||||
<os>NT,<toolset>cw:<library>mswsock
|
||||
<os>NT,<toolset>gcc:<library>ws2_32
|
||||
<os>NT,<toolset>gcc:<library>mswsock
|
||||
<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
|
||||
<include>.
|
||||
:
|
||||
build-dir bin
|
||||
;
|
||||
<define>BOOST_ALL_NO_LIB=1
|
||||
<define>BOOST_SYSTEM_NO_DEPRECATED=1
|
||||
<threading>multi
|
||||
<link>static
|
||||
<runtime-link>shared
|
||||
<debug-symbols>on
|
||||
<toolset>gcc:<cxxflags>-std=c++11
|
||||
<toolset>gcc:<cxxflags>-Wno-unused-variable
|
||||
<toolset>clang:<cxxflags>-std=c++11
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
||||
<os>LINUX:<define>_XOPEN_SOURCE=600
|
||||
<os>LINUX:<define>_GNU_SOURCE=1
|
||||
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
||||
<os>SOLARIS:<define>__EXTENSIONS__
|
||||
<os>SOLARIS:<library>socket
|
||||
<os>SOLARIS:<library>nsl
|
||||
<os>NT:<define>_WIN32_WINNT=0x0501
|
||||
<os>NT,<toolset>cw:<library>ws2_32
|
||||
<os>NT,<toolset>cw:<library>mswsock
|
||||
<os>NT,<toolset>gcc:<library>ws2_32
|
||||
<os>NT,<toolset>gcc:<library>mswsock
|
||||
<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
|
||||
<include>.
|
||||
:
|
||||
build-dir bin
|
||||
;
|
||||
|
||||
build-project test ;
|
||||
build-project examples ;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Beast [](https://travis-ci.org/vinniefalco/Beast)
|
||||
# Beast [](https://travis-ci.org/vinniefalco/Beast) [](https://codecov.io/gh/sublimator/Beast)
|
||||
|
||||
Beast provides implementations of the HTTP and WebSocket protocols
|
||||
built on top of Boost.Asio and other parts of boost.
|
||||
|
||||
@@ -1,32 +1,45 @@
|
||||
* Change build options to C++11 only
|
||||
* Replace Jamroot with Jamfile
|
||||
* Fix failing test/message.cpp
|
||||
* Complete allocator testing in basic_streambuf, basic_headers
|
||||
* Tidy up type_checks
|
||||
- Derive from std::integral_constant
|
||||
* Check DOXYGEN, GENERATIC_DOCS directives in source
|
||||
- See if we can include them now that xsl is fixed
|
||||
* Go over each header and split header material into detail and impl files
|
||||
* Make buffers_debug a detail
|
||||
* Roll header-only http parser
|
||||
* Define Parser concept in HTTP
|
||||
* melpon sandbox?
|
||||
* invokable unit test
|
||||
* trim public interface of rfc2616.h to essentials only
|
||||
* Use new http routines in JSONRPCClient
|
||||
* Remove or change http::headers alias
|
||||
* Do something about the methods.hpp and fields.hpp type headers
|
||||
* Add writer::prepare(msg&) interface to set Content-Type
|
||||
|
||||
General:
|
||||
* Use SFINAE on return values (search for "class =")
|
||||
|
||||
Boost.Http
|
||||
* Use enum instead of bool in isRequest
|
||||
* move version to a subclass of message
|
||||
|
||||
Docs:
|
||||
* Include Example program listings in the docs
|
||||
* Fix index in docs
|
||||
* Fix integer warning in file_body.hpp
|
||||
* Use make_error_code in websocket to set the category right
|
||||
* Figure out why namespace rfc2616 is included in docs
|
||||
(currently disabled via GENERATING_DOCS macro)
|
||||
* Include Example program listings in the docs
|
||||
* Update for rfc7230
|
||||
* melpon sandbox?
|
||||
* Check DOXYGEN, GENERATIC_DOCS directives in source
|
||||
- See if we can include them now that xsl is fixed
|
||||
* Implement cleanup-param to remove spaces around template arguments
|
||||
e.g. in basic_streambuf move constructor members
|
||||
|
||||
Core:
|
||||
* Replace Jamroot with Jamfile
|
||||
* Fix bidirectional buffers iterators operator->()
|
||||
* Complete allocator testing in basic_streambuf, basic_headers
|
||||
|
||||
WebSocket:
|
||||
* optimized versions of key/masking, choose prepared_key size
|
||||
* invokable unit test
|
||||
* Finish up all of static_string including tests
|
||||
* Don't rely on default constructible mutable buffers
|
||||
type in read_frame_op (smb_type). To see the error, use
|
||||
boost::asio::streambuf in websocket_async_echo_peer
|
||||
|
||||
HTTP:
|
||||
* Define Parser concept in HTTP
|
||||
* trim public interface of rfc2616.h to essentials only
|
||||
* add bool should_close(message_v1 const&) to replace the use
|
||||
of eof return value from write and async_write
|
||||
* http type_check, e.g. is_WritableBody
|
||||
* More fine grained parser errors
|
||||
* HTTP parser size limit with test (configurable?)
|
||||
* HTTP parser trailers with test
|
||||
* URL parser, strong URL checking in HTTP parser
|
||||
* Fix method, use string instead of enum
|
||||
* More fine grained parser errors
|
||||
* Fix all the warnings in all projects/build configs
|
||||
* Fix bidirectional buffers iterators operator->()
|
||||
* Update for rfc7230
|
||||
* Consider rename to MessageBody concept
|
||||
|
||||
@@ -103,12 +103,16 @@ WARN_LOGFILE =
|
||||
# Configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = \
|
||||
../include/beast/ \
|
||||
../include/beast/http \
|
||||
../include/beast/websocket \
|
||||
../include/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/buffers_debug.hpp \
|
||||
../include/beast/consuming_buffers.hpp \
|
||||
../include/beast/handler_alloc.hpp \
|
||||
../include/beast/http.hpp \
|
||||
@@ -117,17 +121,20 @@ INPUT = \
|
||||
../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.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 \
|
||||
|
||||
@@ -115,9 +115,10 @@ int main()
|
||||
using namespace beast::http;
|
||||
|
||||
// Send HTTP request using beast
|
||||
request<empty_body> req({method_t::http_get, "/", 11});
|
||||
request<empty_body> req({"GET", "/", 11});
|
||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
||||
req.headers.replace("User-Agent", "Beast");
|
||||
prepare(req);
|
||||
write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
@@ -130,8 +131,8 @@ int main()
|
||||
|
||||
Establish a WebSocket connection, send a message and receive the reply:
|
||||
```
|
||||
#include <beast/to_string.hpp>
|
||||
#include <beast/websocket.hpp>
|
||||
#include <beast/buffers_debug.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@@ -158,8 +159,7 @@ int main()
|
||||
opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(close_code::normal);
|
||||
std::cout <<
|
||||
beast::debug::buffers_to_string(sb.data()) << "\n";
|
||||
std::cout << to_string(sb.data()) << "\n";
|
||||
}
|
||||
```
|
||||
|
||||
@@ -186,7 +186,12 @@ documentation is based.
|
||||
|
||||
[include http.qbk]
|
||||
[include websocket.qbk]
|
||||
[include types.qbk]
|
||||
|
||||
[section:types Type Requirements]
|
||||
[include core_types.qbk]
|
||||
[include http_types.qbk]
|
||||
[endsect]
|
||||
|
||||
[include design.qbk]
|
||||
[section:quickref Quick Reference]
|
||||
[xinclude quickref.xml]
|
||||
|
||||
118
src/beast/doc/core_types.qbk
Normal file
118
src/beast/doc/core_types.qbk
Normal file
@@ -0,0 +1,118 @@
|
||||
[/
|
||||
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:BufferSequence BufferSequence]
|
||||
|
||||
A `BufferSequence` is a type meeting either of the following requirements:
|
||||
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*`ConstBufferSequence`]]
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*`MutableBufferSequence`]]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:stream Streams]
|
||||
|
||||
Stream types represent objects capable of performing synchronous or
|
||||
asynchronous I/O. They are based on concepts from `boost::asio`.
|
||||
|
||||
[heading:Stream Stream]
|
||||
|
||||
A type modeling [*`Stream`] meets either or both of the following requirements:
|
||||
|
||||
* [link beast.types.stream.AsyncStream [*`AsyncStream`]]
|
||||
* [link beast.types.stream.SyncStream [*`SyncStream`]]
|
||||
|
||||
[heading:AsyncStream AsyncStream]
|
||||
|
||||
A type modeling [*`AsyncStream`] meets the following requirements:
|
||||
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*`AsyncReadStream`]]
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*`AsyncWriteStream`]]
|
||||
|
||||
[heading:SyncStream SyncStream]
|
||||
|
||||
A type modeling [*`SyncStream`] meets the following requirements:
|
||||
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*`SyncReadStream`]]
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*`SyncWriteStream`]]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:Streambuf Streambuf]
|
||||
|
||||
In the table below:
|
||||
|
||||
* `X` denotes a class
|
||||
* `a` denotes a value of type `X`
|
||||
* `n` denotes a value convertible to `std::size_t`
|
||||
* `U`, `T` denote unspecified types.
|
||||
|
||||
[table Streambuf requirements
|
||||
[[operation] [type] [semantics, pre/post-conditions]]
|
||||
[
|
||||
[`X::const_buffers_type`]
|
||||
[`T`]
|
||||
[`T` meets the requirements for `ConstBufferSequence`.]
|
||||
]
|
||||
[
|
||||
[`X::mutable_buffers_type`]
|
||||
[`U`]
|
||||
[`U` meets the requirements for `MutableBufferSequence`.]
|
||||
]
|
||||
[
|
||||
[`a.commit(n)`]
|
||||
[`void`]
|
||||
[Moves bytes from the output sequence to the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.consume(n)`]
|
||||
[`void`]
|
||||
[Removes bytes from the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.data()`]
|
||||
[`T`]
|
||||
[Returns a list of buffers that represents the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.prepare(n)`]
|
||||
[`U`]
|
||||
[Returns a list of buffers that represents the output sequence, with
|
||||
the given size.]
|
||||
]
|
||||
[
|
||||
[`a.size()`]
|
||||
[`std::size_t`]
|
||||
[Returns the size of the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.max_size()`]
|
||||
[`std::size_t`]
|
||||
[Returns the maximum size of the `Streambuf`.]
|
||||
]
|
||||
[
|
||||
[`read_size_helper(a, n)`]
|
||||
[`std::size_t`]
|
||||
[
|
||||
Returns the suggested number of bytes to read into the output
|
||||
sequence where `n` is an upper limit on this value. One possible
|
||||
implementation is to return the number of bytes that may be prepared
|
||||
without causing a dynamic allocation or `n`, whichever is smaller.
|
||||
Calls to `read_size_helper` will be made without namespace
|
||||
qualification, to allow the rules for argument dependent lookup to
|
||||
take effect.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
@@ -8,7 +8,7 @@
|
||||
[section:design Design choices]
|
||||
|
||||
The implementations are driven by business needs of cryptocurrency server
|
||||
applications ([link https://ripple.com Ripple] written in C++. These
|
||||
applications ([@https://ripple.com Ripple] written in C++. These
|
||||
needs were not met by existing solutions so new code was written. The new
|
||||
code tries to avoid design flaws encountered in the already-existing software
|
||||
libraries:
|
||||
@@ -194,8 +194,8 @@ start. Other design goals:
|
||||
|
||||
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.wsproto__teardown `teardown`] and
|
||||
[link beast.ref.wsproto__async_teardown `async_teardown`]. These will
|
||||
[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.
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
Beast.HTTP offers programmers simple and performant models of HTTP messages and
|
||||
their associated operations including synchronous and asynchronous reading and
|
||||
writing using Boost.Asio.
|
||||
writing of messages in the HTTP/1 wire format using Boost.Asio.
|
||||
|
||||
The HTTP protocol is described fully in
|
||||
[@https://tools.ietf.org/html/rfc2616 rfc2616]
|
||||
@@ -25,20 +25,43 @@ 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 HTTP parser from NodeJS, which is
|
||||
extensively field tested and exceptionally robust. 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.
|
||||
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.
|
||||
|
||||
[heading Scope]
|
||||
[endsect]
|
||||
|
||||
The scope of this library is meant to include only the functionality of
|
||||
modeling the HTTP message, serializing and deserializing the message, and
|
||||
sending and receiving messages on sockets or streams. It is designed to
|
||||
be a building block for creating higher level abstractions.
|
||||
|
||||
|
||||
[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
|
||||
@@ -59,35 +82,17 @@ both Boost.Asio and the HTTP protocol specification described in
|
||||
```
|
||||
]
|
||||
|
||||
A HTTP message (referred to hereafter as "message") contains a request or
|
||||
response line, 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. The library
|
||||
provides interfaces to perform these operations on messages:
|
||||
|
||||
* [*Parse] a new message from a series of octets.
|
||||
|
||||
* [*Assemble] a new message from scratch or from an existing message.
|
||||
|
||||
* [*Serialize] a message into a series of octets.
|
||||
|
||||
* [*Read] a message from a stream. This can be thought of as a compound
|
||||
operation; a network read, followed by a [*parse].
|
||||
|
||||
* [*Write] a message to a stream. This can be thought of as a compound
|
||||
operation: a [*serialize] followed by a network write.
|
||||
|
||||
In the paragraphs that follow we describe simple interfaces that will serve
|
||||
the majority of users looking merely to interact with a HTTP server, or
|
||||
handle simple HTTP requests from clients. Subsequent sections cover the
|
||||
message model in more depth, for advanced applications.
|
||||
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
|
||||
requires at mininum, a bool indicating whether the message is a request
|
||||
requires at mininum, a value indicating whether the message is a request
|
||||
(versus a response), and a `Body` type. The choice of `Body` determines the
|
||||
kind of container used to represent the message body. Here we will
|
||||
declare a request that has a `std::string` for the body container:
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:types Type Requirements]
|
||||
|
||||
|
||||
|
||||
[section:Body Body]
|
||||
@@ -57,10 +55,10 @@ In this table:
|
||||
|
||||
[section:BufferSequence BufferSequence]
|
||||
|
||||
A `BufferSequence` meets [*one of] the following requirements:
|
||||
A `BufferSequence` is a type meeting either of the following requirements:
|
||||
|
||||
* `ConstBufferSequence`
|
||||
* `MutableBufferSequence`
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*`ConstBufferSequence`]]
|
||||
* [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*`MutableBufferSequence`]]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -223,7 +221,7 @@ In this table:
|
||||
* `m` denotes a value of type `message const&` where
|
||||
`std::is_same<decltype(m.body), Body::value_type>:value == true`.
|
||||
|
||||
* `rc` is an object of type [link beast.reference.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&`.
|
||||
|
||||
@@ -252,7 +250,7 @@ In this table:
|
||||
]
|
||||
[
|
||||
[`a.content_length()`]
|
||||
[`std::size_t`]
|
||||
[`std::uint64_t`]
|
||||
[
|
||||
If this member is present, it is called after initialization
|
||||
and before calls to provide buffers. The serialized message will
|
||||
@@ -373,74 +371,3 @@ public:
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:Stream Stream]
|
||||
|
||||
A `Stream` meets the following requirements:
|
||||
|
||||
* `SyncReadStream`
|
||||
* `SyncWriteStream`
|
||||
* `AsyncReadStream`
|
||||
* `AsyncWriteStream`
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:Streambuf Streambuf]
|
||||
|
||||
In the table below, `X` denotes a class, `a` denotes a value
|
||||
of type `X`, `n` denotes a value convertible to `std::size_t`,
|
||||
and `U` and `T` denote unspecified types.
|
||||
|
||||
[table Streambuf requirements
|
||||
[[operation] [type] [semantics, pre/post-conditions]]
|
||||
[
|
||||
[`X::const_buffers_type`]
|
||||
[`T`]
|
||||
[`T` meets the requirements for `ConstBufferSequence`.]
|
||||
]
|
||||
[
|
||||
[`X::mutable_buffers_type`]
|
||||
[`U`]
|
||||
[`U` meets the requirements for `MutableBufferSequence`.]
|
||||
]
|
||||
[
|
||||
[`a.commit(n)`]
|
||||
[`void`]
|
||||
[Moves bytes from the output sequence to the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.consume(n)`]
|
||||
[`void`]
|
||||
[Removes bytes from the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.data()`]
|
||||
[`T`]
|
||||
[Returns a list of buffers that represents the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.prepare(n)`]
|
||||
[`U`]
|
||||
[Returns a list of buffers that represents the output sequence, with
|
||||
the given size.]
|
||||
]
|
||||
[
|
||||
[`a.size()`]
|
||||
[`std::size_t`]
|
||||
[Returns the size of the input sequence.]
|
||||
]
|
||||
[
|
||||
[`a.max_size()`]
|
||||
[`std::size_t`]
|
||||
[Returns the maximum size of the `Streambuf`.]
|
||||
]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
@@ -30,10 +30,11 @@
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__basic_headers">basic_headers</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_parser">basic_parser</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_streambuf_body">basic_streambuf_body</link></member>
|
||||
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
|
||||
<member><link linkend="beast.ref.http__error_code">error_code</link></member>
|
||||
<member><link linkend="beast.ref.http__headers">headers</link></member>
|
||||
<member><link linkend="beast.ref.http__message">message</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>
|
||||
@@ -41,7 +42,7 @@
|
||||
</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>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
@@ -49,11 +50,14 @@
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__async_read">async_read</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__prepare">prepare</link></member>
|
||||
<member><link linkend="beast.ref.http__read">read</link></member>
|
||||
<member><link linkend="beast.ref.http__write">write</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__connection">connection</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.types.Body">Body</link></member>
|
||||
@@ -67,7 +71,6 @@
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__close_reason">close_reason</link></member>
|
||||
<member><link linkend="beast.ref.websocket__static_string">static_string</link></member>
|
||||
<member><link linkend="beast.ref.websocket__stream">stream</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
@@ -120,6 +123,7 @@
|
||||
<member><link linkend="beast.ref.prepared_buffers">prepared_buffers</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_string">static_string</link></member>
|
||||
<member><link linkend="beast.ref.streambuf">streambuf</link></member>
|
||||
<member><link linkend="beast.ref.streambuf_readstream">streambuf_readstream</link></member>
|
||||
</simplelist>
|
||||
@@ -129,23 +133,28 @@
|
||||
<simplelist type="vert" columns="1">
|
||||
<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.consumed_buffers">consumed_buffers</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.to_string">to_string</link></member>
|
||||
|
||||
<member><link linkend="beast.ref.write">write</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
|
||||
<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_AsyncStream">is_AsyncStream</link></member>
|
||||
<member><link linkend="beast.ref.is_BufferSequence">is_BufferSequence</link></member>
|
||||
<member><link linkend="beast.ref.is_CompletionHandler">is_CompletionHandler</link></member>
|
||||
<member><link linkend="beast.ref.is_ConstBufferSequence">is_ConstBufferSequence</link></member>
|
||||
<member><link linkend="beast.ref.is_Handler">is_Handler</link></member>
|
||||
<member><link linkend="beast.ref.is_MutableBufferSequence">is_MutableBufferSequence</link></member>
|
||||
<member><link linkend="beast.ref.is_Stream">is_Stream</link></member>
|
||||
<member><link linkend="beast.ref.is_Streambuf">is_Streambuf</link></member>
|
||||
<member><link linkend="beast.ref.is_SyncReadStream">is_SyncReadStream</link></member>
|
||||
<member><link linkend="beast.ref.is_SyncStream">is_SyncStream</link></member>
|
||||
<member><link linkend="beast.ref.is_SyncWriteStream">is_SyncWriteStream</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
@@ -153,8 +162,30 @@
|
||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.types.BufferSequence">BufferSequence</link></member>
|
||||
<member><link linkend="beast.types.Stream">Stream</link></member>
|
||||
<member><link linkend="beast.types.stream.AsyncStream">AsyncStream</link></member>
|
||||
<member><link linkend="beast.types.stream.Stream">Stream</link></member>
|
||||
<member><link linkend="beast.types.Streambuf">Streambuf</link></member>
|
||||
<member><link linkend="beast.types.stream.SyncStream">SyncStream</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
<tgroup cols="1">
|
||||
<colspec colname="a"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry valign="center" namest="a" nameend="a">
|
||||
<bridgehead renderas="sect2">Diagnostic</bridgehead>
|
||||
</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry valign="top">
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.doc_debug">doc_debug</link></member>
|
||||
<member><link linkend="beast.ref.nested__nested_doc_debug">nested_doc_debug</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
<xsl:when test="@kind='class' or @kind='struct'">
|
||||
<xsl:if test="
|
||||
contains(compoundname, 'beast::') and
|
||||
not(contains(compoundname, 'boost::')) and
|
||||
not(contains(compoundname, '::detail')) and
|
||||
not(contains(compoundname, 'rfc2616')) and
|
||||
not(contains(@prot, 'private'))">
|
||||
@@ -61,7 +62,6 @@
|
||||
<xsl:text>
[endsect]</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<!--========== Utilities ==========-->
|
||||
|
||||
<xsl:template name="strip-beast-ns">
|
||||
@@ -73,6 +73,9 @@
|
||||
<xsl:when test="contains($name, 'beast::')">
|
||||
<xsl:value-of select="substring-after($name, 'beast::')"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="$name = 'beast'">
|
||||
<xsl:text></xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="$name"/>
|
||||
</xsl:otherwise>
|
||||
@@ -108,6 +111,38 @@
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="cleanup-param">
|
||||
<xsl:param name="name"/>
|
||||
<xsl:variable name="clean">
|
||||
<xsl:value-of select="$name"/>
|
||||
</xsl:variable>
|
||||
<xsl:choose>
|
||||
<xsl:when test="' *' = substring($clean, string-length($clean) - 1)">
|
||||
<xsl:value-of select="substring($clean, 1, string-length($clean) - 2)"/>
|
||||
<xsl:text>*</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="' &' = substring($clean, string-length($clean) - 1)">
|
||||
<xsl:value-of select="substring($clean, 1, string-length($clean) - 2)"/>
|
||||
<xsl:text>&</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="' &...' = substring($clean, string-length($clean) - 4)">
|
||||
<xsl:value-of select="substring($clean, 1, string-length($clean) - 5)"/>
|
||||
<xsl:text>&...</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="' &&' = substring($clean, string-length($clean) - 2)">
|
||||
<xsl:value-of select="substring($clean, 1, string-length($clean) - 3)"/>
|
||||
<xsl:text>&&</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="' &&...' = substring($clean, string-length($clean) - 5)">
|
||||
<xsl:value-of select="substring($clean, 1, string-length($clean) - 6)"/>
|
||||
<xsl:text>&&...</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="$clean"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="cleanup-type">
|
||||
<xsl:param name="name"/>
|
||||
<xsl:variable name="type">
|
||||
@@ -124,20 +159,22 @@
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$type='ConstBufferSequence'">
|
||||
<xsl:text>``[link beast.ref.ConstBufferSequence ['ConstBufferSequence]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$type='implementation_defined'">
|
||||
<xsl:text>``['implementation-defined]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$type='void_or_deduced'">
|
||||
<xsl:text>``[link beast.ref.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="$type"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:variable name="cleaned">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$type='implementation_defined'">
|
||||
<xsl:text>``['implementation-defined]``</xsl:text>
|
||||
</xsl:when>
|
||||
<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:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="$type"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:call-template name="cleanup-param">
|
||||
<xsl:with-param name="name" select="$cleaned"/>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make-id">
|
||||
@@ -260,8 +297,9 @@
|
||||
<!--========== Markup ==========-->
|
||||
|
||||
<xsl:template match="para" mode="markup">
|
||||
<xsl:apply-templates mode="markup"/>
|
||||
<xsl:text>
</xsl:text>
|
||||
<xsl:value-of select="$newline"/>
|
||||
<xsl:apply-templates mode="markup"/>
|
||||
<xsl:value-of select="$newline"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="para" mode="markup-nested">
|
||||
@@ -391,6 +429,8 @@
|
||||
<xsl:apply-templates mode="markup"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="@kind='see'">
|
||||
<xsl:text>[heading See Also]
</xsl:text>
|
||||
<xsl:apply-templates mode="markup"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="@kind='note'">
|
||||
<xsl:text>[heading Remarks]
</xsl:text>
|
||||
@@ -536,12 +576,13 @@
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template match="ref[@kindref='compound']" mode="markup">
|
||||
<xsl:variable name="name">
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:variable>
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains(@refid, 'asio') or contains($name, 'asio::')">
|
||||
<xsl:when test="contains(@refid, 'beast')">
|
||||
<xsl:variable name="dox-ref-id" select="@refid"/>
|
||||
<xsl:variable name="ref-name">
|
||||
<xsl:call-template name="strip-beast-ns">
|
||||
@@ -554,6 +595,14 @@
|
||||
<xsl:with-param name="name" select="$ref-name"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<!--<xsl:text>|1|</xsl:text>-->
|
||||
<!--
|
||||
<xsl:text>[role red ref-name='</xsl:text>
|
||||
<xsl:value-of select="$ref-name"/>
|
||||
<xsl:text>'|ref-id='</xsl:text>
|
||||
<xsl:value-of select="$ref-id"/>
|
||||
<xsl:text>']|</xsl:text>
|
||||
-->
|
||||
<xsl:text>[link beast.ref.</xsl:text>
|
||||
<xsl:value-of select="$ref-id"/>
|
||||
<xsl:text> `</xsl:text>
|
||||
@@ -561,89 +610,106 @@
|
||||
<xsl:text>`]</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>`</xsl:text>
|
||||
<xsl:text>[role red |1|</xsl:text>
|
||||
<xsl:value-of select="."/>
|
||||
<xsl:text>`</xsl:text>
|
||||
<xsl:text>]</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="ref[@kindref='member']" mode="markup">
|
||||
<xsl:variable name="name">
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="dox-ref-id" select="@refid"/>
|
||||
<xsl:variable name="memberdefs" select="/doxygen//compounddef/sectiondef/memberdef[@id=$dox-ref-id]"/>
|
||||
<xsl:variable name="def-kind" select="($memberdefs)/../../@kind"/>
|
||||
<xsl:variable name="sec-kind" select="($memberdefs)/../@kind"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains(@refid, 'beast') and count($memberdefs) > 0">
|
||||
<xsl:variable name="dox-compound-name" select="($memberdefs)[1]/../../compoundname"/>
|
||||
<xsl:variable name="dox-name" select="($memberdefs)[1]/name"/>
|
||||
<xsl:variable name="ref-name">
|
||||
<xsl:call-template name="strip-beast-ns">
|
||||
<xsl:with-param name="name" select="$dox-compound-name"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="ref-id">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name" select="$ref-name"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<!--<xsl:text>|2|</xsl:text>-->
|
||||
<!--
|
||||
<xsl:text>[role red def-kind='</xsl:text>
|
||||
<xsl:value-of select="$def-kind"/>
|
||||
<xsl:text>', sec-kind='</xsl:text>
|
||||
<xsl:value-of select="$sec-kind"/>
|
||||
<xsl:text>', ref-id='</xsl:text>
|
||||
<xsl:value-of select="$ref-id"/>
|
||||
<xsl:text>'] </xsl:text>
|
||||
-->
|
||||
<xsl:choose>
|
||||
<xsl:when test="$def-kind = 'namespace'">
|
||||
<xsl:text>[link beast.ref.</xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="string-length($ref-id) > 0">
|
||||
<xsl:value-of select="concat($ref-id,'__',$dox-name)"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="$dox-name"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:text> `</xsl:text>
|
||||
<xsl:value-of name="text" select="$dox-name"/>
|
||||
<xsl:text>`]</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$def-kind = 'class' or $def-kind = 'struct'">
|
||||
<xsl:text>[link beast.ref.</xsl:text>
|
||||
<xsl:value-of select="concat($ref-id,'.',$dox-name)"/>
|
||||
<xsl:text> `</xsl:text>
|
||||
<xsl:value-of name="text" select="$name"/>
|
||||
<xsl:text>`]</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>[role red </xsl:text>
|
||||
<xsl:value-of select="$name"/>
|
||||
<xsl:text>]</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>[role red </xsl:text>
|
||||
<xsl:value-of select="$name"/>
|
||||
<xsl:text>]</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="ref[@kindref='compound']" mode="markup-nested">
|
||||
<xsl:variable name="name">
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:variable>
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains(@refid, 'asio') or contains($name, 'asio::')">
|
||||
<xsl:variable name="dox-ref-id" select="@refid"/>
|
||||
<xsl:variable name="ref-name">
|
||||
<xsl:call-template name="strip-beast-ns">
|
||||
<xsl:with-param name="name"
|
||||
select="(/doxygen//compounddef[@id=$dox-ref-id])[1]/compoundname"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="ref-id">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name" select="$ref-name"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:text>[link beast.ref.</xsl:text>
|
||||
<xsl:value-of select="$ref-id"/>
|
||||
<xsl:text> `</xsl:text>
|
||||
<xsl:value-of name="text" select="$ref-name"/>
|
||||
<xsl:text>`]</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>`</xsl:text>
|
||||
<xsl:value-of select="."/>
|
||||
<xsl:text>`</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:text>[role red |3|</xsl:text>
|
||||
<xsl:value-of select="."/>
|
||||
<xsl:text>]</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="ref[@kindref='member']" mode="markup">
|
||||
<xsl:variable name="dox-ref-id" select="@refid"/>
|
||||
<xsl:variable name="memberdefs" select="/doxygen//compounddef/sectiondef/memberdef[@id=$dox-ref-id]"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains(@refid, 'namespaceboost_1_1asio') and count($memberdefs) > 0">
|
||||
<xsl:variable name="dox-compound-name" select="($memberdefs)[1]/../../compoundname"/>
|
||||
<xsl:variable name="dox-name" select="($memberdefs)[1]/name"/>
|
||||
<xsl:variable name="ref-name">
|
||||
<xsl:call-template name="strip-beast-ns">
|
||||
<xsl:with-param name="name" select="concat($dox-compound-name,'::',$dox-name)"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="ref-id">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name" select="$ref-name"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:text>[link beast.ref.</xsl:text>
|
||||
<xsl:value-of select="$ref-id"/>
|
||||
<xsl:text> `</xsl:text>
|
||||
<xsl:value-of name="text" select="$ref-name"/>
|
||||
<xsl:text>`]</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>`</xsl:text>
|
||||
<xsl:value-of select="."/>
|
||||
<xsl:text>`</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="ref[@kindref='member']" mode="markup-nested">
|
||||
<xsl:variable name="name">
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="dox-ref-id" select="@refid"/>
|
||||
<xsl:variable name="memberdefs" select="/doxygen//compounddef/sectiondef/memberdef[@id=$dox-ref-id]"/>
|
||||
<xsl:variable name="def-kind" select="($memberdefs)/../../@kind"/>
|
||||
<xsl:variable name="sec-kind" select="($memberdefs)/../@kind"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains(@refid, 'namespaceboost_1_1asio') and count($memberdefs) > 0">
|
||||
<xsl:when test="contains(@refid, 'beast') and count($memberdefs) > 0">
|
||||
<xsl:variable name="dox-compound-name" select="($memberdefs)[1]/../../compoundname"/>
|
||||
<xsl:variable name="dox-name" select="($memberdefs)[1]/name"/>
|
||||
<xsl:variable name="ref-name">
|
||||
<xsl:call-template name="strip-beast-ns">
|
||||
<xsl:with-param name="name" select="concat($dox-compound-name,'::',$dox-name)"/>
|
||||
<xsl:with-param name="name" select="$dox-compound-name"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="ref-id">
|
||||
@@ -651,16 +717,49 @@
|
||||
<xsl:with-param name="name" select="$ref-name"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:text>[link beast.ref.</xsl:text>
|
||||
<!--<xsl:text>|2|</xsl:text>-->
|
||||
<!--
|
||||
<xsl:text>[role red def-kind='</xsl:text>
|
||||
<xsl:value-of select="$def-kind"/>
|
||||
<xsl:text>', sec-kind='</xsl:text>
|
||||
<xsl:value-of select="$sec-kind"/>
|
||||
<xsl:text>', ref-id='</xsl:text>
|
||||
<xsl:value-of select="$ref-id"/>
|
||||
<xsl:text> `</xsl:text>
|
||||
<xsl:value-of name="text" select="$ref-name"/>
|
||||
<xsl:text>`]</xsl:text>
|
||||
<xsl:text>'] </xsl:text>
|
||||
-->
|
||||
<xsl:choose>
|
||||
<xsl:when test="$def-kind = 'namespace'">
|
||||
<xsl:text>[link beast.ref.</xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="string-length($ref-id) > 0">
|
||||
<xsl:value-of select="concat($ref-id,'__',$dox-name)"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="$dox-name"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:text> `</xsl:text>
|
||||
<xsl:value-of name="text" select="$dox-name"/>
|
||||
<xsl:text>`]</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$def-kind = 'class' or $def-kind = 'struct'">
|
||||
<xsl:text>[link beast.ref.</xsl:text>
|
||||
<xsl:value-of select="concat($ref-id,'.',$dox-name)"/>
|
||||
<xsl:text> `</xsl:text>
|
||||
<xsl:value-of name="text" select="$name"/>
|
||||
<xsl:text>`]</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>[role red </xsl:text>
|
||||
<xsl:value-of select="$name"/>
|
||||
<xsl:text>]</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>`</xsl:text>
|
||||
<xsl:value-of select="."/>
|
||||
<xsl:text>`</xsl:text>
|
||||
<xsl:text>[role red </xsl:text>
|
||||
<xsl:value-of select="$name"/>
|
||||
<xsl:text>]</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
@@ -1185,7 +1284,8 @@
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:if test="string-length($stripped-type) > 0">
|
||||
<xsl:value-of select="$stripped-type"/><xsl:text> </xsl:text>
|
||||
<xsl:value-of select="$stripped-type"/>
|
||||
<xsl:text>
</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:text>``[link beast.ref.</xsl:text>
|
||||
<xsl:value-of select="$class-id"/>
|
||||
@@ -1412,21 +1512,62 @@
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template match="templateparamlist" mode="class-detail">
|
||||
<xsl:text>template<
</xsl:text>
|
||||
<xsl:apply-templates select="param" mode="class-detail-template"/>
|
||||
<xsl:text>>
</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template match="param" mode="class-detail-template">
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="type = 'class AsyncStream'">
|
||||
<xsl:text>class ``[link beast.types.stream.AsyncStream [*AsyncStream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<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:when>
|
||||
<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:when>
|
||||
<xsl:when test="type = 'class Body'">
|
||||
<xsl:text>class ``[link beast.types.Body [*Body]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class Streambuf'">
|
||||
<xsl:when test="type = 'class BufferSequence'">
|
||||
<xsl:text>class ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="(type = 'class' or type = 'class...') and declname = 'BufferSequence'">
|
||||
<xsl:value-of select="type"/>
|
||||
<xsl:text> ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<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:when>
|
||||
<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:when>
|
||||
<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:when>
|
||||
<xsl:when test="declname = 'Stream' or type = 'class Stream'">
|
||||
<xsl:text>class ``[link beast.types.stream.Stream [*Stream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Streambuf' or type = 'class Streambuf'">
|
||||
<xsl:text>class ``[link beast.types.Streambuf [*Streambuf]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class SyncStream'">
|
||||
<xsl:text>class ``[link beast.types.stream.SyncStream [*SyncStream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<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:when>
|
||||
<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:when>
|
||||
|
||||
<xsl:when test="declname = 'T'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
@@ -1466,28 +1607,19 @@
|
||||
<xsl:value-of select="array"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:choose>
|
||||
<xsl:when test="' &&' = substring(type, string-length(type) - 2)">
|
||||
<xsl:value-of select="substring(type, 1, string-length(type) - 3)"/>
|
||||
<xsl:text>&&</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="' &' = substring(type, string-length(type) - 1)">
|
||||
<xsl:value-of select="substring(type, 1, string-length(type) - 2)"/>
|
||||
<xsl:text>&</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="' *' = substring(type, string-length(type) - 1)">
|
||||
<xsl:value-of select="substring(type, 1, string-length(type) - 2)"/>
|
||||
<xsl:text>*</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="type"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="declname"/>
|
||||
<xsl:call-template name="cleanup-param">
|
||||
<xsl:with-param name="name" select="type"/>
|
||||
</xsl:call-template>
|
||||
<xsl:if test="count(declname) > 0">
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:if>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:if test="count(defval) > 0"> = <xsl:value-of select="defval"/></xsl:if>
|
||||
<xsl:if test="count(defval) > 0">
|
||||
<xsl:text> = </xsl:text>
|
||||
<xsl:value-of select="defval"/>
|
||||
</xsl:if>
|
||||
<xsl:if test="not(position() = last())">
|
||||
<xsl:text>,</xsl:text>
|
||||
</xsl:if>
|
||||
|
||||
@@ -2,29 +2,48 @@
|
||||
|
||||
GroupSources(include/beast)
|
||||
GroupSources(examples)
|
||||
GroupSources(test)
|
||||
|
||||
add_executable (http-crawl
|
||||
${BEAST_INCLUDES}
|
||||
http_crawl.cpp
|
||||
urls_large_data.hpp
|
||||
urls_large_data.cpp
|
||||
http_crawl.cpp
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(http-crawl ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
add_executable (http-server
|
||||
${BEAST_INCLUDES}
|
||||
file_body.hpp
|
||||
http_async_server.hpp
|
||||
http_stream.hpp
|
||||
http_stream.ipp
|
||||
http_sync_server.hpp
|
||||
../test/sig_wait.hpp
|
||||
http_server.cpp
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(http-server ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
add_executable (http-example
|
||||
${BEAST_INCLUDES}
|
||||
http_example.cpp
|
||||
)
|
||||
|
||||
add_executable (websocket-echo
|
||||
${BEAST_INCLUDES}
|
||||
websocket_echo.cpp
|
||||
)
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(http-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
add_executable (websocket-example
|
||||
${BEAST_INCLUDES}
|
||||
websocket_example.cpp
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(websocket-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
@@ -7,24 +7,20 @@
|
||||
|
||||
import os ;
|
||||
|
||||
exe http_crawl :
|
||||
exe http-crawl :
|
||||
http_crawl.cpp
|
||||
urls_large_data.cpp
|
||||
;
|
||||
|
||||
exe http_server :
|
||||
exe http-server :
|
||||
http_server.cpp
|
||||
;
|
||||
|
||||
exe http_example :
|
||||
exe http-example :
|
||||
http_example.cpp
|
||||
;
|
||||
|
||||
exe websocket_echo :
|
||||
websocket_echo.cpp
|
||||
;
|
||||
|
||||
exe websocket_example :
|
||||
exe websocket-example :
|
||||
websocket_example.cpp
|
||||
;
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <cstdio>
|
||||
@@ -36,15 +35,16 @@ struct file_body
|
||||
|
||||
class writer
|
||||
{
|
||||
std::size_t size_;
|
||||
std::size_t offset_ = 0;
|
||||
std::uint64_t size_;
|
||||
std::uint64_t offset_ = 0;
|
||||
std::string const& path_;
|
||||
FILE* file_ = nullptr;
|
||||
char buf_[4096];
|
||||
std::size_t buf_len_;
|
||||
|
||||
public:
|
||||
static bool constexpr is_single_pass = false;
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
writer(message<isRequest, file_body, Headers> const& m) noexcept
|
||||
@@ -69,7 +69,7 @@ struct file_body
|
||||
size_ = boost::filesystem::file_size(path_);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
{
|
||||
return size_;
|
||||
@@ -79,7 +79,11 @@ struct file_body
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
{
|
||||
buf_len_ = std::min(size_ - offset_, sizeof(buf_));
|
||||
if(size_ - offset_ < sizeof(buf_))
|
||||
buf_len_ = static_cast<std::size_t>(
|
||||
size_ - offset_);
|
||||
else
|
||||
buf_len_ = sizeof(buf_);
|
||||
auto const nread = fread(buf_, 1, sizeof(buf_), file_);
|
||||
(void)nread;
|
||||
offset_ += buf_len_;
|
||||
@@ -20,8 +20,8 @@
|
||||
#ifndef BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
||||
#define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
||||
|
||||
#include "file_body.h"
|
||||
#include "http_stream.h"
|
||||
#include "file_body.hpp"
|
||||
#include "http_stream.hpp"
|
||||
|
||||
#include <beast/placeholders.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
@@ -41,8 +41,8 @@ class http_async_server
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
using req_type = request<string_body>;
|
||||
using resp_type = response<file_body>;
|
||||
using req_type = request_v1<string_body>;
|
||||
using resp_type = response_v1<file_body>;
|
||||
|
||||
boost::asio::io_service ios_;
|
||||
socket_type sock_;
|
||||
@@ -127,20 +127,22 @@ private:
|
||||
path = root_ + path;
|
||||
if(! boost::filesystem::exists(path))
|
||||
{
|
||||
response<string_body> resp(
|
||||
response_v1<string_body> resp(
|
||||
{404, "Not Found", req_.version});
|
||||
resp.headers.replace("Server", "http_async_server");
|
||||
resp.body = "The file '" + path + "' was not found";
|
||||
prepare(resp);
|
||||
stream_.async_write(std::move(resp),
|
||||
std::bind(&peer::on_write, shared_from_this(),
|
||||
asio::placeholders::error));
|
||||
return;
|
||||
}
|
||||
response<file_body> resp(
|
||||
resp_type resp(
|
||||
{200, "OK", req_.version});
|
||||
resp.headers.replace("Server", "http_async_server");
|
||||
resp.headers.replace("Content-Type", "text/html");
|
||||
resp.body = path;
|
||||
prepare(resp);
|
||||
stream_.async_write(std::move(resp),
|
||||
std::bind(&peer::on_write, shared_from_this(),
|
||||
asio::placeholders::error));
|
||||
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "http_stream.h"
|
||||
#include "urls_large_data.h"
|
||||
#include "http_stream.hpp"
|
||||
#include "urls_large_data.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <iostream>
|
||||
@@ -46,12 +46,13 @@ int main(int, char const*[])
|
||||
stream<ip::tcp::socket> hs(ios);
|
||||
connect(hs.lowest_layer(), it);
|
||||
auto ep = hs.lowest_layer().remote_endpoint();
|
||||
request<empty_body> req({method_t::http_get, "/", 11});
|
||||
request_v1<empty_body> req({"GET", "/", 11});
|
||||
req.headers.insert("Host", host +
|
||||
std::string(":") + std::to_string(ep.port()));
|
||||
req.headers.insert("User-Agent", "beast/http");
|
||||
prepare(req);
|
||||
hs.write(req);
|
||||
response<string_body> resp;
|
||||
response_v1<string_body> resp;
|
||||
hs.read(resp);
|
||||
std::cout << resp;
|
||||
}
|
||||
|
||||
@@ -23,14 +23,15 @@ int main()
|
||||
using namespace beast::http;
|
||||
|
||||
// Send HTTP request using beast
|
||||
request<empty_body> req({method_t::http_get, "/", 11});
|
||||
request_v1<empty_body> req({"GET", "/", 11});
|
||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
||||
req.headers.replace("User-Agent", "Beast");
|
||||
prepare(req);
|
||||
write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
beast::streambuf sb;
|
||||
response<streambuf_body> resp;
|
||||
response_v1<streambuf_body> resp;
|
||||
read(sock, sb, resp);
|
||||
std::cout << resp;
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "http_async_server.h"
|
||||
#include "http_sync_server.h"
|
||||
#include "sig_wait.h"
|
||||
#include "http_async_server.hpp"
|
||||
#include "http_sync_server.hpp"
|
||||
#include "../test/sig_wait.hpp"
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
@@ -69,13 +69,8 @@ int main(int ac, char const* av[])
|
||||
endpoint_type ep{address_type::from_string(ip), port};
|
||||
|
||||
if(sync)
|
||||
{
|
||||
http_sync_server server(ep, root);
|
||||
sig_wait();
|
||||
}
|
||||
else
|
||||
{
|
||||
http_async_server server(ep, threads, root);
|
||||
sig_wait();
|
||||
}
|
||||
sig_wait();
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ public:
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
read(message<isRequest, Body, Headers>& msg)
|
||||
read(message_v1<isRequest, Body, Headers>& msg)
|
||||
{
|
||||
error_code ec;
|
||||
read(msg, ec);
|
||||
@@ -295,7 +295,7 @@ public:
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
read(message<isRequest, Body, Headers>& msg,
|
||||
read(message_v1<isRequest, Body, Headers>& msg,
|
||||
error_code& ec);
|
||||
|
||||
/** Start reading a HTTP message from the stream asynchronously.
|
||||
@@ -339,7 +339,7 @@ public:
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_read(message<isRequest, Body, Headers>& msg,
|
||||
async_read(message_v1<isRequest, Body, Headers>& msg,
|
||||
ReadHandler&& handler);
|
||||
|
||||
/** Write a HTTP message to the stream.
|
||||
@@ -365,7 +365,7 @@ public:
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
write(message<isRequest, Body, Headers> const& msg)
|
||||
write(message_v1<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
error_code ec;
|
||||
write(msg, ec);
|
||||
@@ -396,7 +396,7 @@ public:
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
write(message<isRequest, Body, Headers> const& msg,
|
||||
write(message_v1<isRequest, Body, Headers> const& msg,
|
||||
error_code& ec);
|
||||
|
||||
/** Start pipelining a HTTP message to the stream asynchronously.
|
||||
@@ -434,7 +434,7 @@ public:
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_write(message<isRequest, Body, Headers> const& msg,
|
||||
async_write(message_v1<isRequest, Body, Headers> const& msg,
|
||||
WriteHandler&& handler);
|
||||
|
||||
/** Start pipelining a HTTP message to the stream asynchronously.
|
||||
@@ -473,7 +473,7 @@ public:
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_write(message<isRequest, Body, Headers>&& msg,
|
||||
async_write(message_v1<isRequest, Body, Headers>&& msg,
|
||||
WriteHandler&& handler);
|
||||
|
||||
private:
|
||||
@@ -20,10 +20,11 @@
|
||||
#ifndef BEAST_HTTP_STREAM_IPP_INCLUDED
|
||||
#define BEAST_HTTP_STREAM_IPP_INCLUDED
|
||||
|
||||
#include <beast/bind_handler.hpp>
|
||||
#include <beast/handler_alloc.hpp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/http/write.hpp>
|
||||
#include <beast/bind_handler.hpp>
|
||||
#include <beast/handler_alloc.hpp>
|
||||
#include <cassert>
|
||||
|
||||
namespace beast {
|
||||
@@ -40,14 +41,14 @@ class stream<NextLayer, Allocator>::read_op
|
||||
struct data
|
||||
{
|
||||
stream<NextLayer>& s;
|
||||
message<isRequest, Body, Headers>& m;
|
||||
message_v1<isRequest, Body, Headers>& m;
|
||||
Handler h;
|
||||
bool cont;
|
||||
int state = 0;
|
||||
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
||||
message<isRequest, Body, Headers>& m_)
|
||||
message_v1<isRequest, Body, Headers>& m_)
|
||||
: s(s_)
|
||||
, m(m_)
|
||||
, h(std::forward<DeducedHandler>(h_))
|
||||
@@ -142,14 +143,14 @@ class stream<NextLayer, Allocator>::write_op : public op
|
||||
struct data
|
||||
{
|
||||
stream<NextLayer>& s;
|
||||
message<isRequest, Body, Headers> m;
|
||||
message_v1<isRequest, Body, Headers> m;
|
||||
Handler h;
|
||||
bool cont;
|
||||
int state = 0;
|
||||
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
||||
message<isRequest, Body, Headers> const& m_,
|
||||
message_v1<isRequest, Body, Headers> const& m_,
|
||||
bool cont_)
|
||||
: s(s_)
|
||||
, m(m_)
|
||||
@@ -160,7 +161,7 @@ class stream<NextLayer, Allocator>::write_op : public op
|
||||
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
||||
message<isRequest, Body, Headers>&& m_,
|
||||
message_v1<isRequest, Body, Headers>&& m_,
|
||||
bool cont_)
|
||||
: s(s_)
|
||||
, m(std::move(m_))
|
||||
@@ -305,7 +306,7 @@ template<class NextLayer, class Allocator>
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
stream<NextLayer, Allocator>::
|
||||
read(message<isRequest, Body, Headers>& msg,
|
||||
read(message_v1<isRequest, Body, Headers>& msg,
|
||||
error_code& ec)
|
||||
{
|
||||
beast::http::read(next_layer_, rd_buf_, msg, ec);
|
||||
@@ -316,7 +317,7 @@ template<bool isRequest, class Body, class Headers,
|
||||
class ReadHandler>
|
||||
auto
|
||||
stream<NextLayer, Allocator>::
|
||||
async_read(message<isRequest, Body, Headers>& msg,
|
||||
async_read(message_v1<isRequest, Body, Headers>& msg,
|
||||
ReadHandler&& handler) ->
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
@@ -334,7 +335,7 @@ template<class NextLayer, class Allocator>
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
stream<NextLayer, Allocator>::
|
||||
write(message<isRequest, Body, Headers> const& msg,
|
||||
write(message_v1<isRequest, Body, Headers> const& msg,
|
||||
error_code& ec)
|
||||
{
|
||||
beast::http::write(next_layer_, msg, ec);
|
||||
@@ -345,7 +346,7 @@ template<bool isRequest, class Body, class Headers,
|
||||
class WriteHandler>
|
||||
auto
|
||||
stream<NextLayer, Allocator>::
|
||||
async_write(message<isRequest, Body, Headers> const& msg,
|
||||
async_write(message_v1<isRequest, Body, Headers> const& msg,
|
||||
WriteHandler&& handler) ->
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
@@ -376,7 +377,7 @@ template<bool isRequest, class Body, class Headers,
|
||||
class WriteHandler>
|
||||
auto
|
||||
stream<NextLayer, Allocator>::
|
||||
async_write(message<isRequest, Body, Headers>&& msg,
|
||||
async_write(message_v1<isRequest, Body, Headers>&& msg,
|
||||
WriteHandler&& handler) ->
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#ifndef BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
|
||||
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
|
||||
|
||||
#include "file_body.h"
|
||||
#include "http_stream.h"
|
||||
#include "file_body.hpp"
|
||||
#include "http_stream.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <cstdint>
|
||||
@@ -43,8 +43,8 @@ class http_sync_server
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
using req_type = request<string_body>;
|
||||
using resp_type = response<file_body>;
|
||||
using req_type = request_v1<string_body>;
|
||||
using resp_type = response_v1<file_body>;
|
||||
|
||||
boost::asio::io_service ios_;
|
||||
socket_type sock_;
|
||||
@@ -155,19 +155,21 @@ public:
|
||||
path = root_ + path;
|
||||
if(! boost::filesystem::exists(path))
|
||||
{
|
||||
response<string_body> resp(
|
||||
response_v1<string_body> resp(
|
||||
{404, "Not Found", req.version});
|
||||
resp.headers.replace("Server", "http_sync_server");
|
||||
resp.body = "The file '" + path + "' was not found";
|
||||
prepare(resp);
|
||||
hs.write(resp, ec);
|
||||
if(ec)
|
||||
break;
|
||||
}
|
||||
response<file_body> resp(
|
||||
resp_type resp(
|
||||
{200, "OK", req.version});
|
||||
resp.headers.replace("Server", "http_sync_server");
|
||||
resp.headers.replace("Content-Type", "text/html");
|
||||
resp.body = path;
|
||||
prepare(resp);
|
||||
hs.write(resp, ec);
|
||||
if(ec)
|
||||
break;
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "urls_large_data.h"
|
||||
#include "urls_large_data.hpp"
|
||||
|
||||
// Data from Alexa top 1 million sites
|
||||
// http://s3.amazonaws.com/alexa-static/top-1m.csv.zip
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <beast/to_string.hpp>
|
||||
#include <beast/websocket.hpp>
|
||||
#include <beast/buffers_debug.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@@ -33,6 +33,5 @@ int main()
|
||||
opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(close_code::normal);
|
||||
std::cout <<
|
||||
beast::debug::buffers_to_string(sb.data()) << "\n";
|
||||
std::cout << to_string(sb.data()) << "\n";
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef BEAST_ASYNC_COMPLETION_HPP
|
||||
#define BEAST_ASYNC_COMPLETION_HPP
|
||||
|
||||
#include <beast/type_check.hpp>
|
||||
#include <beast/handler_concepts.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/handler_type.hpp>
|
||||
#include <type_traits>
|
||||
@@ -19,11 +19,11 @@ namespace beast {
|
||||
/** Helper for customizing the return type of asynchronous initiation functions.
|
||||
|
||||
This class template is used to transform caller-provided completion
|
||||
tokens in calls to asynchronous initiation functions. The transformation
|
||||
handlers in calls to asynchronous initiation functions. The transformation
|
||||
allows customization of the return type of the initiating function, and the
|
||||
function signature of the final handler.
|
||||
|
||||
@tparam CompletionToken A CompletionHandler, or a user defined type
|
||||
@tparam CompletionHandler A completion handler, or a user defined type
|
||||
with specializations for customizing the return type (for example,
|
||||
`boost::asio::use_future` or `boost::asio::yield_context`).
|
||||
|
||||
@@ -32,22 +32,22 @@ namespace beast {
|
||||
Example:
|
||||
@code
|
||||
...
|
||||
template<class CompletionToken>
|
||||
typename async_completion<CompletionToken,
|
||||
template<class CompletionHandler>
|
||||
typename async_completion<CompletionHandler,
|
||||
void(boost::system::error_code)>::result_type
|
||||
async_initfn(..., CompletionToken&& token)
|
||||
async_initfn(..., CompletionHandler&& handler)
|
||||
{
|
||||
async_completion<CompletionToken,
|
||||
void(boost::system::error_code)> completion(token);
|
||||
async_completion<CompletionHandler,
|
||||
void(boost::system::error_code)> completion(handler);
|
||||
...
|
||||
return completion.result.get();
|
||||
}
|
||||
@endcode
|
||||
|
||||
See <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf">
|
||||
@note See <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf">
|
||||
Library Foundations For Asynchronous Operations</a>
|
||||
*/
|
||||
template <class CompletionToken, class Signature>
|
||||
template <class CompletionHandler, class Signature>
|
||||
struct async_completion
|
||||
{
|
||||
/** The type of the final handler called by the asynchronous initiation function.
|
||||
@@ -56,7 +56,7 @@ struct async_completion
|
||||
*/
|
||||
using handler_type =
|
||||
typename boost::asio::handler_type<
|
||||
CompletionToken, Signature>::type;
|
||||
CompletionHandler, Signature>::type;
|
||||
|
||||
/// The type of the value returned by the asynchronous initiation function.
|
||||
using result_type = typename
|
||||
@@ -64,14 +64,14 @@ struct async_completion
|
||||
|
||||
/** Construct the helper.
|
||||
|
||||
@param token The completion token. Copies will be made as
|
||||
required. If `CompletionToken` is movable, it may also be moved.
|
||||
@param token The completion handler. Copies will be made as
|
||||
required. If `CompletionHandler` is movable, it may also be moved.
|
||||
*/
|
||||
async_completion(typename std::remove_reference<CompletionToken>::type& token)
|
||||
: handler(std::forward<CompletionToken>(token))
|
||||
async_completion(typename std::remove_reference<CompletionHandler>::type& token)
|
||||
: handler(std::forward<CompletionHandler>(token))
|
||||
, result(handler)
|
||||
{
|
||||
static_assert(is_Handler<handler_type, Signature>::value,
|
||||
static_assert(is_CompletionHandler<handler_type, Signature>::value,
|
||||
"Handler requirements not met");
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,15 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A `Streambuf` that uses multiple buffers internally.
|
||||
/** A @b `Streambuf` that uses multiple buffers internally.
|
||||
|
||||
The implementation uses a sequence of one or more character arrays
|
||||
of varying sizes. Additional character array objects are appended to
|
||||
the sequence to accommodate changes in the size of the character
|
||||
sequence.
|
||||
|
||||
@note Meets the requirements of @b Streambuf.
|
||||
|
||||
@tparam Allocator The allocator to use for managing memory.
|
||||
*/
|
||||
template<class Allocator>
|
||||
@@ -36,10 +38,14 @@ class basic_streambuf
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
#if GENERATING_DOCS
|
||||
/// The type of allocator used.
|
||||
using allocator_type = Allocator;
|
||||
#else
|
||||
using allocator_type = typename
|
||||
std::allocator_traits<Allocator>::
|
||||
template rebind_alloc<std::uint8_t>;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Storage for the list of buffers representing the input
|
||||
@@ -93,106 +99,104 @@ public:
|
||||
|
||||
/** Move constructor.
|
||||
|
||||
The output sequence of this object will be empty.
|
||||
The new object will have the input sequence of
|
||||
the other stream buffer, and an empty output sequence.
|
||||
|
||||
After the move, the moved-from object will have an
|
||||
empty input and output sequence, with no internal
|
||||
@note After the move, the moved-from object will have
|
||||
an empty input and output sequence, with no internal
|
||||
buffers allocated.
|
||||
|
||||
@param other The stream buffer to move from.
|
||||
*/
|
||||
basic_streambuf(basic_streambuf&& other);
|
||||
basic_streambuf(basic_streambuf&&);
|
||||
|
||||
/** Move constructor.
|
||||
|
||||
The output sequence of this object will be empty.
|
||||
The new object will have the input sequence of
|
||||
the other stream buffer, and an empty output sequence.
|
||||
|
||||
After the move, the moved-from object will have an
|
||||
empty input and output sequence, with no internal
|
||||
@note After the move, the moved-from object will have
|
||||
an empty input and output sequence, with no internal
|
||||
buffers allocated.
|
||||
|
||||
@param other The stream buffer to move from.
|
||||
|
||||
@param alloc The allocator to associate with the
|
||||
stream buffer.
|
||||
*/
|
||||
basic_streambuf(basic_streambuf&& other,
|
||||
basic_streambuf(basic_streambuf&&,
|
||||
allocator_type const& alloc);
|
||||
|
||||
/** Move assignment.
|
||||
|
||||
The output sequence of this object will be empty.
|
||||
This object will have the input sequence of
|
||||
the other stream buffer, and an empty output sequence.
|
||||
|
||||
After the move, the moved-from object will have an
|
||||
empty input and output sequence, with no internal
|
||||
@note After the move, the moved-from object will have
|
||||
an empty input and output sequence, with no internal
|
||||
buffers allocated.
|
||||
|
||||
@param other The stream buffer to move from.
|
||||
*/
|
||||
basic_streambuf&
|
||||
operator=(basic_streambuf&& other);
|
||||
|
||||
/// Copy constructor.
|
||||
basic_streambuf(basic_streambuf const& other);
|
||||
operator=(basic_streambuf&&);
|
||||
|
||||
/** Copy constructor.
|
||||
|
||||
The output sequence of this object will be empty.
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
*/
|
||||
basic_streambuf(basic_streambuf const&);
|
||||
|
||||
@param other The stream buffer to copy.
|
||||
/** Copy constructor.
|
||||
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
|
||||
@param alloc The allocator to associate with the
|
||||
stream buffer.
|
||||
*/
|
||||
basic_streambuf(basic_streambuf const& other,
|
||||
basic_streambuf(basic_streambuf const&,
|
||||
allocator_type const& alloc);
|
||||
|
||||
/** Copy assignment.
|
||||
|
||||
The output sequence of this object will be empty.
|
||||
|
||||
@param other The stream buffer to copy.
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
*/
|
||||
basic_streambuf& operator=(basic_streambuf const& other);
|
||||
basic_streambuf& operator=(basic_streambuf const&);
|
||||
|
||||
/** Copy constructor.
|
||||
|
||||
The output sequence of this object will be empty.
|
||||
|
||||
@param other The stream buffer to copy.
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
*/
|
||||
template<class OtherAlloc>
|
||||
basic_streambuf(basic_streambuf<OtherAlloc> const& other);
|
||||
basic_streambuf(basic_streambuf<OtherAlloc> const&);
|
||||
|
||||
/** Copy constructor.
|
||||
|
||||
The output sequence of this object will be empty.
|
||||
|
||||
@param other The stream buffer to copy.
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
|
||||
@param alloc The allocator to associate with the
|
||||
stream buffer.
|
||||
*/
|
||||
template<class OtherAlloc>
|
||||
basic_streambuf(basic_streambuf<OtherAlloc> const& other,
|
||||
basic_streambuf(basic_streambuf<OtherAlloc> const&,
|
||||
allocator_type const& alloc);
|
||||
|
||||
/** Copy assignment.
|
||||
|
||||
The output sequence of this object will be empty.
|
||||
|
||||
@param other The stream buffer to copy.
|
||||
This object will have a copy of the other stream
|
||||
buffer's input sequence, and an empty output sequence.
|
||||
*/
|
||||
template<class OtherAlloc>
|
||||
basic_streambuf& operator=(basic_streambuf<OtherAlloc> const& other);
|
||||
basic_streambuf& operator=(basic_streambuf<OtherAlloc> const&);
|
||||
|
||||
/** Default constructor.
|
||||
/** Construct a stream buffer.
|
||||
|
||||
@param alloc_size The size of buffer to allocate. This is a soft
|
||||
limit, calls to prepare for buffers exceeding this size will allocate
|
||||
the larger size.
|
||||
@param alloc_size The size of buffer to allocate. This is a
|
||||
soft limit, calls to prepare for buffers exceeding this size
|
||||
will allocate the larger size. The default allocation size
|
||||
is 1KB (1024 bytes).
|
||||
|
||||
@param alloc The allocator to use.
|
||||
@param alloc The allocator to use. If this parameter is
|
||||
unspecified, a default constructed allocator will be used.
|
||||
*/
|
||||
explicit
|
||||
basic_streambuf(std::size_t alloc_size = 1024,
|
||||
@@ -219,15 +223,26 @@ public:
|
||||
return in_size_;
|
||||
}
|
||||
|
||||
/// Get a list of buffers that represents the output sequence, with the given size.
|
||||
/** Get a list of buffers that represents the output sequence, with the given size.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(size_type n);
|
||||
|
||||
/// Move bytes from the output sequence to the input sequence.
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
void
|
||||
commit(size_type n);
|
||||
|
||||
/// Get a list of buffers that represents the input sequence.
|
||||
/** 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;
|
||||
|
||||
@@ -277,19 +292,9 @@ private:
|
||||
|
||||
@return The stream buffer.
|
||||
*/
|
||||
template<class Alloc, class T>
|
||||
basic_streambuf<Alloc>&
|
||||
operator<<(basic_streambuf<Alloc>& streambuf, T const& t);
|
||||
|
||||
/** Convert the entire basic_streambuf to a string.
|
||||
|
||||
@param streambuf The streambuf to convert.
|
||||
|
||||
@return A string representing the contents of the input sequence.
|
||||
*/
|
||||
template<class Allocator>
|
||||
std::string
|
||||
to_string(basic_streambuf<Allocator> const& streambuf);
|
||||
template<class Allocator, class T>
|
||||
basic_streambuf<Allocator>&
|
||||
operator<<(basic_streambuf<Allocator>& streambuf, T const& t);
|
||||
|
||||
} // beast
|
||||
|
||||
|
||||
@@ -8,110 +8,19 @@
|
||||
#ifndef BEAST_BIND_HANDLER_HPP
|
||||
#define BEAST_BIND_HANDLER_HPP
|
||||
|
||||
#include <beast/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 <functional>
|
||||
#include <beast/handler_concepts.hpp>
|
||||
#include <beast/detail/bind_handler.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/* Nullary handler that calls Handler with bound arguments.
|
||||
|
||||
The bound handler provides the same io_service execution
|
||||
guarantees as the original handler.
|
||||
*/
|
||||
template<class Handler, class... Args>
|
||||
class bound_handler
|
||||
{
|
||||
private:
|
||||
using args_type = std::tuple<typename std::decay<Args>::type...>;
|
||||
|
||||
Handler h_;
|
||||
args_type args_;
|
||||
|
||||
template<class Tuple, std::size_t... S>
|
||||
static void invoke(Handler& h, Tuple& args,
|
||||
index_sequence<S...>)
|
||||
{
|
||||
h(std::get<S>(args)...);
|
||||
}
|
||||
|
||||
public:
|
||||
using result_type = void;
|
||||
|
||||
template<class DeducedHandler>
|
||||
explicit
|
||||
bound_handler(DeducedHandler&& handler, Args&&... args)
|
||||
: h_(std::forward<DeducedHandler>(handler))
|
||||
, args_(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()()
|
||||
{
|
||||
invoke(h_, args_,
|
||||
index_sequence_for<Args...> ());
|
||||
}
|
||||
|
||||
void
|
||||
operator()() const
|
||||
{
|
||||
invoke(h_, args_,
|
||||
index_sequence_for<Args...> ());
|
||||
}
|
||||
|
||||
friend
|
||||
void*
|
||||
asio_handler_allocate(
|
||||
std::size_t size, bound_handler* h)
|
||||
{
|
||||
return boost_asio_handler_alloc_helpers::
|
||||
allocate(size, h->h_);
|
||||
}
|
||||
|
||||
friend
|
||||
void
|
||||
asio_handler_deallocate(
|
||||
void* p, std::size_t size, bound_handler* h)
|
||||
{
|
||||
boost_asio_handler_alloc_helpers::
|
||||
deallocate(p, size, h->h_);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(bound_handler* h)
|
||||
{
|
||||
return boost_asio_handler_cont_helpers::
|
||||
is_continuation (h->h_);
|
||||
}
|
||||
|
||||
template<class F>
|
||||
friend
|
||||
void
|
||||
asio_handler_invoke(F&& f, bound_handler* h)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::
|
||||
invoke(f, h->h_);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Bind parameters to a completion handler, creating a wrapped handler.
|
||||
|
||||
This function creates a new handler which invoked with no parameters
|
||||
calls the original handler with the list of bound arguments. The passed
|
||||
handler and arguments are forwarded into the returned handler, which
|
||||
provides the same `io_service` execution guarantees as the original
|
||||
This function creates a new handler which, when invoked with no
|
||||
parameters, calls the original handler with the list of bound arguments.
|
||||
The passed handler and arguments are forwarded into the returned handler,
|
||||
which provides the same `io_service` execution guarantees as the original
|
||||
handler.
|
||||
|
||||
Unlike `io_service::wrap`, the returned handler can be used in a
|
||||
@@ -145,6 +54,9 @@ detail::bound_handler<
|
||||
#endif
|
||||
bind_handler(CompletionHandler&& handler, Args&&... args)
|
||||
{
|
||||
static_assert(is_CompletionHandler<
|
||||
CompletionHandler, void(Args...)>::value,
|
||||
"CompletionHandler requirements not met");
|
||||
return detail::bound_handler<typename std::decay<
|
||||
CompletionHandler>::type, Args...>(std::forward<
|
||||
CompletionHandler>(handler),
|
||||
@@ -153,10 +65,4 @@ bind_handler(CompletionHandler&& handler, Args&&... args)
|
||||
|
||||
} // beast
|
||||
|
||||
namespace std {
|
||||
template<class Handler, class... Args>
|
||||
void bind(beast::detail::bound_handler<
|
||||
Handler, Args...>, ...) = delete;
|
||||
} // std
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef BEAST_BUFFER_CAT_HPP
|
||||
#define BEAST_BUFFER_CAT_HPP
|
||||
|
||||
#include <beast/detail/buffer_cat.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
@@ -18,463 +19,9 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
class buffer_cat_helper
|
||||
{
|
||||
std::tuple<Bs...> bs_;
|
||||
|
||||
public:
|
||||
using value_type = ValueType;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
buffer_cat_helper(buffer_cat_helper&&) = default;
|
||||
buffer_cat_helper(buffer_cat_helper const&) = default;
|
||||
buffer_cat_helper& operator=(buffer_cat_helper&&) = default;
|
||||
buffer_cat_helper& operator=(buffer_cat_helper const&) = default;
|
||||
|
||||
explicit
|
||||
buffer_cat_helper(Bs const&... bs)
|
||||
: bs_(bs...)
|
||||
{
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const;
|
||||
|
||||
const_iterator
|
||||
end() const;
|
||||
};
|
||||
|
||||
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<class ValueType, class... Bs>
|
||||
class buffer_cat_helper<
|
||||
ValueType, Bs...>::const_iterator
|
||||
{
|
||||
std::size_t n_;
|
||||
std::tuple<Bs...> const* bs_;
|
||||
std::array<std::uint8_t,
|
||||
max_sizeof<typename Bs::const_iterator...>()> buf_;
|
||||
|
||||
friend class buffer_cat_helper<ValueType, Bs...>;
|
||||
|
||||
template<std::size_t I>
|
||||
using C = std::integral_constant<std::size_t, I>;
|
||||
|
||||
template<std::size_t I>
|
||||
using iter_t = typename std::tuple_element<
|
||||
I, std::tuple<Bs...>>::type::const_iterator;
|
||||
|
||||
template<std::size_t I>
|
||||
iter_t<I>&
|
||||
iter()
|
||||
{
|
||||
return *reinterpret_cast<
|
||||
iter_t<I>*>(buf_.data());
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
iter_t<I> const&
|
||||
iter() const
|
||||
{
|
||||
return *reinterpret_cast<
|
||||
iter_t<I> const*>(buf_.data());
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = ValueType;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category =
|
||||
std::bidirectional_iterator_tag;
|
||||
|
||||
~const_iterator();
|
||||
const_iterator();
|
||||
const_iterator(const_iterator&& other);
|
||||
const_iterator(const_iterator const& other);
|
||||
const_iterator& operator=(const_iterator&& other);
|
||||
const_iterator& operator=(const_iterator const& other);
|
||||
|
||||
bool
|
||||
operator==(const_iterator const& other) const;
|
||||
|
||||
bool
|
||||
operator!=(const_iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const;
|
||||
|
||||
pointer
|
||||
operator->() const = delete;
|
||||
|
||||
const_iterator&
|
||||
operator++();
|
||||
|
||||
const_iterator
|
||||
operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
const_iterator&
|
||||
operator--();
|
||||
|
||||
const_iterator
|
||||
operator--(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
const_iterator(
|
||||
std::tuple<Bs...> const& bs, bool at_end);
|
||||
|
||||
void
|
||||
construct(C<sizeof...(Bs)>)
|
||||
{
|
||||
auto constexpr I = sizeof...(Bs);
|
||||
n_ = I;
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
construct(C<I>)
|
||||
{
|
||||
if(std::get<I>(*bs_).begin() !=
|
||||
std::get<I>(*bs_).end())
|
||||
{
|
||||
n_ = I;
|
||||
new(buf_.data()) iter_t<I>{
|
||||
std::get<I>(*bs_).begin()};
|
||||
return;
|
||||
}
|
||||
construct(C<I+1>{});
|
||||
}
|
||||
|
||||
void
|
||||
destroy(C<sizeof...(Bs)>)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
destroy(C<I>)
|
||||
{
|
||||
if(n_ == I)
|
||||
{
|
||||
using Iter = iter_t<I>;
|
||||
iter<I>().~Iter();
|
||||
return;
|
||||
}
|
||||
destroy(C<I+1>{});
|
||||
}
|
||||
|
||||
void
|
||||
move(C<sizeof...(Bs)>, const_iterator&&)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
move(C<I>, const_iterator&& other)
|
||||
{
|
||||
if(n_ == I)
|
||||
{
|
||||
new(buf_.data()) iter_t<I>{
|
||||
std::move(other.iter<I>())};
|
||||
return;
|
||||
}
|
||||
move(C<I+1>{}, std::move(other));
|
||||
}
|
||||
|
||||
void
|
||||
copy(C<sizeof...(Bs)>, const_iterator const&)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
copy(C<I>, const_iterator const& other)
|
||||
{
|
||||
if(n_ == I)
|
||||
{
|
||||
new(buf_.data()) iter_t<I>{
|
||||
other.iter<I>()};
|
||||
return;
|
||||
}
|
||||
copy(C<I+1>{}, other);
|
||||
}
|
||||
|
||||
bool
|
||||
equal(C<sizeof...(Bs)>,
|
||||
const_iterator const&) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
bool
|
||||
equal(C<I>, const_iterator const& other) const
|
||||
{
|
||||
if(n_ == I)
|
||||
return iter<I>() == other.iter<I>();
|
||||
return equal(C<I+1>{}, other);
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
reference
|
||||
dereference(C<sizeof...(Bs)>) const
|
||||
{
|
||||
throw std::logic_error("invalid iterator");
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
reference
|
||||
dereference(C<I>) const
|
||||
{
|
||||
if(n_ == I)
|
||||
return *iter<I>();
|
||||
return dereference(C<I+1>{});
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
void
|
||||
increment(C<sizeof...(Bs)>)
|
||||
{
|
||||
throw std::logic_error("invalid iterator");
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
increment(C<I>)
|
||||
{
|
||||
if(n_ == I)
|
||||
{
|
||||
if(++iter<I>() !=
|
||||
std::get<I>(*bs_).end())
|
||||
return;
|
||||
using Iter = iter_t<I>;
|
||||
iter<I>().~Iter();
|
||||
return construct(C<I+1>{});
|
||||
}
|
||||
increment(C<I+1>{});
|
||||
}
|
||||
|
||||
void
|
||||
decrement(C<sizeof...(Bs)>)
|
||||
{
|
||||
auto constexpr I = sizeof...(Bs);
|
||||
if(n_ == I)
|
||||
{
|
||||
--n_;
|
||||
new(buf_.data()) iter_t<I-1>{
|
||||
std::get<I-1>(*bs_).end()};
|
||||
}
|
||||
decrement(C<I-1>{});
|
||||
}
|
||||
|
||||
void
|
||||
decrement(C<0>)
|
||||
{
|
||||
auto constexpr I = 0;
|
||||
if(iter<I>() != std::get<I>(*bs_).begin())
|
||||
{
|
||||
--iter<I>();
|
||||
return;
|
||||
}
|
||||
throw std::logic_error("invalid iterator");
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
decrement(C<I>)
|
||||
{
|
||||
if(n_ == I)
|
||||
{
|
||||
if(iter<I>() != std::get<I>(*bs_).begin())
|
||||
{
|
||||
--iter<I>();
|
||||
return;
|
||||
}
|
||||
--n_;
|
||||
using Iter = iter_t<I>;
|
||||
iter<I>().~Iter();
|
||||
new(buf_.data()) iter_t<I-1>{
|
||||
std::get<I-1>(*bs_).end()};
|
||||
}
|
||||
decrement(C<I-1>{});
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::~const_iterator()
|
||||
{
|
||||
destroy(C<0>{});
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::const_iterator()
|
||||
: n_(sizeof...(Bs))
|
||||
, bs_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::const_iterator(
|
||||
std::tuple<Bs...> const& bs, bool at_end)
|
||||
: bs_(&bs)
|
||||
{
|
||||
if(at_end)
|
||||
n_ = sizeof...(Bs);
|
||||
else
|
||||
construct(C<0>{});
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::const_iterator(const_iterator&& other)
|
||||
: n_(other.n_)
|
||||
, bs_(other.bs_)
|
||||
{
|
||||
move(C<0>{}, std::move(other));
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::const_iterator(const_iterator const& other)
|
||||
: n_(other.n_)
|
||||
, bs_(other.bs_)
|
||||
{
|
||||
copy(C<0>{}, other);
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator=(const_iterator&& other) ->
|
||||
const_iterator&
|
||||
{
|
||||
if(&other == this)
|
||||
return *this;
|
||||
destroy(C<0>{});
|
||||
n_ = other.n_;
|
||||
bs_ = other.bs_;
|
||||
move(C<0>{}, std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator=(const_iterator const& other) ->
|
||||
const_iterator&
|
||||
{
|
||||
if(&other == this)
|
||||
return *this;
|
||||
destroy(C<0>{});
|
||||
n_ = other.n_;
|
||||
bs_ = other.bs_;
|
||||
copy(C<0>{}, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
bool
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator==(const_iterator const& other) const
|
||||
{
|
||||
if(bs_ != other.bs_)
|
||||
return false;
|
||||
if(n_ != other.n_)
|
||||
return false;
|
||||
return equal(C<0>{}, other);
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator*() const ->
|
||||
reference
|
||||
{
|
||||
return dereference(C<0>{});
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator++() ->
|
||||
const_iterator&
|
||||
{
|
||||
increment(C<0>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator--() ->
|
||||
const_iterator&
|
||||
{
|
||||
decrement(C<sizeof...(Bs)>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator(bs_, false);
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator(bs_, true);
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Concatenate 2 or more buffer sequences to form a `ConstBufferSequence`.
|
||||
|
||||
This function returns a `ConstBufferSequence` that when iterated,
|
||||
This function returns a @b `ConstBufferSequence` that when iterated,
|
||||
efficiently concatenates the input buffer sequences. Copies of the
|
||||
arguments passed will be made; however, the returned object does
|
||||
not take ownership of the underlying memory. The application is still
|
||||
@@ -482,8 +29,8 @@ buffer_cat_helper<ValueType, Bs...>::end() const ->
|
||||
|
||||
@param buffers The list of buffer sequences to concatenate.
|
||||
|
||||
@return A new `ConstBufferSequence` that represents the concatenation
|
||||
of the input buffer sequences.
|
||||
@return A new @b `ConstBufferSequence` that represents the
|
||||
concatenation of the input buffer sequences.
|
||||
*/
|
||||
#if GENERATING_DOCS
|
||||
template<class... BufferSequence>
|
||||
|
||||
61
src/beast/include/beast/buffer_concepts.hpp
Normal file
61
src/beast/include/beast/buffer_concepts.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// 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_BUFFER_CONCEPTS_HPP
|
||||
#define BEAST_BUFFER_CONCEPTS_HPP
|
||||
|
||||
#include <beast/detail/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `BufferSequence`.
|
||||
template<class T, class BufferType>
|
||||
#if GENERATING_DOCS
|
||||
struct is_BufferSequence : std::integral_constant<bool, ...>
|
||||
#else
|
||||
struct is_BufferSequence : detail::is_BufferSequence<T, BufferType>::type
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `ConstBufferSequence`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_ConstBufferSequence : std::integral_constant<bool, ...>
|
||||
#else
|
||||
struct is_ConstBufferSequence :
|
||||
is_BufferSequence<T, boost::asio::const_buffer>
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `MutableBufferSequence`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_MutableBufferSequence : std::integral_constant<bool, ...>
|
||||
#else
|
||||
struct is_MutableBufferSequence :
|
||||
is_BufferSequence<T, boost::asio::mutable_buffer>
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `Streambuf`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_Streambuf : std::integral_constant<bool, ...>
|
||||
#else
|
||||
struct is_Streambuf : detail::is_Streambuf<T>::type
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -8,15 +8,16 @@
|
||||
#ifndef BEAST_BUFFERS_ADAPTER_HPP
|
||||
#define BEAST_BUFFERS_ADAPTER_HPP
|
||||
|
||||
#include <beast/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Adapts a `MutableBufferSequence` into a `Streambuf`.
|
||||
/** Adapts a @b `MutableBufferSequence` into a @b `Streambuf`.
|
||||
|
||||
This class wraps a `MutableBufferSequence` to meet the requirements
|
||||
of `Streambuf`. Upon construction the input and output sequences are
|
||||
This class wraps a @b `MutableBufferSequence` to meet the requirements
|
||||
of @b `Streambuf`. Upon construction the input and output sequences are
|
||||
empty. A copy of the mutable buffer sequence object is stored; however,
|
||||
ownership of the underlying memory is not transferred. The caller is
|
||||
responsible for making sure that referenced memory remains valid
|
||||
@@ -25,20 +26,18 @@ namespace beast {
|
||||
The size of the mutable buffer sequence determines the maximum
|
||||
number of bytes which may be prepared and committed.
|
||||
|
||||
@tparam Buffers The type of mutable buffer sequence to wrap.
|
||||
@tparam MutableBufferSequence The type of mutable buffer sequence to wrap.
|
||||
*/
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
class buffers_adapter
|
||||
{
|
||||
private:
|
||||
using buffers_type = typename std::decay<Buffers>::type;
|
||||
using iter_type = typename buffers_type::const_iterator;
|
||||
static_assert(is_MutableBufferSequence<MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
|
||||
static auto constexpr is_mutable =
|
||||
std::is_constructible<boost::asio::mutable_buffer,
|
||||
typename std::iterator_traits<iter_type>::value_type>::value;
|
||||
using iter_type = typename MutableBufferSequence::const_iterator;
|
||||
|
||||
Buffers bs_;
|
||||
MutableBufferSequence bs_;
|
||||
iter_type begin_;
|
||||
iter_type out_;
|
||||
iter_type end_;
|
||||
@@ -98,7 +97,7 @@ public:
|
||||
transferred.
|
||||
*/
|
||||
explicit
|
||||
buffers_adapter(Buffers const& buffers);
|
||||
buffers_adapter(MutableBufferSequence const& buffers);
|
||||
|
||||
/// Returns the largest size output sequence possible.
|
||||
std::size_t
|
||||
@@ -118,15 +117,25 @@ public:
|
||||
|
||||
@throws std::length_error if the size would exceed the limit
|
||||
imposed by the underlying mutable buffer sequence.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(std::size_t n);
|
||||
|
||||
/// Move bytes from the output sequence to the input sequence.
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
void
|
||||
commit(std::size_t n);
|
||||
|
||||
/// Get a list of buffers that represents the input sequence.
|
||||
/** 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;
|
||||
|
||||
|
||||
@@ -1,44 +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_BUFFERS_DEBUG_HPP
|
||||
#define BEAST_BUFFERS_DEBUG_HPP
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace debug {
|
||||
|
||||
/** Diagnostic utility to convert a `ConstBufferSequence` to a string.
|
||||
|
||||
@note Carriage returns and linefeeds will have additional escape
|
||||
representations printed for visibility.
|
||||
*/
|
||||
template<class Buffers>
|
||||
std::string
|
||||
buffers_to_string(Buffers const& bs)
|
||||
{
|
||||
using boost::asio::buffer_cast;
|
||||
using boost::asio::buffer_size;
|
||||
std::string s;
|
||||
s.reserve(buffer_size(bs));
|
||||
for(auto const& b : bs)
|
||||
s.append(buffer_cast<char const*>(b),
|
||||
buffer_size(b));
|
||||
for(auto i = s.size(); i-- > 0;)
|
||||
if(s[i] == '\r')
|
||||
s.replace(i, 1, "\\r");
|
||||
else if(s[i] == '\n')
|
||||
s.replace(i, 1, "\\n\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
} // debug
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef BEAST_CONSUMING_BUFFERS_HPP
|
||||
#define BEAST_CONSUMING_BUFFERS_HPP
|
||||
|
||||
#include <beast/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
@@ -28,26 +29,29 @@ namespace beast {
|
||||
Ownership of the underlying memory is not transferred, the application
|
||||
is still responsible for managing its lifetime.
|
||||
|
||||
@tparam Buffers The buffer sequence to wrap.
|
||||
@tparam BufferSequence The buffer sequence to wrap.
|
||||
|
||||
@ptaram ValueType The type of buffer of the final buffer sequence. This
|
||||
@tparam ValueType The type of buffer of the final buffer sequence. This
|
||||
can be different from the buffer type of the wrapped sequence. For
|
||||
example, a `MutableBufferSequence` can be transformed into a
|
||||
consumable `ConstBufferSequence`. Violations of buffer const safety
|
||||
are not permitted, and will result in a compile error.
|
||||
*/
|
||||
template<class Buffers,
|
||||
class ValueType = typename Buffers::value_type>
|
||||
template<class BufferSequence,
|
||||
class ValueType = typename BufferSequence::value_type>
|
||||
class consuming_buffers
|
||||
{
|
||||
using iter_type =
|
||||
typename Buffers::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");
|
||||
|
||||
Buffers bs_;
|
||||
BufferSequence bs_;
|
||||
iter_type begin_;
|
||||
std::size_t skip_ = 0;
|
||||
|
||||
@@ -90,7 +94,7 @@ public:
|
||||
underlying memory is not transferred or copied.
|
||||
*/
|
||||
explicit
|
||||
consuming_buffers(Buffers const& buffers);
|
||||
consuming_buffers(BufferSequence const& buffers);
|
||||
|
||||
/// Get a bidirectional iterator to the first element.
|
||||
const_iterator
|
||||
@@ -110,10 +114,24 @@ public:
|
||||
consume(std::size_t n);
|
||||
};
|
||||
|
||||
/// Returns a consumed buffer
|
||||
template<class Buffers>
|
||||
consuming_buffers<Buffers, typename Buffers::value_type>
|
||||
consumed_buffers(Buffers const& bs, 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
|
||||
|
||||
|
||||
113
src/beast/include/beast/detail/bind_handler.hpp
Normal file
113
src/beast/include/beast/detail/bind_handler.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// 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_BIND_DETAIL_HANDLER_HPP
|
||||
#define BEAST_BIND_DETAIL_HANDLER_HPP
|
||||
|
||||
#include <beast/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>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
/* Nullary handler that calls Handler with bound arguments.
|
||||
|
||||
The bound handler provides the same io_service execution
|
||||
guarantees as the original handler.
|
||||
*/
|
||||
template<class Handler, class... Args>
|
||||
class bound_handler
|
||||
{
|
||||
private:
|
||||
using args_type = std::tuple<
|
||||
typename std::decay<Args>::type...>;
|
||||
|
||||
Handler h_;
|
||||
args_type args_;
|
||||
|
||||
template<class Tuple, std::size_t... S>
|
||||
static void invoke(Handler& h, Tuple& args,
|
||||
index_sequence<S...>)
|
||||
{
|
||||
h(std::get<S>(args)...);
|
||||
}
|
||||
|
||||
public:
|
||||
using result_type = void;
|
||||
|
||||
template<class DeducedHandler>
|
||||
explicit
|
||||
bound_handler(DeducedHandler&& handler, Args&&... args)
|
||||
: h_(std::forward<DeducedHandler>(handler))
|
||||
, args_(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()()
|
||||
{
|
||||
invoke(h_, args_,
|
||||
index_sequence_for<Args...> ());
|
||||
}
|
||||
|
||||
void
|
||||
operator()() const
|
||||
{
|
||||
invoke(h_, args_,
|
||||
index_sequence_for<Args...> ());
|
||||
}
|
||||
|
||||
friend
|
||||
void*
|
||||
asio_handler_allocate(
|
||||
std::size_t size, bound_handler* h)
|
||||
{
|
||||
return boost_asio_handler_alloc_helpers::
|
||||
allocate(size, h->h_);
|
||||
}
|
||||
|
||||
friend
|
||||
void
|
||||
asio_handler_deallocate(
|
||||
void* p, std::size_t size, bound_handler* h)
|
||||
{
|
||||
boost_asio_handler_alloc_helpers::
|
||||
deallocate(p, size, h->h_);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(bound_handler* h)
|
||||
{
|
||||
return boost_asio_handler_cont_helpers::
|
||||
is_continuation (h->h_);
|
||||
}
|
||||
|
||||
template<class F>
|
||||
friend
|
||||
void
|
||||
asio_handler_invoke(F&& f, bound_handler* h)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::
|
||||
invoke(f, h->h_);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#include <functional>
|
||||
namespace std {
|
||||
template<class Handler, class... Args>
|
||||
void bind(beast::detail::bound_handler<
|
||||
Handler, Args...>, ...) = delete;
|
||||
} // std
|
||||
|
||||
#endif
|
||||
473
src/beast/include/beast/detail/buffer_cat.hpp
Normal file
473
src/beast/include/beast/detail/buffer_cat.hpp
Normal file
@@ -0,0 +1,473 @@
|
||||
//
|
||||
// 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_BUFFER_CAT_HPP
|
||||
#define BEAST_DETAIL_BUFFER_CAT_HPP
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
class buffer_cat_helper
|
||||
{
|
||||
std::tuple<Bs...> bs_;
|
||||
|
||||
public:
|
||||
using value_type = ValueType;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
buffer_cat_helper(buffer_cat_helper&&) = default;
|
||||
buffer_cat_helper(buffer_cat_helper const&) = default;
|
||||
buffer_cat_helper& operator=(buffer_cat_helper&&) = default;
|
||||
buffer_cat_helper& operator=(buffer_cat_helper const&) = default;
|
||||
|
||||
explicit
|
||||
buffer_cat_helper(Bs const&... bs)
|
||||
: bs_(bs...)
|
||||
{
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const;
|
||||
|
||||
const_iterator
|
||||
end() const;
|
||||
};
|
||||
|
||||
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<class ValueType, class... Bs>
|
||||
class buffer_cat_helper<
|
||||
ValueType, Bs...>::const_iterator
|
||||
{
|
||||
std::size_t n_;
|
||||
std::tuple<Bs...> const* bs_;
|
||||
std::array<std::uint8_t,
|
||||
max_sizeof<typename Bs::const_iterator...>()> buf_;
|
||||
|
||||
friend class buffer_cat_helper<ValueType, Bs...>;
|
||||
|
||||
template<std::size_t I>
|
||||
using C = std::integral_constant<std::size_t, I>;
|
||||
|
||||
template<std::size_t I>
|
||||
using iter_t = typename std::tuple_element<
|
||||
I, std::tuple<Bs...>>::type::const_iterator;
|
||||
|
||||
template<std::size_t I>
|
||||
iter_t<I>&
|
||||
iter()
|
||||
{
|
||||
return *reinterpret_cast<
|
||||
iter_t<I>*>(buf_.data());
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
iter_t<I> const&
|
||||
iter() const
|
||||
{
|
||||
return *reinterpret_cast<
|
||||
iter_t<I> const*>(buf_.data());
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = ValueType;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category =
|
||||
std::bidirectional_iterator_tag;
|
||||
|
||||
~const_iterator();
|
||||
const_iterator();
|
||||
const_iterator(const_iterator&& other);
|
||||
const_iterator(const_iterator const& other);
|
||||
const_iterator& operator=(const_iterator&& other);
|
||||
const_iterator& operator=(const_iterator const& other);
|
||||
|
||||
bool
|
||||
operator==(const_iterator const& other) const;
|
||||
|
||||
bool
|
||||
operator!=(const_iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const;
|
||||
|
||||
pointer
|
||||
operator->() const = delete;
|
||||
|
||||
const_iterator&
|
||||
operator++();
|
||||
|
||||
const_iterator
|
||||
operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
const_iterator&
|
||||
operator--();
|
||||
|
||||
const_iterator
|
||||
operator--(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
const_iterator(
|
||||
std::tuple<Bs...> const& bs, bool at_end);
|
||||
|
||||
void
|
||||
construct(C<sizeof...(Bs)>)
|
||||
{
|
||||
auto constexpr I = sizeof...(Bs);
|
||||
n_ = I;
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
construct(C<I>)
|
||||
{
|
||||
if(std::get<I>(*bs_).begin() !=
|
||||
std::get<I>(*bs_).end())
|
||||
{
|
||||
n_ = I;
|
||||
new(buf_.data()) iter_t<I>{
|
||||
std::get<I>(*bs_).begin()};
|
||||
return;
|
||||
}
|
||||
construct(C<I+1>{});
|
||||
}
|
||||
|
||||
void
|
||||
destroy(C<sizeof...(Bs)>)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
destroy(C<I>)
|
||||
{
|
||||
if(n_ == I)
|
||||
{
|
||||
using Iter = iter_t<I>;
|
||||
iter<I>().~Iter();
|
||||
return;
|
||||
}
|
||||
destroy(C<I+1>{});
|
||||
}
|
||||
|
||||
void
|
||||
move(C<sizeof...(Bs)>, const_iterator&&)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
move(C<I>, const_iterator&& other)
|
||||
{
|
||||
if(n_ == I)
|
||||
{
|
||||
new(buf_.data()) iter_t<I>{
|
||||
std::move(other.iter<I>())};
|
||||
return;
|
||||
}
|
||||
move(C<I+1>{}, std::move(other));
|
||||
}
|
||||
|
||||
void
|
||||
copy(C<sizeof...(Bs)>, const_iterator const&)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
copy(C<I>, const_iterator const& other)
|
||||
{
|
||||
if(n_ == I)
|
||||
{
|
||||
new(buf_.data()) iter_t<I>{
|
||||
other.iter<I>()};
|
||||
return;
|
||||
}
|
||||
copy(C<I+1>{}, other);
|
||||
}
|
||||
|
||||
bool
|
||||
equal(C<sizeof...(Bs)>,
|
||||
const_iterator const&) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
bool
|
||||
equal(C<I>, const_iterator const& other) const
|
||||
{
|
||||
if(n_ == I)
|
||||
return iter<I>() == other.iter<I>();
|
||||
return equal(C<I+1>{}, other);
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
reference
|
||||
dereference(C<sizeof...(Bs)>) const
|
||||
{
|
||||
throw std::logic_error("invalid iterator");
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
reference
|
||||
dereference(C<I>) const
|
||||
{
|
||||
if(n_ == I)
|
||||
return *iter<I>();
|
||||
return dereference(C<I+1>{});
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
void
|
||||
increment(C<sizeof...(Bs)>)
|
||||
{
|
||||
throw std::logic_error("invalid iterator");
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
increment(C<I>)
|
||||
{
|
||||
if(n_ == I)
|
||||
{
|
||||
if(++iter<I>() !=
|
||||
std::get<I>(*bs_).end())
|
||||
return;
|
||||
using Iter = iter_t<I>;
|
||||
iter<I>().~Iter();
|
||||
return construct(C<I+1>{});
|
||||
}
|
||||
increment(C<I+1>{});
|
||||
}
|
||||
|
||||
void
|
||||
decrement(C<sizeof...(Bs)>)
|
||||
{
|
||||
auto constexpr I = sizeof...(Bs);
|
||||
if(n_ == I)
|
||||
{
|
||||
--n_;
|
||||
new(buf_.data()) iter_t<I-1>{
|
||||
std::get<I-1>(*bs_).end()};
|
||||
}
|
||||
decrement(C<I-1>{});
|
||||
}
|
||||
|
||||
void
|
||||
decrement(C<0>)
|
||||
{
|
||||
auto constexpr I = 0;
|
||||
if(iter<I>() != std::get<I>(*bs_).begin())
|
||||
{
|
||||
--iter<I>();
|
||||
return;
|
||||
}
|
||||
throw std::logic_error("invalid iterator");
|
||||
}
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
decrement(C<I>)
|
||||
{
|
||||
if(n_ == I)
|
||||
{
|
||||
if(iter<I>() != std::get<I>(*bs_).begin())
|
||||
{
|
||||
--iter<I>();
|
||||
return;
|
||||
}
|
||||
--n_;
|
||||
using Iter = iter_t<I>;
|
||||
iter<I>().~Iter();
|
||||
new(buf_.data()) iter_t<I-1>{
|
||||
std::get<I-1>(*bs_).end()};
|
||||
}
|
||||
decrement(C<I-1>{});
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::~const_iterator()
|
||||
{
|
||||
destroy(C<0>{});
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::const_iterator()
|
||||
: n_(sizeof...(Bs))
|
||||
, bs_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::const_iterator(
|
||||
std::tuple<Bs...> const& bs, bool at_end)
|
||||
: bs_(&bs)
|
||||
{
|
||||
if(at_end)
|
||||
n_ = sizeof...(Bs);
|
||||
else
|
||||
construct(C<0>{});
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::const_iterator(const_iterator&& other)
|
||||
: n_(other.n_)
|
||||
, bs_(other.bs_)
|
||||
{
|
||||
move(C<0>{}, std::move(other));
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::const_iterator(const_iterator const& other)
|
||||
: n_(other.n_)
|
||||
, bs_(other.bs_)
|
||||
{
|
||||
copy(C<0>{}, other);
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator=(const_iterator&& other) ->
|
||||
const_iterator&
|
||||
{
|
||||
if(&other == this)
|
||||
return *this;
|
||||
destroy(C<0>{});
|
||||
n_ = other.n_;
|
||||
bs_ = other.bs_;
|
||||
move(C<0>{}, std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator=(const_iterator const& other) ->
|
||||
const_iterator&
|
||||
{
|
||||
if(&other == this)
|
||||
return *this;
|
||||
destroy(C<0>{});
|
||||
n_ = other.n_;
|
||||
bs_ = other.bs_;
|
||||
copy(C<0>{}, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
bool
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator==(const_iterator const& other) const
|
||||
{
|
||||
if(bs_ != other.bs_)
|
||||
return false;
|
||||
if(n_ != other.n_)
|
||||
return false;
|
||||
return equal(C<0>{}, other);
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator*() const ->
|
||||
reference
|
||||
{
|
||||
return dereference(C<0>{});
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator++() ->
|
||||
const_iterator&
|
||||
{
|
||||
increment(C<0>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::
|
||||
const_iterator::operator--() ->
|
||||
const_iterator&
|
||||
{
|
||||
decrement(C<sizeof...(Bs)>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator(bs_, false);
|
||||
}
|
||||
|
||||
template<class ValueType, class... Bs>
|
||||
auto
|
||||
buffer_cat_helper<ValueType, Bs...>::end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator(bs_, true);
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
140
src/beast/include/beast/detail/buffer_concepts.hpp
Normal file
140
src/beast/include/beast/detail/buffer_concepts.hpp
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// 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_BUFFER_CONCEPTS_HPP
|
||||
#define BEAST_DETAIL_BUFFER_CONCEPTS_HPP
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
// Types that meet the requirements,
|
||||
// for use with std::declval only.
|
||||
template<class BufferType>
|
||||
struct BufferSequence
|
||||
{
|
||||
using value_type = BufferType;
|
||||
using const_iterator = BufferType const*;
|
||||
~BufferSequence();
|
||||
BufferSequence(BufferSequence const&) = default;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
};
|
||||
using ConstBufferSequence =
|
||||
BufferSequence<boost::asio::const_buffer>;
|
||||
using MutableBufferSequence =
|
||||
BufferSequence<boost::asio::mutable_buffer>;
|
||||
|
||||
template<class T, class BufferType>
|
||||
class is_BufferSequence
|
||||
{
|
||||
template<class U, class R = std::is_convertible<
|
||||
typename U::value_type, BufferType> >
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class U, class R = std::is_base_of<
|
||||
#if 0
|
||||
std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<
|
||||
typename U::const_iterator>::iterator_category>>
|
||||
#else
|
||||
// workaround:
|
||||
// boost::asio::detail::consuming_buffers::const_iterator
|
||||
// is not bidirectional
|
||||
std::forward_iterator_tag,
|
||||
typename std::iterator_traits<
|
||||
typename U::const_iterator>::iterator_category>>
|
||||
#endif
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
template<class U, class R = typename
|
||||
std::is_convertible<decltype(
|
||||
std::declval<U>().begin()),
|
||||
typename U::const_iterator>::type>
|
||||
static R check3(int);
|
||||
template<class>
|
||||
static std::false_type check3(...);
|
||||
using type3 = decltype(check3<T>(0));
|
||||
|
||||
template<class U, class R = typename std::is_convertible<decltype(
|
||||
std::declval<U>().end()),
|
||||
typename U::const_iterator>::type>
|
||||
static R check4(int);
|
||||
template<class>
|
||||
static std::false_type check4(...);
|
||||
using type4 = decltype(check4<T>(0));
|
||||
|
||||
public:
|
||||
using type = std::integral_constant<bool,
|
||||
std::is_copy_constructible<T>::value &&
|
||||
std::is_destructible<T>::value &&
|
||||
type1::value && type2::value &&
|
||||
type3::value && type4::value>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class is_Streambuf
|
||||
{
|
||||
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 check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class U, class R = std::integral_constant<
|
||||
bool, is_BufferSequence<decltype(
|
||||
std::declval<U>().data()),
|
||||
boost::asio::const_buffer>::type::value>>
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().commit(1), std::true_type{})>
|
||||
static R check3(int);
|
||||
template<class>
|
||||
static std::false_type check3(...);
|
||||
using type3 = decltype(check3<T>(0));
|
||||
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().consume(1), std::true_type{})>
|
||||
static R check4(int);
|
||||
template<class>
|
||||
static std::false_type check4(...);
|
||||
using type4 = decltype(check4<T>(0));
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().size()), std::size_t>>
|
||||
static R check5(int);
|
||||
template<class>
|
||||
static std::false_type check5(...);
|
||||
using type5 = decltype(check5<T>(0));
|
||||
|
||||
public:
|
||||
using type = std::integral_constant<bool,
|
||||
type1::value && type2::value &&
|
||||
type3::value && type4::value &&
|
||||
type5::value>;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
53
src/beast/include/beast/detail/get_lowest_layer.hpp
Normal file
53
src/beast/include/beast/detail/get_lowest_layer.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// 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_GET_LOWEST_LAYER_HPP
|
||||
#define BEAST_DETAIL_GET_LOWEST_LAYER_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
class has_lowest_layer
|
||||
{
|
||||
template<class U, class R =
|
||||
typename U::lowest_layer_type>
|
||||
static std::true_type check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
using type = decltype(check<T>(0));
|
||||
public:
|
||||
static bool constexpr value = type::value;
|
||||
};
|
||||
|
||||
template<class T, bool B>
|
||||
struct maybe_get_lowest_layer
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct maybe_get_lowest_layer<T, true>
|
||||
{
|
||||
using type = typename T::lowest_layer_type;
|
||||
};
|
||||
|
||||
// If T has a nested type lowest_layer_type,
|
||||
// returns that, else returns T.
|
||||
template<class T>
|
||||
struct get_lowest_layer
|
||||
{
|
||||
using type = typename maybe_get_lowest_layer<T,
|
||||
has_lowest_layer<T>::value>::type;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
140
src/beast/include/beast/detail/stream_concepts.hpp
Normal file
140
src/beast/include/beast/detail/stream_concepts.hpp
Normal file
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// 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_STREAM_CONCEPTS_HPP
|
||||
#define BEAST_DETAIL_STREAM_CONCEPTS_HPP
|
||||
|
||||
#include <beast/buffer_concepts.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
// Types that meet the requirements,
|
||||
// for use with std::declval only.
|
||||
struct StreamHandler
|
||||
{
|
||||
StreamHandler(StreamHandler const&) = default;
|
||||
void operator()(boost::system::error_code ec, std::size_t);
|
||||
};
|
||||
using ReadHandler = StreamHandler;
|
||||
using WriteHandler = StreamHandler;
|
||||
|
||||
template<class T>
|
||||
class has_get_io_service
|
||||
{
|
||||
template<class U, class R = typename std::is_same<
|
||||
decltype(std::declval<U>().get_io_service()),
|
||||
boost::asio::io_service&>>
|
||||
static R check(int);
|
||||
template <class>
|
||||
static std::false_type check(...);
|
||||
public:
|
||||
using type = decltype(check<T>(0));
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class is_AsyncReadStream
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().async_read_some(
|
||||
std::declval<MutableBufferSequence>(),
|
||||
std::declval<ReadHandler>()),
|
||||
std::true_type{})>
|
||||
static R check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
using type1 = decltype(check<T>(0));
|
||||
public:
|
||||
using type = std::integral_constant<bool,
|
||||
type1::value &&
|
||||
has_get_io_service<T>::type::value>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class is_AsyncWriteStream
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().async_write_some(
|
||||
std::declval<ConstBufferSequence>(),
|
||||
std::declval<WriteHandler>()),
|
||||
std::true_type{})>
|
||||
static R check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
using type1 = decltype(check<T>(0));
|
||||
public:
|
||||
using type = std::integral_constant<bool,
|
||||
type1::value &&
|
||||
has_get_io_service<T>::type::value>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class is_SyncReadStream
|
||||
{
|
||||
using error_code =
|
||||
boost::system::error_code;
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().read_some(
|
||||
std::declval<MutableBufferSequence>())),
|
||||
std::size_t>>
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().read_some(
|
||||
std::declval<MutableBufferSequence>(),
|
||||
std::declval<error_code&>())), std::size_t>>
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
public:
|
||||
using type = std::integral_constant<bool,
|
||||
type1::value && type2::value>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class is_SyncWriteStream
|
||||
{
|
||||
using error_code =
|
||||
boost::system::error_code;
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().write_some(
|
||||
std::declval<ConstBufferSequence>())),
|
||||
std::size_t>>
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().write_some(
|
||||
std::declval<ConstBufferSequence>(),
|
||||
std::declval<error_code&>())), std::size_t>>
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
public:
|
||||
using type = std::integral_constant<bool,
|
||||
type1::value && type2::value>;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef BEAST_DETAIL_WRITE_STREAMBUF_HPP
|
||||
#define BEAST_DETAIL_WRITE_STREAMBUF_HPP
|
||||
|
||||
#include <beast/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <utility>
|
||||
@@ -41,13 +42,6 @@ public:
|
||||
! is_string_literal<T>::value;
|
||||
};
|
||||
|
||||
template<class Streambuf>
|
||||
inline
|
||||
void
|
||||
write_streambuf(Streambuf&)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Streambuf>
|
||||
void
|
||||
write_streambuf(Streambuf& streambuf,
|
||||
@@ -133,11 +127,11 @@ write_streambuf(Streambuf& streambuf, T const& t)
|
||||
|
||||
template<class Streambuf, class T0, class T1, class... TN>
|
||||
void
|
||||
write_streambuf(Streambuf& streambuf, T0&& t0, T1&& t1, TN... tn)
|
||||
write_streambuf(Streambuf& streambuf,
|
||||
T0 const& t0, T1 const& t1, TN const&... tn)
|
||||
{
|
||||
write_streambuf(streambuf, std::forward<T0>(t0));
|
||||
write_streambuf(streambuf, std::forward<T1>(t1));
|
||||
write_streambuf(streambuf, std::forward<TN>(tn)...);
|
||||
write_streambuf(streambuf, t0);
|
||||
write_streambuf(streambuf, t1, tn...);
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
170
src/beast/include/beast/doc_debug.hpp
Normal file
170
src/beast/include/beast/doc_debug.hpp
Normal file
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// 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_DOC_DEBUG_HPP
|
||||
#define BEAST_DOC_DEBUG_HPP
|
||||
|
||||
namespace beast {
|
||||
|
||||
#if GENERATING_DOCS
|
||||
|
||||
/// doc type (documentation debug helper)
|
||||
using doc_type = int;
|
||||
|
||||
/// doc enum (documentation debug helper)
|
||||
enum doc_enum
|
||||
{
|
||||
/// One (documentation debug helper)
|
||||
one,
|
||||
|
||||
/// Two (documentation debug helper)
|
||||
two
|
||||
};
|
||||
|
||||
/// doc enum class (documentation debug helper)
|
||||
enum class doc_enum_class : unsigned
|
||||
{
|
||||
/// one (documentation debug helper)
|
||||
one,
|
||||
|
||||
/// two (documentation debug helper)
|
||||
two
|
||||
};
|
||||
|
||||
/// doc func (documentation debug helper)
|
||||
void doc_func();
|
||||
|
||||
/// doc class (documentation debug helper)
|
||||
struct doc_class
|
||||
{
|
||||
/// doc class member func (documentation debug helper)
|
||||
void func();
|
||||
};
|
||||
|
||||
/// (documentation debug helper)
|
||||
namespace nested {
|
||||
|
||||
/// doc type (documentation debug helper)
|
||||
using nested_doc_type = int;
|
||||
|
||||
/// doc enum (documentation debug helper)
|
||||
enum nested_doc_enum
|
||||
{
|
||||
/// One (documentation debug helper)
|
||||
one,
|
||||
|
||||
/// Two (documentation debug helper)
|
||||
two
|
||||
};
|
||||
|
||||
/// doc enum class (documentation debug helper)
|
||||
enum class nested_doc_enum_class : unsigned
|
||||
{
|
||||
/// one (documentation debug helper)
|
||||
one,
|
||||
|
||||
/// two (documentation debug helper)
|
||||
two
|
||||
};
|
||||
|
||||
/// doc func (documentation debug helper)
|
||||
void nested_doc_func();
|
||||
|
||||
/// doc class (documentation debug helper)
|
||||
struct nested_doc_class
|
||||
{
|
||||
/// doc class member func (documentation debug helper)
|
||||
void func();
|
||||
};
|
||||
|
||||
} // nested
|
||||
|
||||
/** This is here to help troubleshoot doc/reference.xsl problems
|
||||
|
||||
Embedded references:
|
||||
|
||||
@li type @ref doc_type
|
||||
|
||||
@li enum @ref doc_enum
|
||||
|
||||
@li enum item @ref doc_enum::one
|
||||
|
||||
@li enum_class @ref doc_enum_class
|
||||
|
||||
@li enum_class item @ref doc_enum_class::one
|
||||
|
||||
@li func @ref doc_func
|
||||
|
||||
@li class @ref doc_class
|
||||
|
||||
@li class func @ref doc_class::func
|
||||
|
||||
@li nested type @ref nested::nested_doc_type
|
||||
|
||||
@li nested enum @ref nested::nested_doc_enum
|
||||
|
||||
@li nested enum item @ref nested::nested_doc_enum::one
|
||||
|
||||
@li nested enum_class @ref nested::nested_doc_enum_class
|
||||
|
||||
@li nested enum_class item @ref nested::nested_doc_enum_class::one
|
||||
|
||||
@li nested func @ref nested::nested_doc_func
|
||||
|
||||
@li nested class @ref nested::nested_doc_class
|
||||
|
||||
@li nested class func @ref nested::nested_doc_class::func
|
||||
*/
|
||||
void doc_debug();
|
||||
|
||||
namespace nested {
|
||||
|
||||
/** This is here to help troubleshoot doc/reference.xsl problems
|
||||
|
||||
Embedded references:
|
||||
|
||||
@li type @ref doc_type
|
||||
|
||||
@li enum @ref doc_enum
|
||||
|
||||
@li enum item @ref doc_enum::one
|
||||
|
||||
@li enum_class @ref doc_enum_class
|
||||
|
||||
@li enum_class item @ref doc_enum_class::one
|
||||
|
||||
@li func @ref doc_func
|
||||
|
||||
@li class @ref doc_class
|
||||
|
||||
@li class func @ref doc_class::func
|
||||
|
||||
@li nested type @ref nested_doc_type
|
||||
|
||||
@li nested enum @ref nested_doc_enum
|
||||
|
||||
@li nested enum item @ref nested_doc_enum::one
|
||||
|
||||
@li nested enum_class @ref nested_doc_enum_class
|
||||
|
||||
@li nested enum_class item @ref nested_doc_enum_class::one
|
||||
|
||||
@li nested func @ref nested_doc_func
|
||||
|
||||
@li nested class @ref nested_doc_class
|
||||
|
||||
@li nested class func @ref nested_doc_class::func
|
||||
*/
|
||||
void nested_doc_debug();
|
||||
|
||||
} // nested
|
||||
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -28,28 +28,28 @@ namespace beast {
|
||||
|
||||
@tparam T The type of objects allocated by the allocator.
|
||||
|
||||
@tparam Handler The type of handler.
|
||||
@tparam CompletionHandler The type of handler.
|
||||
|
||||
@note Allocated memory is only valid until the handler is called. The
|
||||
caller is still responsible for freeing memory.
|
||||
*/
|
||||
#if GENERATING_DOCS
|
||||
template <class T, class Handler>
|
||||
template <class T, class CompletionHandler>
|
||||
class handler_alloc;
|
||||
#else
|
||||
template <class T, class Handler>
|
||||
template <class T, class CompletionHandler>
|
||||
class handler_alloc
|
||||
{
|
||||
private:
|
||||
// We want a partial template specialization as a friend
|
||||
// but that isn't allowed so we friend all versions. This
|
||||
// should produce a compile error if Handler is not
|
||||
// should produce a compile error if CompletionHandler is not
|
||||
// constructible from H.
|
||||
//
|
||||
template <class U, class H>
|
||||
friend class handler_alloc;
|
||||
|
||||
Handler h_;
|
||||
CompletionHandler h_;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
The handler is moved or copied into the allocator.
|
||||
*/
|
||||
explicit
|
||||
handler_alloc(Handler&& h)
|
||||
handler_alloc(CompletionHandler&& h)
|
||||
: h_(std::move(h))
|
||||
{
|
||||
}
|
||||
@@ -76,21 +76,21 @@ public:
|
||||
A copy of the handler is made.
|
||||
*/
|
||||
explicit
|
||||
handler_alloc(Handler const& h)
|
||||
handler_alloc(CompletionHandler const& h)
|
||||
: h_(h)
|
||||
{
|
||||
}
|
||||
|
||||
template<class U>
|
||||
handler_alloc(
|
||||
handler_alloc<U, Handler>&& other)
|
||||
handler_alloc<U, CompletionHandler>&& other)
|
||||
: h_(std::move(other.h_))
|
||||
{
|
||||
}
|
||||
|
||||
template<class U>
|
||||
handler_alloc(
|
||||
handler_alloc<U, Handler> const& other)
|
||||
handler_alloc<U, CompletionHandler> const& other)
|
||||
: h_(other.h_)
|
||||
{
|
||||
}
|
||||
@@ -127,7 +127,7 @@ public:
|
||||
friend
|
||||
bool
|
||||
operator==(handler_alloc const& lhs,
|
||||
handler_alloc<U, Handler> const& rhs)
|
||||
handler_alloc<U, CompletionHandler> const& rhs)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -136,7 +136,7 @@ public:
|
||||
friend
|
||||
bool
|
||||
operator!=(handler_alloc const& lhs,
|
||||
handler_alloc<U, Handler> const& rhs)
|
||||
handler_alloc<U, CompletionHandler> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
27
src/beast/include/beast/handler_concepts.hpp
Normal file
27
src/beast/include/beast/handler_concepts.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// 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_CONCEPTS_HPP
|
||||
#define BEAST_HANDLER_CONCEPTS_HPP
|
||||
|
||||
#include <beast/detail/is_call_possible.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `CompletionHandler`.
|
||||
template<class T, class Signature>
|
||||
#if GENERATING_DOCS
|
||||
using is_CompletionHandler = std::integral_constant<bool, ...>;
|
||||
#else
|
||||
using is_CompletionHandler = std::integral_constant<bool,
|
||||
std::is_copy_constructible<typename std::decay<T>::type>::value &&
|
||||
detail::is_call_possible<T, Signature>::value>;
|
||||
#endif
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -5,18 +5,19 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_HTTP_HPP_INCLUDED
|
||||
#define BEAST_HTTP_HPP_INCLUDED
|
||||
#ifndef BEAST_HTTP_HPP
|
||||
#define BEAST_HTTP_HPP
|
||||
|
||||
#include <beast/http/basic_headers.hpp>
|
||||
#include <beast/http/basic_parser.hpp>
|
||||
#include <beast/http/chunk_encode.hpp>
|
||||
#include <beast/http/basic_parser_v1.hpp>
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/headers.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <beast/http/parse_error.hpp>
|
||||
#include <beast/http/parser.hpp>
|
||||
#include <beast/http/parser_v1.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/http/reason.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#ifndef BEAST_HTTP_BASIC_HEADERS_HPP
|
||||
#define BEAST_HTTP_BASIC_HEADERS_HPP
|
||||
|
||||
#include <beast/type_check.hpp>
|
||||
#include <beast/detail/ci_char_traits.hpp>
|
||||
#include <beast/detail/empty_base_optimization.hpp>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
@@ -237,9 +236,20 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Container to store HTTP headers.
|
||||
/** A container for storing HTTP headers.
|
||||
|
||||
Meets the requirements of `FieldSequence`.
|
||||
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.
|
||||
The container preserves the order of insertion of fields with
|
||||
different names. For fields with the same name, the implementation
|
||||
concatenates values inserted with duplicate names as per the
|
||||
rules in rfc2616 section 4.2.
|
||||
|
||||
@note Meets the requirements of @b `FieldSequence`.
|
||||
*/
|
||||
template<class Allocator>
|
||||
class basic_headers
|
||||
|
||||
@@ -5,15 +5,14 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_HTTP_BASIC_PARSER_HPP
|
||||
#define BEAST_HTTP_BASIC_PARSER_HPP
|
||||
#ifndef BEAST_HTTP_BASIC_PARSER_v1_HPP
|
||||
#define BEAST_HTTP_BASIC_PARSER_v1_HPP
|
||||
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/parse_error.hpp>
|
||||
#include <beast/http/rfc7230.hpp>
|
||||
#include <beast/http/detail/basic_parser.hpp>
|
||||
#include <beast/type_check.hpp>
|
||||
#include <beast/detail/ci_char_traits.hpp>
|
||||
#include <beast/http/detail/basic_parser_v1.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
@@ -37,55 +36,55 @@ enum values
|
||||
};
|
||||
} // parse_flag
|
||||
|
||||
/** Parser for producing HTTP requests and responses.
|
||||
/** Base class for parsing HTTP/1 requests and responses.
|
||||
|
||||
During parsing, callbacks will be made to the derived class
|
||||
if those members are present (detected through SFINAE). The
|
||||
signatures which can be present in the derived class are:<br>
|
||||
|
||||
@li `void on_method(boost::string_ref const&, error_code& ec)`
|
||||
@li `void on_method(boost::string_ref const&, error_code&)`
|
||||
|
||||
Called for each piece of the Request-Method
|
||||
|
||||
@li `void on_uri(boost::string_ref const&, error_code& ec)`
|
||||
@li `void on_uri(boost::string_ref const&, error_code&)`
|
||||
|
||||
Called for each piece of the Request-URI
|
||||
|
||||
@li `void on_reason(boost::string_ref const&, error_code& ec)`
|
||||
@li `void on_reason(boost::string_ref const&, error_code&)`
|
||||
|
||||
Called for each piece of the reason-phrase
|
||||
|
||||
@li `void on_request(error_code& ec)`
|
||||
@li `void on_request(error_code&)`
|
||||
|
||||
Called after the entire Request-Line has been parsed successfully.
|
||||
|
||||
@li `void on_response(error_code& ec)`
|
||||
@li `void on_response(error_code&)`
|
||||
|
||||
Called after the entire Response-Line has been parsed successfully.
|
||||
|
||||
@li `void on_field(boost::string_ref const&, error_code& ec)`
|
||||
@li `void on_field(boost::string_ref const&, error_code&)`
|
||||
|
||||
Called for each piece of the current header field.
|
||||
|
||||
@li `void on_value(boost::string_ref const&, error_code& ec)`
|
||||
@li `void on_value(boost::string_ref const&, error_code&)`
|
||||
|
||||
Called for each piece of the current header value.
|
||||
|
||||
@li `int on_headers(error_code& ec)`
|
||||
@li `int on_headers(error_code&)`
|
||||
|
||||
Called when all the headers have been parsed successfully.
|
||||
|
||||
@li `void on_body(boost::string_ref const&, error_code& ec)`
|
||||
@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& ec)`
|
||||
@li `void on_complete(error_code&)`
|
||||
|
||||
Called when the entire message has been parsed successfully.
|
||||
At this point, basic_parser::complete() returns `true`, and
|
||||
the parser is ready to parse another message if keep_alive()
|
||||
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
|
||||
@@ -101,7 +100,7 @@ enum values
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -109,10 +108,10 @@ enum values
|
||||
and the error is returned to the caller.
|
||||
*/
|
||||
template<bool isRequest, class Derived>
|
||||
class basic_parser
|
||||
class basic_parser_v1
|
||||
{
|
||||
private:
|
||||
using self = basic_parser;
|
||||
using self = basic_parser_v1;
|
||||
typedef void(self::*pmf_t)(error_code&, boost::string_ref const&);
|
||||
|
||||
static std::uint64_t constexpr no_content_length =
|
||||
@@ -237,13 +236,13 @@ private:
|
||||
|
||||
public:
|
||||
/// Copy constructor.
|
||||
basic_parser(basic_parser const&) = default;
|
||||
basic_parser_v1(basic_parser_v1 const&) = default;
|
||||
|
||||
/// Copy assignment.
|
||||
basic_parser& operator=(basic_parser const&) = default;
|
||||
basic_parser_v1& operator=(basic_parser_v1 const&) = default;
|
||||
|
||||
/// Constructor
|
||||
basic_parser()
|
||||
basic_parser_v1()
|
||||
{
|
||||
init(std::integral_constant<bool, isRequest>{});
|
||||
}
|
||||
@@ -345,7 +344,7 @@ public:
|
||||
return s_ == s_restart;
|
||||
}
|
||||
|
||||
/** Write data to the parser.
|
||||
/** Write a sequence of buffers to the parser.
|
||||
|
||||
@param buffers An object meeting the requirements of
|
||||
ConstBufferSequence that represents the input sequence.
|
||||
@@ -355,19 +354,25 @@ public:
|
||||
@return The number of bytes consumed in the input sequence.
|
||||
*/
|
||||
template<class ConstBufferSequence>
|
||||
#if GENERATING_DOCS
|
||||
std::size_t
|
||||
#else
|
||||
typename std::enable_if<
|
||||
! std::is_convertible<ConstBufferSequence,
|
||||
boost::asio::const_buffer>::value,
|
||||
std::size_t>::type
|
||||
#endif
|
||||
write(ConstBufferSequence const& buffers, error_code& ec);
|
||||
|
||||
/** Write data to the parser.
|
||||
/** Write a single buffer of data to the parser.
|
||||
|
||||
@param data A pointer to a buffer representing the input sequence.
|
||||
@param size The number of bytes in the buffer pointed to by data.
|
||||
@param buffer The buffer to write.
|
||||
@param ec Set to the error, if any error occurred.
|
||||
|
||||
@return The number of bytes consumed in the input sequence.
|
||||
@return The number of bytes consumed in the buffer.
|
||||
*/
|
||||
std::size_t
|
||||
write(void const* data, std::size_t size, error_code& ec);
|
||||
write(boost::asio::const_buffer const& buffer, error_code& ec);
|
||||
|
||||
/** Called to indicate the end of file.
|
||||
|
||||
@@ -377,8 +382,6 @@ public:
|
||||
Callbacks and errors will still be processed as usual.
|
||||
|
||||
@note This is typically called when a socket read returns eof.
|
||||
|
||||
@throws boost::system::system_error Thrown on failure.
|
||||
*/
|
||||
void
|
||||
write_eof(error_code& ec);
|
||||
@@ -756,6 +759,6 @@ private:
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#include <beast/http/impl/basic_parser.ipp>
|
||||
#include <beast/http/impl/basic_parser_v1.ipp>
|
||||
|
||||
#endif
|
||||
19
src/beast/include/beast/http/body_type.hpp
Normal file
19
src/beast/include/beast/http/body_type.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// 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/http/error.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
|
||||
#endif
|
||||
@@ -5,8 +5,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_HPP
|
||||
#define BEAST_HTTP_DETAIL_BASIC_PARSER_HPP
|
||||
#ifndef 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>
|
||||
@@ -5,8 +5,8 @@
|
||||
// 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
|
||||
#ifndef BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
|
||||
#define BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <algorithm>
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Buffers>
|
||||
@@ -237,9 +236,7 @@ chunk_encoded_buffers<Buffers>::const_iterator::const_iterator(
|
||||
{
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
/** Returns a chunk-encoded BufferSequence.
|
||||
/* Returns a chunk-encoded BufferSequence.
|
||||
|
||||
See:
|
||||
http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
|
||||
@@ -276,6 +273,7 @@ chunk_encode_final()
|
||||
"0\r\n\r\n", 5);
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
43
src/beast/include/beast/http/detail/has_content_length.hpp
Normal file
43
src/beast/include/beast/http/detail/has_content_length.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// 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
|
||||
@@ -1,123 +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_WRITE_PREPARATION_HPP
|
||||
#define BEAST_HTTP_DETAIL_WRITE_PREPARATION_HPP
|
||||
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <beast/write_streambuf.hpp>
|
||||
|
||||
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::size_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>;
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
struct write_preparation
|
||||
{
|
||||
using headers_type =
|
||||
basic_headers<std::allocator<char>>;
|
||||
|
||||
message<isRequest, Body, Headers> const& msg;
|
||||
typename Body::writer w;
|
||||
streambuf sb;
|
||||
bool chunked;
|
||||
bool close;
|
||||
|
||||
explicit
|
||||
write_preparation(
|
||||
message<isRequest, Body, Headers> const& msg_)
|
||||
: msg(msg_)
|
||||
, w(msg)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
{
|
||||
w.init(ec);
|
||||
if(ec)
|
||||
return;
|
||||
// VFALCO TODO This implementation requires making a
|
||||
// copy of the headers, we can do better.
|
||||
// VFALCO Should we be using handler_alloc?
|
||||
headers_type h(msg.headers.begin(), msg.headers.end());
|
||||
set_content_length(h, has_content_length<
|
||||
typename Body::writer>{});
|
||||
|
||||
// VFALCO TODO Keep-Alive
|
||||
|
||||
if(close)
|
||||
{
|
||||
if(msg.version >= 11)
|
||||
h.insert("Connection", "close");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(msg.version < 11)
|
||||
h.insert("Connection", "keep-alive");
|
||||
}
|
||||
|
||||
msg.write_firstline(sb);
|
||||
write_fields(sb, h);
|
||||
beast::write(sb, "\r\n");
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
set_content_length(headers_type& h,
|
||||
std::true_type)
|
||||
{
|
||||
close = false;
|
||||
chunked = false;
|
||||
h.insert("Content-Length", w.content_length());
|
||||
}
|
||||
|
||||
void
|
||||
set_content_length(headers_type& h,
|
||||
std::false_type)
|
||||
{
|
||||
if(msg.version >= 11)
|
||||
{
|
||||
close = false;
|
||||
chunked = true;
|
||||
h.insert("Transfer-Encoding", "chunked");
|
||||
}
|
||||
else
|
||||
{
|
||||
close = true;
|
||||
chunked = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -8,8 +8,7 @@
|
||||
#ifndef BEAST_HTTP_EMPTY_BODY_HPP
|
||||
#define BEAST_HTTP_EMPTY_BODY_HPP
|
||||
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <memory>
|
||||
@@ -19,6 +18,8 @@ namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** An empty content-body.
|
||||
|
||||
Meets the requirements of @b `Body`.
|
||||
*/
|
||||
struct empty_body
|
||||
{
|
||||
@@ -35,9 +36,9 @@ private:
|
||||
|
||||
struct reader
|
||||
{
|
||||
template<bool isRequest, class Allocator>
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
reader(message<isRequest, empty_body, Allocator>&)
|
||||
reader(message<isRequest, empty_body, Headers>&)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -49,9 +50,12 @@ private:
|
||||
|
||||
struct writer
|
||||
{
|
||||
template<bool isRequest, class Allocator>
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
writer(message<isRequest, empty_body, Allocator> const& m)
|
||||
writer(message<isRequest, empty_body, Headers> const& m)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -60,7 +64,7 @@ private:
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define BEAST_HTTP_ERROR_HPP
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
@@ -14,10 +14,7 @@
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
template<class Allocator>
|
||||
using headers = basic_headers<Allocator>;
|
||||
|
||||
using http_headers =
|
||||
using headers =
|
||||
basic_headers<std::allocator<char>>;
|
||||
|
||||
} // http
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
|
||||
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
|
||||
|
||||
#include <beast/type_check.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
@@ -59,7 +57,7 @@ delete_all()
|
||||
for(auto it = list_.begin(); it != list_.end();)
|
||||
{
|
||||
auto& e = *it++;
|
||||
e.~element();
|
||||
alloc_traits::destroy(this->member(), &e);
|
||||
alloc_traits::deallocate(
|
||||
this->member(), &e, 1);
|
||||
}
|
||||
@@ -252,6 +250,7 @@ erase(boost::string_ref const& name)
|
||||
auto& e = *it;
|
||||
set_.erase(set_.iterator_to(e));
|
||||
list_.erase(list_.iterator_to(e));
|
||||
alloc_traits::destroy(this->member(), &e);
|
||||
alloc_traits::deallocate(this->member(), &e, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -5,15 +5,17 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_IPP
|
||||
#define BEAST_HTTP_IMPL_BASIC_PARSER_IPP
|
||||
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
|
||||
#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
|
||||
|
||||
#include <beast/buffer_concepts.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
template<bool isRequest, class Derived>
|
||||
bool
|
||||
basic_parser<isRequest, Derived>::
|
||||
basic_parser_v1<isRequest, Derived>::
|
||||
keep_alive() const
|
||||
{
|
||||
if(http_major_ > 0 && http_minor_ > 0)
|
||||
@@ -31,10 +33,31 @@ keep_alive() const
|
||||
|
||||
// Implementation inspired by nodejs/http-parser
|
||||
|
||||
template<bool isRequest, class Derived>
|
||||
template<class ConstBufferSequence>
|
||||
typename std::enable_if<
|
||||
! std::is_convertible<ConstBufferSequence,
|
||||
boost::asio::const_buffer>::value,
|
||||
std::size_t>::type
|
||||
basic_parser_v1<isRequest, Derived>::
|
||||
write(ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
static_assert(is_ConstBufferSequence<ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
std::size_t used = 0;
|
||||
for(auto const& buffer : buffers)
|
||||
{
|
||||
used += write(buffer, ec);
|
||||
if(ec)
|
||||
break;
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
||||
template<bool isRequest, class Derived>
|
||||
std::size_t
|
||||
basic_parser<isRequest, Derived>::
|
||||
write(void const* data, std::size_t size, error_code& ec)
|
||||
basic_parser_v1<isRequest, Derived>::
|
||||
write(boost::asio::const_buffer const& buffer, error_code& ec)
|
||||
{
|
||||
using beast::http::detail::is_digit;
|
||||
using beast::http::detail::is_token;
|
||||
@@ -42,7 +65,12 @@ write(void const* data, std::size_t size, error_code& ec)
|
||||
using beast::http::detail::to_field_char;
|
||||
using beast::http::detail::to_value_char;
|
||||
using beast::http::detail::unhex;
|
||||
using boost::asio::buffer_cast;
|
||||
using boost::asio::buffer_size;
|
||||
|
||||
auto const data = buffer_cast<void const*>(buffer);
|
||||
auto const size = buffer_size(buffer);
|
||||
|
||||
if(size == 0 && s_ != s_closed)
|
||||
return 0;
|
||||
|
||||
@@ -997,30 +1025,9 @@ write(void const* data, std::size_t size, error_code& ec)
|
||||
return used();
|
||||
}
|
||||
|
||||
template<bool isRequest, class Derived>
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
basic_parser<isRequest, Derived>::
|
||||
write(ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
static_assert(is_ConstBufferSequence<ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
std::size_t used = 0;
|
||||
for(auto const& buffer : buffers)
|
||||
{
|
||||
using boost::asio::buffer_cast;
|
||||
using boost::asio::buffer_size;
|
||||
used += write(buffer_cast<void const*>(buffer),
|
||||
buffer_size(buffer), ec);
|
||||
if(ec)
|
||||
break;
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
||||
template<bool isRequest, class Derived>
|
||||
void
|
||||
basic_parser<isRequest, Derived>::
|
||||
basic_parser_v1<isRequest, Derived>::
|
||||
write_eof(error_code& ec)
|
||||
{
|
||||
switch(s_)
|
||||
@@ -1040,7 +1047,7 @@ write_eof(error_code& ec)
|
||||
|
||||
template<bool isRequest, class Derived>
|
||||
bool
|
||||
basic_parser<isRequest, Derived>::
|
||||
basic_parser_v1<isRequest, Derived>::
|
||||
needs_eof(std::true_type) const
|
||||
{
|
||||
return false;
|
||||
@@ -1048,7 +1055,7 @@ needs_eof(std::true_type) const
|
||||
|
||||
template<bool isRequest, class Derived>
|
||||
bool
|
||||
basic_parser<isRequest, Derived>::
|
||||
basic_parser_v1<isRequest, Derived>::
|
||||
needs_eof(std::false_type) const
|
||||
{
|
||||
// See RFC 2616 section 4.4
|
||||
@@ -1,318 +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_IMPL_MESSAGE_IPP
|
||||
#define BEAST_HTTP_IMPL_MESSAGE_IPP
|
||||
|
||||
#include <beast/http/chunk_encode.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <beast/http/rfc2616.hpp>
|
||||
#include <beast/write_streambuf.hpp>
|
||||
#include <beast/type_check.hpp>
|
||||
#include <beast/http/detail/write_preparation.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
message<isRequest, Body, Headers>::
|
||||
message()
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
message<isRequest, Body, Headers>::
|
||||
message(request_params params)
|
||||
{
|
||||
static_assert(isRequest, "message is not a request");
|
||||
this->method = params.method;
|
||||
this->url = std::move(params.url);
|
||||
version = params.version;
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
message<isRequest, Body, Headers>::
|
||||
message(response_params params)
|
||||
{
|
||||
static_assert(! isRequest, "message is not a response");
|
||||
this->status = params.status;
|
||||
this->reason = std::move(params.reason);
|
||||
version = params.version;
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
template<class Streambuf>
|
||||
void
|
||||
message<isRequest, Body, Headers>::
|
||||
write_firstline(Streambuf& streambuf,
|
||||
std::true_type) const
|
||||
{
|
||||
write(streambuf, to_string(this->method));
|
||||
write(streambuf, " ");
|
||||
write(streambuf, this->url);
|
||||
switch(version)
|
||||
{
|
||||
case 10:
|
||||
write(streambuf, " HTTP/1.0\r\n");
|
||||
break;
|
||||
case 11:
|
||||
write(streambuf, " HTTP/1.1\r\n");
|
||||
break;
|
||||
default:
|
||||
write(streambuf, " HTTP/");
|
||||
write(streambuf, version / 10);
|
||||
write(streambuf, ".");
|
||||
write(streambuf, version % 10);
|
||||
write(streambuf, "\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
template<class Streambuf>
|
||||
void
|
||||
message<isRequest, Body, Headers>::
|
||||
write_firstline(Streambuf& streambuf,
|
||||
std::false_type) const
|
||||
{
|
||||
switch(version)
|
||||
{
|
||||
case 10:
|
||||
write(streambuf, "HTTP/1.0 ");
|
||||
break;
|
||||
case 11:
|
||||
write(streambuf, "HTTP/1.1 ");
|
||||
break;
|
||||
default:
|
||||
write(streambuf, " HTTP/");
|
||||
write(streambuf, version / 10);
|
||||
write(streambuf, ".");
|
||||
write(streambuf, version % 10);
|
||||
write(streambuf, " ");
|
||||
break;
|
||||
}
|
||||
write(streambuf, this->status);
|
||||
write(streambuf, " ");
|
||||
write(streambuf, this->reason);
|
||||
write(streambuf, "\r\n");
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
std::string
|
||||
buffers_to_string(ConstBufferSequence const& buffers)
|
||||
{
|
||||
using boost::asio::buffer_cast;
|
||||
using boost::asio::buffer_size;
|
||||
std::string s;
|
||||
s.reserve(buffer_size(buffers));
|
||||
for(auto const& b : buffers)
|
||||
s.append(buffer_cast<char const*>(b),
|
||||
buffer_size(b));
|
||||
return s;
|
||||
}
|
||||
|
||||
class writef_ostream
|
||||
{
|
||||
std::ostream& os_;
|
||||
bool chunked_;
|
||||
|
||||
public:
|
||||
writef_ostream(std::ostream& os, bool chunked)
|
||||
: os_(os)
|
||||
, chunked_(chunked)
|
||||
{
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
void
|
||||
operator()(ConstBufferSequence const& buffers)
|
||||
{
|
||||
if(chunked_)
|
||||
os_ << buffers_to_string(
|
||||
chunk_encode(buffers));
|
||||
else
|
||||
os_ << buffers_to_string(
|
||||
buffers);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
// Diagnostic output only
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os,
|
||||
message<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
error_code ec;
|
||||
detail::write_preparation<isRequest, Body, Headers> wp(msg);
|
||||
wp.init(ec);
|
||||
if(ec)
|
||||
return os;
|
||||
std::mutex m;
|
||||
std::condition_variable cv;
|
||||
bool ready = false;
|
||||
resume_context resume{
|
||||
[&]
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
ready = true;
|
||||
cv.notify_one();
|
||||
}};
|
||||
auto copy = resume;
|
||||
os << detail::buffers_to_string(wp.sb.data());
|
||||
wp.sb.consume(wp.sb.size());
|
||||
detail::writef_ostream writef(os, wp.chunked);
|
||||
for(;;)
|
||||
{
|
||||
{
|
||||
auto result = wp.w(std::move(copy), ec, writef);
|
||||
if(ec)
|
||||
return os;
|
||||
if(result)
|
||||
break;
|
||||
if(boost::indeterminate(result))
|
||||
{
|
||||
copy = resume;
|
||||
std::unique_lock<std::mutex> lock(m);
|
||||
cv.wait(lock, [&]{ return ready; });
|
||||
ready = false;
|
||||
}
|
||||
}
|
||||
wp.sb.consume(wp.sb.size());
|
||||
for(;;)
|
||||
{
|
||||
auto result = wp.w(std::move(copy), ec, writef);
|
||||
if(ec)
|
||||
return os;
|
||||
if(result)
|
||||
break;
|
||||
if(boost::indeterminate(result))
|
||||
{
|
||||
copy = resume;
|
||||
std::unique_lock<std::mutex> lock(m);
|
||||
cv.wait(lock, [&]{ return ready; });
|
||||
ready = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(wp.chunked)
|
||||
{
|
||||
// VFALCO Unfortunately the current interface to the
|
||||
// Writer concept prevents us from using coalescing the
|
||||
// final body chunk with the final chunk delimiter.
|
||||
//
|
||||
// write final chunk
|
||||
os << detail::buffers_to_string(chunk_encode_final());
|
||||
if(ec)
|
||||
return os;
|
||||
}
|
||||
os << std::endl;
|
||||
return os;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
set_connection(bool keep_alive,
|
||||
message<isRequest, Body, Headers>& req)
|
||||
{
|
||||
if(req.version >= 11)
|
||||
{
|
||||
if(! keep_alive)
|
||||
req.headers.replace("Connection", "close");
|
||||
else
|
||||
req.headers.erase("Connection");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(keep_alive)
|
||||
req.headers.replace("Connection", "keep-alive");
|
||||
else
|
||||
req.headers.erase("Connection");
|
||||
}
|
||||
}
|
||||
|
||||
template<class Body, class Headers,
|
||||
class OtherBody, class OtherAllocator>
|
||||
void
|
||||
set_connection(bool keep_alive,
|
||||
message<false, Body, Headers>& resp,
|
||||
message<true, OtherBody, OtherAllocator> const& req)
|
||||
{
|
||||
if(req.version >= 11)
|
||||
{
|
||||
if(rfc2616::token_in_list(req["Connection"], "close"))
|
||||
keep_alive = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(! rfc2616::token_in_list(req["Connection"], "keep-alive"))
|
||||
keep_alive = false;
|
||||
}
|
||||
set_connection(keep_alive, resp);
|
||||
}
|
||||
|
||||
template<class Streambuf, class FieldSequence>
|
||||
void
|
||||
write_fields(Streambuf& streambuf, FieldSequence const& fields)
|
||||
{
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
//static_assert(is_FieldSequence<FieldSequence>::value,
|
||||
// "FieldSequence requirements not met");
|
||||
for(auto const& field : fields)
|
||||
{
|
||||
write(streambuf, field.name());
|
||||
write(streambuf, ": ");
|
||||
write(streambuf, field.value());
|
||||
write(streambuf, "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
bool
|
||||
is_keep_alive(message<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
if(msg.version >= 11)
|
||||
{
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "close"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "keep-alive"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
bool
|
||||
is_upgrade(message<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
if(msg.version < 11)
|
||||
return false;
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "upgrade"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#include <beast/http/impl/message.ipp>
|
||||
|
||||
#endif
|
||||
242
src/beast/include/beast/http/impl/message_v1.ipp
Normal file
242
src/beast/include/beast/http/impl/message_v1.ipp
Normal file
@@ -0,0 +1,242 @@
|
||||
//
|
||||
// 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_V1_IPP
|
||||
#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP
|
||||
|
||||
#include <beast/http/rfc2616.hpp>
|
||||
#include <beast/http/detail/has_content_length.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
message_v1<isRequest, Body, Headers>::
|
||||
message_v1(request_params params)
|
||||
{
|
||||
static_assert(isRequest, "message is not a request");
|
||||
this->method = params.method;
|
||||
this->url = std::move(params.url);
|
||||
version = params.version;
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
message_v1<isRequest, Body, Headers>::
|
||||
message_v1(response_params params)
|
||||
{
|
||||
static_assert(! isRequest, "message is not a response");
|
||||
this->status = params.status;
|
||||
this->reason = std::move(params.reason);
|
||||
version = params.version;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
bool
|
||||
is_keep_alive(message_v1<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
if(msg.version >= 11)
|
||||
{
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "close"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "keep-alive"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
bool
|
||||
is_upgrade(message_v1<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
if(msg.version < 11)
|
||||
return false;
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "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 Headers>
|
||||
inline
|
||||
void
|
||||
prepare_options(prepare_info& pi,
|
||||
message_v1<isRequest, Body, Headers>& msg)
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
prepare_option(prepare_info& pi,
|
||||
message_v1<isRequest, Body, Headers>& msg,
|
||||
connection value)
|
||||
{
|
||||
pi.connection_value = value;
|
||||
}
|
||||
|
||||
template<
|
||||
bool isRequest, class Body, class Headers,
|
||||
class Opt, class... Opts>
|
||||
void
|
||||
prepare_options(prepare_info& pi,
|
||||
message_v1<isRequest, Body, Headers>& msg,
|
||||
Opt&& opt, Opts&&... opts)
|
||||
{
|
||||
prepare_option(pi, msg, opt);
|
||||
prepare_options(pi, msg,
|
||||
std::forward<Opts>(opts)...);
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
prepare_content_length(prepare_info& pi,
|
||||
message_v1<isRequest, Body, Headers> const& msg,
|
||||
std::true_type)
|
||||
{
|
||||
typename Body::writer w(msg);
|
||||
//w.init(ec); // VFALCO This is a design problem!
|
||||
pi.content_length = w.content_length();
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
prepare_content_length(prepare_info& pi,
|
||||
message_v1<isRequest, Body, Headers> const& msg,
|
||||
std::false_type)
|
||||
{
|
||||
pi.content_length = boost::none;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
void
|
||||
prepare_connection(
|
||||
message_v1<isRequest, Body, Headers>& msg)
|
||||
{
|
||||
if(msg.version >= 11)
|
||||
{
|
||||
if(! msg.headers.exists("Content-Length") &&
|
||||
! rfc2616::token_in_list(
|
||||
msg.headers["Transfer-Encoding"], "chunked"))
|
||||
if(! rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "close"))
|
||||
msg.headers.insert("Connection", "close");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(! msg.headers.exists("Content-Length"))
|
||||
{
|
||||
// VFALCO We are erasing the whole header when we
|
||||
// should be removing just the keep-alive.
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "keep-alive"))
|
||||
msg.headers.erase("Connection");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
bool isRequest, class Body, class Headers,
|
||||
class... Options>
|
||||
void
|
||||
prepare(message_v1<isRequest, Body, Headers>& msg,
|
||||
Options&&... options)
|
||||
{
|
||||
// VFALCO TODO
|
||||
//static_assert(is_WritableBody<Body>::value,
|
||||
// "WritableBody 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.headers.exists("Connection"))
|
||||
throw std::invalid_argument(
|
||||
"prepare called with Connection field set");
|
||||
|
||||
if(msg.headers.exists("Content-Length"))
|
||||
throw std::invalid_argument(
|
||||
"prepare called with Content-Length field set");
|
||||
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Transfer-Encoding"], "chunked"))
|
||||
throw std::invalid_argument(
|
||||
"prepare called with Transfer-Encoding: chunked set");
|
||||
|
||||
if(pi.connection_value != connection::upgrade)
|
||||
{
|
||||
if(pi.content_length)
|
||||
{
|
||||
// VFALCO TODO Use a static string here
|
||||
msg.headers.insert("Content-Length",
|
||||
std::to_string(*pi.content_length));
|
||||
}
|
||||
else if(msg.version >= 11)
|
||||
{
|
||||
msg.headers.insert("Transfer-Encoding", "chunked");
|
||||
}
|
||||
}
|
||||
|
||||
auto const content_length =
|
||||
msg.headers.exists("Content-Length");
|
||||
|
||||
if(pi.connection_value)
|
||||
{
|
||||
switch(*pi.connection_value)
|
||||
{
|
||||
case connection::upgrade:
|
||||
msg.headers.insert("Connection", "upgrade");
|
||||
break;
|
||||
|
||||
case connection::keep_alive:
|
||||
if(msg.version < 11)
|
||||
{
|
||||
if(content_length)
|
||||
msg.headers.insert("Connection", "keep-alive");
|
||||
}
|
||||
break;
|
||||
|
||||
case connection::close:
|
||||
if(msg.version >= 11)
|
||||
msg.headers.insert("Connection", "close");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rfc7230 6.7.
|
||||
if(msg.version < 11 && rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "upgrade"))
|
||||
throw std::invalid_argument(
|
||||
"invalid version for Connection: upgrade");
|
||||
|
||||
// rfc7230 3.3.2
|
||||
if(msg.headers.exists("Content-Length") &&
|
||||
msg.headers.exists("Transfer-Encoding"))
|
||||
throw std::invalid_argument(
|
||||
"Content-Length and Transfer-Encoding cannot be combined");
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -8,8 +8,10 @@
|
||||
#ifndef BEAST_HTTP_IMPL_READ_IPP_HPP
|
||||
#define BEAST_HTTP_IMPL_READ_IPP_HPP
|
||||
|
||||
#include <beast/http/parser_v1.hpp>
|
||||
#include <beast/bind_handler.hpp>
|
||||
#include <beast/handler_alloc.hpp>
|
||||
#include <beast/stream_concepts.hpp>
|
||||
#include <cassert>
|
||||
|
||||
namespace beast {
|
||||
@@ -26,10 +28,10 @@ class read_op
|
||||
handler_alloc<char, Handler>;
|
||||
|
||||
using parser_type =
|
||||
parser<isRequest, Body, Headers>;
|
||||
parser_v1<isRequest, Body, Headers>;
|
||||
|
||||
using message_type =
|
||||
message<isRequest, Body, Headers>;
|
||||
message_v1<isRequest, Body, Headers>;
|
||||
|
||||
struct data
|
||||
{
|
||||
@@ -214,14 +216,14 @@ template<class SyncReadStream, class Streambuf,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
message<isRequest, Body, Headers>& m,
|
||||
message_v1<isRequest, Body, Headers>& m,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncReadStream<SyncReadStream>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
parser<isRequest, Body, Headers> p;
|
||||
parser_v1<isRequest, Body, Headers> p;
|
||||
bool started = false;
|
||||
for(;;)
|
||||
{
|
||||
@@ -264,7 +266,7 @@ template<class AsyncReadStream, class Streambuf,
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
async_read(AsyncReadStream& stream, Streambuf& streambuf,
|
||||
message<isRequest, Body, Headers>& m,
|
||||
message_v1<isRequest, Body, Headers>& m,
|
||||
ReadHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncReadStream<AsyncReadStream>::value,
|
||||
|
||||
@@ -8,18 +8,22 @@
|
||||
#ifndef BEAST_HTTP_IMPL_WRITE_IPP
|
||||
#define BEAST_HTTP_IMPL_WRITE_IPP
|
||||
|
||||
#include <beast/http/chunk_encode.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <beast/http/detail/write_preparation.hpp>
|
||||
#include <beast/http/detail/chunk_encode.hpp>
|
||||
#include <beast/http/detail/has_content_length.hpp>
|
||||
#include <beast/buffer_cat.hpp>
|
||||
#include <beast/bind_handler.hpp>
|
||||
#include <beast/buffer_concepts.hpp>
|
||||
#include <beast/handler_alloc.hpp>
|
||||
#include <beast/stream_concepts.hpp>
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <beast/type_check.hpp>
|
||||
#include <beast/write_streambuf.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
@@ -27,6 +31,114 @@ namespace http {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class Streambuf, class Body, class Headers>
|
||||
void
|
||||
write_firstline(Streambuf& streambuf,
|
||||
message_v1<true, Body, Headers> const& msg)
|
||||
{
|
||||
write(streambuf, msg.method);
|
||||
write(streambuf, " ");
|
||||
write(streambuf, msg.url);
|
||||
switch(msg.version)
|
||||
{
|
||||
case 10:
|
||||
write(streambuf, " HTTP/1.0\r\n");
|
||||
break;
|
||||
case 11:
|
||||
write(streambuf, " HTTP/1.1\r\n");
|
||||
break;
|
||||
default:
|
||||
write(streambuf, " HTTP/");
|
||||
write(streambuf, msg.version / 10);
|
||||
write(streambuf, ".");
|
||||
write(streambuf, msg.version % 10);
|
||||
write(streambuf, "\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Streambuf, class Body, class Headers>
|
||||
void
|
||||
write_firstline(Streambuf& streambuf,
|
||||
message_v1<false, Body, Headers> const& msg)
|
||||
{
|
||||
switch(msg.version)
|
||||
{
|
||||
case 10:
|
||||
write(streambuf, "HTTP/1.0 ");
|
||||
break;
|
||||
case 11:
|
||||
write(streambuf, "HTTP/1.1 ");
|
||||
break;
|
||||
default:
|
||||
write(streambuf, " HTTP/");
|
||||
write(streambuf, msg.version / 10);
|
||||
write(streambuf, ".");
|
||||
write(streambuf, msg.version % 10);
|
||||
write(streambuf, " ");
|
||||
break;
|
||||
}
|
||||
write(streambuf, msg.status);
|
||||
write(streambuf, " ");
|
||||
write(streambuf, msg.reason);
|
||||
write(streambuf, "\r\n");
|
||||
}
|
||||
|
||||
template<class Streambuf, class FieldSequence>
|
||||
void
|
||||
write_fields(Streambuf& streambuf, FieldSequence const& fields)
|
||||
{
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
//static_assert(is_FieldSequence<FieldSequence>::value,
|
||||
// "FieldSequence requirements not met");
|
||||
for(auto const& field : fields)
|
||||
{
|
||||
write(streambuf, field.name());
|
||||
write(streambuf, ": ");
|
||||
write(streambuf, field.value());
|
||||
write(streambuf, "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
struct write_preparation
|
||||
{
|
||||
using headers_type =
|
||||
basic_headers<std::allocator<char>>;
|
||||
|
||||
message_v1<isRequest, Body, Headers> const& msg;
|
||||
typename Body::writer w;
|
||||
streambuf sb;
|
||||
bool chunked;
|
||||
bool close;
|
||||
|
||||
explicit
|
||||
write_preparation(
|
||||
message_v1<isRequest, Body, Headers> const& msg_)
|
||||
: msg(msg_)
|
||||
, w(msg)
|
||||
, chunked(rfc2616::token_in_list(
|
||||
msg.headers["Transfer-Encoding"], "chunked"))
|
||||
, close(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "close") ||
|
||||
(msg.version < 11 && ! msg.headers.exists(
|
||||
"Content-Length")))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
{
|
||||
w.init(ec);
|
||||
if(ec)
|
||||
return;
|
||||
write_firstline(sb, msg);
|
||||
write_fields(sb, msg.headers);
|
||||
beast::write(sb, "\r\n");
|
||||
}
|
||||
};
|
||||
|
||||
template<class Stream, class Handler,
|
||||
bool isRequest, class Body, class Headers>
|
||||
class write_op
|
||||
@@ -48,7 +160,7 @@ class write_op
|
||||
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_, Stream& s_,
|
||||
message<isRequest, Body, Headers> const& m_)
|
||||
message_v1<isRequest, Body, Headers> const& m_)
|
||||
: s(s_)
|
||||
, wp(m_)
|
||||
, h(std::forward<DeducedHandler>(h_))
|
||||
@@ -77,7 +189,7 @@ class write_op
|
||||
if(d.wp.chunked)
|
||||
boost::asio::async_write(d.s,
|
||||
buffer_cat(d.wp.sb.data(),
|
||||
chunk_encode(buffers)),
|
||||
detail::chunk_encode(buffers)),
|
||||
std::move(self_));
|
||||
else
|
||||
boost::asio::async_write(d.s,
|
||||
@@ -104,7 +216,7 @@ class write_op
|
||||
// write body
|
||||
if(d.wp.chunked)
|
||||
boost::asio::async_write(d.s,
|
||||
chunk_encode(buffers),
|
||||
detail::chunk_encode(buffers),
|
||||
std::move(self_));
|
||||
else
|
||||
boost::asio::async_write(d.s,
|
||||
@@ -269,7 +381,7 @@ operator()(error_code ec, std::size_t, bool again)
|
||||
// write final chunk
|
||||
d.state = 5;
|
||||
boost::asio::async_write(d.s,
|
||||
chunk_encode_final(), std::move(*this));
|
||||
detail::chunk_encode_final(), std::move(*this));
|
||||
return;
|
||||
|
||||
case 5:
|
||||
@@ -311,7 +423,7 @@ public:
|
||||
// write headers and body
|
||||
if(chunked_)
|
||||
boost::asio::write(stream_, buffer_cat(
|
||||
sb_.data(), chunk_encode(buffers)), ec_);
|
||||
sb_.data(), detail::chunk_encode(buffers)), ec_);
|
||||
else
|
||||
boost::asio::write(stream_, buffer_cat(
|
||||
sb_.data(), buffers), ec_);
|
||||
@@ -340,7 +452,7 @@ public:
|
||||
// write body
|
||||
if(chunked_)
|
||||
boost::asio::write(stream_,
|
||||
chunk_encode(buffers), ec_);
|
||||
detail::chunk_encode(buffers), ec_);
|
||||
else
|
||||
boost::asio::write(stream_, buffers, ec_);
|
||||
}
|
||||
@@ -354,9 +466,25 @@ template<class SyncWriteStream,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
write(SyncWriteStream& stream,
|
||||
message<isRequest, Body, Headers> const& msg,
|
||||
message_v1<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
error_code ec;
|
||||
write(stream, msg, ec);
|
||||
if(ec)
|
||||
throw boost::system::system_error{ec};
|
||||
}
|
||||
|
||||
template<class SyncWriteStream,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
write(SyncWriteStream& stream,
|
||||
message_v1<isRequest, Body, Headers> const& msg,
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
detail::write_preparation<isRequest, Body, Headers> wp(msg);
|
||||
wp.init(ec);
|
||||
if(ec)
|
||||
@@ -420,7 +548,7 @@ write(SyncWriteStream& stream,
|
||||
// final body chunk with the final chunk delimiter.
|
||||
//
|
||||
// write final chunk
|
||||
boost::asio::write(stream, chunk_encode_final(), ec);
|
||||
boost::asio::write(stream, detail::chunk_encode_final(), ec);
|
||||
if(ec)
|
||||
return;
|
||||
}
|
||||
@@ -437,7 +565,7 @@ template<class AsyncWriteStream,
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
async_write(AsyncWriteStream& stream,
|
||||
message<isRequest, Body, Headers> const& msg,
|
||||
message_v1<isRequest, Body, Headers> const& msg,
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
static_assert(
|
||||
@@ -450,6 +578,68 @@ async_write(AsyncWriteStream& stream,
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
class ostream_SyncStream
|
||||
{
|
||||
std::ostream& os_;
|
||||
|
||||
public:
|
||||
ostream_SyncStream(std::ostream& os)
|
||||
: os_(os)
|
||||
{
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(ConstBufferSequence const& buffers)
|
||||
{
|
||||
error_code ec;
|
||||
auto const n = write_some(buffers, ec);
|
||||
if(ec)
|
||||
throw boost::system::system_error{ec};
|
||||
return n;
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(ConstBufferSequence const& buffers,
|
||||
error_code& ec)
|
||||
{
|
||||
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 = boost::system::errc::make_error_code(
|
||||
boost::system::errc::no_stream_resources);
|
||||
break;
|
||||
}
|
||||
n += buffer_size(buffer);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os,
|
||||
message_v1<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
detail::ostream_SyncStream oss(os);
|
||||
error_code ec;
|
||||
write(oss, msg, ec);
|
||||
if(ec && ec != boost::asio::error::eof)
|
||||
throw boost::system::system_error{ec};
|
||||
return os;
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
|
||||
@@ -9,11 +9,7 @@
|
||||
#define BEAST_HTTP_MESSAGE_HPP
|
||||
|
||||
#include <beast/http/basic_headers.hpp>
|
||||
#include <beast/http/method.hpp>
|
||||
#include <beast/buffers_debug.hpp>
|
||||
#include <beast/type_check.hpp>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
@@ -23,7 +19,7 @@ namespace detail {
|
||||
|
||||
struct request_fields
|
||||
{
|
||||
http::method_t method;
|
||||
std::string method;
|
||||
std::string url;
|
||||
};
|
||||
|
||||
@@ -35,24 +31,6 @@ struct response_fields
|
||||
|
||||
} // detail
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
struct request_params
|
||||
{
|
||||
http::method_t method;
|
||||
std::string url;
|
||||
int version;
|
||||
};
|
||||
|
||||
struct response_params
|
||||
{
|
||||
int status;
|
||||
std::string reason;
|
||||
int version;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/** A HTTP message.
|
||||
|
||||
A message can be a request or response, depending on the `isRequest`
|
||||
@@ -73,62 +51,24 @@ struct message
|
||||
: std::conditional<isRequest,
|
||||
detail::request_fields, detail::response_fields>::type
|
||||
{
|
||||
/** The trait type characterizing the body.
|
||||
/** The type controlling the body traits.
|
||||
|
||||
The body member will be of type body_type::value_type.
|
||||
The body member will be of type `body_type::value_type`.
|
||||
*/
|
||||
using body_type = Body;
|
||||
|
||||
/// The type representing the headers.
|
||||
using headers_type = Headers;
|
||||
|
||||
/// Indicates if the message is a request.
|
||||
using is_request =
|
||||
std::integral_constant<bool, isRequest>;
|
||||
|
||||
int version; // 10 or 11
|
||||
/// The container holding the headers.
|
||||
headers_type headers;
|
||||
|
||||
/// A container representing the body.
|
||||
typename Body::value_type body;
|
||||
|
||||
message();
|
||||
message(message&&) = default;
|
||||
message(message const&) = default;
|
||||
message& operator=(message&&) = default;
|
||||
message& operator=(message const&) = default;
|
||||
|
||||
/** Construct a HTTP request.
|
||||
*/
|
||||
explicit
|
||||
message(request_params params);
|
||||
|
||||
/** Construct a HTTP response.
|
||||
*/
|
||||
explicit
|
||||
message(response_params params);
|
||||
|
||||
/// Serialize the request or response line to a Streambuf.
|
||||
template<class Streambuf>
|
||||
void
|
||||
write_firstline(Streambuf& streambuf) const
|
||||
{
|
||||
write_firstline(streambuf,
|
||||
std::integral_constant<bool, isRequest>{});
|
||||
}
|
||||
|
||||
/// Diagnostics only
|
||||
template<bool, class, class>
|
||||
friend
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os,
|
||||
message const& m);
|
||||
|
||||
private:
|
||||
template<class Streambuf>
|
||||
void
|
||||
write_firstline(Streambuf& streambuf,
|
||||
std::true_type) const;
|
||||
|
||||
template<class Streambuf>
|
||||
void
|
||||
write_firstline(Streambuf& streambuf,
|
||||
std::false_type) const;
|
||||
};
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
@@ -145,30 +85,7 @@ using response = message<false, Body, Headers>;
|
||||
|
||||
#endif
|
||||
|
||||
// For diagnostic output only
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os,
|
||||
message<isRequest, Body, Headers> const& m);
|
||||
|
||||
/// Write a FieldSequence to a Streambuf.
|
||||
template<class Streambuf, class FieldSequence>
|
||||
void
|
||||
write_fields(Streambuf& streambuf, FieldSequence const& fields);
|
||||
|
||||
/// Returns `true` if a message indicates a keep alive
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
bool
|
||||
is_keep_alive(message<isRequest, Body, Headers> const& msg);
|
||||
|
||||
/// Returns `true` if a message indicates a HTTP Upgrade request or response
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
bool
|
||||
is_upgrade(message<isRequest, Body, Headers> const& msg);
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#include <beast/http/impl/message.ipp>
|
||||
|
||||
#endif
|
||||
|
||||
130
src/beast/include/beast/http/message_v1.hpp
Normal file
130
src/beast/include/beast/http/message_v1.hpp
Normal file
@@ -0,0 +1,130 @@
|
||||
//
|
||||
// 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_MESSAGE_V1_HPP
|
||||
#define BEAST_HTTP_MESSAGE_V1_HPP
|
||||
|
||||
#include <beast/http/message.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
struct request_params
|
||||
{
|
||||
std::string method;
|
||||
std::string url;
|
||||
int version;
|
||||
};
|
||||
|
||||
struct response_params
|
||||
{
|
||||
int status;
|
||||
std::string reason;
|
||||
int version;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/** A HTTP/1 message.
|
||||
|
||||
A message can be a request or response, depending on the `isRequest`
|
||||
template argument value. Requests and responses have different types,
|
||||
so functions may be overloaded on them if desired.
|
||||
|
||||
The `Body` template argument type determines the model used
|
||||
to read or write the content body of the message.
|
||||
|
||||
@tparam isRequest `true` if this is a request.
|
||||
|
||||
@tparam Body A type meeting the requirements of Body.
|
||||
|
||||
@tparam Headers A type meeting the requirements of Headers.
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
struct message_v1 : message<isRequest, Body, Headers>
|
||||
{
|
||||
/// HTTP/1 version (10 or 11)
|
||||
int version;
|
||||
|
||||
message_v1() = default;
|
||||
|
||||
/// Construct a HTTP/1 request.
|
||||
explicit
|
||||
message_v1(request_params params);
|
||||
|
||||
/// Construct a HTTP/1 response.
|
||||
explicit
|
||||
message_v1(response_params params);
|
||||
};
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
/// A typical HTTP/1 request
|
||||
template<class Body,
|
||||
class Headers = basic_headers<std::allocator<char>>>
|
||||
using request_v1 = message_v1<true, Body, Headers>;
|
||||
|
||||
/// A typical HTTP/1 response
|
||||
template<class Body,
|
||||
class Headers = basic_headers<std::allocator<char>>>
|
||||
using response_v1 = message_v1<false, Body, Headers>;
|
||||
|
||||
#endif
|
||||
|
||||
/// Returns `true` if a HTTP/1 message indicates a keep alive
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
bool
|
||||
is_keep_alive(message_v1<isRequest, Body, Headers> const& msg);
|
||||
|
||||
/// Returns `true` if a HTTP/1 message indicates an Upgrade request or response
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
bool
|
||||
is_upgrade(message_v1<isRequest, Body, Headers> const& msg);
|
||||
|
||||
/** HTTP/1 connection prepare options.
|
||||
|
||||
@note These values are used with @ref prepare.
|
||||
*/
|
||||
enum class connection
|
||||
{
|
||||
/// Specify Connection: close.
|
||||
close,
|
||||
|
||||
/// Specify Connection: keep-alive where possible.
|
||||
keep_alive,
|
||||
|
||||
/// Specify Connection: upgrade.
|
||||
upgrade
|
||||
};
|
||||
|
||||
/** Prepare a HTTP/1 message.
|
||||
|
||||
This function will adjust the Content-Length, Transfer-Encoding,
|
||||
and Connection headers of the message based on the properties of
|
||||
the body and the options passed in.
|
||||
|
||||
@param msg The message to prepare. The headers may be modified.
|
||||
|
||||
@param options A list of prepare options.
|
||||
*/
|
||||
template<
|
||||
bool isRequest, class Body, class Headers,
|
||||
class... Options>
|
||||
void
|
||||
prepare(message_v1<isRequest, Body, Headers>& msg,
|
||||
Options&&... options);
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#include <beast/http/impl/message_v1.ipp>
|
||||
|
||||
#endif
|
||||
@@ -1,179 +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_METHOD_HPP
|
||||
#define BEAST_HTTP_METHOD_HPP
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
enum class method_t
|
||||
{
|
||||
http_delete,
|
||||
http_get,
|
||||
http_head,
|
||||
http_post,
|
||||
http_put,
|
||||
|
||||
// pathological
|
||||
http_connect,
|
||||
http_options,
|
||||
http_trace,
|
||||
|
||||
// webdav
|
||||
http_copy,
|
||||
http_lock,
|
||||
http_mkcol,
|
||||
http_move,
|
||||
http_propfind,
|
||||
http_proppatch,
|
||||
http_search,
|
||||
http_unlock,
|
||||
http_bind,
|
||||
http_rebind,
|
||||
http_unbind,
|
||||
http_acl,
|
||||
|
||||
// subversion
|
||||
http_report,
|
||||
http_mkactivity,
|
||||
http_checkout,
|
||||
http_merge,
|
||||
|
||||
// upnp
|
||||
http_msearch,
|
||||
http_notify,
|
||||
http_subscribe,
|
||||
http_unsubscribe,
|
||||
|
||||
// RFC-5789
|
||||
http_patch,
|
||||
http_purge,
|
||||
|
||||
// CalDav
|
||||
http_mkcalendar,
|
||||
|
||||
// RFC-2068, section 19.6.1.2
|
||||
http_link,
|
||||
http_unlink
|
||||
};
|
||||
|
||||
template<class = void>
|
||||
std::string
|
||||
to_string(method_t m)
|
||||
{
|
||||
switch(m)
|
||||
{
|
||||
case method_t::http_delete: return "DELETE";
|
||||
case method_t::http_get: return "GET";
|
||||
case method_t::http_head: return "HEAD";
|
||||
case method_t::http_post: return "POST";
|
||||
case method_t::http_put: return "PUT";
|
||||
|
||||
case method_t::http_connect: return "CONNECT";
|
||||
case method_t::http_options: return "OPTIONS";
|
||||
case method_t::http_trace: return "TRACE";
|
||||
|
||||
case method_t::http_copy: return "COPY";
|
||||
case method_t::http_lock: return "LOCK";
|
||||
case method_t::http_mkcol: return "MKCOL";
|
||||
case method_t::http_move: return "MOVE";
|
||||
case method_t::http_propfind: return "PROPFIND";
|
||||
case method_t::http_proppatch: return "PROPPATCH";
|
||||
case method_t::http_search: return "SEARCH";
|
||||
case method_t::http_unlock: return "UNLOCK";
|
||||
|
||||
case method_t::http_report: return "REPORT";
|
||||
case method_t::http_mkactivity: return "MKACTIVITY";
|
||||
case method_t::http_checkout: return "CHECKOUT";
|
||||
case method_t::http_merge: return "MERGE";
|
||||
|
||||
case method_t::http_msearch: return "MSEARCH";
|
||||
case method_t::http_notify: return "NOTIFY";
|
||||
case method_t::http_subscribe: return "SUBSCRIBE";
|
||||
case method_t::http_unsubscribe: return "UNSUBSCRIBE";
|
||||
|
||||
case method_t::http_patch: return "PATCH";
|
||||
case method_t::http_purge: return "PURGE";
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
};
|
||||
|
||||
return "GET";
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
Stream&
|
||||
operator<< (Stream& s, method_t m)
|
||||
{
|
||||
return s << to_string(m);
|
||||
}
|
||||
|
||||
/** Returns the string corresponding to the numeric HTTP status code. */
|
||||
template<class = void>
|
||||
std::string
|
||||
status_text (int status)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
case 100: return "Continue";
|
||||
case 101: return "Switching Protocols";
|
||||
case 200: return "OK";
|
||||
case 201: return "Created";
|
||||
case 202: return "Accepted";
|
||||
case 203: return "Non-Authoritative Information";
|
||||
case 204: return "No Content";
|
||||
case 205: return "Reset Content";
|
||||
case 206: return "Partial Content";
|
||||
case 300: return "Multiple Choices";
|
||||
case 301: return "Moved Permanently";
|
||||
case 302: return "Found";
|
||||
case 303: return "See Other";
|
||||
case 304: return "Not Modified";
|
||||
case 305: return "Use Proxy";
|
||||
//case 306: return "<reserved>";
|
||||
case 307: return "Temporary Redirect";
|
||||
case 400: return "Bad Request";
|
||||
case 401: return "Unauthorized";
|
||||
case 402: return "Payment Required";
|
||||
case 403: return "Forbidden";
|
||||
case 404: return "Not Found";
|
||||
case 405: return "Method Not Allowed";
|
||||
case 406: return "Not Acceptable";
|
||||
case 407: return "Proxy Authentication Required";
|
||||
case 408: return "Request Timeout";
|
||||
case 409: return "Conflict";
|
||||
case 410: return "Gone";
|
||||
case 411: return "Length Required";
|
||||
case 412: return "Precondition Failed";
|
||||
case 413: return "Request Entity Too Large";
|
||||
case 414: return "Request-URI Too Long";
|
||||
case 415: return "Unsupported Media Type";
|
||||
case 416: return "Requested Range Not Satisfiable";
|
||||
case 417: return "Expectation Failed";
|
||||
case 500: return "Internal Server Error";
|
||||
case 501: return "Not Implemented";
|
||||
case 502: return "Bad Gateway";
|
||||
case 503: return "Service Unavailable";
|
||||
case 504: return "Gateway Timeout";
|
||||
case 505: return "HTTP Version Not Supported";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "Unknown HTTP status";
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -1,234 +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_PARSER_HPP
|
||||
#define BEAST_HTTP_PARSER_HPP
|
||||
|
||||
#include <beast/http/basic_parser.hpp>
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct parser_request
|
||||
{
|
||||
std::string method_;
|
||||
std::string uri_;
|
||||
};
|
||||
|
||||
struct parser_response
|
||||
{
|
||||
std::string reason_;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
class parser
|
||||
: public basic_parser<isRequest,
|
||||
parser<isRequest, Body, Headers>>
|
||||
, private std::conditional<isRequest,
|
||||
detail::parser_request, detail::parser_response>::type
|
||||
{
|
||||
using message_type =
|
||||
message<isRequest, Body, Headers>;
|
||||
|
||||
std::string field_;
|
||||
std::string value_;
|
||||
message_type m_;
|
||||
typename message_type::body_type::reader r_;
|
||||
|
||||
public:
|
||||
parser(parser&&) = default;
|
||||
|
||||
parser()
|
||||
: r_(m_)
|
||||
{
|
||||
}
|
||||
|
||||
message_type
|
||||
release()
|
||||
{
|
||||
return std::move(m_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class basic_parser<isRequest, parser>;
|
||||
|
||||
void flush()
|
||||
{
|
||||
if(! value_.empty())
|
||||
{
|
||||
rfc2616::trim_right_in_place(value_);
|
||||
// VFALCO could std::move
|
||||
m_.headers.insert(field_, value_);
|
||||
field_.clear();
|
||||
value_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
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_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());
|
||||
}
|
||||
|
||||
void set(std::true_type)
|
||||
{
|
||||
// VFALCO This is terrible for setting method
|
||||
auto m =
|
||||
[&](char const* s, method_t m)
|
||||
{
|
||||
if(this->method_ == s)
|
||||
{
|
||||
m_.method = m;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
do
|
||||
{
|
||||
if(m("DELETE", method_t::http_delete))
|
||||
break;
|
||||
if(m("GET", method_t::http_get))
|
||||
break;
|
||||
if(m("HEAD", method_t::http_head))
|
||||
break;
|
||||
if(m("POST", method_t::http_post))
|
||||
break;
|
||||
if(m("PUT", method_t::http_put))
|
||||
break;
|
||||
if(m("CONNECT", method_t::http_connect))
|
||||
break;
|
||||
if(m("OPTIONS", method_t::http_options))
|
||||
break;
|
||||
if(m("TRACE", method_t::http_trace))
|
||||
break;
|
||||
if(m("COPY", method_t::http_copy))
|
||||
break;
|
||||
if(m("LOCK", method_t::http_lock))
|
||||
break;
|
||||
if(m("MKCOL", method_t::http_mkcol))
|
||||
break;
|
||||
if(m("MOVE", method_t::http_move))
|
||||
break;
|
||||
if(m("PROPFIND", method_t::http_propfind))
|
||||
break;
|
||||
if(m("PROPPATCH", method_t::http_proppatch))
|
||||
break;
|
||||
if(m("SEARCH", method_t::http_search))
|
||||
break;
|
||||
if(m("UNLOCK", method_t::http_unlock))
|
||||
break;
|
||||
if(m("BIND", method_t::http_bind))
|
||||
break;
|
||||
if(m("REBID", method_t::http_rebind))
|
||||
break;
|
||||
if(m("UNBIND", method_t::http_unbind))
|
||||
break;
|
||||
if(m("ACL", method_t::http_acl))
|
||||
break;
|
||||
if(m("REPORT", method_t::http_report))
|
||||
break;
|
||||
if(m("MKACTIVITY", method_t::http_mkactivity))
|
||||
break;
|
||||
if(m("CHECKOUT", method_t::http_checkout))
|
||||
break;
|
||||
if(m("MERGE", method_t::http_merge))
|
||||
break;
|
||||
if(m("MSEARCH", method_t::http_msearch))
|
||||
break;
|
||||
if(m("NOTIFY", method_t::http_notify))
|
||||
break;
|
||||
if(m("SUBSCRIBE", method_t::http_subscribe))
|
||||
break;
|
||||
if(m("UNSUBSCRIBE",method_t::http_unsubscribe))
|
||||
break;
|
||||
if(m("PATCH", method_t::http_patch))
|
||||
break;
|
||||
if(m("PURGE", method_t::http_purge))
|
||||
break;
|
||||
if(m("MKCALENDAR", method_t::http_mkcalendar))
|
||||
break;
|
||||
if(m("LINK", method_t::http_link))
|
||||
break;
|
||||
if(m("UNLINK", method_t::http_unlink))
|
||||
break;
|
||||
}
|
||||
while(false);
|
||||
|
||||
m_.url = std::move(this->uri_);
|
||||
|
||||
}
|
||||
|
||||
void set(std::false_type)
|
||||
{
|
||||
m_.status = this->status_code();
|
||||
m_.reason = this->reason_;
|
||||
}
|
||||
|
||||
int on_headers(error_code&)
|
||||
{
|
||||
flush();
|
||||
m_.version = 10 * this->http_major() + this->http_minor();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void on_request(error_code& ec)
|
||||
{
|
||||
set(std::integral_constant<
|
||||
bool, isRequest>{});
|
||||
}
|
||||
|
||||
void on_response(error_code& ec)
|
||||
{
|
||||
set(std::integral_constant<
|
||||
bool, isRequest>{});
|
||||
}
|
||||
|
||||
void on_body(boost::string_ref const& s, error_code& ec)
|
||||
{
|
||||
r_.write(s.data(), s.size(), ec);
|
||||
}
|
||||
|
||||
void on_complete(error_code&)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
157
src/beast/include/beast/http/parser_v1.hpp
Normal file
157
src/beast/include/beast/http/parser_v1.hpp
Normal file
@@ -0,0 +1,157 @@
|
||||
//
|
||||
// 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_PARSER_V1_HPP
|
||||
#define BEAST_HTTP_PARSER_V1_HPP
|
||||
|
||||
#include <beast/http/basic_parser_v1.hpp>
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct parser_request
|
||||
{
|
||||
std::string method_;
|
||||
std::string uri_;
|
||||
};
|
||||
|
||||
struct parser_response
|
||||
{
|
||||
std::string reason_;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
/** A parser for producing HTTP/1 messages.
|
||||
|
||||
This class uses the basic HTTP/1 wire format parser to convert
|
||||
a series of octets into a `message_v1`.
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
class parser_v1
|
||||
: public basic_parser_v1<isRequest,
|
||||
parser_v1<isRequest, Body, Headers>>
|
||||
, private std::conditional<isRequest,
|
||||
detail::parser_request, detail::parser_response>::type
|
||||
{
|
||||
using message_type =
|
||||
message_v1<isRequest, Body, Headers>;
|
||||
|
||||
std::string field_;
|
||||
std::string value_;
|
||||
message_type m_;
|
||||
typename message_type::body_type::reader r_;
|
||||
|
||||
public:
|
||||
parser_v1(parser_v1&&) = default;
|
||||
|
||||
parser_v1()
|
||||
: r_(m_)
|
||||
{
|
||||
}
|
||||
|
||||
message_type
|
||||
release()
|
||||
{
|
||||
return std::move(m_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class basic_parser_v1<isRequest, parser_v1>;
|
||||
|
||||
void flush()
|
||||
{
|
||||
if(! value_.empty())
|
||||
{
|
||||
rfc2616::trim_right_in_place(value_);
|
||||
// VFALCO could std::move
|
||||
m_.headers.insert(field_, value_);
|
||||
field_.clear();
|
||||
value_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
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_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());
|
||||
}
|
||||
|
||||
void set(std::true_type)
|
||||
{
|
||||
m_.method = std::move(this->method_);
|
||||
m_.url = std::move(this->uri_);
|
||||
}
|
||||
|
||||
void set(std::false_type)
|
||||
{
|
||||
m_.status = this->status_code();
|
||||
m_.reason = std::move(this->reason_);
|
||||
}
|
||||
|
||||
int on_headers(error_code&)
|
||||
{
|
||||
flush();
|
||||
m_.version = 10 * this->http_major() + this->http_minor();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void on_request(error_code& ec)
|
||||
{
|
||||
set(std::integral_constant<
|
||||
bool, isRequest>{});
|
||||
}
|
||||
|
||||
void on_response(error_code& ec)
|
||||
{
|
||||
set(std::integral_constant<
|
||||
bool, isRequest>{});
|
||||
}
|
||||
|
||||
void on_body(boost::string_ref const& s, error_code& ec)
|
||||
{
|
||||
r_.write(s.data(), s.size(), ec);
|
||||
}
|
||||
|
||||
void on_complete(error_code&)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -8,34 +8,46 @@
|
||||
#ifndef BEAST_HTTP_READ_HPP
|
||||
#define BEAST_HTTP_READ_HPP
|
||||
|
||||
#include <beast/async_completion.hpp>
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/parser.hpp>
|
||||
#include <beast/http/parser_v1.hpp>
|
||||
#include <beast/async_completion.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** Read a HTTP message from a stream.
|
||||
/** Read a HTTP/1 message from a stream.
|
||||
|
||||
@param stream The stream to read the message from.
|
||||
This function is used to synchronously read a message from
|
||||
the stream. The call blocks until one of the following conditions
|
||||
is true:
|
||||
|
||||
@param streambuf A Streambuf used to hold unread bytes. The
|
||||
implementation may read past the end of the message. The extra
|
||||
bytes are stored here, to be presented in a subsequent call to
|
||||
read.
|
||||
@li A complete message is read in.
|
||||
|
||||
@param msg An object used to store the read message. Any
|
||||
@li An error occurs on the stream.
|
||||
|
||||
This function is implemented in terms of one or more calls to the
|
||||
stream's `read_some` function.
|
||||
|
||||
@param stream The stream to which the data is to be written.
|
||||
The type must support the @b `SyncReadStream` concept.
|
||||
|
||||
@param streambuf An object meeting the @b `Streambuf` type requirements
|
||||
used to hold unread bytes. The implementation may read past the end of
|
||||
the message. The extra bytes are stored here, to be presented in a
|
||||
subsequent call to @ref read.
|
||||
|
||||
@param msg An object used to store the message. Any
|
||||
contents will be overwritten.
|
||||
|
||||
@throws boost::system::system_error on failure.
|
||||
@throws boost::system::system_error Thrown on failure.
|
||||
*/
|
||||
template<class SyncReadStream, class Streambuf,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
message<isRequest, Body, Headers>& msg)
|
||||
message_v1<isRequest, Body, Headers>& msg)
|
||||
{
|
||||
error_code ec;
|
||||
read(stream, streambuf, msg, ec);
|
||||
@@ -43,17 +55,29 @@ read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
throw boost::system::system_error{ec};
|
||||
}
|
||||
|
||||
/** Read a HTTP message from a stream.
|
||||
/** Read a HTTP/1 message from a stream.
|
||||
|
||||
@param stream The stream to read the message from.
|
||||
This function is used to synchronously read a message from
|
||||
the stream. The call blocks until one of the following conditions
|
||||
is true:
|
||||
|
||||
@param streambuf A Streambuf used to hold unread bytes. The
|
||||
implementation may read past the end of the message. The extra
|
||||
bytes are stored here, to be presented in a subsequent call to
|
||||
read.
|
||||
@li A complete message is read in.
|
||||
|
||||
@param msg An object used to store the read message. Any
|
||||
contents will be overwritten.
|
||||
@li An error occurs on the stream.
|
||||
|
||||
This function is implemented in terms of one or more calls to the
|
||||
stream's `read_some` function.
|
||||
|
||||
@param stream The stream to which the data is to be written.
|
||||
The type must support the @b `SyncReadStream` concept.
|
||||
|
||||
@param streambuf An object meeting the @b `Streambuf` type requirements
|
||||
used to hold unread bytes. The implementation may read past the end of
|
||||
the message. The extra bytes are stored here, to be presented in a
|
||||
subsequent call to @ref read.
|
||||
|
||||
@param msg An object used to store the message. Any contents
|
||||
will be overwritten.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
@@ -61,20 +85,34 @@ template<class SyncReadStream, class Streambuf,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
message<isRequest, Body, Headers>& msg,
|
||||
message_v1<isRequest, Body, Headers>& msg,
|
||||
error_code& ec);
|
||||
|
||||
/** Start reading a HTTP message from a stream asynchronously.
|
||||
/** Start an asynchronous operation to read a HTTP/1 message from a stream.
|
||||
|
||||
This function is used to asynchronously read a message from the
|
||||
stream. The function call always returns immediately. The asynchronous
|
||||
operation will continue until one of the following conditions is true:
|
||||
|
||||
@li A complete message is read in.
|
||||
|
||||
@li An error occurs on the stream.
|
||||
|
||||
This operation is implemented in terms of one or more calls to the
|
||||
next layer's `async_read_some` function, and is known as a
|
||||
<em>composed operation</em>. The program must ensure that the stream
|
||||
performs no other operations until this operation completes.
|
||||
|
||||
@param stream The stream to read the message from.
|
||||
The type must support the @b `AsyncReadStream` concept.
|
||||
|
||||
@param streambuf A Streambuf used to hold unread bytes. The
|
||||
implementation may read past the end of the message. The extra
|
||||
bytes are stored here, to be presented in a subsequent call to
|
||||
async_read.
|
||||
@ref async_read.
|
||||
|
||||
@param msg An object used to store the read message. Any
|
||||
contents will be overwritten.
|
||||
@param msg An object used to store the message. Any contents
|
||||
will be overwritten.
|
||||
|
||||
@param handler The handler to be called when the request completes.
|
||||
Copies will be made of the handler as required. The equivalent
|
||||
@@ -85,7 +123,7 @@ read(SyncReadStream& stream, Streambuf& streambuf,
|
||||
Regardless of whether the asynchronous operation completes
|
||||
immediately or not, the handler will not be invoked from within
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using boost::asio::io_service::post().
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class AsyncReadStream, class Streambuf,
|
||||
bool isRequest, class Body, class Headers,
|
||||
@@ -97,7 +135,7 @@ typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_read(AsyncReadStream& stream, Streambuf& streambuf,
|
||||
message<isRequest, Body, Headers>& msg,
|
||||
message_v1<isRequest, Body, Headers>& msg,
|
||||
ReadHandler&& handler);
|
||||
|
||||
} // http
|
||||
|
||||
71
src/beast/include/beast/http/status.hpp
Normal file
71
src/beast/include/beast/http/status.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// 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_STATUS_HPP
|
||||
#define BEAST_HTTP_STATUS_HPP
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** Returns the string corresponding to the numeric HTTP status code. */
|
||||
template<class = void>
|
||||
char const*
|
||||
status_text(int status)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
case 100: return "Continue";
|
||||
case 101: return "Switching Protocols";
|
||||
case 200: return "OK";
|
||||
case 201: return "Created";
|
||||
case 202: return "Accepted";
|
||||
case 203: return "Non-Authoritative Information";
|
||||
case 204: return "No Content";
|
||||
case 205: return "Reset Content";
|
||||
case 206: return "Partial Content";
|
||||
case 300: return "Multiple Choices";
|
||||
case 301: return "Moved Permanently";
|
||||
case 302: return "Found";
|
||||
case 303: return "See Other";
|
||||
case 304: return "Not Modified";
|
||||
case 305: return "Use Proxy";
|
||||
// case 306: return "<reserved>";
|
||||
case 307: return "Temporary Redirect";
|
||||
case 400: return "Bad Request";
|
||||
case 401: return "Unauthorized";
|
||||
case 402: return "Payment Required";
|
||||
case 403: return "Forbidden";
|
||||
case 404: return "Not Found";
|
||||
case 405: return "Method Not Allowed";
|
||||
case 406: return "Not Acceptable";
|
||||
case 407: return "Proxy Authentication Required";
|
||||
case 408: return "Request Timeout";
|
||||
case 409: return "Conflict";
|
||||
case 410: return "Gone";
|
||||
case 411: return "Length Required";
|
||||
case 412: return "Precondition Failed";
|
||||
case 413: return "Request Entity Too Large";
|
||||
case 414: return "Request-URI Too Long";
|
||||
case 415: return "Unsupported Media Type";
|
||||
case 416: return "Requested Range Not Satisfiable";
|
||||
case 417: return "Expectation Failed";
|
||||
case 500: return "Internal Server Error";
|
||||
case 501: return "Not Implemented";
|
||||
case 502: return "Bad Gateway";
|
||||
case 503: return "Service Unavailable";
|
||||
case 504: return "Gateway Timeout";
|
||||
case 505: return "HTTP Version Not Supported";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "Unknown HTTP status";
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -8,8 +8,7 @@
|
||||
#ifndef BEAST_HTTP_STREAMBUF_BODY_HPP
|
||||
#define BEAST_HTTP_STREAMBUF_BODY_HPP
|
||||
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/buffer_cat.hpp>
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <memory>
|
||||
@@ -18,7 +17,9 @@
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** A Body represented by a Streambuf
|
||||
/** A message body represented by a Streambuf
|
||||
|
||||
Meets the requirements of @b `Body`.
|
||||
*/
|
||||
template<class Streambuf>
|
||||
struct basic_streambuf_body
|
||||
@@ -35,10 +36,10 @@ private:
|
||||
value_type& sb_;
|
||||
|
||||
public:
|
||||
template<bool isRequest, class Allocator>
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
reader(message<isRequest,
|
||||
basic_streambuf_body, Allocator>& m) noexcept
|
||||
basic_streambuf_body, Headers>& m) noexcept
|
||||
: sb_(m.body)
|
||||
{
|
||||
}
|
||||
@@ -59,10 +60,13 @@ private:
|
||||
Streambuf const& body_;
|
||||
|
||||
public:
|
||||
template<bool isRequest, class Allocator>
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
writer(message<isRequest, basic_streambuf_body,
|
||||
Allocator> const& m)
|
||||
writer(message<
|
||||
isRequest, basic_streambuf_body, Headers> const& m)
|
||||
: body_(m.body)
|
||||
{
|
||||
}
|
||||
@@ -72,7 +76,7 @@ private:
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
{
|
||||
return body_.size();
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
#ifndef BEAST_HTTP_STRING_BODY_HPP
|
||||
#define BEAST_HTTP_STRING_BODY_HPP
|
||||
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/buffer_cat.hpp>
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <memory>
|
||||
@@ -20,6 +18,8 @@ namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** A Body represented by a std::string.
|
||||
|
||||
Meets the requirements of @b `Body`.
|
||||
*/
|
||||
struct string_body
|
||||
{
|
||||
@@ -35,10 +35,10 @@ private:
|
||||
value_type& s_;
|
||||
|
||||
public:
|
||||
template<bool isRequest, class Allocator>
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
reader(message<isRequest,
|
||||
string_body, Allocator>& m) noexcept
|
||||
string_body, Headers>& m) noexcept
|
||||
: s_(m.body)
|
||||
{
|
||||
}
|
||||
@@ -58,9 +58,13 @@ private:
|
||||
value_type const& body_;
|
||||
|
||||
public:
|
||||
template<bool isRequest, class Allocator>
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
writer(message<isRequest, string_body, Allocator> const& msg)
|
||||
writer(message<
|
||||
isRequest, string_body, Headers> const& msg)
|
||||
: body_(msg.body)
|
||||
{
|
||||
}
|
||||
@@ -70,7 +74,7 @@ private:
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
{
|
||||
return body_.size();
|
||||
|
||||
62
src/beast/include/beast/http/type_check.hpp
Normal file
62
src/beast/include/beast/http/type_check.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// 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_TYPE_CHECK_HPP
|
||||
#define BEAST_HTTP_TYPE_CHECK_HPP
|
||||
|
||||
#include <beast/http/error.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/// Determine if `T` meets the requirements of `Parser`.
|
||||
template<class T>
|
||||
class is_Parser
|
||||
{
|
||||
template<class U, class R =
|
||||
std::is_convertible<decltype(
|
||||
std::declval<U>().complete()),
|
||||
bool>>
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class U, class R =
|
||||
std::is_convertible<decltype(
|
||||
std::declval<U>().write(
|
||||
std::declval<boost::asio::const_buffer const&>(),
|
||||
std::declval<error_code&>())),
|
||||
std::size_t>>
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
template<class U, class R =
|
||||
std::is_convertible<decltype(
|
||||
std::declval<U>().write_eof(
|
||||
std::declval<error_code&>())),
|
||||
std::size_t>>
|
||||
static R check3(int);
|
||||
template<class>
|
||||
static std::false_type check3(...);
|
||||
using type3 = decltype(check3<T>(0));
|
||||
|
||||
public:
|
||||
/// `true` if `T` meets the requirements.
|
||||
static bool const value =
|
||||
type1::value && type2::value && type3::value;
|
||||
};
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -9,39 +9,68 @@
|
||||
#define BEAST_HTTP_WRITE_HPP
|
||||
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <beast/async_completion.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** Write a HTTP message to a stream.
|
||||
/** Write a HTTP/1 message on a stream.
|
||||
|
||||
@param stream The stream to send the message on.
|
||||
This function is used to write a message to a stream. The call
|
||||
will block until one of the following conditions is true:
|
||||
|
||||
@param msg The message to send.
|
||||
@li The entire message is sent.
|
||||
|
||||
@throws boost::system::error code on failure.
|
||||
@li An error occurs.
|
||||
|
||||
This operation is implemented in terms of one or more calls
|
||||
to the stream's `write_some` function.
|
||||
|
||||
The implementation will automatically perform chunk encoding if
|
||||
the contents of the message indicate that chunk encoding is required.
|
||||
If the semantics of the message indicate that the connection should
|
||||
be closed after the message is sent, the error returns from this
|
||||
function will be `boost::asio::error::eof`.
|
||||
|
||||
@param stream The stream to which the data is to be written.
|
||||
The type must support the @b `SyncWriteStream` concept.
|
||||
|
||||
@param msg The message to write.
|
||||
|
||||
@throws boost::system::error Thrown on failure.
|
||||
*/
|
||||
template<class SyncWriteStream,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
write(SyncWriteStream& stream,
|
||||
message<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
error_code ec;
|
||||
write(stream, msg, ec);
|
||||
if(ec)
|
||||
throw boost::system::system_error{ec};
|
||||
}
|
||||
message_v1<isRequest, Body, Headers> const& msg);
|
||||
|
||||
/** Write a HTTP message to a stream.
|
||||
/** Write a HTTP/1 message on a stream.
|
||||
|
||||
@param stream The stream to send the message on.
|
||||
This function is used to write a message to a stream. The call
|
||||
will block until one of the following conditions is true:
|
||||
|
||||
@param msg The message to send.
|
||||
@li The entire message is sent.
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
This operation is implemented in terms of one or more calls
|
||||
to the stream's `write_some` function.
|
||||
|
||||
The implementation will automatically perform chunk encoding if
|
||||
the contents of the message indicate that chunk encoding is required.
|
||||
If the semantics of the message indicate that the connection should
|
||||
be closed after the message is sent, the error returns from this
|
||||
function will be `boost::asio::error::eof`.
|
||||
|
||||
@param stream The stream to which the data is to be written.
|
||||
The type must support the @b `SyncWriteStream` concept.
|
||||
|
||||
@param msg The message to write.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
@@ -49,16 +78,38 @@ template<class SyncWriteStream,
|
||||
bool isRequest, class Body, class Headers>
|
||||
void
|
||||
write(SyncWriteStream& stream,
|
||||
message<isRequest, Body, Headers> const& msg,
|
||||
message_v1<isRequest, Body, Headers> const& msg,
|
||||
error_code& ec);
|
||||
|
||||
/** Start writing a HTTP message to a stream asynchronously.
|
||||
/** Start an asynchronous operation to write a HTTP/1 message to a stream.
|
||||
|
||||
@param stream The stream to send the message on.
|
||||
This function is used to asynchronously write a message to a stream.
|
||||
The function call always returns immediately. The asynchronous
|
||||
operation will continue until one of the following conditions is true:
|
||||
|
||||
@li The entire message is sent.
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
This operation is implemented in terms of one or more calls to the
|
||||
stream's `async_write_some` functions, and is known as a <em>composed
|
||||
operation</em>. The program must ensure that the stream performs no
|
||||
other write operations (such as @ref async_write, the stream's
|
||||
`async_write_some` function, or any other composed operations that
|
||||
perform writes) until this operation completes.
|
||||
|
||||
The implementation will automatically perform chunk encoding if
|
||||
the contents of the message indicate that chunk encoding is required.
|
||||
If the semantics of the message indicate that the connection should
|
||||
be closed after the message is sent, the operation will complete with
|
||||
the error set to `boost::asio::error::eof`.
|
||||
|
||||
@param stream The stream to which the data is to be written.
|
||||
The type must support the @b `AsyncWriteStream` concept.
|
||||
|
||||
@param msg The message to send.
|
||||
|
||||
@param token The handler to be called when the request completes.
|
||||
@param handler The handler to be called when the request completes.
|
||||
Copies will be made of the handler as required. The equivalent
|
||||
function signature of the handler must be:
|
||||
@code void handler(
|
||||
@@ -67,9 +118,9 @@ write(SyncWriteStream& stream,
|
||||
Regardless of whether the asynchronous operation completes
|
||||
immediately or not, the handler will not be invoked from within
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using boost::asio::io_service::post().
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
|
||||
@note The message must remain valid at least until the
|
||||
@note The message object must remain valid at least until the
|
||||
completion handler is called, no copies are made.
|
||||
*/
|
||||
template<class AsyncWriteStream,
|
||||
@@ -82,9 +133,26 @@ typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_write(AsyncWriteStream& stream,
|
||||
message<isRequest, Body, Headers> const& msg,
|
||||
message_v1<isRequest, Body, Headers> const& msg,
|
||||
WriteHandler&& handler);
|
||||
|
||||
/** Serialize a HTTP/1 message to an ostream.
|
||||
|
||||
The function converts the message to its HTTP/1 serialized
|
||||
representation and stores the result in the output stream.
|
||||
|
||||
The implementation will automatically perform chunk encoding if
|
||||
the contents of the message indicate that chunk encoding is required.
|
||||
|
||||
@param os The ostream to write to.
|
||||
|
||||
@param msg The message to write.
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os,
|
||||
message_v1<isRequest, Body, Headers> const& msg);
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef BEAST_IMPL_BASIC_STREAMBUF_IPP
|
||||
#define BEAST_IMPL_BASIC_STREAMBUF_IPP
|
||||
|
||||
#include <beast/detail/write_streambuf.hpp>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
@@ -118,7 +119,7 @@ public:
|
||||
template<class Allocator>
|
||||
class basic_streambuf<Allocator>::const_buffers_type
|
||||
{
|
||||
basic_streambuf const* sb_ = nullptr;
|
||||
basic_streambuf const* sb_;
|
||||
|
||||
friend class basic_streambuf;
|
||||
|
||||
@@ -126,12 +127,12 @@ class basic_streambuf<Allocator>::const_buffers_type
|
||||
const_buffers_type(basic_streambuf const& sb);
|
||||
|
||||
public:
|
||||
/// Why?
|
||||
// Why?
|
||||
using value_type = boost::asio::const_buffer;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
const_buffers_type() = default;
|
||||
const_buffers_type() = delete;
|
||||
const_buffers_type(const_buffers_type const&) = default;
|
||||
const_buffers_type& operator=(const_buffers_type const&) = default;
|
||||
|
||||
@@ -157,7 +158,7 @@ public:
|
||||
|
||||
class const_iterator;
|
||||
|
||||
mutable_buffers_type() = default;
|
||||
mutable_buffers_type() = delete;
|
||||
mutable_buffers_type(mutable_buffers_type const&) = default;
|
||||
mutable_buffers_type& operator=(mutable_buffers_type const&) = default;
|
||||
|
||||
@@ -849,22 +850,6 @@ basic_streambuf<Allocator>::debug_check() const
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class Alloc, class T>
|
||||
basic_streambuf<Alloc>&
|
||||
operator<<(basic_streambuf<Alloc>& streambuf, T const& t)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
std::stringstream ss;
|
||||
ss << t;
|
||||
auto const& s = ss.str();
|
||||
streambuf.commit(buffer_copy(
|
||||
streambuf.prepare(s.size()), buffer(s)));
|
||||
return streambuf;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
std::size_t
|
||||
read_size_helper(basic_streambuf<
|
||||
@@ -874,17 +859,12 @@ read_size_helper(basic_streambuf<
|
||||
std::max<std::size_t>(512, streambuf.prepare_size()));
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
std::string
|
||||
to_string(basic_streambuf<Allocator> const& streambuf)
|
||||
template<class Alloc, class T>
|
||||
basic_streambuf<Alloc>&
|
||||
operator<<(basic_streambuf<Alloc>& streambuf, T const& t)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
std::string s;
|
||||
s.resize(streambuf.size());
|
||||
buffer_copy(
|
||||
buffer(&s[0], s.size()), streambuf.data());
|
||||
return s;
|
||||
detail::write_streambuf(streambuf, t);
|
||||
return streambuf;
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
template<class Buffers>
|
||||
class buffers_adapter<Buffers>::const_buffers_type
|
||||
template<class MutableBufferSequence>
|
||||
class buffers_adapter<MutableBufferSequence>::
|
||||
const_buffers_type
|
||||
{
|
||||
buffers_adapter const* ba_;
|
||||
|
||||
@@ -27,7 +28,7 @@ public:
|
||||
|
||||
class const_iterator;
|
||||
|
||||
const_buffers_type() = default;
|
||||
const_buffers_type() = delete;
|
||||
const_buffers_type(
|
||||
const_buffers_type const&) = default;
|
||||
const_buffers_type& operator=(
|
||||
@@ -48,11 +49,12 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template<class Buffers>
|
||||
class buffers_adapter<Buffers>::const_buffers_type::const_iterator
|
||||
template<class MutableBufferSequence>
|
||||
class buffers_adapter<MutableBufferSequence>::
|
||||
const_buffers_type::const_iterator
|
||||
{
|
||||
iter_type it_;
|
||||
buffers_adapter const* ba_;
|
||||
buffers_adapter const* ba_ = nullptr;
|
||||
|
||||
public:
|
||||
using value_type = boost::asio::const_buffer;
|
||||
@@ -136,19 +138,19 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
inline
|
||||
auto
|
||||
buffers_adapter<Buffers>::const_buffers_type::begin() const ->
|
||||
buffers_adapter<MutableBufferSequence>::const_buffers_type::begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*ba_, ba_->begin_};
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
inline
|
||||
auto
|
||||
buffers_adapter<Buffers>::const_buffers_type::end() const ->
|
||||
buffers_adapter<MutableBufferSequence>::const_buffers_type::end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*ba_, ba_->out_ ==
|
||||
@@ -157,8 +159,9 @@ buffers_adapter<Buffers>::const_buffers_type::end() const ->
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Buffers>
|
||||
class buffers_adapter<Buffers>::mutable_buffers_type
|
||||
template<class MutableBufferSequence>
|
||||
class buffers_adapter<MutableBufferSequence>::
|
||||
mutable_buffers_type
|
||||
{
|
||||
buffers_adapter const* ba_;
|
||||
|
||||
@@ -167,7 +170,7 @@ public:
|
||||
|
||||
class const_iterator;
|
||||
|
||||
mutable_buffers_type() = default;
|
||||
mutable_buffers_type() = delete;
|
||||
mutable_buffers_type(
|
||||
mutable_buffers_type const&) = default;
|
||||
mutable_buffers_type& operator=(
|
||||
@@ -189,11 +192,12 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template<class Buffers>
|
||||
class buffers_adapter<Buffers>::mutable_buffers_type::const_iterator
|
||||
template<class MutableBufferSequence>
|
||||
class buffers_adapter<MutableBufferSequence>::
|
||||
mutable_buffers_type::const_iterator
|
||||
{
|
||||
iter_type it_;
|
||||
buffers_adapter const* ba_;
|
||||
buffers_adapter const* ba_ = nullptr;
|
||||
|
||||
public:
|
||||
using value_type = boost::asio::mutable_buffer;
|
||||
@@ -277,19 +281,19 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
inline
|
||||
auto
|
||||
buffers_adapter<Buffers>::mutable_buffers_type::begin() const ->
|
||||
buffers_adapter<MutableBufferSequence>::mutable_buffers_type::begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*ba_, ba_->out_};
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
inline
|
||||
auto
|
||||
buffers_adapter<Buffers>::mutable_buffers_type::end() const ->
|
||||
buffers_adapter<MutableBufferSequence>::mutable_buffers_type::end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*ba_, ba_->end_};
|
||||
@@ -297,8 +301,8 @@ buffers_adapter<Buffers>::mutable_buffers_type::end() const ->
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Buffers>
|
||||
buffers_adapter<Buffers>::buffers_adapter(
|
||||
template<class MutableBufferSequence>
|
||||
buffers_adapter<MutableBufferSequence>::buffers_adapter(
|
||||
buffers_adapter&& other)
|
||||
: buffers_adapter(std::move(other),
|
||||
std::distance<iter_type>(other.bs_.begin(), other.begin_),
|
||||
@@ -307,8 +311,8 @@ buffers_adapter<Buffers>::buffers_adapter(
|
||||
{
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
buffers_adapter<Buffers>::buffers_adapter(
|
||||
template<class MutableBufferSequence>
|
||||
buffers_adapter<MutableBufferSequence>::buffers_adapter(
|
||||
buffers_adapter const& other)
|
||||
: buffers_adapter(other,
|
||||
std::distance<iter_type>(other.bs_.begin(), other.begin_),
|
||||
@@ -317,9 +321,9 @@ buffers_adapter<Buffers>::buffers_adapter(
|
||||
{
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
auto
|
||||
buffers_adapter<Buffers>::operator=(
|
||||
buffers_adapter<MutableBufferSequence>::operator=(
|
||||
buffers_adapter&& other) -> buffers_adapter&
|
||||
{
|
||||
auto const nbegin = std::distance<iter_type>(
|
||||
@@ -340,9 +344,9 @@ buffers_adapter<Buffers>::operator=(
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
auto
|
||||
buffers_adapter<Buffers>::operator=(
|
||||
buffers_adapter<MutableBufferSequence>::operator=(
|
||||
buffers_adapter const& other) -> buffers_adapter&
|
||||
{
|
||||
auto const nbegin = std::distance<iter_type>(
|
||||
@@ -363,9 +367,9 @@ buffers_adapter<Buffers>::operator=(
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
buffers_adapter<Buffers>::buffers_adapter(
|
||||
Buffers const& bs)
|
||||
template<class MutableBufferSequence>
|
||||
buffers_adapter<MutableBufferSequence>::buffers_adapter(
|
||||
MutableBufferSequence const& bs)
|
||||
: bs_(bs)
|
||||
, begin_(bs_.begin())
|
||||
, out_(bs_.begin())
|
||||
@@ -374,14 +378,12 @@ buffers_adapter<Buffers>::buffers_adapter(
|
||||
{
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
auto
|
||||
buffers_adapter<Buffers>::prepare(std::size_t n) ->
|
||||
buffers_adapter<MutableBufferSequence>::prepare(std::size_t n) ->
|
||||
mutable_buffers_type
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
static_assert(is_mutable,
|
||||
"Operation not valid for ConstBufferSequence");
|
||||
end_ = out_;
|
||||
if(end_ != bs_.end())
|
||||
{
|
||||
@@ -416,13 +418,11 @@ buffers_adapter<Buffers>::prepare(std::size_t n) ->
|
||||
return mutable_buffers_type{*this};
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
void
|
||||
buffers_adapter<Buffers>::commit(std::size_t n)
|
||||
buffers_adapter<MutableBufferSequence>::commit(std::size_t n)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
static_assert(is_mutable,
|
||||
"Operation not valid for ConstBufferSequence");
|
||||
if(out_ == end_)
|
||||
return;
|
||||
auto const last = std::prev(end_);
|
||||
@@ -456,18 +456,18 @@ buffers_adapter<Buffers>::commit(std::size_t n)
|
||||
}
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
inline
|
||||
auto
|
||||
buffers_adapter<Buffers>::data() const ->
|
||||
buffers_adapter<MutableBufferSequence>::data() const ->
|
||||
const_buffers_type
|
||||
{
|
||||
return const_buffers_type{*this};
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
template<class MutableBufferSequence>
|
||||
void
|
||||
buffers_adapter<Buffers>::consume(std::size_t n)
|
||||
buffers_adapter<MutableBufferSequence>::consume(std::size_t n)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef BEAST_IMPL_CONSUMING_BUFFERS_IPP
|
||||
#define BEAST_IMPL_CONSUMING_BUFFERS_IPP
|
||||
|
||||
#include <beast/type_check.hpp>
|
||||
#include <beast/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
@@ -18,16 +18,16 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
template<class Buffers, class ValueType>
|
||||
class consuming_buffers<Buffers, ValueType>::const_iterator
|
||||
template<class BufferSequence, class ValueType>
|
||||
class consuming_buffers<BufferSequence, ValueType>::const_iterator
|
||||
{
|
||||
friend class consuming_buffers<Buffers, ValueType>;
|
||||
friend class consuming_buffers<BufferSequence, ValueType>;
|
||||
|
||||
using iter_type =
|
||||
typename Buffers::const_iterator;
|
||||
typename BufferSequence::const_iterator;
|
||||
|
||||
iter_type it_;
|
||||
consuming_buffers const* b_;
|
||||
consuming_buffers const* b_ = nullptr;
|
||||
|
||||
public:
|
||||
using value_type =
|
||||
@@ -59,9 +59,8 @@ public:
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
if(it_ == b_->begin_)
|
||||
return *it_ + b_->skip_;
|
||||
return *it_;
|
||||
return it_ == b_->begin_ ?
|
||||
*it_ + b_->skip_ : *it_;
|
||||
}
|
||||
|
||||
pointer
|
||||
@@ -106,8 +105,8 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template<class Buffers, class ValueType>
|
||||
consuming_buffers<Buffers, ValueType>::
|
||||
template<class BufferSequence, class ValueType>
|
||||
consuming_buffers<BufferSequence, ValueType>::
|
||||
consuming_buffers(consuming_buffers&& other)
|
||||
: consuming_buffers(std::move(other),
|
||||
std::distance<iter_type>(
|
||||
@@ -115,8 +114,8 @@ consuming_buffers(consuming_buffers&& other)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Buffers, class ValueType>
|
||||
consuming_buffers<Buffers, ValueType>::
|
||||
template<class BufferSequence, class ValueType>
|
||||
consuming_buffers<BufferSequence, ValueType>::
|
||||
consuming_buffers(consuming_buffers const& other)
|
||||
: consuming_buffers(other,
|
||||
std::distance<iter_type>(
|
||||
@@ -124,9 +123,9 @@ consuming_buffers(consuming_buffers const& other)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Buffers, class ValueType>
|
||||
template<class BufferSequence, class ValueType>
|
||||
auto
|
||||
consuming_buffers<Buffers, ValueType>::
|
||||
consuming_buffers<BufferSequence, ValueType>::
|
||||
operator=(consuming_buffers&& other) ->
|
||||
consuming_buffers&
|
||||
{
|
||||
@@ -138,9 +137,9 @@ operator=(consuming_buffers&& other) ->
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Buffers, class ValueType>
|
||||
template<class BufferSequence, class ValueType>
|
||||
auto
|
||||
consuming_buffers<Buffers, ValueType>::
|
||||
consuming_buffers<BufferSequence, ValueType>::
|
||||
operator=(consuming_buffers const& other) ->
|
||||
consuming_buffers&
|
||||
{
|
||||
@@ -152,35 +151,35 @@ operator=(consuming_buffers const& other) ->
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Buffers, class ValueType>
|
||||
consuming_buffers<Buffers, ValueType>::
|
||||
consuming_buffers(Buffers const& bs)
|
||||
template<class BufferSequence, class ValueType>
|
||||
consuming_buffers<BufferSequence, ValueType>::
|
||||
consuming_buffers(BufferSequence const& bs)
|
||||
: bs_(bs)
|
||||
, begin_(bs_.begin())
|
||||
{
|
||||
static_assert(is_BufferSequence<Buffers, ValueType>::value,
|
||||
static_assert(is_BufferSequence<BufferSequence, ValueType>::value,
|
||||
"BufferSequence requirements not met");
|
||||
}
|
||||
|
||||
template<class Buffers, class ValueType>
|
||||
template<class BufferSequence, class ValueType>
|
||||
auto
|
||||
consuming_buffers<Buffers, ValueType>::begin() const ->
|
||||
consuming_buffers<BufferSequence, ValueType>::begin() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*this, begin_};
|
||||
}
|
||||
|
||||
template<class Buffers, class ValueType>
|
||||
template<class BufferSequence, class ValueType>
|
||||
auto
|
||||
consuming_buffers<Buffers, ValueType>::end() const ->
|
||||
consuming_buffers<BufferSequence, ValueType>::end() const ->
|
||||
const_iterator
|
||||
{
|
||||
return const_iterator{*this, bs_.end()};
|
||||
}
|
||||
|
||||
template<class Buffers, class ValueType>
|
||||
template<class BufferSequence, class ValueType>
|
||||
void
|
||||
consuming_buffers<Buffers, ValueType>::consume(std::size_t n)
|
||||
consuming_buffers<BufferSequence, ValueType>::consume(std::size_t n)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
for(;n > 0 && begin_ != bs_.end(); ++begin_)
|
||||
@@ -197,11 +196,11 @@ consuming_buffers<Buffers, ValueType>::consume(std::size_t n)
|
||||
}
|
||||
}
|
||||
|
||||
template<class Buffers>
|
||||
consuming_buffers<Buffers, typename Buffers::value_type>
|
||||
consumed_buffers(Buffers const& bs, 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<Buffers> cb(bs);
|
||||
consuming_buffers<BufferSequence> cb(bs);
|
||||
cb.consume(n);
|
||||
return cb;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ class prepared_buffers<BufferSequence>::const_iterator
|
||||
using iter_type =
|
||||
typename BufferSequence::const_iterator;
|
||||
|
||||
prepared_buffers const* b_;
|
||||
prepared_buffers const* b_ = nullptr;
|
||||
typename BufferSequence::const_iterator it_;
|
||||
|
||||
public:
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
|
||||
class const_iterator;
|
||||
|
||||
const_buffers_type() = default;
|
||||
const_buffers_type() = delete;
|
||||
const_buffers_type(
|
||||
const_buffers_type const&) = default;
|
||||
const_buffers_type& operator=(
|
||||
@@ -51,8 +51,8 @@ private:
|
||||
|
||||
class static_streambuf::const_buffers_type::const_iterator
|
||||
{
|
||||
std::size_t n_;
|
||||
std::uint8_t const* p_;
|
||||
std::size_t n_ = 0;
|
||||
std::uint8_t const* p_ = nullptr;
|
||||
|
||||
public:
|
||||
using value_type = boost::asio::const_buffer;
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
|
||||
class const_iterator;
|
||||
|
||||
mutable_buffers_type() = default;
|
||||
mutable_buffers_type() = delete;
|
||||
mutable_buffers_type(
|
||||
mutable_buffers_type const&) = default;
|
||||
mutable_buffers_type& operator=(
|
||||
@@ -183,8 +183,8 @@ private:
|
||||
|
||||
class static_streambuf::mutable_buffers_type::const_iterator
|
||||
{
|
||||
std::size_t n_;
|
||||
std::uint8_t* p_;
|
||||
std::size_t n_ = 0;
|
||||
std::uint8_t* p_ = nullptr;
|
||||
|
||||
public:
|
||||
using value_type = boost::asio::mutable_buffer;
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
#define BEAST_IMPL_STREAMBUF_READSTREAM_IPP
|
||||
|
||||
#include <beast/bind_handler.hpp>
|
||||
#include <beast/handler_concepts.hpp>
|
||||
#include <beast/handler_alloc.hpp>
|
||||
#include <beast/type_check.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
@@ -158,10 +160,6 @@ streambuf_readstream<Stream, Streambuf>::
|
||||
streambuf_readstream(Args&&... args)
|
||||
: next_layer_(std::forward<Args>(args)...)
|
||||
{
|
||||
static_assert(is_Stream<next_layer_type>::value,
|
||||
"Stream requirements not met");
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
}
|
||||
|
||||
template<class Stream, class Streambuf>
|
||||
@@ -173,10 +171,12 @@ async_write_some(ConstBufferSequence const& buffers,
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
{
|
||||
static_assert(is_AsyncWriteStream<next_layer_type>::value,
|
||||
"AsyncWriteStream requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
static_assert(is_Handler<WriteHandler,
|
||||
static_assert(is_CompletionHandler<WriteHandler,
|
||||
void(error_code, std::size_t)>::value,
|
||||
"WriteHandler requirements not met");
|
||||
return next_layer_.async_write_some(buffers,
|
||||
@@ -190,6 +190,8 @@ streambuf_readstream<Stream, Streambuf>::
|
||||
read_some(
|
||||
MutableBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_SyncReadStream<next_layer_type>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_MutableBufferSequence<
|
||||
MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
@@ -207,6 +209,8 @@ streambuf_readstream<Stream, Streambuf>::
|
||||
read_some(MutableBufferSequence const& buffers,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncReadStream<next_layer_type>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_MutableBufferSequence<
|
||||
MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
@@ -239,6 +243,8 @@ async_read_some(
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
{
|
||||
static_assert(is_AsyncReadStream<next_layer_type>::value,
|
||||
"Stream requirements not met");
|
||||
static_assert(is_MutableBufferSequence<
|
||||
MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
|
||||
@@ -15,15 +15,15 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A `Streambuf` with a fixed size internal buffer.
|
||||
/** A @b `Streambuf` with a fixed size internal buffer.
|
||||
|
||||
Ownership of the underlying storage belongs to the derived class.
|
||||
|
||||
@note Variables are usually declared using the template class
|
||||
`static_streambuf_n`; however, to reduce the number of instantiations
|
||||
@ref static_streambuf_n; however, to reduce the number of instantiations
|
||||
of template functions receiving static stream buffer arguments in a
|
||||
deduced context, the signature of the receiving function should use
|
||||
`static_streambuf`.
|
||||
@ref static_streambuf.
|
||||
*/
|
||||
class static_streambuf
|
||||
{
|
||||
@@ -75,18 +75,28 @@ public:
|
||||
|
||||
@throws std::length_error if the size would exceed the limit
|
||||
imposed by the underlying mutable buffer sequence.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
mutable_buffers_type
|
||||
prepare(std::size_t n);
|
||||
|
||||
/// Move bytes from the output sequence to the input sequence.
|
||||
/** Move bytes from the output sequence to the input sequence.
|
||||
|
||||
@note Buffers representing the input sequence acquired prior to
|
||||
this call remain valid.
|
||||
*/
|
||||
void
|
||||
commit(std::size_t n)
|
||||
{
|
||||
out_ += std::min<std::size_t>(n, last_ - out_);
|
||||
}
|
||||
|
||||
/// Get a list of buffers that represents the input sequence.
|
||||
/** 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;
|
||||
|
||||
@@ -129,9 +139,11 @@ protected:
|
||||
*/
|
||||
template<std::size_t N>
|
||||
class static_streambuf_n
|
||||
: private boost::base_from_member<
|
||||
: public static_streambuf
|
||||
#if ! GENERATING_DOCS
|
||||
, private boost::base_from_member<
|
||||
std::array<std::uint8_t, N>>
|
||||
, public static_streambuf
|
||||
#endif
|
||||
{
|
||||
using member_type = boost::base_from_member<
|
||||
std::array<std::uint8_t, N>>;
|
||||
|
||||
692
src/beast/include/beast/static_string.hpp
Normal file
692
src/beast/include/beast/static_string.hpp
Normal file
@@ -0,0 +1,692 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_WEBSOCKET_STATIC_STRING_HPP
|
||||
#define BEAST_WEBSOCKET_STATIC_STRING_HPP
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A string with a fixed-size storage area.
|
||||
|
||||
These objects behave like `std::string` except that the storage
|
||||
is not dynamically allocated but rather fixed in size.
|
||||
|
||||
These strings offer performance advantages when a protocol
|
||||
imposes a natural small upper limit on the size of a value.
|
||||
|
||||
@note The stored string is always null-terminated.
|
||||
*/
|
||||
template<
|
||||
std::size_t N,
|
||||
class CharT = char,
|
||||
class Traits = std::char_traits<CharT>>
|
||||
class static_string
|
||||
{
|
||||
template<std::size_t, class, class>
|
||||
friend class static_string;
|
||||
|
||||
std::size_t n_;
|
||||
std::array<CharT, N+1> s_;
|
||||
|
||||
public:
|
||||
using traits_type = Traits;
|
||||
using value_type = typename Traits::char_type;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using const_pointer = value_type const*;
|
||||
using const_reference = value_type const&;
|
||||
using iterator = value_type*;
|
||||
using const_iterator = value_type const*;
|
||||
using reverse_iterator =
|
||||
std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator =
|
||||
std::reverse_iterator<const_iterator>;
|
||||
|
||||
/** Default constructor.
|
||||
|
||||
The string is initially empty, and null terminated.
|
||||
*/
|
||||
static_string();
|
||||
|
||||
/// Copy constructor.
|
||||
static_string(static_string const& s);
|
||||
|
||||
/// Copy constructor.
|
||||
template<std::size_t M>
|
||||
static_string(static_string<M, CharT, Traits> const& s);
|
||||
|
||||
/// Copy assignment.
|
||||
static_string&
|
||||
operator=(static_string const& s);
|
||||
|
||||
/// Copy assignment.
|
||||
template<std::size_t M>
|
||||
static_string&
|
||||
operator=(static_string<M, CharT, Traits> const& s);
|
||||
|
||||
/// Construct from string literal.
|
||||
template<std::size_t M>
|
||||
static_string(const CharT (&s)[M]);
|
||||
|
||||
/// Assign from string literal.
|
||||
template<std::size_t M>
|
||||
static_string& operator=(const CharT (&s)[M]);
|
||||
|
||||
/// Access specified character with bounds checking.
|
||||
reference
|
||||
at(size_type pos);
|
||||
|
||||
/// Access specified character with bounds checking.
|
||||
const_reference
|
||||
at(size_type pos) const;
|
||||
|
||||
/// Access specified character.
|
||||
reference
|
||||
operator[](size_type pos)
|
||||
{
|
||||
return s_[pos];
|
||||
}
|
||||
|
||||
/// Access specified character.
|
||||
const_reference
|
||||
operator[](size_type pos) const
|
||||
{
|
||||
return s_[pos];
|
||||
}
|
||||
|
||||
/// Accesses the first character.
|
||||
CharT&
|
||||
front()
|
||||
{
|
||||
return s_[0];
|
||||
}
|
||||
|
||||
/// Accesses the first character.
|
||||
CharT const&
|
||||
front() const
|
||||
{
|
||||
return s_[0];
|
||||
}
|
||||
|
||||
/// Accesses the last character.
|
||||
CharT&
|
||||
back()
|
||||
{
|
||||
return s_[n_-1];
|
||||
}
|
||||
|
||||
/// Accesses the last character.
|
||||
CharT const&
|
||||
back() const
|
||||
{
|
||||
return s_[n_-1];
|
||||
}
|
||||
|
||||
/// Returns a pointer to the first character of a string.
|
||||
CharT*
|
||||
data()
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns a pointer to the first character of a string.
|
||||
CharT const*
|
||||
data() const
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns a non-modifiable standard C character array version of the string.
|
||||
CharT const*
|
||||
c_str() const
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the beginning.
|
||||
iterator
|
||||
begin()
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the beginning.
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the beginning.
|
||||
const_iterator
|
||||
cbegin() const
|
||||
{
|
||||
return &s_[0];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the end.
|
||||
iterator
|
||||
end()
|
||||
{
|
||||
return &s_[n_];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the end.
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return &s_[n_];
|
||||
}
|
||||
|
||||
/// Returns an iterator to the end.
|
||||
const_iterator
|
||||
cend() const
|
||||
{
|
||||
return &s_[n_];
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the beginning.
|
||||
reverse_iterator
|
||||
rbegin()
|
||||
{
|
||||
return reverse_iterator{end()};
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the beginning.
|
||||
const_reverse_iterator
|
||||
rbegin() const
|
||||
{
|
||||
return const_reverse_iterator{cend()};
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the beginning.
|
||||
const_reverse_iterator
|
||||
crbegin() const
|
||||
{
|
||||
return const_reverse_iterator{cend()};
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the end.
|
||||
reverse_iterator
|
||||
rend()
|
||||
{
|
||||
return reverse_iterator{begin()};
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the end.
|
||||
const_reverse_iterator
|
||||
rend() const
|
||||
{
|
||||
return const_reverse_iterator{cbegin()};
|
||||
}
|
||||
|
||||
/// Returns a reverse iterator to the end.
|
||||
const_reverse_iterator
|
||||
crend() const
|
||||
{
|
||||
return const_reverse_iterator{cbegin()};
|
||||
}
|
||||
|
||||
/// Returns `true` if the string is empty.
|
||||
bool
|
||||
empty() const
|
||||
{
|
||||
return n_ == 0;
|
||||
}
|
||||
|
||||
/// Returns the number of characters, excluding the null terminator.
|
||||
size_type
|
||||
size() const
|
||||
{
|
||||
return n_;
|
||||
}
|
||||
|
||||
/// Returns the maximum number of characters that can be stored, excluding the null terminator.
|
||||
size_type constexpr
|
||||
max_size() const
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
/// Returns the number of characters that can be held in currently allocated storage.
|
||||
size_type
|
||||
capacity() const
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
/// Reduces memory usage by freeing unused memory.
|
||||
void
|
||||
shrink_to_fit()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
/// Clears the contents.
|
||||
void
|
||||
clear()
|
||||
{
|
||||
resize(0);
|
||||
}
|
||||
|
||||
/** Changes the number of characters stored.
|
||||
|
||||
@note No value-initialization is performed.
|
||||
*/
|
||||
void
|
||||
resize(std::size_t n);
|
||||
|
||||
/** Changes the number of characters stored.
|
||||
|
||||
If the resulting string is larger, the new
|
||||
characters are initialized to the value of `c`.
|
||||
*/
|
||||
void
|
||||
resize(std::size_t n, CharT c);
|
||||
|
||||
/// Compare two character sequences.
|
||||
template<std::size_t M>
|
||||
int compare(static_string<M, CharT, Traits> const& rhs) const;
|
||||
|
||||
/// Return the characters as a `basic_string`.
|
||||
std::basic_string<CharT, Traits>
|
||||
to_string() const
|
||||
{
|
||||
return std::basic_string<
|
||||
CharT, Traits>{&s_[0], n_};
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
assign(CharT const* s);
|
||||
};
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
static_string<N, CharT, Traits>::
|
||||
static_string()
|
||||
: n_(0)
|
||||
{
|
||||
s_[0] = 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
static_string<N, CharT, Traits>::
|
||||
static_string(static_string const& s)
|
||||
: n_(s.n_)
|
||||
{
|
||||
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
template<std::size_t M>
|
||||
static_string<N, CharT, Traits>::
|
||||
static_string(static_string<M, CharT, Traits> const& s)
|
||||
{
|
||||
if(s.size() > N)
|
||||
throw std::length_error("static_string overflow");
|
||||
n_ = s.size();
|
||||
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
auto
|
||||
static_string<N, CharT, Traits>::
|
||||
operator=(static_string const& s) ->
|
||||
static_string&
|
||||
{
|
||||
n_ = s.n_;
|
||||
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
template<std::size_t M>
|
||||
auto
|
||||
static_string<N, CharT, Traits>::
|
||||
operator=(static_string<M, CharT, Traits> const& s) ->
|
||||
static_string&
|
||||
{
|
||||
if(s.size() > N)
|
||||
throw std::length_error("static_string overflow");
|
||||
n_ = s.size();
|
||||
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
template<std::size_t M>
|
||||
static_string<N, CharT, Traits>::
|
||||
static_string(const CharT (&s)[M])
|
||||
: n_(M-1)
|
||||
{
|
||||
static_assert(M-1 <= N,
|
||||
"static_string overflow");
|
||||
Traits::copy(&s_[0], &s[0], M);
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
template<std::size_t M>
|
||||
auto
|
||||
static_string<N, CharT, Traits>::
|
||||
operator=(const CharT (&s)[M]) ->
|
||||
static_string&
|
||||
{
|
||||
static_assert(M-1 <= N,
|
||||
"static_string overflow");
|
||||
n_ = M-1;
|
||||
Traits::copy(&s_[0], &s[0], M);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
auto
|
||||
static_string<N, CharT, Traits>::
|
||||
at(size_type pos) ->
|
||||
reference
|
||||
{
|
||||
if(pos >= n_)
|
||||
throw std::out_of_range("static_string::at");
|
||||
return s_[pos];
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
auto
|
||||
static_string<N, CharT, Traits>::
|
||||
at(size_type pos) const ->
|
||||
const_reference
|
||||
{
|
||||
if(pos >= n_)
|
||||
throw std::out_of_range("static_string::at");
|
||||
return s_[pos];
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
void
|
||||
static_string<N, CharT, Traits>::
|
||||
resize(std::size_t n)
|
||||
{
|
||||
if(n > N)
|
||||
throw std::length_error("static_string overflow");
|
||||
n_ = n;
|
||||
s_[n_] = 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
void
|
||||
static_string<N, CharT, Traits>::
|
||||
resize(std::size_t n, CharT c)
|
||||
{
|
||||
if(n > N)
|
||||
throw std::length_error("static_string overflow");
|
||||
if(n > n_)
|
||||
Traits::assign(&s_[n_], n - n_, c);
|
||||
n_ = n;
|
||||
s_[n_] = 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
template<std::size_t M>
|
||||
int
|
||||
static_string<N, CharT, Traits>::
|
||||
compare(static_string<M, CharT, Traits> const& rhs) const
|
||||
{
|
||||
if(size() < rhs.size())
|
||||
{
|
||||
auto const v = Traits::compare(
|
||||
data(), rhs.data(), size());
|
||||
if(v == 0)
|
||||
return -1;
|
||||
return v;
|
||||
}
|
||||
else if(size() > rhs.size())
|
||||
{
|
||||
auto const v = Traits::compare(
|
||||
data(), rhs.data(), rhs.size());
|
||||
if(v == 0)
|
||||
return 1;
|
||||
return v;
|
||||
}
|
||||
return Traits::compare(data(), rhs.data(), size());
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits>
|
||||
void
|
||||
static_string<N, CharT, Traits>::
|
||||
assign(CharT const* s)
|
||||
{
|
||||
auto const n = Traits::length(s);
|
||||
if(n > N)
|
||||
throw std::out_of_range("too large");
|
||||
n_ = n;
|
||||
Traits::copy(&s_[0], s, n_ + 1);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
int compare(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
if(lhs.size() < M-1)
|
||||
{
|
||||
auto const v = Traits::compare(
|
||||
lhs.data(), &s[0], lhs.size());
|
||||
if(v == 0)
|
||||
return -1;
|
||||
return v;
|
||||
}
|
||||
else if(lhs.size() > M-1)
|
||||
{
|
||||
auto const v = Traits::compare(
|
||||
lhs.data(), &s[0], M-1);
|
||||
if(v == 0)
|
||||
return 1;
|
||||
return v;
|
||||
}
|
||||
return Traits::compare(lhs.data(), &s[0], lhs.size());
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
int compare(
|
||||
const CharT (&s)[M],
|
||||
static_string<N, CharT, Traits> const& rhs)
|
||||
{
|
||||
if(M-1 < rhs.size())
|
||||
{
|
||||
auto const v = Traits::compare(
|
||||
&s[0], rhs.data(), M-1);
|
||||
if(v == 0)
|
||||
return -1;
|
||||
return v;
|
||||
}
|
||||
else if(M-1 > rhs.size())
|
||||
{
|
||||
auto const v = Traits::compare(
|
||||
&s[0], rhs.data(), rhs.size());
|
||||
if(v == 0)
|
||||
return 1;
|
||||
return v;
|
||||
}
|
||||
return Traits::compare(&s[0], rhs.data(), M-1);
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator==(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) == 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator!=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) != 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator<(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) < 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator<=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) <= 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator>(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) > 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator>=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return lhs.compare(rhs) >= 0;
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator==(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) == 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool operator==(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) == 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator!=(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) != 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool operator!=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) != 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator<(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) < 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool operator<(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) < 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator<=(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) <= 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool operator<=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) <= 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator>(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) > 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool operator>(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) > 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||
bool operator>=(
|
||||
const CharT (&s)[N],
|
||||
static_string<M, CharT, Traits> const& rhs)
|
||||
{
|
||||
return detail::compare(s, rhs) >= 0;
|
||||
}
|
||||
|
||||
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||
bool operator>=(
|
||||
static_string<N, CharT, Traits> const& lhs,
|
||||
const CharT (&s)[M])
|
||||
{
|
||||
return detail::compare(lhs, s) >= 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
76
src/beast/include/beast/stream_concepts.hpp
Normal file
76
src/beast/include/beast/stream_concepts.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// 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_STREAM_CONCEPTS_HPP
|
||||
#define BEAST_STREAM_CONCEPTS_HPP
|
||||
|
||||
#include <beast/detail/stream_concepts.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/// Determine if `T` has the `get_io_service` member.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct has_get_io_service : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using has_get_io_service = typename detail::has_get_io_service<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `AsyncReadStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_AsyncReadStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_AsyncReadStream = typename detail::is_AsyncReadStream<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `AsyncWriteStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_AsyncWriteStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_AsyncWriteStream = typename detail::is_AsyncWriteStream<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `SyncReadStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_SyncReadStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_SyncReadStream = typename detail::is_SyncReadStream<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `SyncWriterStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_SyncWriteStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_SyncWriteStream = typename detail::is_SyncWriteStream<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `AsyncStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_AsyncStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_AsyncStream = std::integral_constant<bool,
|
||||
is_AsyncReadStream<T>::value && is_AsyncWriteStream<T>::value>;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b `SyncStream`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_SyncStream : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_SyncStream = std::integral_constant<bool,
|
||||
is_SyncReadStream<T>::value && is_SyncWriteStream<T>::value>;
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -12,6 +12,15 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A @b `Streambuf` that uses multiple buffers internally.
|
||||
|
||||
The implementation uses a sequence of one or more character arrays
|
||||
of varying sizes. Additional character array objects are appended to
|
||||
the sequence to accommodate changes in the size of the character
|
||||
sequence.
|
||||
|
||||
@note Meets the requirements of @b `Streambuf`.
|
||||
*/
|
||||
using streambuf = basic_streambuf<std::allocator<char>>;
|
||||
|
||||
} // beast
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
#define BEAST_STREAMBUF_READSTREAM_HPP
|
||||
|
||||
#include <beast/async_completion.hpp>
|
||||
#include <beast/buffer_concepts.hpp>
|
||||
#include <beast/stream_concepts.hpp>
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <beast/detail/get_lowest_layer.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
@@ -18,11 +21,11 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A `Stream` with attached `Streambuf` to buffer reads.
|
||||
/** A @b `Stream` with attached @b `Streambuf` to buffer reads.
|
||||
|
||||
This wraps a `Stream` implementation so that calls to write are
|
||||
This wraps a @b `Stream` implementation so that calls to write are
|
||||
passed through to the underlying stream, while calls to read will
|
||||
first consume the input sequence stored in a `Streambuf` which
|
||||
first consume the input sequence stored in a @b `Streambuf` which
|
||||
is part of the object.
|
||||
|
||||
The use-case for this class is different than that of the
|
||||
@@ -35,10 +38,10 @@ namespace beast {
|
||||
|
||||
Uses:
|
||||
|
||||
* Transparently leave untouched input acquired in calls
|
||||
@li Transparently leave untouched input acquired in calls
|
||||
to `boost::asio::read_until` behind for subsequent callers.
|
||||
|
||||
* "Preload" a stream with handshake input data acquired
|
||||
@li "Preload" a stream with handshake input data acquired
|
||||
from other sources.
|
||||
|
||||
Example:
|
||||
@@ -83,10 +86,12 @@ namespace beast {
|
||||
|
||||
@tparam Streambuf The type of stream buffer to use.
|
||||
*/
|
||||
template<class Stream,
|
||||
class Streambuf = streambuf>
|
||||
template<class Stream, class Streambuf>
|
||||
class streambuf_readstream
|
||||
{
|
||||
static_assert(is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
|
||||
using error_code = boost::system::error_code;
|
||||
|
||||
template<class Buffers, class Handler>
|
||||
@@ -106,11 +111,27 @@ public:
|
||||
|
||||
/// The type of the lowest layer.
|
||||
using lowest_layer_type =
|
||||
typename next_layer_type::lowest_layer_type;
|
||||
#if GENERATING_DOCS
|
||||
implementation_defined;
|
||||
#else
|
||||
typename detail::get_lowest_layer<
|
||||
next_layer_type>::type;
|
||||
#endif
|
||||
|
||||
/// Move constructor.
|
||||
/** Move constructor.
|
||||
|
||||
@note The behavior of move assignment on or from streams
|
||||
with active or pending operations is undefined.
|
||||
*/
|
||||
streambuf_readstream(streambuf_readstream&&) = default;
|
||||
|
||||
/** Move assignment.
|
||||
|
||||
@note The behavior of move assignment on or from streams
|
||||
with active or pending operations is undefined.
|
||||
*/
|
||||
streambuf_readstream& operator=(streambuf_readstream&&) = default;
|
||||
|
||||
/** Construct the wrapping stream.
|
||||
|
||||
@param args Parameters forwarded to the `Stream` constructor.
|
||||
@@ -200,6 +221,8 @@ public:
|
||||
std::size_t
|
||||
write_some(ConstBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_SyncWriteStream<next_layer_type>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
return next_layer_.write_some(buffers);
|
||||
}
|
||||
|
||||
@@ -210,14 +233,19 @@ public:
|
||||
write_some(ConstBufferSequence const& buffers,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncWriteStream<next_layer_type>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
return next_layer_.write_some(buffers, ec);
|
||||
}
|
||||
|
||||
/// Start an asynchronous write. The data being written must be valid for the
|
||||
/// lifetime of the asynchronous operation.
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
typename async_completion<WriteHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_write_some(ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler);
|
||||
|
||||
@@ -237,8 +265,11 @@ public:
|
||||
/// Start an asynchronous read. The buffer into which the data will be read
|
||||
/// must be valid for the lifetime of the asynchronous operation.
|
||||
template<class MutableBufferSequence, class ReadHandler>
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
#if GENERATING_DOCS
|
||||
void_or_deduced
|
||||
#else
|
||||
typename async_completion<ReadHandler, void(error_code)>::result_type
|
||||
#endif
|
||||
async_read_some(MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler);
|
||||
};
|
||||
|
||||
51
src/beast/include/beast/to_string.hpp
Normal file
51
src/beast/include/beast/to_string.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// 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_TO_STRING_HPP
|
||||
#define BEAST_TO_STRING_HPP
|
||||
|
||||
#include <beast/buffer_concepts.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Convert a @b `ConstBufferSequence` to a `std::string`.
|
||||
|
||||
This function will convert the octets in a buffer sequence to a string.
|
||||
All octets will be inserted into the resulting string, including null
|
||||
or unprintable characters.
|
||||
|
||||
@param buffers The buffer sequence to convert.
|
||||
|
||||
@return A string representing the contents of the input area.
|
||||
|
||||
@note This function participates in overload resolution only if
|
||||
the streambuf parameter meets the requirements of @b `Streambuf`.
|
||||
*/
|
||||
template<class ConstBufferSequence
|
||||
#if ! GENERATING_DOCS
|
||||
,class = std::enable_if<is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value>
|
||||
#endif
|
||||
>
|
||||
std::string
|
||||
to_string(ConstBufferSequence const& buffers)
|
||||
{
|
||||
using boost::asio::buffer_cast;
|
||||
using boost::asio::buffer_size;
|
||||
std::string s;
|
||||
s.reserve(buffer_size(buffers));
|
||||
for(auto const& buffer : buffers)
|
||||
s.append(buffer_cast<char const*>(buffer),
|
||||
buffer_size(buffer));
|
||||
return s;
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -1,348 +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_TYPE_CHECK_HPP
|
||||
#define BEAST_TYPE_CHECK_HPP
|
||||
|
||||
#include <beast/detail/is_call_possible.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Types that meet the requirements,
|
||||
// for use with std::declval only.
|
||||
//
|
||||
|
||||
#if GENERATING_DOCS
|
||||
namespace detail {
|
||||
#else
|
||||
namespace concept {
|
||||
#endif
|
||||
|
||||
template<class BufferType>
|
||||
struct BufferSequence
|
||||
{
|
||||
using value_type = BufferType;
|
||||
using const_iterator = BufferType const*;
|
||||
~BufferSequence();
|
||||
BufferSequence(BufferSequence const&) = default;
|
||||
const_iterator
|
||||
begin() const noexcept;
|
||||
const_iterator
|
||||
end() const noexcept;
|
||||
};
|
||||
|
||||
using ConstBufferSequence =
|
||||
BufferSequence<boost::asio::const_buffer>;
|
||||
|
||||
using MutableBufferSequence =
|
||||
BufferSequence<boost::asio::mutable_buffer>;
|
||||
|
||||
struct StreamHandler
|
||||
{
|
||||
StreamHandler(StreamHandler const&) = default;
|
||||
void
|
||||
operator()(boost::system::error_code ec,
|
||||
std::size_t);
|
||||
};
|
||||
|
||||
using ReadHandler = StreamHandler;
|
||||
using WriteHandler = StreamHandler;
|
||||
|
||||
} // concept
|
||||
|
||||
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html
|
||||
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html
|
||||
//
|
||||
/// Determine if `T` meets the requirements of `BufferSequence`.
|
||||
template<class T, class BufferType>
|
||||
class is_BufferSequence
|
||||
{
|
||||
template<class U, class R = std::is_convertible<
|
||||
typename U::value_type, BufferType> >
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class U, class R = std::is_base_of<
|
||||
#if 0
|
||||
std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<
|
||||
typename U::const_iterator>::iterator_category>>
|
||||
#else
|
||||
// workaround:
|
||||
// boost::asio::detail::consuming_buffers::const_iterator
|
||||
// is not bidirectional
|
||||
std::forward_iterator_tag,
|
||||
typename std::iterator_traits<
|
||||
typename U::const_iterator>::iterator_category>>
|
||||
#endif
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
template<class U, class R = typename
|
||||
std::is_convertible<decltype(
|
||||
std::declval<U>().begin()),
|
||||
typename U::const_iterator>::type>
|
||||
static R check3(int);
|
||||
template<class>
|
||||
static std::false_type check3(...);
|
||||
using type3 = decltype(check3<T>(0));
|
||||
|
||||
template<class U, class R = typename std::is_convertible<decltype(
|
||||
std::declval<U>().end()),
|
||||
typename U::const_iterator>::type>
|
||||
static R check4(int);
|
||||
template<class>
|
||||
static std::false_type check4(...);
|
||||
using type4 = decltype(check4<T>(0));
|
||||
|
||||
public:
|
||||
/// `true` if `T` meets the requirements.
|
||||
static bool const value =
|
||||
std::is_copy_constructible<T>::value &&
|
||||
std::is_destructible<T>::value &&
|
||||
type1::value && type2::value &&
|
||||
type3::value && type4::value;
|
||||
};
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
/// Determine if `T` meets the requirements of `ConstBufferSequence`.
|
||||
template<class T>
|
||||
using is_ConstBufferSequence =
|
||||
is_BufferSequence<T, boost::asio::const_buffer>;
|
||||
static_assert(is_ConstBufferSequence<concept::ConstBufferSequence>::value, "");
|
||||
static_assert(! is_ConstBufferSequence<int>::value, "");
|
||||
|
||||
/// Determine if `T` meets the requirements of `MutableBufferSequence`.
|
||||
template<class C>
|
||||
using is_MutableBufferSequence =
|
||||
is_BufferSequence<C, boost::asio::mutable_buffer>;
|
||||
static_assert(is_MutableBufferSequence<concept::MutableBufferSequence>::value, "");
|
||||
static_assert(! is_MutableBufferSequence<int>::value, "");
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Determine if `T` has the `get_io_service` member.
|
||||
template<class T>
|
||||
class has_get_io_service
|
||||
{
|
||||
template<class U, class R = typename std::is_same<
|
||||
decltype(std::declval<U>().get_io_service()),
|
||||
boost::asio::io_service&>>
|
||||
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;
|
||||
};
|
||||
static_assert(! has_get_io_service<int>::value, "");
|
||||
|
||||
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html
|
||||
//
|
||||
/// Determine if `T` meets the requirements of `AsyncReadStream`.
|
||||
template<class T>
|
||||
class is_AsyncReadStream
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().async_read_some(
|
||||
std::declval<concept::MutableBufferSequence>(),
|
||||
std::declval<concept::ReadHandler>()),
|
||||
std::true_type{})>
|
||||
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 =
|
||||
has_get_io_service<T>::value && type::value;
|
||||
};
|
||||
static_assert(! is_AsyncReadStream<int>::value, "");
|
||||
|
||||
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html
|
||||
//
|
||||
/// Determine if `T` meets the requirements of `AsyncWriteStream`.
|
||||
template<class T>
|
||||
class is_AsyncWriteStream
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().async_write_some(
|
||||
std::declval<concept::ConstBufferSequence>(),
|
||||
std::declval<concept::WriteHandler>()),
|
||||
std::true_type{})>
|
||||
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 =
|
||||
has_get_io_service<T>::value && type::value;
|
||||
};
|
||||
static_assert(! is_AsyncWriteStream<int>::value, "");
|
||||
|
||||
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html
|
||||
//
|
||||
/// Determine if `T` meets the requirements of `SyncReadStream`.
|
||||
template<class T>
|
||||
class is_SyncReadStream
|
||||
{
|
||||
using error_code =
|
||||
boost::system::error_code;
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().read_some(
|
||||
std::declval<concept::MutableBufferSequence>())),
|
||||
std::size_t>>
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().read_some(
|
||||
std::declval<concept::MutableBufferSequence>(),
|
||||
std::declval<error_code&>())), std::size_t>>
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
public:
|
||||
/// `true` if `T` meets the requirements.
|
||||
static bool const value =
|
||||
type1::value && type2::value;
|
||||
};
|
||||
static_assert(! is_SyncReadStream<int>::value, "");
|
||||
|
||||
// http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html
|
||||
//
|
||||
/// Determine if `T` meets the requirements of `SyncWriterStream`.
|
||||
template<class T>
|
||||
class is_SyncWriteStream
|
||||
{
|
||||
using error_code =
|
||||
boost::system::error_code;
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().write_some(
|
||||
std::declval<concept::ConstBufferSequence>())),
|
||||
std::size_t>>
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().write_some(
|
||||
std::declval<concept::ConstBufferSequence>(),
|
||||
std::declval<error_code&>())), std::size_t>>
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
public:
|
||||
/// `true` if `T` meets the requirements.
|
||||
static bool const value =
|
||||
type1::value && type2::value;
|
||||
};
|
||||
static_assert(! is_SyncWriteStream<int>::value, "");
|
||||
|
||||
/// Determine if `T` meets the requirements of `Stream`.
|
||||
template<class T>
|
||||
struct is_Stream
|
||||
{
|
||||
/// `true` if `T` meets the requirements.
|
||||
static bool const value =
|
||||
is_AsyncReadStream<T>::value &&
|
||||
is_AsyncWriteStream<T>::value &&
|
||||
is_SyncReadStream<T>::value &&
|
||||
is_SyncWriteStream<T>::value;
|
||||
};
|
||||
|
||||
/// Determine if `T` meets the requirements of `Streambuf`.
|
||||
template<class T>
|
||||
class is_Streambuf
|
||||
{
|
||||
template<class U, class R = std::integral_constant<
|
||||
bool, is_MutableBufferSequence<decltype(
|
||||
std::declval<U>().prepare(1))>::value>>
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class U, class R = std::integral_constant<
|
||||
bool, is_ConstBufferSequence<decltype(
|
||||
std::declval<U>().data())>::value>>
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().commit(1), std::true_type{})>
|
||||
static R check3(int);
|
||||
template<class>
|
||||
static std::false_type check3(...);
|
||||
using type3 = decltype(check3<T>(0));
|
||||
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().consume(1), std::true_type{})>
|
||||
static R check4(int);
|
||||
template<class>
|
||||
static std::false_type check4(...);
|
||||
using type4 = decltype(check4<T>(0));
|
||||
|
||||
template<class U, class R = std::is_same<decltype(
|
||||
std::declval<U>().size()), std::size_t>>
|
||||
static R check5(int);
|
||||
template<class>
|
||||
static std::false_type check5(...);
|
||||
using type5 = decltype(check5<T>(0));
|
||||
|
||||
public:
|
||||
/// `true` if `T` meets the requirements.
|
||||
static bool const value =
|
||||
type1::value && type2::value &&
|
||||
type3::value && type4::value &&
|
||||
type5::value;
|
||||
};
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
/// Determine if `T` meets the requirements of `CompletionHandler`.
|
||||
template<class T, class Signature>
|
||||
using is_Handler = std::integral_constant<bool,
|
||||
std::is_copy_constructible<typename std::decay<T>::type>::value &&
|
||||
detail::is_call_possible<T, Signature>::value>;
|
||||
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -16,6 +16,6 @@
|
||||
//
|
||||
#define BEAST_VERSION 100000
|
||||
|
||||
#define BEAST_VERSION_STRING "1.0.0-b2"
|
||||
#define BEAST_VERSION_STRING "1.0.0-b3"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <beast/websocket/option.hpp>
|
||||
#include <beast/websocket/rfc6455.hpp>
|
||||
#include <beast/websocket/stream.hpp>
|
||||
#include <beast/websocket/static_string.hpp>
|
||||
#include <beast/websocket/teardown.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_WSPROTO_DEBUG_H_INCLUDED
|
||||
#define BEAST_WSPROTO_DEBUG_H_INCLUDED
|
||||
#ifndef BEAST_WEBSOCKET_DETAIL_DEBUG_HPP
|
||||
#define BEAST_WEBSOCKET_DETAIL_DEBUG_HPP
|
||||
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
@@ -82,7 +81,7 @@ format(std::string s)
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // wsproto
|
||||
} // websocket
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
@@ -53,6 +53,17 @@ little_uint32_to_native(void const* buf)
|
||||
(static_cast<std::uint64_t>(p[3])<<24);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
native_to_little_uint32(std::uint32_t v, void* buf)
|
||||
{
|
||||
auto p = reinterpret_cast<std::uint8_t*>(buf);
|
||||
p[0] = v & 0xff;
|
||||
p[1] = (v >> 8) & 0xff;
|
||||
p[2] = (v >> 16) & 0xff;
|
||||
p[3] = (v >> 24) & 0xff;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // websocket
|
||||
} // beast
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
const char*
|
||||
name() const noexcept override
|
||||
{
|
||||
return "wsproto";
|
||||
return "websocket";
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
case error::request_invalid: return "upgrade request invalid";
|
||||
case error::request_denied: return "upgrade request denied";
|
||||
default:
|
||||
return "wsproto.error";
|
||||
return "websocket error";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
#define BEAST_WEBSOCKET_DETAIL_FRAME_HPP
|
||||
|
||||
#include <beast/websocket/rfc6455.hpp>
|
||||
#include <beast/websocket/static_string.hpp>
|
||||
#include <beast/websocket/detail/endian.hpp>
|
||||
#include <beast/websocket/detail/utf8_checker.hpp>
|
||||
#include <beast/consuming_buffers.hpp>
|
||||
#include <beast/static_streambuf.hpp>
|
||||
#include <beast/static_string.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/endian/buffers.hpp>
|
||||
#include <cassert>
|
||||
@@ -70,10 +70,9 @@ is_control(opcode op)
|
||||
// Returns `true` if a close code is valid
|
||||
inline
|
||||
bool
|
||||
is_valid(close_code code)
|
||||
is_valid(close_code::value code)
|
||||
{
|
||||
auto const v = static_cast<
|
||||
std::uint16_t>(code);
|
||||
auto const v = code;
|
||||
switch(v)
|
||||
{
|
||||
case 1000:
|
||||
@@ -141,9 +140,7 @@ write(Streambuf& sb, frame_header const& fh)
|
||||
}
|
||||
if(fh.mask)
|
||||
{
|
||||
little_uint32_buf_t key(fh.key);
|
||||
std::copy(key.data(),
|
||||
key.data() + 4, &b[n]);
|
||||
native_to_little_uint32(fh.key, &b[n]);
|
||||
n += 4;
|
||||
}
|
||||
sb.commit(buffer_copy(
|
||||
@@ -156,7 +153,7 @@ write(Streambuf& sb, frame_header const& fh)
|
||||
template<class Streambuf>
|
||||
std::size_t
|
||||
read_fh1(frame_header& fh, Streambuf& sb,
|
||||
role_type role, close_code& code)
|
||||
role_type role, close_code::value& code)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
@@ -173,7 +170,8 @@ read_fh1(frame_header& fh, Streambuf& sb,
|
||||
default:
|
||||
need = 0;
|
||||
}
|
||||
if((fh.mask = (b[1] & 0x80) != 0))
|
||||
fh.mask = (b[1] & 0x80) != 0;
|
||||
if(fh.mask)
|
||||
need += 4;
|
||||
fh.op = static_cast<opcode>(b[0] & 0x0f);
|
||||
fh.fin = (b[0] & 0x80) != 0;
|
||||
@@ -232,7 +230,7 @@ read_fh1(frame_header& fh, Streambuf& sb,
|
||||
template<class Streambuf>
|
||||
void
|
||||
read_fh2(frame_header& fh, Streambuf& sb,
|
||||
role_type role, close_code& code)
|
||||
role_type role, close_code::value& code)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
@@ -303,7 +301,7 @@ read_fh2(frame_header& fh, Streambuf& sb,
|
||||
template<class Buffers>
|
||||
void
|
||||
read(ping_payload_type& data,
|
||||
Buffers const& bs, close_code& code)
|
||||
Buffers const& bs, close_code::value& code)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
@@ -320,7 +318,7 @@ read(ping_payload_type& data,
|
||||
template<class Buffers>
|
||||
void
|
||||
read(close_reason& cr,
|
||||
Buffers const& bs, close_code& code)
|
||||
Buffers const& bs, close_code::value& code)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
@@ -343,15 +341,7 @@ read(close_reason& cr,
|
||||
{
|
||||
std::uint8_t b[2];
|
||||
buffer_copy(buffer(b), cb);
|
||||
#if 0
|
||||
// Causes strict-aliasing warning in gcc
|
||||
cr.code = static_cast<close_code>(
|
||||
reinterpret_cast<
|
||||
big_uint16_buf_t const*>(&b[0])->value());
|
||||
#else
|
||||
cr.code = static_cast<close_code>(
|
||||
big_uint16_to_native(&b[0]));
|
||||
#endif
|
||||
cr.code = big_uint16_to_native(&b[0]);
|
||||
cb.consume(2);
|
||||
n -= 2;
|
||||
if(! is_valid(cr.code))
|
||||
|
||||
@@ -85,8 +85,6 @@ public:
|
||||
#endif
|
||||
|
||||
invokable() = default;
|
||||
invokable(invokable const&) = delete;
|
||||
invokable& operator=(invokable const&) = delete;
|
||||
|
||||
invokable(invokable&& other)
|
||||
{
|
||||
|
||||
@@ -41,9 +41,6 @@ class maskgen_t
|
||||
public:
|
||||
using result_type = typename std::mt19937::result_type;
|
||||
|
||||
maskgen_t(maskgen_t const&) = delete;
|
||||
maskgen_t& operator=(maskgen_t const&) = delete;
|
||||
|
||||
maskgen_t();
|
||||
|
||||
result_type
|
||||
|
||||
@@ -108,7 +108,7 @@ protected:
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
prepare_fh(close_code& code);
|
||||
prepare_fh(close_code::value& code);
|
||||
|
||||
template<class Streambuf>
|
||||
void
|
||||
|
||||
@@ -73,12 +73,6 @@ class utf8_checker_t
|
||||
std::uint32_t codepoint_ = 0;
|
||||
|
||||
public:
|
||||
utf8_checker_t() = default;
|
||||
utf8_checker_t(utf8_checker_t&&) = default;
|
||||
utf8_checker_t(utf8_checker_t const&) = default;
|
||||
utf8_checker_t& operator=(utf8_checker_t&&) = default;
|
||||
utf8_checker_t& operator=(utf8_checker_t const&) = default;
|
||||
|
||||
void
|
||||
reset();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define BEAST_WEBSOCKET_ERROR_HPP
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
@@ -16,7 +17,7 @@ namespace websocket {
|
||||
/// The type of error used by functions and completion handlers.
|
||||
using error_code = boost::system::error_code;
|
||||
|
||||
/// Error values
|
||||
/// Error codes returned from @ref stream operations.
|
||||
enum class error
|
||||
{
|
||||
/// Both sides performed a WebSocket close
|
||||
@@ -50,8 +51,10 @@ enum class error
|
||||
request_denied
|
||||
};
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
error_code
|
||||
make_error_code(error e);
|
||||
#endif
|
||||
|
||||
} // websocket
|
||||
} // beast
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
#define BEAST_WEBSOCKET_IMPL_ACCEPT_OP_HPP
|
||||
|
||||
#include <beast/websocket/impl/response_op.ipp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <beast/http/parser_v1.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/handler_alloc.hpp>
|
||||
#include <beast/prepare_buffers.hpp>
|
||||
#include <beast/http/parser.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
@@ -32,7 +33,7 @@ class stream<NextLayer>::accept_op
|
||||
struct data
|
||||
{
|
||||
stream<NextLayer>& ws;
|
||||
http::request<http::empty_body> req;
|
||||
http::request_v1<http::empty_body> req;
|
||||
Handler h;
|
||||
bool cont;
|
||||
int state = 0;
|
||||
@@ -124,7 +125,7 @@ operator()(error_code const& ec,
|
||||
case 0:
|
||||
// read message
|
||||
d.state = 1;
|
||||
http::async_read(d.ws.next_layer_,
|
||||
http::async_read(d.ws.next_layer(),
|
||||
d.ws.stream_.buffer(), d.req,
|
||||
std::move(*this));
|
||||
return;
|
||||
|
||||
@@ -34,7 +34,6 @@ class stream<NextLayer>::close_op
|
||||
close_reason cr;
|
||||
Handler h;
|
||||
fb_type fb;
|
||||
fmb_type fmb;
|
||||
bool cont;
|
||||
int state = 0;
|
||||
|
||||
@@ -176,8 +175,8 @@ stream<NextLayer>::close_op<Handler>::operator()(
|
||||
d.ws.error_ = true;
|
||||
if(d.ws.wr_block_ == &d)
|
||||
d.ws.wr_block_ = nullptr;
|
||||
d.h(ec);
|
||||
d.ws.rd_op_.maybe_invoke();
|
||||
d.h(ec);
|
||||
}
|
||||
|
||||
} // websocket
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <beast/handler_alloc.hpp>
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/http/write.hpp>
|
||||
#include <cassert>
|
||||
@@ -33,8 +33,8 @@ class stream<NextLayer>::handshake_op
|
||||
stream<NextLayer>& ws;
|
||||
Handler h;
|
||||
std::string key;
|
||||
http::request<http::empty_body> req;
|
||||
http::response<http::string_body> resp;
|
||||
http::request_v1<http::empty_body> req;
|
||||
http::response_v1<http::string_body> resp;
|
||||
bool cont;
|
||||
int state = 0;
|
||||
|
||||
@@ -134,7 +134,7 @@ stream<NextLayer>::handshake_op<
|
||||
case 1:
|
||||
// read http response
|
||||
d.state = 2;
|
||||
http::async_read(d.ws.next_layer_,
|
||||
http::async_read(d.ws.next_layer(),
|
||||
d.ws.stream_.buffer(), d.resp,
|
||||
std::move(*this));
|
||||
return;
|
||||
|
||||
@@ -42,10 +42,10 @@ class stream<NextLayer>::read_frame_op
|
||||
stream<NextLayer>& ws;
|
||||
frame_info& fi;
|
||||
Streambuf& sb;
|
||||
smb_type smb;
|
||||
Handler h;
|
||||
fb_type fb;
|
||||
fmb_type fmb;
|
||||
boost::optional<smb_type> smb;
|
||||
boost::optional<fmb_type> fmb;
|
||||
bool cont;
|
||||
int state = 0;
|
||||
|
||||
@@ -132,7 +132,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
{
|
||||
auto& d = *d_;
|
||||
d.cont = d.cont || again;
|
||||
close_code code;
|
||||
close_code::value code = close_code::none;
|
||||
while(! ec && d.state != 99)
|
||||
{
|
||||
switch(d.state)
|
||||
@@ -161,7 +161,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
d.smb = d.sb.prepare(
|
||||
detail::clamp(d.ws.rd_need_));
|
||||
d.ws.stream_.async_read_some(
|
||||
d.smb, std::move(*this));
|
||||
*d.smb, std::move(*this));
|
||||
return;
|
||||
|
||||
case 2:
|
||||
@@ -176,7 +176,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
{
|
||||
d.ws.rd_need_ -= bytes_transferred;
|
||||
auto const pb = prepare_buffers(
|
||||
bytes_transferred, d.smb);
|
||||
bytes_transferred, *d.smb);
|
||||
if(d.ws.rd_fh_.mask)
|
||||
detail::mask_inplace(pb, d.ws.rd_key_);
|
||||
if(d.ws.rd_opcode_ == opcode::text)
|
||||
@@ -195,7 +195,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
d.state = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// call handler
|
||||
case 4:
|
||||
d.state = 99;
|
||||
@@ -252,7 +252,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
d.fmb = d.fb.prepare(static_cast<
|
||||
std::size_t>(d.ws.rd_fh_.len));
|
||||
boost::asio::async_read(d.ws.stream_,
|
||||
d.fmb, std::move(*this));
|
||||
*d.fmb, std::move(*this));
|
||||
return;
|
||||
}
|
||||
d.state = 8;
|
||||
@@ -276,7 +276,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
case 7:
|
||||
if(d.ws.rd_fh_.mask)
|
||||
detail::mask_inplace(
|
||||
d.fmb, d.ws.rd_key_);
|
||||
*d.fmb, d.ws.rd_key_);
|
||||
d.fb.commit(bytes_transferred);
|
||||
d.state = 8;
|
||||
break;
|
||||
@@ -396,8 +396,8 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
// teardown
|
||||
case 11:
|
||||
d.state = 12;
|
||||
wsproto_helpers::call_async_teardown(
|
||||
d.ws.next_layer_, std::move(*this));
|
||||
websocket_helpers::call_async_teardown(
|
||||
d.ws.next_layer(), std::move(*this));
|
||||
return;
|
||||
|
||||
case 12:
|
||||
@@ -482,8 +482,8 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
// teardown
|
||||
case 19:
|
||||
d.state = 20;
|
||||
wsproto_helpers::call_async_teardown(
|
||||
d.ws.next_layer_, std::move(*this));
|
||||
websocket_helpers::call_async_teardown(
|
||||
d.ws.next_layer(), std::move(*this));
|
||||
return;
|
||||
|
||||
case 20:
|
||||
@@ -497,8 +497,8 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
d.ws.error_ = true;
|
||||
if(d.ws.wr_block_ == &d)
|
||||
d.ws.wr_block_ = nullptr;
|
||||
d.h(ec);
|
||||
d.ws.wr_op_.maybe_invoke();
|
||||
d.h(ec);
|
||||
}
|
||||
|
||||
} // websocket
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define BEAST_WEBSOCKET_IMPL_RESPONSE_OP_HPP
|
||||
|
||||
#include <beast/handler_alloc.hpp>
|
||||
#include <beast/http/message_v1.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <beast/http/write.hpp>
|
||||
#include <memory>
|
||||
@@ -27,7 +28,7 @@ class stream<NextLayer>::response_op
|
||||
struct data
|
||||
{
|
||||
stream<NextLayer>& ws;
|
||||
http::response<http::string_body> resp;
|
||||
http::response_v1<http::string_body> resp;
|
||||
Handler h;
|
||||
error_code final_ec;
|
||||
bool cont;
|
||||
@@ -36,7 +37,7 @@ class stream<NextLayer>::response_op
|
||||
template<class DeducedHandler,
|
||||
class Body, class Headers>
|
||||
data(DeducedHandler&& h_, stream<NextLayer>& ws_,
|
||||
http::message<true, Body, Headers> const& req,
|
||||
http::request_v1<Body, Headers> const& req,
|
||||
bool cont_)
|
||||
: ws(ws_)
|
||||
, resp(ws_.build_response(req))
|
||||
@@ -113,7 +114,7 @@ operator()(error_code ec, bool again)
|
||||
case 0:
|
||||
// send response
|
||||
d.state = 1;
|
||||
http::async_write(d.ws.next_layer_,
|
||||
http::async_write(d.ws.next_layer(),
|
||||
d.resp, std::move(*this));
|
||||
return;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user