mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-27 22:45:52 +00:00
Merge commit '2f9a8440c2432d8a196571d6300404cb76314125' into develop
This commit is contained in:
30
src/beast/.gitignore
vendored
30
src/beast/.gitignore
vendored
@@ -1,30 +1,2 @@
|
|||||||
docs/
|
|
||||||
._*
|
|
||||||
*.mode1v3
|
|
||||||
*.pbxuser
|
|
||||||
*.perspectivev3
|
|
||||||
*.user
|
|
||||||
*.ncb
|
|
||||||
*.suo
|
|
||||||
*.obj
|
|
||||||
*.ilk
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.dep
|
|
||||||
*.idb
|
|
||||||
*.manifest
|
|
||||||
*.manifest.res
|
|
||||||
*.o
|
|
||||||
*.opensdf
|
|
||||||
*.d
|
|
||||||
*.sdf
|
|
||||||
xcuserdata
|
|
||||||
contents.xcworkspacedata
|
|
||||||
.DS_Store
|
|
||||||
.svn
|
|
||||||
profile
|
|
||||||
bin/
|
bin/
|
||||||
node_modules/
|
bin64/
|
||||||
cov-int/
|
|
||||||
nohup.out
|
|
||||||
venv/
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ language: cpp
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
|
- LLVM_VERSION=3.8.0
|
||||||
# Maintenance note: to move to a new version
|
# Maintenance note: to move to a new version
|
||||||
# of boost, update both BOOST_ROOT and BOOST_URL.
|
# of boost, update both BOOST_ROOT and BOOST_URL.
|
||||||
# Note that for simplicity, BOOST_ROOT's final
|
# Note that for simplicity, BOOST_ROOT's final
|
||||||
@@ -27,57 +28,50 @@ packages: &gcc5_pkgs
|
|||||||
- autotools-dev
|
- autotools-dev
|
||||||
- libc6-dbg
|
- libc6-dbg
|
||||||
|
|
||||||
packages: &clang38_pkgs
|
|
||||||
- clang-3.8
|
|
||||||
- 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:
|
matrix:
|
||||||
include:
|
include:
|
||||||
# GCC/Coverage
|
# GCC/Coverage/Autobahn
|
||||||
- compiler: gcc
|
- compiler: gcc
|
||||||
env: GCC_VER=5 VARIANT=coverage ADDRESS_MODEL=64
|
env:
|
||||||
|
- GCC_VER=5
|
||||||
|
- VARIANT=coverage
|
||||||
|
- ADDRESS_MODEL=64
|
||||||
|
- BUILD_SYSTEM=cmake
|
||||||
|
- PATH=$PWD/cmake/bin:$PATH
|
||||||
addons: &ao_gcc5
|
addons: &ao_gcc5
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: *gcc5_pkgs
|
packages: *gcc5_pkgs
|
||||||
|
|
||||||
# # GCC/Debug
|
|
||||||
# - compiler: gcc
|
|
||||||
# env: GCC_VER=5 VARIANT=debug ADDRESS_MODEL=64
|
|
||||||
# addons: *ao_gcc5
|
|
||||||
# branches: # NOTE: this does NOT work, though it SHOULD
|
|
||||||
# - master
|
|
||||||
# - develop
|
|
||||||
|
|
||||||
# Clang/UndefinedBehaviourSanitizer
|
# Clang/UndefinedBehaviourSanitizer
|
||||||
- compiler: clang
|
- compiler: clang
|
||||||
env: GCC_VER=5 VARIANT=usan CLANG_VER=3.8 ADDRESS_MODEL=64 UBSAN_OPTIONS='print_stacktrace=1'
|
env:
|
||||||
addons: &ao_clang38
|
- GCC_VER=5
|
||||||
apt:
|
- VARIANT=usan
|
||||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8']
|
- CLANG_VER=3.8
|
||||||
packages: *clang38_pkgs
|
- ADDRESS_MODEL=64
|
||||||
|
- UBSAN_OPTIONS='print_stacktrace=1'
|
||||||
|
- BUILD_SYSTEM=cmake
|
||||||
|
- PATH=$PWD/cmake/bin:$PATH
|
||||||
|
- PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
||||||
|
addons: *ao_gcc5
|
||||||
|
|
||||||
# Clang/AddressSanitizer
|
# Clang/AddressSanitizer
|
||||||
- compiler: clang
|
- compiler: clang
|
||||||
env: GCC_VER=5 VARIANT=asan CLANG_VER=3.8 ADDRESS_MODEL=64
|
env:
|
||||||
addons: *ao_clang38
|
- GCC_VER=5
|
||||||
|
- VARIANT=asan
|
||||||
|
- CLANG_VER=3.8
|
||||||
|
- ADDRESS_MODEL=64
|
||||||
|
- PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
||||||
|
addons: *ao_gcc5
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $BOOST_ROOT
|
- $BOOST_ROOT
|
||||||
- $VALGRIND_ROOT
|
- $VALGRIND_ROOT
|
||||||
|
- llvm-$LLVM_VERSION
|
||||||
|
- cmake
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- scripts/install-dependencies.sh
|
- scripts/install-dependencies.sh
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
1.0.0-b6
|
|
||||||
|
|
||||||
* Use SFINAE on return values
|
|
||||||
* Use beast::error_code instead of nested types
|
|
||||||
* Tidy up use of GENERATING_DOCS
|
|
||||||
* Remove obsolete RFC2616 functions
|
|
||||||
* Add message swap members and free functions
|
|
||||||
* Add HTTP field value parser containers: ext_list, param_list, token_list
|
|
||||||
* Fixes for some corner cases in basic_parser_v1
|
|
||||||
* Configurable limits on headers and body sizes in basic_parser_v1
|
|
||||||
|
|
||||||
API Changes:
|
|
||||||
|
|
||||||
* ci_equal is moved to beast::http namespace, in rfc7230.hpp
|
|
||||||
|
|
||||||
* "DynamicBuffer","dynabuf" renamed from "Streambuf", "streambuf". See:
|
|
||||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4478.html#requirements.dynamic_buffers
|
|
||||||
|
|
||||||
* basic_parser_v1 adheres to rfc7230 as strictly as possible
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
86
src/beast/CHANGELOG.md
Normal file
86
src/beast/CHANGELOG.md
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
1.0.0-b13
|
||||||
|
|
||||||
|
* dstream improvements
|
||||||
|
* Remove bin and bin64 directories
|
||||||
|
* Tidy up .vcxproj file groupings
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b12
|
||||||
|
|
||||||
|
* Use -p to print suites from unit test main.
|
||||||
|
* BEAST_EXPECTS to add a reason string to test failures
|
||||||
|
* Fix unit test runner to output all case names
|
||||||
|
* Update README for build requirements
|
||||||
|
* Rename to CHANGELOG.md
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b11
|
||||||
|
|
||||||
|
* Set URI in generated WebSocket Upgrade requests
|
||||||
|
* Rename echo server class and file names
|
||||||
|
* Rename to DynamicBuffer in some code and documentation
|
||||||
|
* Fix integer warnings in Windows builds
|
||||||
|
* Add 32 and 64 bit Windows build support
|
||||||
|
* Update README for build instructions and more
|
||||||
|
* Add repository and documention banners
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b10
|
||||||
|
|
||||||
|
* Fix compilation warnings
|
||||||
|
* Add websocketpp comparison to HTML documentation
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b9
|
||||||
|
|
||||||
|
* Fix CMakeLists.txt
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b8
|
||||||
|
|
||||||
|
* Fix include in example code
|
||||||
|
* Fix basic_headers rfc2616 Section 4.2 compliance
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b7
|
||||||
|
|
||||||
|
* Fix prepare by calling init. prepare() can throw depending on the
|
||||||
|
implementation of Writer. Publicly provided beast::http writers never throw.
|
||||||
|
* Fixes to example HTTP server
|
||||||
|
* Fully qualify ambiguous calls to read and parse
|
||||||
|
* Remove deprecated http::stream wrapper
|
||||||
|
* Example HTTP server now calculates the MIME-type
|
||||||
|
* Fixes and documentation for teardown and use with SSL:
|
||||||
|
* Add example code to rfc7230 javadocs
|
||||||
|
* Remove extraneous header file <beast/http/status.hpp>
|
||||||
|
* Add skip_body parser option
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b6
|
||||||
|
|
||||||
|
* Use SFINAE on return values
|
||||||
|
* Use beast::error_code instead of nested types
|
||||||
|
* Tidy up use of GENERATING_DOCS
|
||||||
|
* Remove obsolete RFC2616 functions
|
||||||
|
* Add message swap members and free functions
|
||||||
|
* Add HTTP field value parser containers: ext_list, param_list, token_list
|
||||||
|
* Fixes for some corner cases in basic_parser_v1
|
||||||
|
* Configurable limits on headers and body sizes in basic_parser_v1
|
||||||
|
|
||||||
|
API Changes:
|
||||||
|
|
||||||
|
* ci_equal is moved to beast::http namespace, in rfc7230.hpp
|
||||||
|
|
||||||
|
* "DynamicBuffer","dynabuf" renamed from "Streambuf", "streambuf". See:
|
||||||
|
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4478.html#requirements.dynamic_buffers
|
||||||
|
|
||||||
|
* basic_parser_v1 adheres to rfc7230 as strictly as possible
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
@@ -7,7 +7,7 @@ project (Beast)
|
|||||||
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4 /wd4100 /D_SCL_SECURE_NO_WARNINGS=1 /D_CRT_SECURE_NO_WARNINGS=1")
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4 /wd4100 /bigobj /D _WIN32_WINNT=0x0601 /D_SCL_SECURE_NO_WARNINGS=1 /D_CRT_SECURE_NO_WARNINGS=1")
|
||||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
||||||
else()
|
else()
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
@@ -20,10 +20,29 @@ else()
|
|||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS
|
set(CMAKE_CXX_FLAGS
|
||||||
"${CMAKE_CXX_FLAGS} -g -std=c++11 -Wall -Wpedantic")
|
"${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wpedantic")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
message ("cxx Flags: " ${CMAKE_CXX_FLAGS})
|
if ("${VARIANT}" STREQUAL "coverage")
|
||||||
|
set(CMAKE_CXX_FLAGS
|
||||||
|
"${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||||
|
set(CMAKE_BUILD_TYPE RELWITHDEBINFO)
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov")
|
||||||
|
elseif ("${VARIANT}" STREQUAL "asan")
|
||||||
|
set(CMAKE_CXX_FLAGS
|
||||||
|
"${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||||
|
set(CMAKE_BUILD_TYPE RELWITHDEBINFO)
|
||||||
|
elseif ("${VARIANT}" STREQUAL "usan")
|
||||||
|
set(CMAKE_CXX_FLAGS
|
||||||
|
"${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-omit-frame-pointer")
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
|
||||||
|
set(CMAKE_BUILD_TYPE RELWITHDEBINFO)
|
||||||
|
elseif ("${VARIANT}" STREQUAL "debug")
|
||||||
|
set(CMAKE_BUILD_TYPE DEBUG)
|
||||||
|
elseif ("${VARIANT}" STREQUAL "release")
|
||||||
|
set(CMAKE_BUILD_TYPE RELEASE)
|
||||||
|
endif()
|
||||||
|
|
||||||
function(DoGroupSources curdir rootdir folder)
|
function(DoGroupSources curdir rootdir folder)
|
||||||
file(GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${curdir} ${PROJECT_SOURCE_DIR}/${curdir}/*)
|
file(GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${curdir} ${PROJECT_SOURCE_DIR}/${curdir}/*)
|
||||||
@@ -51,6 +70,9 @@ include_directories (include)
|
|||||||
file(GLOB_RECURSE BEAST_INCLUDES
|
file(GLOB_RECURSE BEAST_INCLUDES
|
||||||
${PROJECT_SOURCE_DIR}/include/beast/*.hpp
|
${PROJECT_SOURCE_DIR}/include/beast/*.hpp
|
||||||
${PROJECT_SOURCE_DIR}/include/beast/*.ipp
|
${PROJECT_SOURCE_DIR}/include/beast/*.ipp
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE EXTRAS_INCLUDES
|
||||||
${PROJECT_SOURCE_DIR}/extras/beast/*.hpp
|
${PROJECT_SOURCE_DIR}/extras/beast/*.hpp
|
||||||
${PROJECT_SOURCE_DIR}/extras/beast/*.ipp
|
${PROJECT_SOURCE_DIR}/extras/beast/*.ipp
|
||||||
)
|
)
|
||||||
@@ -60,5 +82,3 @@ add_subdirectory (test)
|
|||||||
add_subdirectory (test/core)
|
add_subdirectory (test/core)
|
||||||
add_subdirectory (test/http)
|
add_subdirectory (test/http)
|
||||||
add_subdirectory (test/websocket)
|
add_subdirectory (test/websocket)
|
||||||
|
|
||||||
#enable_testing()
|
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ project beast
|
|||||||
<toolset>clang:<cxxflags>-std=c++11
|
<toolset>clang:<cxxflags>-std=c++11
|
||||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||||
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
||||||
|
<toolset>msvc:<cxxflags>-bigobj
|
||||||
<os>LINUX:<define>_XOPEN_SOURCE=600
|
<os>LINUX:<define>_XOPEN_SOURCE=600
|
||||||
<os>LINUX:<define>_GNU_SOURCE=1
|
<os>LINUX:<define>_GNU_SOURCE=1
|
||||||
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Beast
|
<img width="880" height = "80" alt = "Beast"
|
||||||
|
src="https://raw.githubusercontent.com/vinniefalco/Beast/master/doc/images/readme.png">
|
||||||
|
|
||||||
[](https://gitter.im/vinniefalco/Beast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status]
|
[](https://gitter.im/vinniefalco/Beast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status]
|
||||||
(https://travis-ci.org/vinniefalco/Beast.svg?branch=master)](https://travis-ci.org/vinniefalco/Beast) [![codecov]
|
(https://travis-ci.org/vinniefalco/Beast.svg?branch=master)](https://travis-ci.org/vinniefalco/Beast) [![codecov]
|
||||||
@@ -7,23 +8,151 @@
|
|||||||
(https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/) [![License]
|
(https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/) [![License]
|
||||||
(https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)
|
(https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)
|
||||||
|
|
||||||
Beast provides implementations of the HTTP and WebSocket protocols
|
# HTTP and WebSocket implementations built on Boost.Asio
|
||||||
built on top of Boost.Asio and other parts of boost.
|
|
||||||
|
|
||||||
Requirements:
|
---
|
||||||
|
|
||||||
* Boost
|
## CppCon 2016
|
||||||
* C++11 or greater
|
|
||||||
* OpenSSL (optional)
|
|
||||||
|
|
||||||
This software is currently in beta: interfaces are subject to change. For
|
I will be giving a lightning talk on Beast at CppCon 2016 in Bellevue,
|
||||||
recent changes see [CHANGELOG](CHANGELOG).
|
Washington from September 18 to September 22. If you'd like to meet me
|
||||||
|
and hear the talk or ask questions about Beast feel free to approach
|
||||||
|
me in person or send me an email at vinnie.falco@gmail.com to schedule
|
||||||
|
some time.
|
||||||
|
|
||||||
|
About CppCon 2016:
|
||||||
|
http://cppcon.org
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- [Introduction](#introduction)
|
||||||
|
- [Description](#description)
|
||||||
|
- [Requirements](#requirements)
|
||||||
|
- [Building](#building)
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [Licence](#licence)
|
||||||
|
- [Contact](#contact)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Beast is a header-only, cross-platform C++ library built on Boost.Asio and
|
||||||
|
Boost, containing two modules implementing widely used network protocols.
|
||||||
|
Beast.HTTP offers a universal model for describing, sending, and receiving
|
||||||
|
HTTP messages while Beast.WebSocket provides a complete implementation of
|
||||||
|
the WebSocket protocol. Their design achieves these goals:
|
||||||
|
|
||||||
|
* **Symmetry.** Interfaces are role-agnostic; the same interfaces can be
|
||||||
|
used to build clients, servers, or both.
|
||||||
|
|
||||||
|
* **Ease of Use.** HTTP messages are modeled using simple, readily
|
||||||
|
accessible objects. Functions and classes used to send and receive HTTP
|
||||||
|
or WebSocket messages are designed to resemble Boost.Asio as closely as
|
||||||
|
possible. Users familiar with Boost.Asio will be immediately comfortable
|
||||||
|
using this library.
|
||||||
|
|
||||||
|
* **Flexibility.** Interfaces do not mandate specific implementation
|
||||||
|
strategies; important decisions such as buffer or thread management are
|
||||||
|
left to users of the library.
|
||||||
|
|
||||||
|
* **Performance.** The implementation performs competitively, making it a
|
||||||
|
realistic choice for building high performance network servers.
|
||||||
|
|
||||||
|
* **Scalability.** Development of network applications that scale to thousands
|
||||||
|
of concurrent connections is possible with the implementation.
|
||||||
|
|
||||||
|
* **Basis for further abstraction.** The interfaces facilitate the
|
||||||
|
development of other libraries that provide higher levels of abstraction.
|
||||||
|
|
||||||
|
Beast is used in [rippled](https://github.com/ripple/rippled), an
|
||||||
|
open source server application that implements a decentralized
|
||||||
|
cryptocurrency system.
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This software is currently in beta: interfaces may change.
|
||||||
|
For recent changes see the [CHANGELOG](CHANGELOG.md).
|
||||||
The library has been submitted to the
|
The library has been submitted to the
|
||||||
[Boost Library Incubator](http://rrsd.com/blincubator.com/bi_library/beast-2/?gform_post_id=1579)
|
[Boost Library Incubator](http://rrsd.com/blincubator.com/bi_library/beast-2/?gform_post_id=1579)
|
||||||
|
|
||||||
|
* [Project Site](http://vinniefalco.github.io/)
|
||||||
|
* [Repository](https://github.com/vinniefalco/Beast)
|
||||||
|
* [Project Documentation](http://vinniefalco.github.io/beast/)
|
||||||
|
* [Autobahn.testsuite results](http://vinniefalco.github.io/autobahn/index.html)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
* Boost 1.58 or higher
|
||||||
|
* C++11 or greater
|
||||||
|
* OpenSSL (optional)
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Beast is header-only so there are no libraries to build or link with.
|
||||||
|
To use Beast in your project, simply copy the Beast sources to your
|
||||||
|
project's source tree (alternatively, bring Beast into your Git repository
|
||||||
|
using the `git subtree` or `git submodule` commands). Then, edit your
|
||||||
|
build scripts to add the `include/` directory to the list of paths checked
|
||||||
|
by the C++ compiler when searching for includes. Beast `#include` lines
|
||||||
|
will look like this:
|
||||||
|
```
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
#include <beast/websocket.hpp>
|
||||||
|
```
|
||||||
|
|
||||||
|
To link your program successfully, you'll need to add the Boost.System
|
||||||
|
library to link with. If you use coroutines you'll also need the
|
||||||
|
Boost.Coroutine library. Please visit the Boost documentation for
|
||||||
|
instructions on how to do this for your particular build system.
|
||||||
|
|
||||||
|
For the examples and tests, Beast provides build scripts for Boost.Build (bjam)
|
||||||
|
and CMake. Developers using Microsoft Visual Studio can generate Visual Studio
|
||||||
|
project files by executing these commands from the root of the repository:
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
cd bin
|
||||||
|
cmake .. # for 32-bit Windows build
|
||||||
|
|
||||||
|
cd ../bin64
|
||||||
|
cmake .. # for Linux/Mac builds, OR
|
||||||
|
cmake -G"Visual Studio 14 2015 Win64" .. # for 64-bit Windows builds
|
||||||
|
```
|
||||||
|
|
||||||
|
To build with Boost.Build, it is necessary to have the bjam executable
|
||||||
|
in your path. And bjam needs to know how to find the Boost sources. The
|
||||||
|
easiest way to do this is make sure that the version of bjam in your path
|
||||||
|
is the one at the root of the Boost source tree, which is built when
|
||||||
|
running `bootstrap.sh` (or `bootstrap.bat` on Windows).
|
||||||
|
|
||||||
|
Once bjam is in your path, simply run bjam in the root of the Beast
|
||||||
|
repository to automatically build the required Boost libraries if they
|
||||||
|
are not already built, build the examples, then build and run the unit
|
||||||
|
tests.
|
||||||
|
|
||||||
|
The files in the repository are laid out thusly:
|
||||||
|
|
||||||
|
```
|
||||||
|
./
|
||||||
|
bin/ Holds executables and project files
|
||||||
|
bin64/ Holds 64-bit Windows executables and project files
|
||||||
|
include/ Add this to your compiler includes
|
||||||
|
beast/
|
||||||
|
extras/ Additional APIs, may change
|
||||||
|
examples/ Self contained example programs
|
||||||
|
test/ Unit tests and benchmarks
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
These examples are complete, self-contained programs that you can build
|
||||||
|
and run yourself (they are in the `examples` directory).
|
||||||
|
|
||||||
Example WebSocket program:
|
Example WebSocket program:
|
||||||
```C++
|
```C++
|
||||||
#include <beast/to_string.hpp>
|
#include <beast/core/to_string.hpp>
|
||||||
#include <beast/websocket.hpp>
|
#include <beast/websocket.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -34,13 +163,13 @@ int main()
|
|||||||
// Normal boost::asio setup
|
// Normal boost::asio setup
|
||||||
std::string const host = "echo.websocket.org";
|
std::string const host = "echo.websocket.org";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
boost::asio::ip::tcp::socket sock(ios);
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||||
|
|
||||||
// WebSocket connect and send message using beast
|
// WebSocket connect and send message using beast
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
ws.handshake(host, "/");
|
ws.handshake(host, "/");
|
||||||
ws.write(boost::asio::buffer("Hello, world!"));
|
ws.write(boost::asio::buffer("Hello, world!"));
|
||||||
|
|
||||||
@@ -65,8 +194,8 @@ int main()
|
|||||||
// Normal boost::asio setup
|
// Normal boost::asio setup
|
||||||
std::string const host = "boost.org";
|
std::string const host = "boost.org";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
boost::asio::ip::tcp::socket sock(ios);
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
@@ -88,12 +217,13 @@ int main()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Links:
|
## License
|
||||||
|
|
||||||
* [Home](http://vinniefalco.github.io/)
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
* [Repository](https://github.com/vinniefalco/Beast)
|
(See accompanying file [LICENSE_1_0.txt](LICENSE_1_0.txt) or copy at
|
||||||
* [Documentation](http://vinniefalco.github.io/beast/)
|
http://www.boost.org/LICENSE_1_0.txt)
|
||||||
* [Autobahn.testsuite results](http://vinniefalco.github.io/autobahn/index.html)
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
Please report issues or questions here:
|
Please report issues or questions here:
|
||||||
https://github.com/vinniefalco/Beast/issues
|
https://github.com/vinniefalco/Beast/issues
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ using boostbook ;
|
|||||||
using quickbook ;
|
using quickbook ;
|
||||||
using doxygen ;
|
using doxygen ;
|
||||||
|
|
||||||
xml beast_boostbook : beast.qbk ;
|
xml beast_boostbook : master.qbk ;
|
||||||
|
|
||||||
path-constant out : . ;
|
path-constant out : . ;
|
||||||
|
|
||||||
@@ -56,8 +56,8 @@ boostbook doc
|
|||||||
<xsl:param>chapter.autolabel=0
|
<xsl:param>chapter.autolabel=0
|
||||||
<xsl:param>boost.image.src=images/beast.png
|
<xsl:param>boost.image.src=images/beast.png
|
||||||
<xsl:param>boost.image.alt="Beast Logo"
|
<xsl:param>boost.image.alt="Beast Logo"
|
||||||
<xsl:param>boost.image.w=1007
|
<xsl:param>boost.image.w=2400
|
||||||
<xsl:param>boost.image.h=107
|
<xsl:param>boost.image.h=80
|
||||||
<xsl:param>boost.root=$(broot)
|
<xsl:param>boost.root=$(broot)
|
||||||
<xsl:param>chapter.autolabel=0
|
<xsl:param>chapter.autolabel=0
|
||||||
<xsl:param>chunk.first.sections=1 # Chunk the first top-level section?
|
<xsl:param>chunk.first.sections=1 # Chunk the first top-level section?
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
[section:design Design choices]
|
[section:design Design choices]
|
||||||
|
|
||||||
The implementations are driven by business needs of cryptocurrency server
|
The implementations are driven by business needs of cryptocurrency server
|
||||||
applications ([@https://ripple.com Ripple] written in C++. These
|
applications (e.g. [@https://ripple.com Ripple]) written in C++. These
|
||||||
needs were not met by existing solutions so new code was written. The new
|
needs were not met by existing solutions so Beast was written from scratch
|
||||||
code tries to avoid design flaws encountered in the already-existing software
|
as a solution. Beast's design philosophy avoid flaws exhibited by other
|
||||||
libraries:
|
libraries:
|
||||||
|
|
||||||
* Don't sacrifice performance.
|
* Don't sacrifice performance.
|
||||||
@@ -44,11 +44,13 @@ to address those issues.
|
|||||||
in production. That would give some evidence that the design
|
in production. That would give some evidence that the design
|
||||||
works in practice.""
|
works in practice.""
|
||||||
][
|
][
|
||||||
Beast.HTTP and Beast.WebSocket will be used in [*rippled], an
|
Beast.HTTP and Beast.WebSocket are production ready and currently
|
||||||
asynchronous peer to peer server that implements the
|
running on public servers receiving traffic and handling millions of
|
||||||
[*Ripple Consensus Protocol]. These servers are deployed in multiple
|
dollars worth of financial transactions daily. The servers run [*rippled],
|
||||||
production environments, with banks in many countries running client
|
open source software ([@https://github.com/ripple/rippled repository])
|
||||||
applications that connect to [*rippled].
|
implementing the
|
||||||
|
[@https://ripple.com/files/ripple_consensus_whitepaper.pdf [*Ripple Consensus Protocol]],
|
||||||
|
technology provided by [@http://ripple.com Ripple].
|
||||||
]]
|
]]
|
||||||
|
|
||||||
]
|
]
|
||||||
@@ -171,26 +173,453 @@ start. Other design goals:
|
|||||||
[section:websocket WebSocket]
|
[section:websocket WebSocket]
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
|
[[
|
||||||
|
How does this compare to [@https://www.zaphoyd.com/websocketpp websocketpp],
|
||||||
|
an alternate header-only WebSocket implementation?
|
||||||
|
][
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[1. Synchronous Interface][
|
||||||
|
|
||||||
|
Beast offers full support for WebSockets using a synchronous interface. It
|
||||||
|
uses the same style of interfaces found in Boost.Asio: versions that throw
|
||||||
|
exceptions, or versions that return the error code in a reference parameter:
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]]
|
||||||
|
[websocketpp]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class DynamicBuffer>
|
||||||
|
void
|
||||||
|
read(opcode& op, DynamicBuffer& dynabuf)
|
||||||
|
```]
|
||||||
|
[
|
||||||
|
/<not available>/
|
||||||
|
]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[2. Connection Model][
|
||||||
|
|
||||||
|
websocketpp supports multiple transports by utilizing a trait, the `config::transport_type`
|
||||||
|
([@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/connection.hpp#L60 asio transport example])
|
||||||
|
To get an idea of the complexity involved with implementing a transport,
|
||||||
|
compare the asio transport to the
|
||||||
|
[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport]
|
||||||
|
(a layer that allows websocket communication over a std iostream).
|
||||||
|
|
||||||
|
In contrast, Beast abstracts the transport by defining just one [*`NextLayer`]
|
||||||
|
template argument The type requirements for [*`NextLayer`] are
|
||||||
|
already familiar to users as they are documented in Asio:
|
||||||
|
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html SyncReadStream],
|
||||||
|
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html SyncWriteStream],
|
||||||
|
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html AsyncReadStream], and
|
||||||
|
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html AsyncWriteStream].
|
||||||
|
The type requirements for instantiating `beast::websocket::stream` versus
|
||||||
|
`websocketpp::connection` with user defined types are vastly reduced
|
||||||
|
(18 functions versus 2). Note that websocketpp connections are passed by
|
||||||
|
`shared_ptr`. Beast does not use `shared_ptr` anywhere in its public interface.
|
||||||
|
A `beast::websocket::stream` is constructible and movable in a manner identical
|
||||||
|
`to a boost::asio::ip::tcp::socket`. Callers can put such objects in a
|
||||||
|
`shared_ptr` if they want to, but there is no requirement to do so.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp Beast]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L234 websocketpp]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class NextLayer>
|
||||||
|
class stream
|
||||||
|
{
|
||||||
|
NextLayer next_layer_;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
template <typename config>
|
||||||
|
class connection
|
||||||
|
: public config::transport_type::transport_con_type
|
||||||
|
, public config::connection_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef lib::shared_ptr<type> ptr;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[3. Client and Server Role][
|
||||||
|
|
||||||
|
websocketpp provides multi-role support through a hierarchy of
|
||||||
|
different classes. A `beast::websocket::stream` is role-agnostic, it
|
||||||
|
offers member functions to perform both client and server handshakes
|
||||||
|
in the same class. The same types are used for client and server
|
||||||
|
streams.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[Beast]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/server_endpoint.hpp#L39 websocketpp],
|
||||||
|
[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/client_endpoint.hpp#L42 also]]
|
||||||
|
][
|
||||||
|
[
|
||||||
|
/<not needed>/
|
||||||
|
]
|
||||||
|
[```
|
||||||
|
template <typename config>
|
||||||
|
class client : public endpoint<connection<config>,config>;
|
||||||
|
template <typename config>
|
||||||
|
class server : public endpoint<connection<config>,config>;
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[4. Thread Safety][
|
||||||
|
|
||||||
|
websocketpp uses mutexes to protect shared data from concurrent
|
||||||
|
access. In contrast, Beast does not use mutexes anywhere in its
|
||||||
|
implementation. Instead, it follows the Asio pattern. Calls to
|
||||||
|
asynchronous initiation functions use the same method to invoke
|
||||||
|
intermediate handlers as the method used to invoke the final handler,
|
||||||
|
through the
|
||||||
|
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/asio_handler_invoke.html asio_handler_invoke] mechanism.
|
||||||
|
|
||||||
|
The only requirement in Beast is that calls to asynchronous initiation
|
||||||
|
functions are made from the same implicit or explicit strand. For
|
||||||
|
example, if the `io_service` associated with a `beast::websocket::stream`
|
||||||
|
is single threaded, this counts as an implicit strand and no performance
|
||||||
|
costs associated with mutexes are incurred.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/read_frame_op.ipp#L118 Beast]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L706 websocketpp]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template <class Function>
|
||||||
|
friend
|
||||||
|
void asio_handler_invoke(Function&& f, read_frame_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_invoke_helpers::invoke(f, op->d_->h);
|
||||||
|
}
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
mutex_type m_read_mutex;
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[5. Callback Model][
|
||||||
|
|
||||||
|
websocketpp requires a one-time call to set the handler for each event
|
||||||
|
in its interface (for example, upon message receipt). The handler is
|
||||||
|
represented by a `std::function equivalent`. Its important to recognize
|
||||||
|
that the websocketpp interface performs type-erasure on this handler.
|
||||||
|
|
||||||
|
In comparison, Beast handlers are specified in a manner identical to
|
||||||
|
Boost.Asio. They are function objects which can be copied or moved but
|
||||||
|
most importantly they are not type erased. The compiler can see
|
||||||
|
through the type directly to the implementation, permitting
|
||||||
|
optimization. Furthermore, Beast follows the Asio rules for treatment
|
||||||
|
of handlers. It respects any allocation, continuation, or invocation
|
||||||
|
customizations associated with the handler through the use of argument
|
||||||
|
dependent lookup overloads of functions such as `asio_handler_allocate`.
|
||||||
|
|
||||||
|
The Beast completion handler is provided at the call site. For each
|
||||||
|
call to an asynchronous initiation function, it is guaranteed that
|
||||||
|
there will be exactly one final call to the handler. This functions
|
||||||
|
exactly the same way as the asynchronous initiation functions found in
|
||||||
|
Boost.Asio, allowing the composition of higher level abstractions.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L834 Beast]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L281 websocketpp],
|
||||||
|
[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L473 also]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class DynamicBuffer, class ReadHandler>
|
||||||
|
typename async_completion<ReadHandler, void(error_code)>::result_type
|
||||||
|
async_read(opcode& op, DynamicBuffer& dynabuf, ReadHandler&& handler);
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
typedef lib::function<void(connection_hdl,message_ptr)> message_handler;
|
||||||
|
void set_message_handler(message_handler h);
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[6. Extensible Asynchronous Model][
|
||||||
|
|
||||||
|
Beast fully supports the
|
||||||
|
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf Extensible Asynchronous Model]
|
||||||
|
developed by Christopher Kohlhoff, author of Boost.Asio (see Section 8).
|
||||||
|
|
||||||
|
Beast websocket asynchronous interfaces may be used seamlessly with
|
||||||
|
`std::future` stackful/stackless coroutines, or user defined customizations.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/stream.ipp#L378 Beast]]
|
||||||
|
[websocketpp]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
beast::async_completion<ReadHandler, void(error_code)> completion(handler);
|
||||||
|
read_op<DynamicBuffer, decltype(completion.handler)>{
|
||||||
|
completion.handler, *this, op, streambuf};
|
||||||
|
return completion.result.get();
|
||||||
|
```]
|
||||||
|
[
|
||||||
|
/<not available>/
|
||||||
|
]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[7. Message Buffering][
|
||||||
|
|
||||||
|
websocketpp defines a message buffer, passed in arguments by
|
||||||
|
`shared_ptr`, and an associated message manager which permits
|
||||||
|
aggregation and memory reuse of memory. The implementation of
|
||||||
|
`websocketpp::message` uses a `std::string` to hold the payload. If an
|
||||||
|
incoming message is broken up into multiple frames, the string may be
|
||||||
|
reallocated for each continuation frame. The std::string always uses
|
||||||
|
the standard allocator, it is not possible to customize the choice of
|
||||||
|
allocator.
|
||||||
|
|
||||||
|
Beast allows callers to specify the object for receiving the message
|
||||||
|
or frame data, which is of any type meeting the requirements of
|
||||||
|
[@http://vinniefalco.github.io/beast/beast/types/DynamicBuffer.html [*DynamicBuffer]]
|
||||||
|
(modeled after `boost::asio::streambuf`).
|
||||||
|
|
||||||
|
Beast comes with the class `beast::basic_streambuf`, an efficient
|
||||||
|
implementation of the [*DynamicBuffer] concept which makes use of multiple
|
||||||
|
allocated octet arrays. If an incoming message is broken up into
|
||||||
|
multiple pieces, no reallocation occurs. Instead, new allocations are
|
||||||
|
appended to the sequence when existing allocations are filled. Beast
|
||||||
|
does not impose any particular memory management model on callers. The
|
||||||
|
`basic_streambuf` provided by beast supports standard allocators through
|
||||||
|
a template argument. Use the [*DynamicBuffer] that comes with beast,
|
||||||
|
customize the allocator if you desire, or provide your own type that
|
||||||
|
meets the
|
||||||
|
[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/basic_streambuf.hpp#L21 concept requirements].
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/message_buffer/message.hpp#L78 websocketpp]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class DynamicBuffer>
|
||||||
|
read(opcode& op, DynamicBuffer& dynabuf);
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
template <template<class> class con_msg_manager>
|
||||||
|
class message {
|
||||||
|
public:
|
||||||
|
typedef lib::shared_ptr<message> ptr;
|
||||||
|
...
|
||||||
|
std::string m_payload;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[8. Sending Messages][
|
||||||
|
|
||||||
|
When sending a message, websocketpp requires that the payload is
|
||||||
|
packaged in a `websocketpp::message` object using `std::string` as the
|
||||||
|
storage, or it requires a copy of the caller provided buffer by
|
||||||
|
constructing a new message object. Messages are placed onto an
|
||||||
|
outgoing queue. An asynchronous write operation runs in the background
|
||||||
|
to clear the queue. No user facing handler can be registered to be
|
||||||
|
notified when messages or frames have completed sending.
|
||||||
|
|
||||||
|
Beast doesn't allocate or make copies of buffers when sending data. The
|
||||||
|
caller's buffers are sent in-place. You can use any object meeting the
|
||||||
|
requirements of
|
||||||
|
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html ConstBufferSequence],
|
||||||
|
permitting efficient scatter-gather I/O.
|
||||||
|
|
||||||
|
The [*ConstBufferSequence] interface allows callers to send data from
|
||||||
|
memory-mapped regions (not possible in websocketpp). Callers can also
|
||||||
|
use the same buffers to send data to multiple streams, for example
|
||||||
|
broadcasting common subscription data to many clients at once. For
|
||||||
|
each call to `async_write` the completion handler is called once when
|
||||||
|
the data finishes sending, in a manner identical to `boost::asio::async_write`.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1048 Beast]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L672 websocketpp]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
void
|
||||||
|
write(ConstBufferSequence const& buffers);
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
lib::error_code send(std::string const & payload,
|
||||||
|
frame::opcode::value op = frame::opcode::text);
|
||||||
|
...
|
||||||
|
lib::error_code send(message_ptr msg);
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[9. Streaming Messages][
|
||||||
|
|
||||||
|
websocketpp requires that the entire message fit into memory, and that
|
||||||
|
the size is known ahead of time.
|
||||||
|
|
||||||
|
Beast allows callers to compose messages in individual frames. This is
|
||||||
|
useful when the size of the data is not known ahead of time or if it
|
||||||
|
is not desired to buffer the entire message in memory at once before
|
||||||
|
sending it. For example, sending periodic output of a database query
|
||||||
|
running on a coroutine. Or sending the contents of a file in pieces,
|
||||||
|
without bringing it all into memory.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1151 Beast]]
|
||||||
|
[websocketpp]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
void
|
||||||
|
write_frame(bool fin,
|
||||||
|
ConstBufferSequence const& buffers);
|
||||||
|
```]
|
||||||
|
[
|
||||||
|
/<not available>/
|
||||||
|
]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[10. Flow Control][
|
||||||
|
|
||||||
|
The websocketpp read implementation continuously reads asynchronously
|
||||||
|
from the network and buffers message data. To prevent unbounded growth
|
||||||
|
and leverage TCP/IP's flow control mechanism, callers can periodically
|
||||||
|
turn this 'read pump' off and back on.
|
||||||
|
|
||||||
|
In contrast a `beast::websocket::stream` does not independently begin
|
||||||
|
background activity, nor does it buffer messages. It receives data only
|
||||||
|
when there is a call to an asynchronous initiation function (for
|
||||||
|
example `beast::websocket::stream::async_read`) with an associated handler.
|
||||||
|
Applications do not need to implement explicit logic to regulate the
|
||||||
|
flow of data. Instead, they follow the traditional model of issuing a
|
||||||
|
read, receiving a read completion, processing the message, then
|
||||||
|
issuing a new read and repeating the process.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[Beast]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L728 websocketpp]]
|
||||||
|
][
|
||||||
|
[
|
||||||
|
/<implicit>/
|
||||||
|
]
|
||||||
|
[```
|
||||||
|
lib::error_code pause_reading();
|
||||||
|
lib::error_code resume_reading();
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[11. Connection Establishment][
|
||||||
|
|
||||||
|
websocketpp offers the `endpoint` class which can handle binding and
|
||||||
|
listening to a port, and spawning connection objects.
|
||||||
|
|
||||||
|
Beast does not reinvent the wheel here, callers use the interfaces
|
||||||
|
already in `boost::asio` for receiving incoming connections resolving
|
||||||
|
host names, or establishing outgoing connections. After the socket (or
|
||||||
|
`boost::asio::ssl::stream`) is connected, the `beast::websocket::stream`
|
||||||
|
is constructed around it and the WebSocket handshake can be performed.
|
||||||
|
|
||||||
|
Beast users are free to implement their own "connection manager", but
|
||||||
|
there is no requirement to do so.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/async_connect.html Beast],
|
||||||
|
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html also]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/endpoint.hpp#L52 websocketpp]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
template <typename config>
|
||||||
|
class endpoint : public config::socket_type;
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[12. WebSocket Handshaking][
|
||||||
|
|
||||||
|
Callers invoke `beast::websocket::accept` to perform the WebSocket
|
||||||
|
handshake, but there is no requirement to use this function. Advanced
|
||||||
|
users can perform the WebSocket handshake themselves. Beast WebSocket
|
||||||
|
provides the tools for composing the request or response, and the
|
||||||
|
Beast HTTP interface provides the container and algorithms for sending
|
||||||
|
and receiving HTTP/1 messages including the necessary HTTP Upgrade
|
||||||
|
request for establishing the WebSocket session.
|
||||||
|
|
||||||
|
Beast allows the caller to pass the incoming HTTP Upgrade request for
|
||||||
|
the cases where the caller has already received an HTTP message.
|
||||||
|
This flexibility permits novel and robust implementations. For example,
|
||||||
|
a listening socket that can handshake in multiple protocols on the
|
||||||
|
same port.
|
||||||
|
|
||||||
|
Sometimes callers want to read some bytes on the socket before reading
|
||||||
|
the WebSocket HTTP Upgrade request. Beast allows these already-received
|
||||||
|
bytes to be supplied to an overload of the accepting function to permit
|
||||||
|
sophisticated features. For example, a listening socket that can
|
||||||
|
accept both regular WebSocket and Secure WebSocket (SSL) connections.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L501 Beast],
|
||||||
|
[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L401 also]]
|
||||||
|
[websocketpp]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
void
|
||||||
|
accept(ConstBufferSequence const& buffers);
|
||||||
|
|
||||||
|
template<class Body, class Headers>
|
||||||
|
void
|
||||||
|
accept(http::request_v1<Body, Headers> const& request);
|
||||||
|
```]
|
||||||
|
[
|
||||||
|
/<not available>/
|
||||||
|
]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
]
|
||||||
|
]]
|
||||||
|
|
||||||
[[
|
[[
|
||||||
What about message compression?
|
What about message compression?
|
||||||
][
|
][
|
||||||
The feature is not currently present in the library, but the choice
|
The author is currently porting ZLib 1.2.8 to modern, header-only C++11
|
||||||
of type requirements for buffers passed to the read functions have been
|
that does not use macros or try to support ancient architectures. This
|
||||||
made with compression in mind. There is the plan to add this feature;
|
deflate implementation will be available as its own individually
|
||||||
however, we feel that even without compression users can begin taking
|
usable interface, and also will be used to power Beast WebSocket's
|
||||||
advantage of the WebSocket protocol immediately with this library.
|
permessage-deflate implementation, due Q4 of 2016.
|
||||||
|
|
||||||
|
However, Beast currently has sufficient functionality that users can
|
||||||
|
begin taking advantage of the WebSocket protocol using this library
|
||||||
|
immediately.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
[[
|
[[
|
||||||
Where is the TLS/SSL interface?
|
Where is the TLS/SSL interface?
|
||||||
][
|
][
|
||||||
The `websocket::stream` just wraps the socket or stream that you
|
The `websocket::stream` wraps the socket or stream that you provide
|
||||||
provide (for example, a `boost::asio::ip::tcp::socket` or a
|
(for example, a `boost::asio::ip::tcp::socket` or a
|
||||||
`boost::asio::ssl::stream`). You establish your TLS connection
|
`boost::asio::ssl::stream`). You establish your TLS connection using the
|
||||||
using the interface on `ssl::stream` like shown in all of the Asio
|
interface on `ssl::stream` like shown in all of the Asio examples, they
|
||||||
examples, they construct your `websocket::stream` around it.
|
construct your `websocket::stream` around it. It works perfectly fine;
|
||||||
It works perfectly fine - Beast.WebSocket doesn't try to reinvent the
|
Beast.WebSocket doesn't try to reinvent the wheel or put a fresh coat of
|
||||||
wheel or put a fresh coat of interface paint on the `ssl::stream`.
|
interface paint on the `ssl::stream`.
|
||||||
|
|
||||||
The WebSocket implementation [*does] provides support for shutting down
|
The WebSocket implementation [*does] provides support for shutting down
|
||||||
the TLS connection through the use of the ADL compile-time virtual functions
|
the TLS connection through the use of the ADL compile-time virtual functions
|
||||||
@@ -200,14 +629,11 @@ start. Other design goals:
|
|||||||
for TLS streams. Callers may provide their own overloads of these functions
|
for TLS streams. Callers may provide their own overloads of these functions
|
||||||
for user-defined next layer types.
|
for user-defined next layer types.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|||||||
@@ -92,19 +92,20 @@ and its customization points in more depth, for advanced applications.
|
|||||||
[heading Declarations]
|
[heading Declarations]
|
||||||
|
|
||||||
To do anything, a message must be declared. The message class template
|
To do anything, a message must be declared. The message class template
|
||||||
requires at mininum, a value indicating whether the message is a request
|
requires at minimum, a value indicating whether the message is a request
|
||||||
(versus a response), and a `Body` type. The choice of `Body` determines the
|
(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
|
kind of container used to represent the message body. Here we will
|
||||||
declare a request that has a `std::string` for the body container:
|
declare a HTTP/1 request that has a `std::string` for the body container:
|
||||||
```
|
```
|
||||||
http::message<true, http::string_body> req;
|
http::message_v1<true, http::string_body> req;
|
||||||
```
|
```
|
||||||
|
|
||||||
Two type aliases are provided for notational convenience when declaring
|
Two type aliases are provided for notational convenience when declaring
|
||||||
messages. These two statements declare a request and a response respectively:
|
HTTP/1 messages. These two statements declare a request and a response
|
||||||
|
respectively:
|
||||||
```
|
```
|
||||||
http::request<http::string_body> req;
|
http::request_v1<http::string_body> req;
|
||||||
http::response<http::string_body> resp;
|
http::response_v1<http::string_body> resp;
|
||||||
```
|
```
|
||||||
|
|
||||||
[heading Members]
|
[heading Members]
|
||||||
@@ -113,14 +114,14 @@ Message objects are default constructible, with public access to data members.
|
|||||||
Request and response objects have some common members, and some members unique
|
Request and response objects have some common members, and some members unique
|
||||||
to the message type. These statements set all the members in each message:
|
to the message type. These statements set all the members in each message:
|
||||||
```
|
```
|
||||||
http::request<http::string_body> req;
|
http::request_v1<http::string_body> req;
|
||||||
req.method = http::method_t::http_get;
|
req.method = "GET";
|
||||||
req.url = "/index.html";
|
req.url = "/index.html";
|
||||||
req.version = 11; // HTTP/1.1
|
req.version = 11; // HTTP/1.1
|
||||||
req.headers.insert("User-Agent", "hello_world");
|
req.headers.insert("User-Agent", "hello_world");
|
||||||
req.body = "";
|
req.body = "";
|
||||||
|
|
||||||
http::response<http::string_body> resp;
|
http::response_v1<http::string_body> resp;
|
||||||
resp.status = 404;
|
resp.status = 404;
|
||||||
resp.reason = "Not Found";
|
resp.reason = "Not Found";
|
||||||
resp.version = 10; // HTTP/1.0
|
resp.version = 10; // HTTP/1.0
|
||||||
@@ -128,17 +129,6 @@ to the message type. These statements set all the members in each message:
|
|||||||
resp.body = "The requested resource was not found.";
|
resp.body = "The requested resource was not found.";
|
||||||
```
|
```
|
||||||
|
|
||||||
The following statements achieve the same effects as the statements above:
|
|
||||||
```
|
|
||||||
http::request<http::string_body> req({http::method_t::http_get, "/index.html", 11});
|
|
||||||
req.headers.insert("User-Agent", "hello_world");
|
|
||||||
req.body = "";
|
|
||||||
|
|
||||||
http::response<http::string_body> resp({404, "Not Found", 10});
|
|
||||||
resp.headers.insert("Server", "Beast.HTTP");
|
|
||||||
resp.body = "The requested resource was not found.";
|
|
||||||
```
|
|
||||||
|
|
||||||
[heading Headers]
|
[heading Headers]
|
||||||
|
|
||||||
The `message::headers` member is a container for setting the field/value
|
The `message::headers` member is a container for setting the field/value
|
||||||
@@ -146,7 +136,7 @@ pairs in the message. These statements change the values of the headers
|
|||||||
in the message passed:
|
in the message passed:
|
||||||
```
|
```
|
||||||
template<class Body>
|
template<class Body>
|
||||||
void set_fields(http::request<Body>& req)
|
void set_fields(http::request_v1<Body>& req)
|
||||||
{
|
{
|
||||||
if(! req.exists("User-Agent"))
|
if(! req.exists("User-Agent"))
|
||||||
req.insert("User-Agent", "myWebClient");
|
req.insert("User-Agent", "myWebClient");
|
||||||
@@ -168,7 +158,10 @@ following types, provided by the library, are suitable choices for the
|
|||||||
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
|
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
|
||||||
Used in GET requests where there is no message body. Example:
|
Used in GET requests where there is no message body. Example:
|
||||||
```
|
```
|
||||||
http::request<http::empty_body> req({http::method_t::http_get, "/index.html", 11});
|
http::request_v1<http::empty_body> req;
|
||||||
|
req.version = 11;
|
||||||
|
req.method = "GET";
|
||||||
|
req.url = "/index.html";
|
||||||
```
|
```
|
||||||
|
|
||||||
* [link beast.ref.http__string_body [*`string_body`:]] A body with a
|
* [link beast.ref.http__string_body [*`string_body`:]] A body with a
|
||||||
@@ -177,7 +170,7 @@ or response with simple text in the message body (such as an error message).
|
|||||||
Has the same insertion complexity of `std::string`. This is the type of body
|
Has the same insertion complexity of `std::string`. This is the type of body
|
||||||
used in the examples:
|
used in the examples:
|
||||||
```
|
```
|
||||||
http::response<http::string_body> resp;
|
http::response_v1<http::string_body> resp;
|
||||||
static_assert(std::is_same<decltype(resp.body), std::string>::value);
|
static_assert(std::is_same<decltype(resp.body), std::string>::value);
|
||||||
resp.body = "Here is the data you requested";
|
resp.body = "Here is the data you requested";
|
||||||
```
|
```
|
||||||
@@ -197,7 +190,10 @@ functions:
|
|||||||
```
|
```
|
||||||
void send_request(boost::asio::ip::tcp::socket& sock)
|
void send_request(boost::asio::ip::tcp::socket& sock)
|
||||||
{
|
{
|
||||||
http::request<http::empty_body> req({http::method_t::http_get, "/index.html", 11});
|
http::request<http::empty_body> req;
|
||||||
|
req.version = 11;
|
||||||
|
req.method = "GET";
|
||||||
|
req.url = "/index.html";
|
||||||
...
|
...
|
||||||
http::write(sock, req); // Throws exception on error
|
http::write(sock, req); // Throws exception on error
|
||||||
...
|
...
|
||||||
@@ -213,7 +209,7 @@ An asynchronous interface is available:
|
|||||||
```
|
```
|
||||||
void handle_write(boost::system::error_code);
|
void handle_write(boost::system::error_code);
|
||||||
...
|
...
|
||||||
http::request<http::empty_body> req;
|
http::request_v1<http::empty_body> req;
|
||||||
...
|
...
|
||||||
http::async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
|
http::async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
|
||||||
```
|
```
|
||||||
@@ -222,13 +218,13 @@ When the implementation reads messages from a socket, it can read bytes lying
|
|||||||
after the end of the message if they are present (the alternative is to read
|
after the end of the message if they are present (the alternative is to read
|
||||||
a single byte at a time which is unsuitable for performance reasons). To
|
a single byte at a time which is unsuitable for performance reasons). To
|
||||||
store and re-use these extra bytes on subsequent messages, the read interface
|
store and re-use these extra bytes on subsequent messages, the read interface
|
||||||
requires an additional paramter: a [link beast.types.DynamicBuffer [*`DynamicBuffer`]]
|
requires an additional parameter: a [link beast.types.DynamicBuffer [*`DynamicBuffer`]]
|
||||||
object. This example reads a message from the socket, with the extra bytes
|
object. This example reads a message from the socket, with the extra bytes
|
||||||
stored in the streambuf parameter for use in a subsequent call to read:
|
stored in the streambuf parameter for use in a subsequent call to read:
|
||||||
```
|
```
|
||||||
boost::asio::streambuf sb;
|
boost::asio::streambuf sb;
|
||||||
...
|
...
|
||||||
http::response<http::string_body> resp;
|
http::response_v1<http::string_body> resp;
|
||||||
http::read(sock, sb, resp); // Throws exception on error
|
http::read(sock, sb, resp); // Throws exception on error
|
||||||
...
|
...
|
||||||
// Alternatively
|
// Alternatively
|
||||||
@@ -245,7 +241,7 @@ called:
|
|||||||
void handle_read(boost::system::error_code);
|
void handle_read(boost::system::error_code);
|
||||||
...
|
...
|
||||||
boost::asio::streambuf sb;
|
boost::asio::streambuf sb;
|
||||||
http::response<http::string_body> resp;
|
http::response_v1<http::string_body> resp;
|
||||||
...
|
...
|
||||||
http::async_read(sock, resp, std::bind(&handle_read, std::placeholders::_1));
|
http::async_read(sock, resp, std::bind(&handle_read, std::placeholders::_1));
|
||||||
```
|
```
|
||||||
@@ -257,7 +253,7 @@ An alternative to using a `boost::asio::streambuf` is to use a
|
|||||||
void handle_read(boost::system::error_code);
|
void handle_read(boost::system::error_code);
|
||||||
...
|
...
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
http::response<http::string_body> resp;
|
http::response_v1<http::string_body> resp;
|
||||||
http::read(sock, sb, resp);
|
http::read(sock, sb, resp);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 241 KiB |
Binary file not shown.
BIN
src/beast/doc/images/readme.png
Normal file
BIN
src/beast/doc/images/readme.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
@@ -6,7 +6,7 @@
|
|||||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
mkdir -p ../bin/doc/xml
|
mkdir -p ../bin/doc/xml
|
||||||
doxygen beast.dox
|
doxygen source.dox
|
||||||
cd ../bin/doc/xml
|
cd ../bin/doc/xml
|
||||||
xsltproc combine.xslt index.xml > all.xml
|
xsltproc combine.xslt index.xml > all.xml
|
||||||
cd ../../../doc
|
cd ../../../doc
|
||||||
|
|||||||
@@ -39,11 +39,11 @@
|
|||||||
|
|
||||||
[section:intro Introduction]
|
[section:intro Introduction]
|
||||||
|
|
||||||
Beast is a cross-platform C++ library built on Boost.Asio and Boost, containing
|
Beast is a header-only, cross-platform C++ library built on Boost.Asio and
|
||||||
two modules implementing widely used network protocols. Beast.HTTP offers a
|
Boost, containing two modules implementing widely used network protocols.
|
||||||
universal model for describing, sending, and receiving HTTP messages while
|
Beast.HTTP offers a universal model for describing, sending, and receiving
|
||||||
Beast.WebSocket provides a complete implementation of the WebSocket protocol.
|
HTTP messages while Beast.WebSocket provides a complete implementation of
|
||||||
Their design achieves these goals:
|
the WebSocket protocol. Their design achieves these goals:
|
||||||
|
|
||||||
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
|
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
|
||||||
used to build clients, servers, or both.
|
used to build clients, servers, or both.
|
||||||
@@ -106,8 +106,8 @@ int main()
|
|||||||
// Normal boost::asio setup
|
// Normal boost::asio setup
|
||||||
std::string const host = "boost.org";
|
std::string const host = "boost.org";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
boost::asio::ip::tcp::socket sock(ios);
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ int main()
|
|||||||
|
|
||||||
Establish a WebSocket connection, send a message and receive the reply:
|
Establish a WebSocket connection, send a message and receive the reply:
|
||||||
```
|
```
|
||||||
#include <beast/to_string.hpp>
|
#include <beast/core/to_string.hpp>
|
||||||
#include <beast/websocket.hpp>
|
#include <beast/websocket.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -142,13 +142,13 @@ int main()
|
|||||||
// Normal boost::asio setup
|
// Normal boost::asio setup
|
||||||
std::string const host = "echo.websocket.org";
|
std::string const host = "echo.websocket.org";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
boost::asio::ip::tcp::socket sock(ios);
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||||
|
|
||||||
// WebSocket connect and send message using beast
|
// WebSocket connect and send message using beast
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
ws.handshake(host, "/");
|
ws.handshake(host, "/");
|
||||||
ws.write(boost::asio::buffer("Hello, world!"));
|
ws.write(boost::asio::buffer("Hello, world!"));
|
||||||
|
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
||||||
<member><link linkend="beast.ref.http__headers_max_size">headers_max_size</link></member>
|
<member><link linkend="beast.ref.http__headers_max_size">headers_max_size</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__skip_body">skip_body</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
@@ -85,6 +86,7 @@
|
|||||||
<member><link linkend="beast.ref.websocket__ping_data">ping_data</link></member>
|
<member><link linkend="beast.ref.websocket__ping_data">ping_data</link></member>
|
||||||
<member><link linkend="beast.ref.websocket__stream">stream</link></member>
|
<member><link linkend="beast.ref.websocket__stream">stream</link></member>
|
||||||
<member><link linkend="beast.ref.websocket__reason_string">reason_string</link></member>
|
<member><link linkend="beast.ref.websocket__reason_string">reason_string</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__teardown_tag">teardown_tag</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Options</bridgehead>
|
<bridgehead renderas="sect3">Options</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||||
|
|
||||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
file LICENSE_1_0.txt or copy at http://www.beast.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<xsl:output method="text"/>
|
<xsl:output method="text"/>
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ both Boost.Asio and the WebSocket protocol specification described in
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:creating Creating the socket]
|
[section:creation Creation]
|
||||||
|
|
||||||
The interface to Beast's WebSocket implementation is a single template
|
The interface to Beast's WebSocket implementation is a single template
|
||||||
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
|
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
|
||||||
@@ -75,24 +75,40 @@ of [link beast.types.streams.SyncStream [*`SyncReadStream`]] if synchronous
|
|||||||
operations are performed, or
|
operations are performed, or
|
||||||
[link beast.types.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
[link beast.types.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
||||||
operations are performed, or both. Arguments supplied during construction are
|
operations are performed, or both. Arguments supplied during construction are
|
||||||
passed to next layer's constructor. Here we declare two websockets which have
|
passed to next layer's constructor. Here we declare a websocket stream over
|
||||||
ownership of the next layer:
|
a TCP/IP socket with ownership of the socket:
|
||||||
```
|
```
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||||
|
|
||||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
|
||||||
beast::websocket::stream<
|
|
||||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> wss(ios, ctx);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[heading Using SSL]
|
||||||
|
|
||||||
|
To use WebSockets over SSL, choose an SSL stream for the next layer template
|
||||||
|
argument when constructing the stream.
|
||||||
|
```
|
||||||
|
#include <beast/websocket/ssl.hpp>
|
||||||
|
#include <beast/websocket.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
||||||
|
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ws(ios, ctx);
|
||||||
|
```
|
||||||
|
|
||||||
|
[note
|
||||||
|
When creating websocket stream objects using SSL, it is necessary
|
||||||
|
to include the file `<beast/websocket/ssl.hpp>`.
|
||||||
|
]
|
||||||
|
|
||||||
|
[heading Non-owning references]
|
||||||
|
|
||||||
For servers that can handshake in multiple protocols, it may be desired
|
For servers that can handshake in multiple protocols, it may be desired
|
||||||
to wrap an object that already exists. This socket can be moved in:
|
to wrap an object that already exists. This socket can be moved in:
|
||||||
```
|
```
|
||||||
boost::asio::ip::tcp::socket&& sock;
|
boost::asio::ip::tcp::socket&& sock;
|
||||||
...
|
...
|
||||||
beast::websocket::stream<
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(std::move(sock));
|
||||||
boost::asio::ip::tcp::socket> ws(std::move(sock));
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, the wrapper can be constructed with a non-owning reference. In
|
Or, the wrapper can be constructed with a non-owning reference. In
|
||||||
@@ -108,8 +124,7 @@ The layer being wrapped can be accessed through the websocket's "next layer",
|
|||||||
permitting callers to interact directly with its interface.
|
permitting callers to interact directly with its interface.
|
||||||
```
|
```
|
||||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
||||||
beast::websocket::stream<
|
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws(ios, ctx);
|
||||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws(ios, ctx);
|
|
||||||
...
|
...
|
||||||
ws.next_layer().shutdown(); // ssl::stream shutdown
|
ws.next_layer().shutdown(); // ssl::stream shutdown
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,49 +1,52 @@
|
|||||||
# Part of Beast
|
# Part of Beast
|
||||||
|
|
||||||
GroupSources(extras/beast beast)
|
GroupSources(extras/beast extras)
|
||||||
GroupSources(include/beast beast)
|
GroupSources(include/beast beast)
|
||||||
|
|
||||||
GroupSources(examples "/")
|
GroupSources(examples "/")
|
||||||
|
|
||||||
add_executable (http-crawl
|
add_executable (http-crawl
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
urls_large_data.hpp
|
urls_large_data.hpp
|
||||||
urls_large_data.cpp
|
urls_large_data.cpp
|
||||||
http_crawl.cpp
|
http_crawl.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(http-crawl ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(http-crawl ${Boost_LIBRARIES} Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable (http-server
|
add_executable (http-server
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
file_body.hpp
|
file_body.hpp
|
||||||
|
mime_type.hpp
|
||||||
http_async_server.hpp
|
http_async_server.hpp
|
||||||
http_stream.hpp
|
|
||||||
http_stream.ipp
|
|
||||||
http_sync_server.hpp
|
http_sync_server.hpp
|
||||||
http_server.cpp
|
http_server.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(http-server ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(http-server ${Boost_LIBRARIES} Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable (http-example
|
add_executable (http-example
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
http_example.cpp
|
http_example.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(http-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(http-example ${Boost_LIBRARIES} Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable (websocket-example
|
add_executable (websocket-example
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
websocket_example.cpp
|
websocket_example.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(websocket-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(websocket-example ${Boost_LIBRARIES} Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ struct file_body
|
|||||||
|
|
||||||
class writer
|
class writer
|
||||||
{
|
{
|
||||||
std::uint64_t size_;
|
std::uint64_t size_ = 0;
|
||||||
std::uint64_t offset_ = 0;
|
std::uint64_t offset_ = 0;
|
||||||
std::string const& path_;
|
std::string const& path_;
|
||||||
FILE* file_ = nullptr;
|
FILE* file_ = nullptr;
|
||||||
|
|||||||
@@ -9,10 +9,13 @@
|
|||||||
#define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
#define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
||||||
|
|
||||||
#include "file_body.hpp"
|
#include "file_body.hpp"
|
||||||
#include "http_stream.hpp"
|
#include "mime_type.hpp"
|
||||||
|
|
||||||
|
#include <beast/http.hpp>
|
||||||
#include <beast/core/placeholders.hpp>
|
#include <beast/core/placeholders.hpp>
|
||||||
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -32,17 +35,19 @@ class http_async_server
|
|||||||
using req_type = request_v1<string_body>;
|
using req_type = request_v1<string_body>;
|
||||||
using resp_type = response_v1<file_body>;
|
using resp_type = response_v1<file_body>;
|
||||||
|
|
||||||
|
std::mutex m_;
|
||||||
|
bool log_ = true;
|
||||||
boost::asio::io_service ios_;
|
boost::asio::io_service ios_;
|
||||||
socket_type sock_;
|
|
||||||
boost::asio::ip::tcp::acceptor acceptor_;
|
boost::asio::ip::tcp::acceptor acceptor_;
|
||||||
|
socket_type sock_;
|
||||||
std::string root_;
|
std::string root_;
|
||||||
std::vector<std::thread> thread_;
|
std::vector<std::thread> thread_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
http_async_server(endpoint_type const& ep,
|
http_async_server(endpoint_type const& ep,
|
||||||
int threads, std::string const& root)
|
std::size_t threads, std::string const& root)
|
||||||
: sock_(ios_)
|
: acceptor_(ios_)
|
||||||
, acceptor_(ios_)
|
, sock_(ios_)
|
||||||
, root_(root)
|
, root_(root)
|
||||||
{
|
{
|
||||||
acceptor_.open(ep.protocol());
|
acceptor_.open(ep.protocol());
|
||||||
@@ -53,7 +58,7 @@ public:
|
|||||||
std::bind(&http_async_server::on_accept, this,
|
std::bind(&http_async_server::on_accept, this,
|
||||||
beast::asio::placeholders::error));
|
beast::asio::placeholders::error));
|
||||||
thread_.reserve(threads);
|
thread_.reserve(threads);
|
||||||
for(int i = 0; i < threads; ++i)
|
for(std::size_t i = 0; i < threads; ++i)
|
||||||
thread_.emplace_back(
|
thread_.emplace_back(
|
||||||
[&] { ios_.run(); });
|
[&] { ios_.run(); });
|
||||||
}
|
}
|
||||||
@@ -67,13 +72,124 @@ public:
|
|||||||
t.join();
|
t.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
void
|
||||||
|
log(Args const&... args)
|
||||||
|
{
|
||||||
|
if(log_)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_);
|
||||||
|
log_args(args...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template<class Stream, class Handler,
|
||||||
|
bool isRequest, class Body, class Headers>
|
||||||
|
class write_op
|
||||||
|
{
|
||||||
|
using alloc_type =
|
||||||
|
handler_alloc<char, Handler>;
|
||||||
|
|
||||||
|
struct data
|
||||||
|
{
|
||||||
|
Stream& s;
|
||||||
|
message_v1<isRequest, Body, Headers> m;
|
||||||
|
Handler h;
|
||||||
|
bool cont;
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
|
data(DeducedHandler&& h_, Stream& s_,
|
||||||
|
message_v1<isRequest, Body, Headers>&& m_)
|
||||||
|
: s(s_)
|
||||||
|
, m(std::move(m_))
|
||||||
|
, h(std::forward<DeducedHandler>(h_))
|
||||||
|
, cont(boost_asio_handler_cont_helpers::
|
||||||
|
is_continuation(h))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<data> d_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
write_op(write_op&&) = default;
|
||||||
|
write_op(write_op const&) = default;
|
||||||
|
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
write_op(DeducedHandler&& h, Stream& s, Args&&... args)
|
||||||
|
: d_(std::allocate_shared<data>(alloc_type{h},
|
||||||
|
std::forward<DeducedHandler>(h), s,
|
||||||
|
std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
(*this)(error_code{}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(error_code ec, bool again = true)
|
||||||
|
{
|
||||||
|
auto& d = *d_;
|
||||||
|
d.cont = d.cont || again;
|
||||||
|
if(! again)
|
||||||
|
{
|
||||||
|
beast::http::async_write(d.s, d.m, std::move(*this));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d.h(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void* asio_handler_allocate(
|
||||||
|
std::size_t size, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
allocate(size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_alloc_helpers::
|
||||||
|
deallocate(p, size, op->d_->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
bool asio_handler_is_continuation(write_op* op)
|
||||||
|
{
|
||||||
|
return op->d_->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Function>
|
||||||
|
friend
|
||||||
|
void asio_handler_invoke(Function&& f, write_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_invoke_helpers::
|
||||||
|
invoke(f, op->d_->h);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Stream,
|
||||||
|
bool isRequest, class Body, class Headers,
|
||||||
|
class DeducedHandler>
|
||||||
|
static
|
||||||
|
void
|
||||||
|
async_write(Stream& stream, message_v1<
|
||||||
|
isRequest, Body, Headers>&& msg,
|
||||||
|
DeducedHandler&& handler)
|
||||||
|
{
|
||||||
|
write_op<Stream, typename std::decay<DeducedHandler>::type,
|
||||||
|
isRequest, Body, Headers>{std::forward<DeducedHandler>(
|
||||||
|
handler), stream, std::move(msg)};
|
||||||
|
}
|
||||||
|
|
||||||
class peer : public std::enable_shared_from_this<peer>
|
class peer : public std::enable_shared_from_this<peer>
|
||||||
{
|
{
|
||||||
int id_;
|
int id_;
|
||||||
stream<socket_type> stream_;
|
streambuf sb_;
|
||||||
|
socket_type sock_;
|
||||||
|
http_async_server& server_;
|
||||||
boost::asio::io_service::strand strand_;
|
boost::asio::io_service::strand strand_;
|
||||||
std::string root_;
|
|
||||||
req_type req_;
|
req_type req_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -82,16 +198,22 @@ private:
|
|||||||
peer& operator=(peer&&) = delete;
|
peer& operator=(peer&&) = delete;
|
||||||
peer& operator=(peer const&) = delete;
|
peer& operator=(peer const&) = delete;
|
||||||
|
|
||||||
explicit
|
peer(socket_type&& sock, http_async_server& server)
|
||||||
peer(socket_type&& sock, std::string const& root)
|
: sock_(std::move(sock))
|
||||||
: stream_(std::move(sock))
|
, server_(server)
|
||||||
, strand_(stream_.get_io_service())
|
, strand_(sock_.get_io_service())
|
||||||
, root_(root)
|
|
||||||
{
|
{
|
||||||
static int n = 0;
|
static int n = 0;
|
||||||
id_ = ++n;
|
id_ = ++n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fail(error_code ec, std::string what)
|
||||||
|
{
|
||||||
|
if(ec != boost::asio::error::operation_aborted)
|
||||||
|
server_.log("#", id_, " ", what, ": ", ec.message(), "\n");
|
||||||
|
}
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
do_read();
|
do_read();
|
||||||
@@ -99,43 +221,58 @@ private:
|
|||||||
|
|
||||||
void do_read()
|
void do_read()
|
||||||
{
|
{
|
||||||
stream_.async_read(req_, strand_.wrap(
|
async_read(sock_, sb_, req_, strand_.wrap(
|
||||||
std::bind(&peer::on_read, shared_from_this(),
|
std::bind(&peer::on_read, shared_from_this(),
|
||||||
asio::placeholders::error)));
|
asio::placeholders::error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_read(error_code ec)
|
void on_read(error_code const& ec)
|
||||||
{
|
{
|
||||||
if(ec)
|
if(ec)
|
||||||
return fail(ec, "read");
|
return fail(ec, "read");
|
||||||
do_read();
|
|
||||||
auto path = req_.url;
|
auto path = req_.url;
|
||||||
if(path == "/")
|
if(path == "/")
|
||||||
path = "/index.html";
|
path = "/index.html";
|
||||||
path = root_ + path;
|
path = server_.root_ + path;
|
||||||
if(! boost::filesystem::exists(path))
|
if(! boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
response_v1<string_body> resp;
|
response_v1<string_body> res;
|
||||||
resp.status = 404;
|
res.status = 404;
|
||||||
resp.reason = "Not Found";
|
res.reason = "Not Found";
|
||||||
resp.version = req_.version;
|
res.version = req_.version;
|
||||||
resp.headers.replace("Server", "http_async_server");
|
res.headers.insert("Server", "http_async_server");
|
||||||
resp.body = "The file '" + path + "' was not found";
|
res.headers.insert("Content-Type", "text/html");
|
||||||
prepare(resp);
|
res.body = "The file '" + path + "' was not found";
|
||||||
stream_.async_write(std::move(resp),
|
prepare(res);
|
||||||
|
async_write(sock_, std::move(res),
|
||||||
std::bind(&peer::on_write, shared_from_this(),
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
asio::placeholders::error));
|
asio::placeholders::error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resp_type resp;
|
resp_type res;
|
||||||
resp.status = 200;
|
res.status = 200;
|
||||||
resp.reason = "OK";
|
res.reason = "OK";
|
||||||
resp.version = req_.version;
|
res.version = req_.version;
|
||||||
resp.headers.replace("Server", "http_async_server");
|
res.headers.insert("Server", "http_async_server");
|
||||||
resp.headers.replace("Content-Type", "text/html");
|
res.headers.insert("Content-Type", mime_type(path));
|
||||||
resp.body = path;
|
res.body = path;
|
||||||
prepare(resp);
|
try
|
||||||
stream_.async_write(std::move(resp),
|
{
|
||||||
|
prepare(res);
|
||||||
|
}
|
||||||
|
catch(std::exception const& e)
|
||||||
|
{
|
||||||
|
res = {};
|
||||||
|
res.status = 500;
|
||||||
|
res.reason = "Internal Error";
|
||||||
|
res.version = req_.version;
|
||||||
|
res.headers.insert("Server", "http_async_server");
|
||||||
|
res.headers.insert("Content-Type", "text/html");
|
||||||
|
res.body =
|
||||||
|
std::string{"An internal error occurred"} + e.what();
|
||||||
|
prepare(res);
|
||||||
|
}
|
||||||
|
async_write(sock_, std::move(res),
|
||||||
std::bind(&peer::on_write, shared_from_this(),
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
asio::placeholders::error));
|
asio::placeholders::error));
|
||||||
}
|
}
|
||||||
@@ -144,36 +281,27 @@ private:
|
|||||||
{
|
{
|
||||||
if(ec)
|
if(ec)
|
||||||
fail(ec, "write");
|
fail(ec, "write");
|
||||||
}
|
do_read();
|
||||||
|
|
||||||
private:
|
|
||||||
void
|
|
||||||
fail(error_code ec, std::string what)
|
|
||||||
{
|
|
||||||
if(ec != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
std::cerr <<
|
|
||||||
"#" << std::to_string(id_) << " " <<
|
|
||||||
what << ": " << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
fail(error_code ec, std::string what)
|
log_args()
|
||||||
{
|
{
|
||||||
std::cerr <<
|
}
|
||||||
what << ": " << ec.message() << std::endl;
|
|
||||||
|
template<class Arg, class... Args>
|
||||||
|
void
|
||||||
|
log_args(Arg const& arg, Args const&... args)
|
||||||
|
{
|
||||||
|
std::cerr << arg;
|
||||||
|
log_args(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
maybe_throw(error_code ec, std::string what)
|
fail(error_code ec, std::string what)
|
||||||
{
|
{
|
||||||
if(ec)
|
log(what, ": ", ec.message(), "\n");
|
||||||
{
|
|
||||||
fail(ec, what);
|
|
||||||
throw ec;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -181,12 +309,13 @@ private:
|
|||||||
{
|
{
|
||||||
if(! acceptor_.is_open())
|
if(! acceptor_.is_open())
|
||||||
return;
|
return;
|
||||||
maybe_throw(ec, "accept");
|
if(ec)
|
||||||
|
return fail(ec, "accept");
|
||||||
socket_type sock(std::move(sock_));
|
socket_type sock(std::move(sock_));
|
||||||
acceptor_.async_accept(sock_,
|
acceptor_.async_accept(sock_,
|
||||||
std::bind(&http_async_server::on_accept, this,
|
std::bind(&http_async_server::on_accept, this,
|
||||||
asio::placeholders::error));
|
asio::placeholders::error));
|
||||||
std::make_shared<peer>(std::move(sock), root_)->run();
|
std::make_shared<peer>(std::move(sock), *this)->run();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "http_stream.hpp"
|
|
||||||
#include "urls_large_data.hpp"
|
#include "urls_large_data.hpp"
|
||||||
|
|
||||||
|
#include <beast/core/streambuf.hpp>
|
||||||
|
#include <beast/http.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@@ -31,9 +32,9 @@ int main(int, char const*[])
|
|||||||
ip::tcp::resolver r(ios);
|
ip::tcp::resolver r(ios);
|
||||||
auto it = r.resolve(
|
auto it = r.resolve(
|
||||||
ip::tcp::resolver::query{host, "http"});
|
ip::tcp::resolver::query{host, "http"});
|
||||||
stream<ip::tcp::socket> hs(ios);
|
ip::tcp::socket sock(ios);
|
||||||
connect(hs.lowest_layer(), it);
|
connect(sock, it);
|
||||||
auto ep = hs.lowest_layer().remote_endpoint();
|
auto ep = sock.remote_endpoint();
|
||||||
request_v1<empty_body> req;
|
request_v1<empty_body> req;
|
||||||
req.method = "GET";
|
req.method = "GET";
|
||||||
req.url = "/";
|
req.url = "/";
|
||||||
@@ -42,10 +43,11 @@ int main(int, char const*[])
|
|||||||
std::string(":") + std::to_string(ep.port()));
|
std::string(":") + std::to_string(ep.port()));
|
||||||
req.headers.insert("User-Agent", "beast/http");
|
req.headers.insert("User-Agent", "beast/http");
|
||||||
prepare(req);
|
prepare(req);
|
||||||
hs.write(req);
|
write(sock, req);
|
||||||
response_v1<string_body> resp;
|
response_v1<string_body> res;
|
||||||
hs.read(resp);
|
streambuf sb;
|
||||||
std::cout << resp;
|
beast::http::read(sock, sb, res);
|
||||||
|
std::cout << res;
|
||||||
}
|
}
|
||||||
catch(boost::system::system_error const& ec)
|
catch(boost::system::system_error const& ec)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ int main()
|
|||||||
// Normal boost::asio setup
|
// Normal boost::asio setup
|
||||||
std::string const host = "boost.org";
|
std::string const host = "boost.org";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
boost::asio::ip::tcp::socket sock(ios);
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,13 @@ int main(int ac, char const* av[])
|
|||||||
endpoint_type ep{address_type::from_string(ip), port};
|
endpoint_type ep{address_type::from_string(ip), port};
|
||||||
|
|
||||||
if(sync)
|
if(sync)
|
||||||
|
{
|
||||||
http_sync_server server(ep, root);
|
http_sync_server server(ep, root);
|
||||||
|
beast::test::sig_wait();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
http_async_server server(ep, threads, root);
|
http_async_server server(ep, threads, root);
|
||||||
beast::test::sig_wait();
|
beast::test::sig_wait();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,480 +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_STREAM_H_INCLUDED
|
|
||||||
#define BEAST_HTTP_STREAM_H_INCLUDED
|
|
||||||
|
|
||||||
#include <beast/core/async_completion.hpp>
|
|
||||||
#include <beast/core/basic_streambuf.hpp>
|
|
||||||
#include <beast/http.hpp>
|
|
||||||
#include <boost/asio/io_service.hpp>
|
|
||||||
#include <boost/intrusive/list.hpp>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace http {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
class stream_base
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
struct op
|
|
||||||
: boost::intrusive::list_base_hook<
|
|
||||||
boost::intrusive::link_mode<
|
|
||||||
boost::intrusive::normal_link>>
|
|
||||||
{
|
|
||||||
virtual ~op() = default;
|
|
||||||
virtual void operator()() = 0;
|
|
||||||
virtual void cancel() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
using op_list = typename boost::intrusive::make_list<
|
|
||||||
op, boost::intrusive::constant_time_size<false>>::type;
|
|
||||||
|
|
||||||
op_list wr_q_;
|
|
||||||
bool wr_active_ = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // detail
|
|
||||||
|
|
||||||
/** Provides message-oriented functionality using HTTP.
|
|
||||||
|
|
||||||
The stream class template provides asynchronous and blocking
|
|
||||||
message-oriented functionality necessary for clients and servers
|
|
||||||
to utilize the HTTP protocol.
|
|
||||||
|
|
||||||
@par Thread Safety
|
|
||||||
@e Distinct @e objects: Safe.@n
|
|
||||||
@e Shared @e objects: Unsafe. The application must ensure that
|
|
||||||
all asynchronous operations are performed within the same
|
|
||||||
implicit or explicit strand.
|
|
||||||
|
|
||||||
@par Example
|
|
||||||
|
|
||||||
To use the class template with an `ip::tcp::socket`, you would write:
|
|
||||||
|
|
||||||
@code
|
|
||||||
http::stream<ip::tcp::socket> hs(io_service);
|
|
||||||
@endcode
|
|
||||||
Alternatively, you can write:
|
|
||||||
@code
|
|
||||||
ip::tcp::socket sock(io_service);
|
|
||||||
http::stream<ip::tcp::socket&> hs(sock);
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
@note A stream object must not be destroyed while there are
|
|
||||||
pending asynchronous operations associated with it.
|
|
||||||
|
|
||||||
@par Concepts
|
|
||||||
AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
|
|
||||||
*/
|
|
||||||
template<class NextLayer,
|
|
||||||
class Allocator = std::allocator<char>>
|
|
||||||
class stream : public detail::stream_base
|
|
||||||
{
|
|
||||||
NextLayer next_layer_;
|
|
||||||
basic_streambuf<Allocator> rd_buf_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// The type of the next layer.
|
|
||||||
using next_layer_type =
|
|
||||||
typename std::remove_reference<NextLayer>::type;
|
|
||||||
|
|
||||||
/// The type of the lowest layer.
|
|
||||||
using lowest_layer_type =
|
|
||||||
typename next_layer_type::lowest_layer_type;
|
|
||||||
|
|
||||||
/// The type of endpoint of the lowest layer.
|
|
||||||
using endpoint_type =
|
|
||||||
typename lowest_layer_type::endpoint_type;
|
|
||||||
|
|
||||||
/// The protocol of the next layer.
|
|
||||||
using protocol_type =
|
|
||||||
typename lowest_layer_type::protocol_type;
|
|
||||||
|
|
||||||
/// The type of resolver of the next layer.
|
|
||||||
using resolver_type =
|
|
||||||
typename protocol_type::resolver;
|
|
||||||
|
|
||||||
/** Destructor.
|
|
||||||
|
|
||||||
@note A stream object must not be destroyed while there
|
|
||||||
are pending asynchronous operations associated with it.
|
|
||||||
*/
|
|
||||||
~stream();
|
|
||||||
|
|
||||||
/** Move constructor.
|
|
||||||
|
|
||||||
Undefined behavior if operations are active or pending.
|
|
||||||
*/
|
|
||||||
stream(stream&&) = default;
|
|
||||||
|
|
||||||
/** Move assignment.
|
|
||||||
|
|
||||||
Undefined behavior if operations are active or pending.
|
|
||||||
*/
|
|
||||||
stream& operator=(stream&&) = default;
|
|
||||||
|
|
||||||
/** Construct a HTTP stream.
|
|
||||||
|
|
||||||
This constructor creates a HTTP stream and initialises
|
|
||||||
the next layer.
|
|
||||||
|
|
||||||
@throws Any exceptions thrown by the Stream constructor.
|
|
||||||
|
|
||||||
@param args The arguments to be passed to initialise the
|
|
||||||
next layer. The arguments are forwarded to the next layer's
|
|
||||||
constructor.
|
|
||||||
*/
|
|
||||||
template<class... Args>
|
|
||||||
explicit
|
|
||||||
stream(Args&&... args);
|
|
||||||
|
|
||||||
/** Get the io_service associated with the stream.
|
|
||||||
|
|
||||||
This function may be used to obtain the io_service object
|
|
||||||
that the stream uses to dispatch handlers for asynchronous
|
|
||||||
operations.
|
|
||||||
|
|
||||||
@return A reference to the io_service object that the stream
|
|
||||||
will use to dispatch handlers. Ownership is not transferred
|
|
||||||
to the caller.
|
|
||||||
*/
|
|
||||||
boost::asio::io_service&
|
|
||||||
get_io_service()
|
|
||||||
{
|
|
||||||
return next_layer_.lowest_layer().get_io_service();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a reference to the next layer.
|
|
||||||
|
|
||||||
This function returns a reference to the next layer
|
|
||||||
in a stack of stream layers.
|
|
||||||
|
|
||||||
@return A reference to the next layer in the stack of
|
|
||||||
stream layers. Ownership is not transferred to the caller.
|
|
||||||
*/
|
|
||||||
next_layer_type&
|
|
||||||
next_layer()
|
|
||||||
{
|
|
||||||
return next_layer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a reference to the next layer.
|
|
||||||
|
|
||||||
This function returns a reference to the next layer in a
|
|
||||||
stack of stream layers.
|
|
||||||
|
|
||||||
@return A reference to the next layer in the stack of
|
|
||||||
stream layers. Ownership is not transferred to the caller.
|
|
||||||
*/
|
|
||||||
next_layer_type const&
|
|
||||||
next_layer() const
|
|
||||||
{
|
|
||||||
return next_layer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a reference to the lowest layer.
|
|
||||||
|
|
||||||
This function returns a reference to the lowest layer
|
|
||||||
in a stack of stream layers.
|
|
||||||
|
|
||||||
@return A reference to the lowest layer in the stack of
|
|
||||||
stream layers. Ownership is not transferred to the caller.
|
|
||||||
*/
|
|
||||||
lowest_layer_type&
|
|
||||||
lowest_layer()
|
|
||||||
{
|
|
||||||
return next_layer_.lowest_layer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a reference to the lowest layer.
|
|
||||||
|
|
||||||
This function returns a reference to the lowest layer
|
|
||||||
in a stack of stream layers.
|
|
||||||
|
|
||||||
@return A reference to the lowest layer in the stack of
|
|
||||||
stream layers. Ownership is not transferred to the caller.
|
|
||||||
*/
|
|
||||||
lowest_layer_type const&
|
|
||||||
lowest_layer() const
|
|
||||||
{
|
|
||||||
return next_layer_.lowest_layer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Cancel pending operations.
|
|
||||||
|
|
||||||
This will cancel all of the asynchronous operations pending,
|
|
||||||
including pipelined writes that have not been started. Handlers for
|
|
||||||
canceled writes will be called with
|
|
||||||
`boost::asio::error::operation_aborted`.
|
|
||||||
|
|
||||||
@throws boost::system::system_error Thrown on failure.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
cancel()
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
cancel(ec);
|
|
||||||
if(ec)
|
|
||||||
throw system_error{ec};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Cancel pending operations.
|
|
||||||
|
|
||||||
This will cancel all of the asynchronous operations pending,
|
|
||||||
including pipelined writes that have not been started. Handlers for
|
|
||||||
canceled writes will be called with
|
|
||||||
`boost::asio::error::operation_aborted`.
|
|
||||||
|
|
||||||
@param ec Set to indicate what error occurred, if any.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
cancel(error_code& ec);
|
|
||||||
|
|
||||||
/** Read a HTTP message from the stream.
|
|
||||||
|
|
||||||
This function is used to read a single HTTP message from the stream.
|
|
||||||
The call will block until one of the followign conditions is true:
|
|
||||||
|
|
||||||
@li A message has been read.
|
|
||||||
|
|
||||||
@li An error occurred.
|
|
||||||
|
|
||||||
The operation is implemented in terms of zero or more calls to the
|
|
||||||
next layer's `read_some` function.
|
|
||||||
|
|
||||||
@param msg An object used to store the message. The previous
|
|
||||||
contents of the object will be overwritten.
|
|
||||||
|
|
||||||
@throws boost::system::system_error Thrown on failure.
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
read(message_v1<isRequest, Body, Headers>& msg)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
read(msg, ec);
|
|
||||||
if(ec)
|
|
||||||
throw system_error{ec};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read a HTTP message from the stream.
|
|
||||||
|
|
||||||
This function is used to read a single HTTP message from the stream.
|
|
||||||
The call will block until one of the followign conditions is true:
|
|
||||||
|
|
||||||
@li A message has been read.
|
|
||||||
|
|
||||||
@li An error occurred.
|
|
||||||
|
|
||||||
The operation is implemented in terms of zero or more calls to the
|
|
||||||
next layer's `read_some` function.
|
|
||||||
|
|
||||||
@param msg An object used to store the message. The previous
|
|
||||||
contents of the object will be overwritten.
|
|
||||||
|
|
||||||
@param ec Set to indicate what error occurred, if any.
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
read(message_v1<isRequest, Body, Headers>& msg,
|
|
||||||
error_code& ec);
|
|
||||||
|
|
||||||
/** Start reading a HTTP message from the stream asynchronously.
|
|
||||||
|
|
||||||
This function is used to asynchronously read a single HTTP message
|
|
||||||
from the stream. The function call always returns immediately. The
|
|
||||||
asynchronous operation will continue until one of the following
|
|
||||||
conditions is true:
|
|
||||||
|
|
||||||
@li The message has been written.
|
|
||||||
|
|
||||||
@li An error occurred.
|
|
||||||
|
|
||||||
This operation is implemented in terms of zero or more calls to the
|
|
||||||
next layer's async_read_some function, and is known as a composed
|
|
||||||
operation. The program must ensure that the stream performs no other
|
|
||||||
read operations or any other composed operations that perform reads
|
|
||||||
until this operation completes.
|
|
||||||
|
|
||||||
@param msg An object used to store the message. The previous
|
|
||||||
contents of the object will be overwritten. Ownership of the message
|
|
||||||
is not transferred; the caller must guarantee that the object remains
|
|
||||||
valid until the handler is called.
|
|
||||||
|
|
||||||
@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(
|
|
||||||
error_code const& error // result of operation
|
|
||||||
); @endcode
|
|
||||||
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().
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class ReadHandler>
|
|
||||||
#if GENERATING_DOCS
|
|
||||||
void_or_deduced
|
|
||||||
#else
|
|
||||||
typename async_completion<
|
|
||||||
ReadHandler, void(error_code)>::result_type
|
|
||||||
#endif
|
|
||||||
async_read(message_v1<isRequest, Body, Headers>& msg,
|
|
||||||
ReadHandler&& handler);
|
|
||||||
|
|
||||||
/** Write a HTTP message to the stream.
|
|
||||||
|
|
||||||
This function is used to write a single HTTP message to the
|
|
||||||
stream. The call will block until one of the following conditions
|
|
||||||
is true:
|
|
||||||
|
|
||||||
@li The entire message is sent.
|
|
||||||
|
|
||||||
@li An error occurred.
|
|
||||||
|
|
||||||
If the semantics of the message require that the connection is
|
|
||||||
closed to indicate the end of the content body,
|
|
||||||
`boost::asio::error::eof` is thrown after the message is sent.
|
|
||||||
successfuly. The caller is responsible for actually closing the
|
|
||||||
connection. For regular TCP/IP streams this means shutting down the
|
|
||||||
send side, while SSL streams may call the SSL shutdown function.
|
|
||||||
|
|
||||||
@param msg The message to send.
|
|
||||||
|
|
||||||
@throws boost::system::system_error Thrown on failure.
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
write(message_v1<isRequest, Body, Headers> const& msg)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
write(msg, ec);
|
|
||||||
if(ec)
|
|
||||||
throw system_error{ec};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write a HTTP message to the stream.
|
|
||||||
|
|
||||||
This function is used to write a single HTTP message to the
|
|
||||||
stream. The call will block until one of the following conditions
|
|
||||||
is true:
|
|
||||||
|
|
||||||
@li The entire message is sent.
|
|
||||||
|
|
||||||
@li An error occurred.
|
|
||||||
|
|
||||||
If the semantics of the message require that the connection is
|
|
||||||
closed to indicate the end of the content body,
|
|
||||||
`boost::asio::error::eof` is returned after the message is sent.
|
|
||||||
successfuly. The caller is responsible for actually closing the
|
|
||||||
connection. For regular TCP/IP streams this means shutting down the
|
|
||||||
send side, while SSL streams may call the SSL shutdown function.
|
|
||||||
|
|
||||||
@param msg The message to send.
|
|
||||||
|
|
||||||
@param ec Set to the error, if any occurred.
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
write(message_v1<isRequest, Body, Headers> const& msg,
|
|
||||||
error_code& ec);
|
|
||||||
|
|
||||||
/** Start pipelining a HTTP message to the stream asynchronously.
|
|
||||||
|
|
||||||
This function is used to queue a message to be sent on the stream.
|
|
||||||
Unlike the free function, this version will place the message on an
|
|
||||||
outgoing message queue if there is already a write pending.
|
|
||||||
|
|
||||||
If the semantics of the message require that the connection is
|
|
||||||
closed to indicate the end of the content body, the handler
|
|
||||||
is called with the error `boost::asio::error::eof` after the message
|
|
||||||
has been sent successfully. The caller is responsible for actually
|
|
||||||
closing the connection. For regular TCP/IP streams this means
|
|
||||||
shutting down the send side, while SSL streams may call the SSL
|
|
||||||
`async_shutdown` function.
|
|
||||||
|
|
||||||
@param msg The message to send. A copy of the message will be made.
|
|
||||||
|
|
||||||
@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(
|
|
||||||
error_code const& error // result of operation
|
|
||||||
); @endcode
|
|
||||||
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().
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class WriteHandler>
|
|
||||||
#if GENERATING_DOCS
|
|
||||||
void_or_deduced
|
|
||||||
#else
|
|
||||||
typename async_completion<
|
|
||||||
WriteHandler, void(error_code)>::result_type
|
|
||||||
#endif
|
|
||||||
async_write(message_v1<isRequest, Body, Headers> const& msg,
|
|
||||||
WriteHandler&& handler);
|
|
||||||
|
|
||||||
/** Start pipelining a HTTP message to the stream asynchronously.
|
|
||||||
|
|
||||||
This function is used to queue a message to be sent on the stream.
|
|
||||||
Unlike the free function, this version will place the message on an
|
|
||||||
outgoing message queue if there is already a write pending.
|
|
||||||
|
|
||||||
If the semantics of the message require that the connection is
|
|
||||||
closed to indicate the end of the content body, the handler
|
|
||||||
is called with the error boost::asio::error::eof. The caller is
|
|
||||||
responsible for actually closing the connection. For regular
|
|
||||||
TCP/IP streams this means shutting down the send side, while SSL
|
|
||||||
streams may call the SSL async_shutdown function.
|
|
||||||
|
|
||||||
@param msg The message to send. Ownership of the message, which
|
|
||||||
must be movable, is transferred to the implementation. The message
|
|
||||||
will not be destroyed until the asynchronous operation 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(
|
|
||||||
error_code const& error // result of operation
|
|
||||||
); @endcode
|
|
||||||
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().
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class WriteHandler>
|
|
||||||
#if GENERATING_DOCS
|
|
||||||
void_or_deduced
|
|
||||||
#else
|
|
||||||
typename async_completion<
|
|
||||||
WriteHandler, void(error_code)>::result_type
|
|
||||||
#endif
|
|
||||||
async_write(message_v1<isRequest, Body, Headers>&& msg,
|
|
||||||
WriteHandler&& handler);
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<bool, class, class, class> class read_op;
|
|
||||||
template<bool, class, class, class> class write_op;
|
|
||||||
|
|
||||||
void
|
|
||||||
cancel_all();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // http
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#include "http_stream.ipp"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,412 +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_STREAM_IPP_INCLUDED
|
|
||||||
#define BEAST_HTTP_STREAM_IPP_INCLUDED
|
|
||||||
|
|
||||||
#include <beast/core/bind_handler.hpp>
|
|
||||||
#include <beast/core/handler_alloc.hpp>
|
|
||||||
#include <beast/http/message_v1.hpp>
|
|
||||||
#include <beast/http/read.hpp>
|
|
||||||
#include <beast/http/write.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace http {
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class Handler>
|
|
||||||
class stream<NextLayer, Allocator>::read_op
|
|
||||||
{
|
|
||||||
using alloc_type =
|
|
||||||
handler_alloc<char, Handler>;
|
|
||||||
|
|
||||||
struct data
|
|
||||||
{
|
|
||||||
stream<NextLayer>& s;
|
|
||||||
message_v1<isRequest, Body, Headers>& m;
|
|
||||||
Handler h;
|
|
||||||
bool cont;
|
|
||||||
int state = 0;
|
|
||||||
|
|
||||||
template<class DeducedHandler>
|
|
||||||
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
|
||||||
message_v1<isRequest, Body, Headers>& m_)
|
|
||||||
: s(s_)
|
|
||||||
, m(m_)
|
|
||||||
, h(std::forward<DeducedHandler>(h_))
|
|
||||||
, cont(boost_asio_handler_cont_helpers::
|
|
||||||
is_continuation(h))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<data> d_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
read_op(read_op&&) = default;
|
|
||||||
read_op(read_op const&) = default;
|
|
||||||
|
|
||||||
template<class DeducedHandler, class... Args>
|
|
||||||
read_op(DeducedHandler&& h,
|
|
||||||
stream<NextLayer>& s, Args&&... args)
|
|
||||||
: d_(std::allocate_shared<data>(alloc_type{h},
|
|
||||||
std::forward<DeducedHandler>(h), s,
|
|
||||||
std::forward<Args>(args)...))
|
|
||||||
{
|
|
||||||
(*this)(error_code{}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(error_code const& ec, bool again = true);
|
|
||||||
|
|
||||||
friend
|
|
||||||
void* asio_handler_allocate(
|
|
||||||
std::size_t size, read_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_alloc_helpers::
|
|
||||||
allocate(size, op->d_->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
void asio_handler_deallocate(
|
|
||||||
void* p, std::size_t size, read_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_alloc_helpers::
|
|
||||||
deallocate(p, size, op->d_->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
bool asio_handler_is_continuation(read_op* op)
|
|
||||||
{
|
|
||||||
return op->d_->cont;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Function>
|
|
||||||
friend
|
|
||||||
void asio_handler_invoke(Function&& f, read_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_invoke_helpers::
|
|
||||||
invoke(f, op->d_->h);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers, class Handler>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
read_op<isRequest, Body, Headers, Handler>::
|
|
||||||
operator()(error_code const& ec, bool again)
|
|
||||||
{
|
|
||||||
auto& d = *d_;
|
|
||||||
d.cont = d.cont || again;
|
|
||||||
while(! ec && d.state != 99)
|
|
||||||
{
|
|
||||||
switch(d.state)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
d.state = 99;
|
|
||||||
beast::http::async_read(d.s.next_layer_,
|
|
||||||
d.s.rd_buf_, d.m, std::move(*this));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.h(ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class Handler>
|
|
||||||
class stream<NextLayer, Allocator>::write_op : public op
|
|
||||||
{
|
|
||||||
using alloc_type =
|
|
||||||
handler_alloc<char, Handler>;
|
|
||||||
|
|
||||||
struct data
|
|
||||||
{
|
|
||||||
stream<NextLayer>& s;
|
|
||||||
message_v1<isRequest, Body, Headers> m;
|
|
||||||
Handler h;
|
|
||||||
bool cont;
|
|
||||||
int state = 0;
|
|
||||||
|
|
||||||
template<class DeducedHandler>
|
|
||||||
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
|
||||||
message_v1<isRequest, Body, Headers> const& m_,
|
|
||||||
bool cont_)
|
|
||||||
: s(s_)
|
|
||||||
, m(m_)
|
|
||||||
, h(std::forward<DeducedHandler>(h_))
|
|
||||||
, cont(cont_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class DeducedHandler>
|
|
||||||
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
|
||||||
message_v1<isRequest, Body, Headers>&& m_,
|
|
||||||
bool cont_)
|
|
||||||
: s(s_)
|
|
||||||
, m(std::move(m_))
|
|
||||||
, h(std::forward<DeducedHandler>(h_))
|
|
||||||
, cont(cont_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<data> d_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
write_op(write_op&&) = default;
|
|
||||||
write_op(write_op const&) = default;
|
|
||||||
|
|
||||||
template<class DeducedHandler, class... Args>
|
|
||||||
write_op(DeducedHandler&& h,
|
|
||||||
stream<NextLayer>& s, Args&&... args)
|
|
||||||
: d_(std::allocate_shared<data>(alloc_type{h},
|
|
||||||
std::forward<DeducedHandler>(h), s,
|
|
||||||
std::forward<Args>(args)...))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
operator()() override
|
|
||||||
{
|
|
||||||
(*this)(error_code{}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cancel() override;
|
|
||||||
|
|
||||||
void operator()(error_code const& ec, bool again = true);
|
|
||||||
|
|
||||||
friend
|
|
||||||
void* asio_handler_allocate(
|
|
||||||
std::size_t size, write_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_alloc_helpers::
|
|
||||||
allocate(size, op->d_->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
void asio_handler_deallocate(
|
|
||||||
void* p, std::size_t size, write_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_alloc_helpers::
|
|
||||||
deallocate(p, size, op->d_->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
bool asio_handler_is_continuation(write_op* op)
|
|
||||||
{
|
|
||||||
return op->d_->cont;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Function>
|
|
||||||
friend
|
|
||||||
void asio_handler_invoke(Function&& f, write_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_invoke_helpers::
|
|
||||||
invoke(f, op->d_->h);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers, class Handler>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
write_op<isRequest, Body, Headers, Handler>::
|
|
||||||
cancel()
|
|
||||||
{
|
|
||||||
auto& d = *d_;
|
|
||||||
d.s.get_io_service().post(
|
|
||||||
bind_handler(std::move(*this),
|
|
||||||
boost::asio::error::operation_aborted));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers, class Handler>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
write_op<isRequest, Body, Headers, Handler>::
|
|
||||||
operator()(error_code const& ec, bool again)
|
|
||||||
{
|
|
||||||
auto& d = *d_;
|
|
||||||
d.cont = d.cont || again;
|
|
||||||
while(! ec && d.state != 99)
|
|
||||||
{
|
|
||||||
switch(d.state)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
d.state = 99;
|
|
||||||
beast::http::async_write(d.s.next_layer_,
|
|
||||||
d.m, std::move(*this));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.h(ec);
|
|
||||||
if(! d.s.wr_q_.empty())
|
|
||||||
{
|
|
||||||
auto& op = d.s.wr_q_.front();
|
|
||||||
op();
|
|
||||||
// VFALCO Use allocator
|
|
||||||
delete &op;
|
|
||||||
d.s.wr_q_.pop_front();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d.s.wr_active_ = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
~stream()
|
|
||||||
{
|
|
||||||
// Can't destroy with pending operations!
|
|
||||||
assert(wr_q_.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<class... Args>
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
stream(Args&&... args)
|
|
||||||
: next_layer_(std::forward<Args>(args)...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
cancel(error_code& ec)
|
|
||||||
{
|
|
||||||
cancel_all();
|
|
||||||
lowest_layer().cancel(ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
read(message_v1<isRequest, Body, Headers>& msg,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
beast::http::read(next_layer_, rd_buf_, msg, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class ReadHandler>
|
|
||||||
auto
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
async_read(message_v1<isRequest, Body, Headers>& msg,
|
|
||||||
ReadHandler&& handler) ->
|
|
||||||
typename async_completion<
|
|
||||||
ReadHandler, void(error_code)>::result_type
|
|
||||||
{
|
|
||||||
async_completion<
|
|
||||||
ReadHandler, void(error_code)
|
|
||||||
> completion(handler);
|
|
||||||
read_op<isRequest, Body, Headers,
|
|
||||||
decltype(completion.handler)>{
|
|
||||||
completion.handler, *this, msg};
|
|
||||||
return completion.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
write(message_v1<isRequest, Body, Headers> const& msg,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
beast::http::write(next_layer_, msg, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class WriteHandler>
|
|
||||||
auto
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
async_write(message_v1<isRequest, Body, Headers> const& msg,
|
|
||||||
WriteHandler&& handler) ->
|
|
||||||
typename async_completion<
|
|
||||||
WriteHandler, void(error_code)>::result_type
|
|
||||||
{
|
|
||||||
async_completion<
|
|
||||||
WriteHandler, void(error_code)> completion(handler);
|
|
||||||
auto const cont = wr_active_ ||
|
|
||||||
boost_asio_handler_cont_helpers::is_continuation(handler);
|
|
||||||
if(! wr_active_)
|
|
||||||
{
|
|
||||||
wr_active_ = true;
|
|
||||||
write_op<isRequest, Body, Headers,
|
|
||||||
decltype(completion.handler)>{
|
|
||||||
completion.handler, *this, msg, cont }();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// VFALCO Use allocator
|
|
||||||
wr_q_.push_back(*new write_op<isRequest, Body, Headers,
|
|
||||||
decltype(completion.handler)>(
|
|
||||||
completion.handler, *this, msg, cont));
|
|
||||||
}
|
|
||||||
return completion.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class WriteHandler>
|
|
||||||
auto
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
async_write(message_v1<isRequest, Body, Headers>&& msg,
|
|
||||||
WriteHandler&& handler) ->
|
|
||||||
typename async_completion<
|
|
||||||
WriteHandler, void(error_code)>::result_type
|
|
||||||
{
|
|
||||||
async_completion<
|
|
||||||
WriteHandler, void(error_code)> completion(handler);
|
|
||||||
auto const cont = wr_active_ ||
|
|
||||||
boost_asio_handler_cont_helpers::is_continuation(handler);
|
|
||||||
if(! wr_active_)
|
|
||||||
{
|
|
||||||
wr_active_ = true;
|
|
||||||
write_op<isRequest, Body, Headers,
|
|
||||||
decltype(completion.handler)>{completion.handler,
|
|
||||||
*this, std::move(msg), cont}();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// VFALCO Use allocator
|
|
||||||
wr_q_.push_back(*new write_op<isRequest, Body, Headers,
|
|
||||||
decltype(completion.handler)>(completion.handler,
|
|
||||||
*this, std::move(msg), cont));
|
|
||||||
}
|
|
||||||
return completion.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
cancel_all()
|
|
||||||
{
|
|
||||||
for(auto it = wr_q_.begin(); it != wr_q_.end();)
|
|
||||||
{
|
|
||||||
auto& op = *it++;
|
|
||||||
op.cancel();
|
|
||||||
// VFALCO Use allocator
|
|
||||||
delete &op;
|
|
||||||
}
|
|
||||||
wr_q_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // http
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -9,8 +9,9 @@
|
|||||||
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
|
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
|
||||||
|
|
||||||
#include "file_body.hpp"
|
#include "file_body.hpp"
|
||||||
#include "http_stream.hpp"
|
#include "mime_type.hpp"
|
||||||
|
|
||||||
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -34,6 +35,8 @@ class http_sync_server
|
|||||||
using req_type = request_v1<string_body>;
|
using req_type = request_v1<string_body>;
|
||||||
using resp_type = response_v1<file_body>;
|
using resp_type = response_v1<file_body>;
|
||||||
|
|
||||||
|
bool log_ = true;
|
||||||
|
std::mutex m_;
|
||||||
boost::asio::io_service ios_;
|
boost::asio::io_service ios_;
|
||||||
socket_type sock_;
|
socket_type sock_;
|
||||||
boost::asio::ip::tcp::acceptor acceptor_;
|
boost::asio::ip::tcp::acceptor acceptor_;
|
||||||
@@ -65,21 +68,43 @@ public:
|
|||||||
thread_.join();
|
thread_.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
void
|
void
|
||||||
fail(error_code ec, std::string what)
|
log(Args const&... args)
|
||||||
{
|
{
|
||||||
std::cerr <<
|
if(log_)
|
||||||
what << ": " << ec.message() << std::endl;
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_);
|
||||||
|
log_args(args...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void
|
||||||
|
log_args()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Arg, class... Args>
|
||||||
|
void
|
||||||
|
log_args(Arg const& arg, Args const&... args)
|
||||||
|
{
|
||||||
|
std::cerr << arg;
|
||||||
|
log_args(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
maybe_throw(error_code ec, std::string what)
|
fail(error_code ec, std::string what)
|
||||||
{
|
{
|
||||||
if(ec)
|
log(what, ": ", ec.message(), "\n");
|
||||||
{
|
}
|
||||||
fail(ec, what);
|
|
||||||
throw ec;
|
void
|
||||||
}
|
fail(int id, error_code const& ec)
|
||||||
|
{
|
||||||
|
if(ec != boost::asio::error::operation_aborted &&
|
||||||
|
ec != boost::asio::error::eof)
|
||||||
|
log("#", id, " ", ec.message(), "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lambda
|
struct lambda
|
||||||
@@ -109,7 +134,8 @@ public:
|
|||||||
{
|
{
|
||||||
if(! acceptor_.is_open())
|
if(! acceptor_.is_open())
|
||||||
return;
|
return;
|
||||||
maybe_throw(ec, "accept");
|
if(ec)
|
||||||
|
return fail(ec, "accept");
|
||||||
static int id_ = 0;
|
static int id_ = 0;
|
||||||
std::thread{lambda{++id_, *this, std::move(sock_)}}.detach();
|
std::thread{lambda{++id_, *this, std::move(sock_)}}.detach();
|
||||||
acceptor_.async_accept(sock_,
|
acceptor_.async_accept(sock_,
|
||||||
@@ -118,23 +144,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fail(int id, error_code const& ec)
|
do_peer(int id, socket_type&& sock0)
|
||||||
{
|
{
|
||||||
if(ec != boost::asio::error::operation_aborted &&
|
socket_type sock(std::move(sock0));
|
||||||
ec != boost::asio::error::eof)
|
streambuf sb;
|
||||||
std::cerr <<
|
|
||||||
"#" << std::to_string(id) << " " << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_peer(int id, socket_type&& sock)
|
|
||||||
{
|
|
||||||
http::stream<socket_type> hs(std::move(sock));
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
req_type req;
|
req_type req;
|
||||||
hs.read(req, ec);
|
http::read(sock, sb, req, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
auto path = req.url;
|
auto path = req.url;
|
||||||
@@ -143,26 +161,42 @@ public:
|
|||||||
path = root_ + path;
|
path = root_ + path;
|
||||||
if(! boost::filesystem::exists(path))
|
if(! boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
response_v1<string_body> resp;
|
response_v1<string_body> res;
|
||||||
resp.status = 404;
|
res.status = 404;
|
||||||
resp.reason = "Not Found";
|
res.reason = "Not Found";
|
||||||
resp.version = req.version;
|
res.version = req.version;
|
||||||
resp.headers.replace("Server", "http_sync_server");
|
res.headers.insert("Server", "http_sync_server");
|
||||||
resp.body = "The file '" + path + "' was not found";
|
res.headers.insert("Content-Type", "text/html");
|
||||||
prepare(resp);
|
res.body = "The file '" + path + "' was not found";
|
||||||
hs.write(resp, ec);
|
prepare(res);
|
||||||
|
write(sock, res, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
resp_type resp;
|
resp_type res;
|
||||||
resp.status = 200;
|
res.status = 200;
|
||||||
resp.reason = "OK";
|
res.reason = "OK";
|
||||||
resp.version = req.version;
|
res.version = req.version;
|
||||||
resp.headers.replace("Server", "http_sync_server");
|
res.headers.insert("Server", "http_sync_server");
|
||||||
resp.headers.replace("Content-Type", "text/html");
|
res.headers.insert("Content-Type", mime_type(path));
|
||||||
resp.body = path;
|
res.body = path;
|
||||||
prepare(resp);
|
try
|
||||||
hs.write(resp, ec);
|
{
|
||||||
|
prepare(res);
|
||||||
|
}
|
||||||
|
catch(std::exception const& e)
|
||||||
|
{
|
||||||
|
res = {};
|
||||||
|
res.status = 500;
|
||||||
|
res.reason = "Internal Error";
|
||||||
|
res.version = req.version;
|
||||||
|
res.headers.insert("Server", "http_sync_server");
|
||||||
|
res.headers.insert("Content-Type", "text/html");
|
||||||
|
res.body =
|
||||||
|
std::string{"An internal error occurred"} + e.what();
|
||||||
|
prepare(res);
|
||||||
|
}
|
||||||
|
write(sock, res, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/beast/examples/mime_type.hpp
Normal file
51
src/beast/examples/mime_type.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_EXAMPLE_HTTP_MIME_TYPE_H_INCLUDED
|
||||||
|
#define BEAST_EXAMPLE_HTTP_MIME_TYPE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
// Return the Mime-Type for a given file extension
|
||||||
|
template<class = void>
|
||||||
|
std::string
|
||||||
|
mime_type(std::string const& path)
|
||||||
|
{
|
||||||
|
auto const ext =
|
||||||
|
boost::filesystem::path{path}.extension().string();
|
||||||
|
if(ext == ".txt") return "text/plain";
|
||||||
|
if(ext == ".htm") return "text/html";
|
||||||
|
if(ext == ".html") return "text/html";
|
||||||
|
if(ext == ".php") return "text/html";
|
||||||
|
if(ext == ".css") return "text/css";
|
||||||
|
if(ext == ".js") return "application/javascript";
|
||||||
|
if(ext == ".json") return "application/json";
|
||||||
|
if(ext == ".xml") return "application/xml";
|
||||||
|
if(ext == ".swf") return "application/x-shockwave-flash";
|
||||||
|
if(ext == ".flv") return "video/x-flv";
|
||||||
|
if(ext == ".png") return "image/png";
|
||||||
|
if(ext == ".jpe") return "image/jpeg";
|
||||||
|
if(ext == ".jpeg") return "image/jpeg";
|
||||||
|
if(ext == ".jpg") return "image/jpeg";
|
||||||
|
if(ext == ".gif") return "image/gif";
|
||||||
|
if(ext == ".bmp") return "image/bmp";
|
||||||
|
if(ext == ".ico") return "image/vnd.microsoft.icon";
|
||||||
|
if(ext == ".tiff") return "image/tiff";
|
||||||
|
if(ext == ".tif") return "image/tiff";
|
||||||
|
if(ext == ".svg") return "image/svg+xml";
|
||||||
|
if(ext == ".svgz") return "image/svg+xml";
|
||||||
|
return "application/text";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,13 +16,13 @@ int main()
|
|||||||
// Normal boost::asio setup
|
// Normal boost::asio setup
|
||||||
std::string const host = "echo.websocket.org";
|
std::string const host = "echo.websocket.org";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
boost::asio::ip::tcp::socket sock(ios);
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||||
|
|
||||||
// WebSocket connect and send message using beast
|
// WebSocket connect and send message using beast
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
ws.handshake(host, "/");
|
ws.handshake(host, "/");
|
||||||
ws.write(boost::asio::buffer("Hello, world!"));
|
ws.write(boost::asio::buffer("Hello, world!"));
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ namespace test {
|
|||||||
|
|
||||||
enum error
|
enum error
|
||||||
{
|
{
|
||||||
fail_error = 1
|
success = 0,
|
||||||
|
|
||||||
|
fail_error
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|||||||
@@ -161,19 +161,21 @@ public:
|
|||||||
|
|
||||||
friend
|
friend
|
||||||
void
|
void
|
||||||
teardown(fail_stream<NextLayer>& stream,
|
teardown(websocket::teardown_tag,
|
||||||
boost::system::error_code& ec)
|
fail_stream<NextLayer>& stream,
|
||||||
|
boost::system::error_code& ec)
|
||||||
{
|
{
|
||||||
if(stream.pfc_->fail(ec))
|
if(stream.pfc_->fail(ec))
|
||||||
return;
|
return;
|
||||||
websocket_helpers::call_teardown(stream.next_layer(), ec);
|
beast::websocket_helpers::call_teardown(stream.next_layer(), ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class TeardownHandler>
|
template<class TeardownHandler>
|
||||||
friend
|
friend
|
||||||
void
|
void
|
||||||
async_teardown(fail_stream<NextLayer>& stream,
|
async_teardown(websocket::teardown_tag,
|
||||||
TeardownHandler&& handler)
|
fail_stream<NextLayer>& stream,
|
||||||
|
TeardownHandler&& handler)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
if(stream.pfc_->fail(ec))
|
if(stream.pfc_->fail(ec))
|
||||||
@@ -182,7 +184,7 @@ public:
|
|||||||
bind_handler(std::move(handler), ec));
|
bind_handler(std::move(handler), ec));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
websocket_helpers::call_async_teardown(
|
beast::websocket_helpers::call_async_teardown(
|
||||||
stream.next_layer(), std::forward<TeardownHandler>(handler));
|
stream.next_layer(), std::forward<TeardownHandler>(handler));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,29 +23,29 @@ private:
|
|||||||
std::string const& what_;
|
std::string const& what_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
amount (amount const&) = default;
|
amount(amount const&) = default;
|
||||||
amount& operator= (amount const&) = delete;
|
amount& operator=(amount const&) = delete;
|
||||||
|
|
||||||
template <class = void>
|
template<class = void>
|
||||||
amount (std::size_t n, std::string const& what);
|
amount(std::size_t n, std::string const& what);
|
||||||
|
|
||||||
friend
|
friend
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<< (std::ostream& s, amount const& t);
|
operator<<(std::ostream& s, amount const& t);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class>
|
template<class>
|
||||||
amount::amount (std::size_t n, std::string const& what)
|
amount::amount(std::size_t n, std::string const& what)
|
||||||
: n_ (n)
|
: n_(n)
|
||||||
, what_ (what)
|
, what_(what)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<< (std::ostream& s, amount const& t)
|
operator<<(std::ostream& s, amount const& t)
|
||||||
{
|
{
|
||||||
s << t.n_ << " " << t.what_ << ((t.n_ != 1) ? "s" : "");
|
s << t.n_ << " " << t.what_ <<((t.n_ != 1) ? "s" : "");
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace detail {
|
|||||||
The interface allows for limited read only operations. Derived classes
|
The interface allows for limited read only operations. Derived classes
|
||||||
provide additional behavior.
|
provide additional behavior.
|
||||||
*/
|
*/
|
||||||
template <class Container>
|
template<class Container>
|
||||||
class const_container
|
class const_container
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -8,11 +8,10 @@
|
|||||||
#ifndef BEAST_UNIT_TEST_DSTREAM_HPP
|
#ifndef BEAST_UNIT_TEST_DSTREAM_HPP
|
||||||
#define BEAST_UNIT_TEST_DSTREAM_HPP
|
#define BEAST_UNIT_TEST_DSTREAM_HPP
|
||||||
|
|
||||||
#include <boost/utility/base_from_member.hpp>
|
#include <ios>
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <sstream>
|
#include <streambuf>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@@ -30,15 +29,18 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace unit_test {
|
namespace unit_test {
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
template<class CharT, class Traits, class Allocator>
|
template<class CharT, class Traits, class Allocator>
|
||||||
class dstream_buf
|
class dstream_buf
|
||||||
: public std::basic_stringbuf<CharT, Traits, Allocator>
|
: public std::basic_stringbuf<CharT, Traits, Allocator>
|
||||||
{
|
{
|
||||||
|
using ostream = std::basic_ostream<CharT, Traits>;
|
||||||
|
|
||||||
bool dbg_;
|
bool dbg_;
|
||||||
|
ostream& os_;
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void write(T const*) = delete;
|
void write(T const*) = delete;
|
||||||
@@ -47,21 +49,21 @@ class dstream_buf
|
|||||||
{
|
{
|
||||||
if(dbg_)
|
if(dbg_)
|
||||||
OutputDebugStringA(s);
|
OutputDebugStringA(s);
|
||||||
else
|
os_ << s;
|
||||||
std::cout << s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(wchar_t const* s)
|
void write(wchar_t const* s)
|
||||||
{
|
{
|
||||||
if(dbg_)
|
if(dbg_)
|
||||||
OutputDebugStringW(s);
|
OutputDebugStringW(s);
|
||||||
else
|
os_ << s;
|
||||||
std::wcout << s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
dstream_buf()
|
explicit
|
||||||
: dbg_(IsDebuggerPresent() != FALSE)
|
dstream_buf(ostream& os)
|
||||||
|
: os_(os)
|
||||||
|
, dbg_(IsDebuggerPresent() != FALSE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,66 +81,52 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
template<class CharT, class Traits, class Allocator>
|
|
||||||
class dstream_buf
|
|
||||||
: public std::basic_stringbuf<CharT, Traits, Allocator>
|
|
||||||
{
|
|
||||||
template<class T>
|
|
||||||
void write(T const*) = delete;
|
|
||||||
|
|
||||||
void write(char const* s)
|
|
||||||
{
|
|
||||||
std::cout << s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(wchar_t const* s)
|
|
||||||
{
|
|
||||||
std::wcout << s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
~dstream_buf()
|
|
||||||
{
|
|
||||||
sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sync() override
|
|
||||||
{
|
|
||||||
write(this->str().c_str());
|
|
||||||
this->str("");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
/// A std::ostream that redirects output to the debugger if attached.
|
/** std::ostream with Visual Studio IDE redirection.
|
||||||
|
|
||||||
|
Instances of this stream wrap a specified `std::ostream`
|
||||||
|
(such as `std::cout` or `std::cerr`). If the IDE debugger
|
||||||
|
is attached when the stream is created, output will be
|
||||||
|
additionally copied to the Visual Studio Output window.
|
||||||
|
*/
|
||||||
template<
|
template<
|
||||||
class CharT,
|
class CharT,
|
||||||
class Traits = std::char_traits<CharT>,
|
class Traits = std::char_traits<CharT>,
|
||||||
class Allocator = std::allocator<CharT>
|
class Allocator = std::allocator<CharT>
|
||||||
>
|
>
|
||||||
class basic_dstream
|
class basic_dstream
|
||||||
: private boost::base_from_member<
|
: public std::basic_ostream<CharT, Traits>
|
||||||
detail::dstream_buf<CharT, Traits, Allocator>>
|
|
||||||
, public std::basic_ostream<CharT, Traits>
|
|
||||||
{
|
{
|
||||||
|
detail::dstream_buf<
|
||||||
|
CharT, Traits, Allocator> buf_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
basic_dstream()
|
/** Construct a stream.
|
||||||
: std::basic_ostream<CharT, Traits>(&this->member)
|
|
||||||
|
@param os The output stream to wrap.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
basic_dstream(std::ostream& os)
|
||||||
|
: std::basic_ostream<CharT, Traits>(&buf_)
|
||||||
|
, buf_(os)
|
||||||
{
|
{
|
||||||
|
if(os.flags() && std::ios::unitbuf)
|
||||||
|
std::unitbuf(*this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using dstream = basic_dstream<char>;
|
using dstream = basic_dstream<char>;
|
||||||
using dwstream = basic_dstream<wchar_t>;
|
using dwstream = basic_dstream<wchar_t>;
|
||||||
|
|
||||||
} // test
|
#else
|
||||||
|
|
||||||
|
using dstream = std::ostream&;
|
||||||
|
using dwstream = std::wostream&;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // unit_test
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ static
|
|||||||
std::string
|
std::string
|
||||||
prefix(suite_info const& s)
|
prefix(suite_info const& s)
|
||||||
{
|
{
|
||||||
if (s.manual())
|
if(s.manual())
|
||||||
return "|M| ";
|
return "|M| ";
|
||||||
return " ";
|
return " ";
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ print(std::ostream& os, suite_list const& c)
|
|||||||
std::size_t manual = 0;
|
std::size_t manual = 0;
|
||||||
for(auto const& s : c)
|
for(auto const& s : c)
|
||||||
{
|
{
|
||||||
os << prefix (s) << s.full_name() << '\n';
|
os << prefix(s) << s.full_name() << '\n';
|
||||||
if(s.manual())
|
if(s.manual())
|
||||||
++manual;
|
++manual;
|
||||||
}
|
}
|
||||||
@@ -80,18 +80,18 @@ int main(int ac, char const* av[])
|
|||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
{
|
{
|
||||||
int flags = _CrtSetDbgFlag (_CRTDBG_REPORT_FLAG);
|
int flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
||||||
flags |= _CRTDBG_LEAK_CHECK_DF;
|
flags |= _CRTDBG_LEAK_CHECK_DF;
|
||||||
_CrtSetDbgFlag (flags);
|
_CrtSetDbgFlag(flags);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace po = boost::program_options;
|
namespace po = boost::program_options;
|
||||||
po::options_description desc("Options");
|
po::options_description desc("Options");
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
("help,h", "Produce a help message")
|
("help,h", "Produce a help message")
|
||||||
("print,r", "Print the list of available test suites")
|
("print,p", "Print the list of available test suites")
|
||||||
("suites,s", po::value<string>(), "suites to run")
|
("suites,s", po::value<string>(), "suites to run")
|
||||||
;
|
;
|
||||||
|
|
||||||
po::positional_options_description p;
|
po::positional_options_description p;
|
||||||
@@ -99,7 +99,8 @@ int main(int ac, char const* av[])
|
|||||||
po::store(po::parse_command_line(ac, av, desc), vm);
|
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||||
po::notify(vm);
|
po::notify(vm);
|
||||||
|
|
||||||
dstream log;
|
dstream log{std::cerr};
|
||||||
|
std::unitbuf(log);
|
||||||
|
|
||||||
if(vm.count("help"))
|
if(vm.count("help"))
|
||||||
{
|
{
|
||||||
@@ -121,7 +122,7 @@ int main(int ac, char const* av[])
|
|||||||
match_auto(suites));
|
match_auto(suites));
|
||||||
else
|
else
|
||||||
failed = r.run_each(global_suites());
|
failed = r.run_each(global_suites());
|
||||||
if (failed)
|
if(failed)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,42 +45,42 @@ private:
|
|||||||
std::string library_;
|
std::string library_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <class = void>
|
template<class = void>
|
||||||
explicit
|
explicit
|
||||||
selector (mode_t mode, std::string const& pattern = "");
|
selector(mode_t mode, std::string const& pattern = "");
|
||||||
|
|
||||||
template <class = void>
|
template<class = void>
|
||||||
bool
|
bool
|
||||||
operator() (suite_info const& s);
|
operator()(suite_info const& s);
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <class>
|
template<class>
|
||||||
selector::selector (mode_t mode, std::string const& pattern)
|
selector::selector(mode_t mode, std::string const& pattern)
|
||||||
: mode_ (mode)
|
: mode_(mode)
|
||||||
, pat_ (pattern)
|
, pat_(pattern)
|
||||||
{
|
{
|
||||||
if (mode_ == automatch && pattern.empty())
|
if(mode_ == automatch && pattern.empty())
|
||||||
mode_ = all;
|
mode_ = all;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class>
|
template<class>
|
||||||
bool
|
bool
|
||||||
selector::operator() (suite_info const& s)
|
selector::operator()(suite_info const& s)
|
||||||
{
|
{
|
||||||
switch (mode_)
|
switch(mode_)
|
||||||
{
|
{
|
||||||
case automatch:
|
case automatch:
|
||||||
// suite or full name
|
// suite or full name
|
||||||
if (s.name() == pat_ || s.full_name() == pat_)
|
if(s.name() == pat_ || s.full_name() == pat_)
|
||||||
{
|
{
|
||||||
mode_ = none;
|
mode_ = none;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check module
|
// check module
|
||||||
if (pat_ == s.module())
|
if(pat_ == s.module())
|
||||||
{
|
{
|
||||||
mode_ = module;
|
mode_ = module;
|
||||||
library_ = s.library();
|
library_ = s.library();
|
||||||
@@ -88,7 +88,7 @@ selector::operator() (suite_info const& s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check library
|
// check library
|
||||||
if (pat_ == s.library())
|
if(pat_ == s.library())
|
||||||
{
|
{
|
||||||
mode_ = library;
|
mode_ = library;
|
||||||
return ! s.manual();
|
return ! s.manual();
|
||||||
@@ -138,9 +138,9 @@ selector::operator() (suite_info const& s)
|
|||||||
*/
|
*/
|
||||||
inline
|
inline
|
||||||
selector
|
selector
|
||||||
match_auto (std::string const& name)
|
match_auto(std::string const& name)
|
||||||
{
|
{
|
||||||
return selector (selector::automatch, name);
|
return selector(selector::automatch, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return a predicate that matches all suites not marked manual. */
|
/** Return a predicate that matches all suites not marked manual. */
|
||||||
@@ -148,23 +148,23 @@ inline
|
|||||||
selector
|
selector
|
||||||
match_all()
|
match_all()
|
||||||
{
|
{
|
||||||
return selector (selector::all);
|
return selector(selector::all);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a predicate that matches a specific suite. */
|
/** Returns a predicate that matches a specific suite. */
|
||||||
inline
|
inline
|
||||||
selector
|
selector
|
||||||
match_suite (std::string const& name)
|
match_suite(std::string const& name)
|
||||||
{
|
{
|
||||||
return selector (selector::suite, name);
|
return selector(selector::suite, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a predicate that matches all suites in a library. */
|
/** Returns a predicate that matches all suites in a library. */
|
||||||
inline
|
inline
|
||||||
selector
|
selector
|
||||||
match_library (std::string const& name)
|
match_library(std::string const& name)
|
||||||
{
|
{
|
||||||
return selector (selector::library, name);
|
return selector(selector::library, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // unit_test
|
} // unit_test
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
recorder() = default;
|
recorder() = default;
|
||||||
recorder (recorder const&) = default;
|
recorder(recorder const&) = default;
|
||||||
recorder& operator= (recorder const&) = default;
|
recorder& operator=(recorder const&) = default;
|
||||||
|
|
||||||
/** Returns a report with the results of all completed suites. */
|
/** Returns a report with the results of all completed suites. */
|
||||||
results const&
|
results const&
|
||||||
@@ -37,31 +37,31 @@ public:
|
|||||||
private:
|
private:
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_suite_begin (suite_info const& info) override
|
on_suite_begin(suite_info const& info) override
|
||||||
{
|
{
|
||||||
m_suite = suite_results (info.full_name());
|
m_suite = suite_results(info.full_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_suite_end() override
|
on_suite_end() override
|
||||||
{
|
{
|
||||||
m_results.insert (std::move (m_suite));
|
m_results.insert(std::move(m_suite));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_case_begin (std::string const& name) override
|
on_case_begin(std::string const& name) override
|
||||||
{
|
{
|
||||||
m_case = case_results (name);
|
m_case = case_results(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_case_end() override
|
on_case_end() override
|
||||||
{
|
{
|
||||||
if (m_case.tests.size() > 0)
|
if(m_case.tests.size() > 0)
|
||||||
m_suite.insert (std::move (m_case));
|
m_suite.insert(std::move(m_case));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
@@ -73,16 +73,16 @@ private:
|
|||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_fail (std::string const& reason) override
|
on_fail(std::string const& reason) override
|
||||||
{
|
{
|
||||||
m_case.tests.fail (reason);
|
m_case.tests.fail(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_log (std::string const& s) override
|
on_log(std::string const& s) override
|
||||||
{
|
{
|
||||||
m_case.log.insert (s);
|
m_case.log.insert(s);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ private:
|
|||||||
typename clock_type::time_point start = clock_type::now();
|
typename clock_type::time_point start = clock_type::now();
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
suite_results(std::string const& name_ = "")
|
suite_results(std::string name_ = "")
|
||||||
: name(std::move(name_))
|
: name(std::move(name_))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ private:
|
|||||||
typename clock_type::time_point start = clock_type::now();
|
typename clock_type::time_point start = clock_type::now();
|
||||||
|
|
||||||
void
|
void
|
||||||
add (suite_results const& r);
|
add(suite_results const& r);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& os_;
|
std::ostream& os_;
|
||||||
@@ -107,7 +107,7 @@ private:
|
|||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_suite_begin (suite_info const& info) override;
|
on_suite_begin(suite_info const& info) override;
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
@@ -115,7 +115,7 @@ private:
|
|||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_case_begin (std::string const& name) override;
|
on_case_begin(std::string const& name) override;
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
@@ -127,11 +127,11 @@ private:
|
|||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_fail (std::string const& reason) override;
|
on_fail(std::string const& reason) override;
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
on_log (std::string const& s) override;
|
on_log(std::string const& s) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -156,7 +156,7 @@ results::add(suite_results const& r)
|
|||||||
cases += r.cases;
|
cases += r.cases;
|
||||||
failed += r.failed;
|
failed += r.failed;
|
||||||
auto const elapsed = clock_type::now() - r.start;
|
auto const elapsed = clock_type::now() - r.start;
|
||||||
if (elapsed >= std::chrono::seconds{1})
|
if(elapsed >= std::chrono::seconds{1})
|
||||||
{
|
{
|
||||||
auto const iter = std::lower_bound(top.begin(),
|
auto const iter = std::lower_bound(top.begin(),
|
||||||
top.end(), elapsed,
|
top.end(), elapsed,
|
||||||
@@ -165,13 +165,13 @@ results::add(suite_results const& r)
|
|||||||
{
|
{
|
||||||
return t1.second > t2;
|
return t1.second > t2;
|
||||||
});
|
});
|
||||||
if (iter != top.end())
|
if(iter != top.end())
|
||||||
{
|
{
|
||||||
if (top.size() == max_top)
|
if(top.size() == max_top)
|
||||||
top.resize(top.size() - 1);
|
top.resize(top.size() - 1);
|
||||||
top.emplace(iter, r.name, elapsed);
|
top.emplace(iter, r.name, elapsed);
|
||||||
}
|
}
|
||||||
else if (top.size() < max_top)
|
else if(top.size() < max_top)
|
||||||
{
|
{
|
||||||
top.emplace_back(r.name, elapsed);
|
top.emplace_back(r.name, elapsed);
|
||||||
}
|
}
|
||||||
@@ -213,11 +213,11 @@ reporter<_>::fmtdur(typename clock_type::duration const& d)
|
|||||||
{
|
{
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
auto const ms = duration_cast<milliseconds>(d);
|
auto const ms = duration_cast<milliseconds>(d);
|
||||||
if (ms < seconds{1})
|
if(ms < seconds{1})
|
||||||
return std::to_string(ms.count()) + "ms";
|
return std::to_string(ms.count()) + "ms";
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << std::fixed << std::setprecision(1) <<
|
ss << std::fixed << std::setprecision(1) <<
|
||||||
(ms.count()/1000.) << "s";
|
(ms.count()/1000.) << "s";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,11 +241,10 @@ void
|
|||||||
reporter<_>::
|
reporter<_>::
|
||||||
on_case_begin(std::string const& name)
|
on_case_begin(std::string const& name)
|
||||||
{
|
{
|
||||||
case_results_ = case_results (name);
|
case_results_ = case_results(name);
|
||||||
os_ <<
|
os_ << suite_results_.name <<
|
||||||
suite_results_.name <<
|
(case_results_.name.empty() ? "" :
|
||||||
(case_results_.name.empty() ?
|
(" " + case_results_.name)) << std::endl;
|
||||||
"" : (" " + case_results_.name)) << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class _>
|
template<class _>
|
||||||
@@ -273,7 +272,7 @@ on_fail(std::string const& reason)
|
|||||||
++case_results_.total;
|
++case_results_.total;
|
||||||
os_ <<
|
os_ <<
|
||||||
"#" << case_results_.total << " failed" <<
|
"#" << case_results_.total << " failed" <<
|
||||||
(reason.empty() ? "" : ": ") << reason << std::endl;
|
(reason.empty() ? "" : ": ") << reason << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class _>
|
template<class _>
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ public:
|
|||||||
/** Holds the result of evaluating one test condition. */
|
/** Holds the result of evaluating one test condition. */
|
||||||
struct test
|
struct test
|
||||||
{
|
{
|
||||||
explicit test (bool pass_)
|
explicit test(bool pass_)
|
||||||
: pass (pass_)
|
: pass(pass_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
test (bool pass_, std::string const& reason_)
|
test(bool pass_, std::string const& reason_)
|
||||||
: pass (pass_)
|
: pass(pass_)
|
||||||
, reason (reason_)
|
, reason(reason_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,8 +46,8 @@ private:
|
|||||||
std::size_t failed_;
|
std::size_t failed_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
tests_t ()
|
tests_t()
|
||||||
: failed_ (0)
|
: failed_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,15 +69,15 @@ private:
|
|||||||
void
|
void
|
||||||
pass()
|
pass()
|
||||||
{
|
{
|
||||||
cont().emplace_back (true);
|
cont().emplace_back(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Register a failed test condition. */
|
/** Register a failed test condition. */
|
||||||
void
|
void
|
||||||
fail (std::string const& reason = "")
|
fail(std::string const& reason = "")
|
||||||
{
|
{
|
||||||
++failed_;
|
++failed_;
|
||||||
cont().emplace_back (false, reason);
|
cont().emplace_back(false, reason);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -87,17 +87,17 @@ private:
|
|||||||
public:
|
public:
|
||||||
/** Insert a string into the log. */
|
/** Insert a string into the log. */
|
||||||
void
|
void
|
||||||
insert (std::string const& s)
|
insert(std::string const& s)
|
||||||
{
|
{
|
||||||
cont().push_back (s);
|
cont().push_back(s);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit case_results (std::string const& name = "")
|
explicit case_results(std::string const& name = "")
|
||||||
: name_ (name)
|
: name_(name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,8 +127,8 @@ private:
|
|||||||
std::size_t failed_ = 0;
|
std::size_t failed_ = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit suite_results (std::string const& name = "")
|
explicit suite_results(std::string const& name = "")
|
||||||
: name_ (name)
|
: name_(name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,17 +156,17 @@ public:
|
|||||||
/** Insert a set of testcase results. */
|
/** Insert a set of testcase results. */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
void
|
void
|
||||||
insert (case_results&& r)
|
insert(case_results&& r)
|
||||||
{
|
{
|
||||||
cont().emplace_back (std::move (r));
|
cont().emplace_back(std::move(r));
|
||||||
total_ += r.tests.total();
|
total_ += r.tests.total();
|
||||||
failed_ += r.tests.failed();
|
failed_ += r.tests.failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
insert (case_results const& r)
|
insert(case_results const& r)
|
||||||
{
|
{
|
||||||
cont().push_back (r);
|
cont().push_back(r);
|
||||||
total_ += r.tests.total();
|
total_ += r.tests.total();
|
||||||
failed_ += r.tests.failed();
|
failed_ += r.tests.failed();
|
||||||
}
|
}
|
||||||
@@ -187,9 +187,9 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
results()
|
results()
|
||||||
: m_cases (0)
|
: m_cases(0)
|
||||||
, total_ (0)
|
, total_(0)
|
||||||
, failed_ (0)
|
, failed_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,21 +217,21 @@ public:
|
|||||||
/** Insert a set of suite results. */
|
/** Insert a set of suite results. */
|
||||||
/** @{ */
|
/** @{ */
|
||||||
void
|
void
|
||||||
insert (suite_results&& r)
|
insert(suite_results&& r)
|
||||||
{
|
{
|
||||||
m_cases += r.size();
|
m_cases += r.size();
|
||||||
total_ += r.total();
|
total_ += r.total();
|
||||||
failed_ += r.failed();
|
failed_ += r.failed();
|
||||||
cont().emplace_back (std::move (r));
|
cont().emplace_back(std::move(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
insert (suite_results const& r)
|
insert(suite_results const& r)
|
||||||
{
|
{
|
||||||
m_cases += r.size();
|
m_cases += r.size();
|
||||||
total_ += r.total();
|
total_ += r.total();
|
||||||
failed_ += r.failed();
|
failed_ += r.failed();
|
||||||
cont().push_back (r);
|
cont().push_back(r);
|
||||||
}
|
}
|
||||||
/** @} */
|
/** @} */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ namespace beast {
|
|||||||
namespace unit_test {
|
namespace unit_test {
|
||||||
|
|
||||||
/** Unit test runner interface.
|
/** Unit test runner interface.
|
||||||
|
|
||||||
Derived classes can customize the reporting behavior. This interface is
|
Derived classes can customize the reporting behavior. This interface is
|
||||||
injected into the unit_test class to receive the results of the tests.
|
injected into the unit_test class to receive the results of the tests.
|
||||||
*/
|
*/
|
||||||
@@ -60,7 +61,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<class = void>
|
template<class = void>
|
||||||
bool
|
bool
|
||||||
run (suite_info const& s);
|
run(suite_info const& s);
|
||||||
|
|
||||||
/** Run a sequence of suites.
|
/** Run a sequence of suites.
|
||||||
The expression
|
The expression
|
||||||
@@ -68,44 +69,40 @@ public:
|
|||||||
must be convertible to `suite_info`.
|
must be convertible to `suite_info`.
|
||||||
@return `true` if any conditions failed.
|
@return `true` if any conditions failed.
|
||||||
*/
|
*/
|
||||||
template <class FwdIter>
|
template<class FwdIter>
|
||||||
bool
|
bool
|
||||||
run (FwdIter first, FwdIter last);
|
run(FwdIter first, FwdIter last);
|
||||||
|
|
||||||
/** Conditionally run a sequence of suites.
|
/** Conditionally run a sequence of suites.
|
||||||
pred will be called as:
|
pred will be called as:
|
||||||
@code
|
@code
|
||||||
bool pred (suite_info const&);
|
bool pred(suite_info const&);
|
||||||
@endcode
|
@endcode
|
||||||
@return `true` if any conditions failed.
|
@return `true` if any conditions failed.
|
||||||
*/
|
*/
|
||||||
template <class FwdIter, class Pred>
|
template<class FwdIter, class Pred>
|
||||||
bool
|
bool
|
||||||
run_if (FwdIter first, FwdIter last, Pred pred = Pred{});
|
run_if(FwdIter first, FwdIter last, Pred pred = Pred{});
|
||||||
|
|
||||||
/** Run all suites in a container.
|
/** Run all suites in a container.
|
||||||
@return `true` if any conditions failed.
|
@return `true` if any conditions failed.
|
||||||
*/
|
*/
|
||||||
template <class SequenceContainer>
|
template<class SequenceContainer>
|
||||||
bool
|
bool
|
||||||
run_each (SequenceContainer const& c);
|
run_each(SequenceContainer const& c);
|
||||||
|
|
||||||
/** Conditionally run suites in a container.
|
/** Conditionally run suites in a container.
|
||||||
pred will be called as:
|
pred will be called as:
|
||||||
@code
|
@code
|
||||||
bool pred (suite_info const&);
|
bool pred(suite_info const&);
|
||||||
@endcode
|
@endcode
|
||||||
@return `true` if any conditions failed.
|
@return `true` if any conditions failed.
|
||||||
*/
|
*/
|
||||||
template <class SequenceContainer, class Pred>
|
template<class SequenceContainer, class Pred>
|
||||||
bool
|
bool
|
||||||
run_each_if (SequenceContainer const& c, Pred pred = Pred{});
|
run_each_if(SequenceContainer const& c, Pred pred = Pred{});
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//
|
|
||||||
// Overrides
|
|
||||||
//
|
|
||||||
|
|
||||||
/// Called when a new suite starts.
|
/// Called when a new suite starts.
|
||||||
virtual
|
virtual
|
||||||
void
|
void
|
||||||
@@ -159,130 +156,130 @@ private:
|
|||||||
friend class suite;
|
friend class suite;
|
||||||
|
|
||||||
// Start a new testcase.
|
// Start a new testcase.
|
||||||
template <class = void>
|
template<class = void>
|
||||||
void
|
void
|
||||||
testcase (std::string const& name);
|
testcase(std::string const& name);
|
||||||
|
|
||||||
template <class = void>
|
template<class = void>
|
||||||
void
|
void
|
||||||
pass();
|
pass();
|
||||||
|
|
||||||
template <class = void>
|
template<class = void>
|
||||||
void
|
void
|
||||||
fail (std::string const& reason);
|
fail(std::string const& reason);
|
||||||
|
|
||||||
template <class = void>
|
template<class = void>
|
||||||
void
|
void
|
||||||
log (std::string const& s);
|
log(std::string const& s);
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <class>
|
template<class>
|
||||||
bool
|
bool
|
||||||
runner::run (suite_info const& s)
|
runner::run(suite_info const& s)
|
||||||
{
|
{
|
||||||
// Enable 'default' testcase
|
// Enable 'default' testcase
|
||||||
default_ = true;
|
default_ = true;
|
||||||
failed_ = false;
|
failed_ = false;
|
||||||
on_suite_begin (s);
|
on_suite_begin(s);
|
||||||
s.run (*this);
|
s.run(*this);
|
||||||
// Forgot to call pass or fail.
|
// Forgot to call pass or fail.
|
||||||
assert (cond_);
|
assert(cond_);
|
||||||
on_case_end();
|
on_case_end();
|
||||||
on_suite_end();
|
on_suite_end();
|
||||||
return failed_;
|
return failed_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FwdIter>
|
template<class FwdIter>
|
||||||
bool
|
bool
|
||||||
runner::run (FwdIter first, FwdIter last)
|
runner::run(FwdIter first, FwdIter last)
|
||||||
{
|
{
|
||||||
bool failed (false);
|
bool failed(false);
|
||||||
for (;first != last; ++first)
|
for(;first != last; ++first)
|
||||||
failed = run (*first) || failed;
|
failed = run(*first) || failed;
|
||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FwdIter, class Pred>
|
template<class FwdIter, class Pred>
|
||||||
bool
|
bool
|
||||||
runner::run_if (FwdIter first, FwdIter last, Pred pred)
|
runner::run_if(FwdIter first, FwdIter last, Pred pred)
|
||||||
{
|
{
|
||||||
bool failed (false);
|
bool failed(false);
|
||||||
for (;first != last; ++first)
|
for(;first != last; ++first)
|
||||||
if (pred (*first))
|
if(pred(*first))
|
||||||
failed = run (*first) || failed;
|
failed = run(*first) || failed;
|
||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class SequenceContainer>
|
template<class SequenceContainer>
|
||||||
bool
|
bool
|
||||||
runner::run_each (SequenceContainer const& c)
|
runner::run_each(SequenceContainer const& c)
|
||||||
{
|
{
|
||||||
bool failed (false);
|
bool failed(false);
|
||||||
for (auto const& s : c)
|
for(auto const& s : c)
|
||||||
failed = run (s) || failed;
|
failed = run(s) || failed;
|
||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class SequenceContainer, class Pred>
|
template<class SequenceContainer, class Pred>
|
||||||
bool
|
bool
|
||||||
runner::run_each_if (SequenceContainer const& c, Pred pred)
|
runner::run_each_if(SequenceContainer const& c, Pred pred)
|
||||||
{
|
{
|
||||||
bool failed (false);
|
bool failed(false);
|
||||||
for (auto const& s : c)
|
for(auto const& s : c)
|
||||||
if (pred (s))
|
if(pred(s))
|
||||||
failed = run (s) || failed;
|
failed = run(s) || failed;
|
||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class>
|
template<class>
|
||||||
void
|
void
|
||||||
runner::testcase (std::string const& name)
|
runner::testcase(std::string const& name)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||||
// Name may not be empty
|
// Name may not be empty
|
||||||
assert (default_ || ! name.empty());
|
assert(default_ || ! name.empty());
|
||||||
// Forgot to call pass or fail
|
// Forgot to call pass or fail
|
||||||
assert (default_ || cond_);
|
assert(default_ || cond_);
|
||||||
if (! default_)
|
if(! default_)
|
||||||
on_case_end();
|
on_case_end();
|
||||||
default_ = false;
|
default_ = false;
|
||||||
cond_ = false;
|
cond_ = false;
|
||||||
on_case_begin (name);
|
on_case_begin(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class>
|
template<class>
|
||||||
void
|
void
|
||||||
runner::pass()
|
runner::pass()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||||
if (default_)
|
if(default_)
|
||||||
testcase ("");
|
testcase("");
|
||||||
on_pass();
|
on_pass();
|
||||||
cond_ = true;
|
cond_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class>
|
template<class>
|
||||||
void
|
void
|
||||||
runner::fail (std::string const& reason)
|
runner::fail(std::string const& reason)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||||
if (default_)
|
if(default_)
|
||||||
testcase ("");
|
testcase("");
|
||||||
on_fail (reason);
|
on_fail(reason);
|
||||||
failed_ = true;
|
failed_ = true;
|
||||||
cond_ = true;
|
cond_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class>
|
template<class>
|
||||||
void
|
void
|
||||||
runner::log (std::string const& s)
|
runner::log(std::string const& s)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||||
if (default_)
|
if(default_)
|
||||||
testcase ("");
|
testcase("");
|
||||||
on_log (s);
|
on_log(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // unit_test
|
} // unit_test
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#define BEAST_UNIT_TEST_SUITE_HPP
|
#define BEAST_UNIT_TEST_SUITE_HPP
|
||||||
|
|
||||||
#include <beast/unit_test/runner.hpp>
|
#include <beast/unit_test/runner.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -72,7 +73,7 @@ private:
|
|||||||
{
|
{
|
||||||
auto const& s = this->str();
|
auto const& s = this->str();
|
||||||
if(s.size() > 0)
|
if(s.size() > 0)
|
||||||
suite_.runner_->on_log(s);
|
suite_.runner_->log(s);
|
||||||
this->str("");
|
this->str("");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -127,7 +128,7 @@ private:
|
|||||||
scoped_testcase
|
scoped_testcase
|
||||||
operator()(abort_t abort);
|
operator()(abort_t abort);
|
||||||
|
|
||||||
template <class T>
|
template<class T>
|
||||||
scoped_testcase
|
scoped_testcase
|
||||||
operator<<(T const& t);
|
operator<<(T const& t);
|
||||||
};
|
};
|
||||||
@@ -146,7 +147,9 @@ public:
|
|||||||
/** Returns the "current" running suite.
|
/** Returns the "current" running suite.
|
||||||
If no suite is running, nullptr is returned.
|
If no suite is running, nullptr is returned.
|
||||||
*/
|
*/
|
||||||
static suite* this_suite()
|
static
|
||||||
|
suite*
|
||||||
|
this_suite()
|
||||||
{
|
{
|
||||||
return *p_this_suite();
|
return *p_this_suite();
|
||||||
}
|
}
|
||||||
@@ -158,6 +161,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Invokes the test using the specified runner.
|
/** Invokes the test using the specified runner.
|
||||||
|
|
||||||
Data members are set up here instead of the constructor as a
|
Data members are set up here instead of the constructor as a
|
||||||
convenience to writing the derived class to avoid repetition of
|
convenience to writing the derived class to avoid repetition of
|
||||||
forwarded constructor arguments to the base.
|
forwarded constructor arguments to the base.
|
||||||
@@ -165,67 +169,95 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<class = void>
|
template<class = void>
|
||||||
void
|
void
|
||||||
operator() (runner& r);
|
operator()(runner& r);
|
||||||
|
|
||||||
|
/** Record a successful test condition. */
|
||||||
|
template<class = void>
|
||||||
|
void
|
||||||
|
pass();
|
||||||
|
|
||||||
|
/** Record a failure.
|
||||||
|
|
||||||
|
@param reason
|
||||||
|
*/
|
||||||
|
template<class = void>
|
||||||
|
void
|
||||||
|
fail(std::string const& reason = "");
|
||||||
|
|
||||||
/** Evaluate a test condition.
|
/** Evaluate a test condition.
|
||||||
The condition is passed as a template argument instead of `bool` so
|
|
||||||
that implicit conversion is not required. The `reason` argument is
|
This function provides improved logging by incorporating the
|
||||||
logged if the condition is false.
|
file name and line number into the reported output on failure,
|
||||||
|
as well as additional text specified by the caller.
|
||||||
|
|
||||||
|
@param shouldBeTrue The condition to test. The condition
|
||||||
|
is evaluated in a boolean context.
|
||||||
|
|
||||||
|
@param reason Optional added text to output on a failure.
|
||||||
|
|
||||||
|
@param file The source code file where the test failed.
|
||||||
|
|
||||||
|
@param line The source code line number where the test failed.
|
||||||
|
|
||||||
@return `true` if the test condition indicates success.
|
@return `true` if the test condition indicates success.
|
||||||
*/
|
*/
|
||||||
template<class Condition, class String>
|
/** @{ */
|
||||||
bool
|
|
||||||
expect(Condition const& shouldBeTrue,
|
|
||||||
String const& reason);
|
|
||||||
|
|
||||||
template<class Condition>
|
template<class Condition>
|
||||||
bool
|
bool
|
||||||
expect(Condition const& shouldBeTrue)
|
expect(Condition const& shouldBeTrue)
|
||||||
{
|
{
|
||||||
return expect(shouldBeTrue, "");
|
return expect(shouldBeTrue, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Expect an exception from f() */
|
template<class Condition>
|
||||||
/** @{ */
|
|
||||||
template <class F, class String>
|
|
||||||
bool
|
bool
|
||||||
except (F&& f, String const& reason);
|
expect(Condition const& shouldBeTrue, std::string const& reason);
|
||||||
|
|
||||||
template <class F>
|
template<class Condition>
|
||||||
bool
|
bool
|
||||||
except (F&& f)
|
expect(Condition const& shouldBeTrue,
|
||||||
|
char const* file, int line)
|
||||||
|
{
|
||||||
|
return expect(shouldBeTrue, {}, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Condition>
|
||||||
|
bool
|
||||||
|
expect(Condition const& shouldBeTrue,
|
||||||
|
std::string const& reason, char const* file, int line);
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
//
|
||||||
|
// DEPRECATED
|
||||||
|
//
|
||||||
|
// Expect an exception from f()
|
||||||
|
template<class F, class String>
|
||||||
|
bool
|
||||||
|
except(F&& f, String const& reason);
|
||||||
|
template<class F>
|
||||||
|
bool
|
||||||
|
except(F&& f)
|
||||||
{
|
{
|
||||||
return except(f, "");
|
return except(f, "");
|
||||||
}
|
}
|
||||||
/** @} */
|
template<class E, class F, class String>
|
||||||
|
|
||||||
/** Expect an exception of the given type from f() */
|
|
||||||
/** @{ */
|
|
||||||
template <class E, class F, class String>
|
|
||||||
bool
|
bool
|
||||||
except (F&& f, String const& reason);
|
except(F&& f, String const& reason);
|
||||||
|
template<class E, class F>
|
||||||
template <class E, class F>
|
|
||||||
bool
|
bool
|
||||||
except (F&& f)
|
except(F&& f)
|
||||||
{
|
{
|
||||||
return except<E>(f, "");
|
return except<E>(f, "");
|
||||||
}
|
}
|
||||||
/** @} */
|
template<class F, class String>
|
||||||
|
|
||||||
/** Fail if f() throws */
|
|
||||||
/** @{ */
|
|
||||||
template <class F, class String>
|
|
||||||
bool
|
bool
|
||||||
unexcept (F&& f, String const& reason);
|
unexcept(F&& f, String const& reason);
|
||||||
|
template<class F>
|
||||||
template <class F>
|
|
||||||
bool
|
bool
|
||||||
unexcept (F&& f)
|
unexcept(F&& f)
|
||||||
{
|
{
|
||||||
return unexcept(f, "");
|
return unexcept(f, "");
|
||||||
}
|
}
|
||||||
/** @} */
|
|
||||||
|
|
||||||
/** Return the argument associated with the runner. */
|
/** Return the argument associated with the runner. */
|
||||||
std::string const&
|
std::string const&
|
||||||
@@ -235,29 +267,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DEPRECATED
|
// DEPRECATED
|
||||||
// @return `true` if the test condition indicates success (a false value)
|
// @return `true` if the test condition indicates success(a false value)
|
||||||
template <class Condition, class String>
|
template<class Condition, class String>
|
||||||
bool
|
bool
|
||||||
unexpected (Condition shouldBeFalse,
|
unexpected(Condition shouldBeFalse,
|
||||||
String const& reason);
|
String const& reason);
|
||||||
|
|
||||||
template <class Condition>
|
template<class Condition>
|
||||||
bool
|
bool
|
||||||
unexpected (Condition shouldBeFalse)
|
unexpected(Condition shouldBeFalse)
|
||||||
{
|
{
|
||||||
return unexpected (shouldBeFalse, "");
|
return unexpected(shouldBeFalse, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Record a successful test condition. */
|
|
||||||
template <class = void>
|
|
||||||
void
|
|
||||||
pass();
|
|
||||||
|
|
||||||
/** Record a failure. */
|
|
||||||
template <class = void>
|
|
||||||
void
|
|
||||||
fail (std::string const& reason = "");
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class thread;
|
friend class thread;
|
||||||
|
|
||||||
@@ -277,9 +299,9 @@ private:
|
|||||||
void
|
void
|
||||||
propagate_abort();
|
propagate_abort();
|
||||||
|
|
||||||
template <class = void>
|
template<class = void>
|
||||||
void
|
void
|
||||||
run (runner& r);
|
run(runner& r);
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -298,7 +320,10 @@ public:
|
|||||||
{
|
{
|
||||||
auto const& name = ss_.str();
|
auto const& name = ss_.str();
|
||||||
if(! name.empty())
|
if(! name.empty())
|
||||||
suite_.runner_->testcase (name);
|
{
|
||||||
|
suite_.log.flush();
|
||||||
|
suite_.runner_->testcase(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_testcase(suite& self, std::stringstream& ss)
|
scoped_testcase(suite& self, std::stringstream& ss)
|
||||||
@@ -333,16 +358,17 @@ public:
|
|||||||
|
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
suite::testcase_t::operator() (std::string const& name,
|
suite::testcase_t::operator()(
|
||||||
abort_t abort)
|
std::string const& name, abort_t abort)
|
||||||
{
|
{
|
||||||
suite_.abort_ = abort == abort_on_fail;
|
suite_.abort_ = abort == abort_on_fail;
|
||||||
suite_.runner_->testcase (name);
|
suite_.log.flush();
|
||||||
|
suite_.runner_->testcase(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
suite::scoped_testcase
|
suite::scoped_testcase
|
||||||
suite::testcase_t::operator() (abort_t abort)
|
suite::testcase_t::operator()(abort_t abort)
|
||||||
{
|
{
|
||||||
suite_.abort_ = abort == abort_on_fail;
|
suite_.abort_ = abort == abort_on_fail;
|
||||||
return { suite_, ss_ };
|
return { suite_, ss_ };
|
||||||
@@ -351,7 +377,7 @@ suite::testcase_t::operator() (abort_t abort)
|
|||||||
template<class T>
|
template<class T>
|
||||||
inline
|
inline
|
||||||
suite::scoped_testcase
|
suite::scoped_testcase
|
||||||
suite::testcase_t::operator<< (T const& t)
|
suite::testcase_t::operator<<(T const& t)
|
||||||
{
|
{
|
||||||
return { suite_, ss_, t };
|
return { suite_, ss_, t };
|
||||||
}
|
}
|
||||||
@@ -360,7 +386,8 @@ suite::testcase_t::operator<< (T const& t)
|
|||||||
|
|
||||||
template<class>
|
template<class>
|
||||||
void
|
void
|
||||||
suite::operator()(runner& r)
|
suite::
|
||||||
|
operator()(runner& r)
|
||||||
{
|
{
|
||||||
*p_this_suite() = this;
|
*p_this_suite() = this;
|
||||||
try
|
try
|
||||||
@@ -375,11 +402,11 @@ suite::operator()(runner& r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Condition, class String>
|
template<class Condition>
|
||||||
inline
|
|
||||||
bool
|
bool
|
||||||
suite::expect(Condition const& shouldBeTrue,
|
suite::
|
||||||
String const& reason)
|
expect(
|
||||||
|
Condition const& shouldBeTrue, std::string const& reason)
|
||||||
{
|
{
|
||||||
if(shouldBeTrue)
|
if(shouldBeTrue)
|
||||||
{
|
{
|
||||||
@@ -390,9 +417,35 @@ suite::expect(Condition const& shouldBeTrue,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class F, class String>
|
template<class Condition>
|
||||||
bool
|
bool
|
||||||
suite::except (F&& f, String const& reason)
|
suite::
|
||||||
|
expect(Condition const& shouldBeTrue,
|
||||||
|
std::string const& reason, char const* file, int line)
|
||||||
|
{
|
||||||
|
if(shouldBeTrue)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
std::string s;
|
||||||
|
if(! reason.empty())
|
||||||
|
{
|
||||||
|
s += reason;
|
||||||
|
s += " ";
|
||||||
|
}
|
||||||
|
s += boost::filesystem::path{file}.filename().string() +
|
||||||
|
"(" + std::to_string(line) + ")";
|
||||||
|
fail(s);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
|
|
||||||
|
template<class F, class String>
|
||||||
|
bool
|
||||||
|
suite::
|
||||||
|
except(F&& f, String const& reason)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -407,9 +460,10 @@ suite::except (F&& f, String const& reason)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class E, class F, class String>
|
template<class E, class F, class String>
|
||||||
bool
|
bool
|
||||||
suite::except (F&& f, String const& reason)
|
suite::
|
||||||
|
except(F&& f, String const& reason)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -424,9 +478,10 @@ suite::except (F&& f, String const& reason)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class F, class String>
|
template<class F, class String>
|
||||||
bool
|
bool
|
||||||
suite::unexcept (F&& f, String const& reason)
|
suite::
|
||||||
|
unexcept(F&& f, String const& reason)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -441,36 +496,39 @@ suite::unexcept (F&& f, String const& reason)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Condition, class String>
|
template<class Condition, class String>
|
||||||
inline
|
|
||||||
bool
|
bool
|
||||||
suite::unexpected (Condition shouldBeFalse,
|
suite::
|
||||||
String const& reason)
|
unexpected(
|
||||||
|
Condition shouldBeFalse, String const& reason)
|
||||||
{
|
{
|
||||||
bool const b =
|
bool const b =
|
||||||
static_cast<bool>(shouldBeFalse);
|
static_cast<bool>(shouldBeFalse);
|
||||||
if (! b)
|
if(! b)
|
||||||
pass();
|
pass();
|
||||||
else
|
else
|
||||||
fail (reason);
|
fail(reason);
|
||||||
return ! b;
|
return ! b;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class>
|
template<class>
|
||||||
void
|
void
|
||||||
suite::pass()
|
suite::
|
||||||
|
pass()
|
||||||
{
|
{
|
||||||
propagate_abort();
|
propagate_abort();
|
||||||
runner_->pass();
|
runner_->pass();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class>
|
// ::fail
|
||||||
|
template<class>
|
||||||
void
|
void
|
||||||
suite::fail (std::string const& reason)
|
suite::
|
||||||
|
fail(std::string const& reason)
|
||||||
{
|
{
|
||||||
propagate_abort();
|
propagate_abort();
|
||||||
runner_->fail (reason);
|
runner_->fail(reason);
|
||||||
if (abort_)
|
if(abort_)
|
||||||
{
|
{
|
||||||
aborted_ = true;
|
aborted_ = true;
|
||||||
throw abort_exception();
|
throw abort_exception();
|
||||||
@@ -479,15 +537,17 @@ suite::fail (std::string const& reason)
|
|||||||
|
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
suite::propagate_abort()
|
suite::
|
||||||
|
propagate_abort()
|
||||||
{
|
{
|
||||||
if (abort_ && aborted_)
|
if(abort_ && aborted_)
|
||||||
throw abort_exception();
|
throw abort_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class>
|
template<class>
|
||||||
void
|
void
|
||||||
suite::run (runner& r)
|
suite::
|
||||||
|
run(runner& r)
|
||||||
{
|
{
|
||||||
runner_ = &r;
|
runner_ = &r;
|
||||||
|
|
||||||
@@ -495,21 +555,37 @@ suite::run (runner& r)
|
|||||||
{
|
{
|
||||||
run();
|
run();
|
||||||
}
|
}
|
||||||
catch (abort_exception const&)
|
catch(abort_exception const&)
|
||||||
{
|
{
|
||||||
// ends the suite
|
// ends the suite
|
||||||
}
|
}
|
||||||
catch (std::exception const& e)
|
catch(std::exception const& e)
|
||||||
{
|
{
|
||||||
runner_->fail ("unhandled exception: " +
|
runner_->fail("unhandled exception: " +
|
||||||
std::string (e.what()));
|
std::string(e.what()));
|
||||||
}
|
}
|
||||||
catch (...)
|
catch(...)
|
||||||
{
|
{
|
||||||
runner_->fail ("unhandled exception");
|
runner_->fail("unhandled exception");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef BEAST_EXPECT
|
||||||
|
/** Check a precondition.
|
||||||
|
|
||||||
|
If the condition is false, the file and line number are reported.
|
||||||
|
*/
|
||||||
|
#define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BEAST_EXPECTS
|
||||||
|
/** Check a precondition.
|
||||||
|
|
||||||
|
If the condition is false, the file and line number are reported.
|
||||||
|
*/
|
||||||
|
#define BEAST_EXPECTS(cond, reason) expect(cond, reason, __FILE__, __LINE__)
|
||||||
|
#endif
|
||||||
|
|
||||||
} // unit_test
|
} // unit_test
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
@@ -519,7 +595,7 @@ suite::run (runner& r)
|
|||||||
// This inserts the suite with the given manual flag
|
// This inserts the suite with the given manual flag
|
||||||
#define BEAST_DEFINE_TESTSUITE_INSERT(Class,Module,Library,manual) \
|
#define BEAST_DEFINE_TESTSUITE_INSERT(Class,Module,Library,manual) \
|
||||||
static beast::unit_test::detail::insert_suite <Class##_test> \
|
static beast::unit_test::detail::insert_suite <Class##_test> \
|
||||||
Library ## Module ## Class ## _test_instance ( \
|
Library ## Module ## Class ## _test_instance( \
|
||||||
#Class, #Module, #Library, manual)
|
#Class, #Module, #Library, manual)
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public:
|
|||||||
void
|
void
|
||||||
run(runner& r) const
|
run(runner& r) const
|
||||||
{
|
{
|
||||||
run_ (r);
|
run_(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public:
|
|||||||
|
|
||||||
The suite must not already exist.
|
The suite must not already exist.
|
||||||
*/
|
*/
|
||||||
template <class Suite>
|
template<class Suite>
|
||||||
void
|
void
|
||||||
insert(
|
insert(
|
||||||
char const* name,
|
char const* name,
|
||||||
@@ -44,7 +44,7 @@ public:
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <class Suite>
|
template<class Suite>
|
||||||
void
|
void
|
||||||
suite_list::insert(
|
suite_list::insert(
|
||||||
char const* name,
|
char const* name,
|
||||||
@@ -56,14 +56,14 @@ suite_list::insert(
|
|||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
s = std::string(library) + "." + module + "." + name;
|
s = std::string(library) + "." + module + "." + name;
|
||||||
auto const result (names_.insert(s));
|
auto const result(names_.insert(s));
|
||||||
assert (result.second); // Duplicate name
|
assert(result.second); // Duplicate name
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto const result (classes_.insert (
|
auto const result(classes_.insert(
|
||||||
std::type_index (typeid(Suite))));
|
std::type_index(typeid(Suite))));
|
||||||
assert (result.second); // Duplicate type
|
assert(result.second); // Duplicate type
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
cont().emplace(make_suite_info<Suite>(
|
cont().emplace(make_suite_info<Suite>(
|
||||||
|
|||||||
@@ -28,31 +28,31 @@ public:
|
|||||||
using native_handle_type = std::thread::native_handle_type;
|
using native_handle_type = std::thread::native_handle_type;
|
||||||
|
|
||||||
thread() = default;
|
thread() = default;
|
||||||
thread (thread const&) = delete;
|
thread(thread const&) = delete;
|
||||||
thread& operator= (thread const&) = delete;
|
thread& operator=(thread const&) = delete;
|
||||||
|
|
||||||
thread (thread&& other)
|
thread(thread&& other)
|
||||||
: s_ (other.s_)
|
: s_(other.s_)
|
||||||
, t_ (std::move(other.t_))
|
, t_(std::move(other.t_))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
thread& operator= (thread&& other)
|
thread& operator=(thread&& other)
|
||||||
{
|
{
|
||||||
s_ = other.s_;
|
s_ = other.s_;
|
||||||
t_ = std::move(other.t_);
|
t_ = std::move(other.t_);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class F, class... Args>
|
template<class F, class... Args>
|
||||||
explicit
|
explicit
|
||||||
thread (suite& s, F&& f, Args&&... args)
|
thread(suite& s, F&& f, Args&&... args)
|
||||||
: s_ (&s)
|
: s_(&s)
|
||||||
{
|
{
|
||||||
std::function<void(void)> b =
|
std::function<void(void)> b =
|
||||||
std::bind(std::forward<F>(f),
|
std::bind(std::forward<F>(f),
|
||||||
std::forward<Args>(args)...);
|
std::forward<Args>(args)...);
|
||||||
t_ = std::thread (&thread::run, this,
|
t_ = std::thread(&thread::run, this,
|
||||||
std::move(b));
|
std::move(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
swap (thread& other)
|
swap(thread& other)
|
||||||
{
|
{
|
||||||
std::swap(s_, other.s_);
|
std::swap(s_, other.s_);
|
||||||
std::swap(t_, other.t_);
|
std::swap(t_, other.t_);
|
||||||
@@ -97,23 +97,23 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void
|
void
|
||||||
run (std::function <void(void)> f)
|
run(std::function <void(void)> f)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
catch (suite::abort_exception const&)
|
catch(suite::abort_exception const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
catch (std::exception const& e)
|
catch(std::exception const& e)
|
||||||
{
|
{
|
||||||
s_->fail ("unhandled exception: " +
|
s_->fail("unhandled exception: " +
|
||||||
std::string (e.what()));
|
std::string(e.what()));
|
||||||
}
|
}
|
||||||
catch (...)
|
catch(...)
|
||||||
{
|
{
|
||||||
s_->fail ("unhandled exception");
|
s_->fail("unhandled exception");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace beast {
|
|||||||
@note 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>
|
Library Foundations For Asynchronous Operations</a>
|
||||||
*/
|
*/
|
||||||
template <class CompletionHandler, class Signature>
|
template<class CompletionHandler, class Signature>
|
||||||
struct async_completion
|
struct async_completion
|
||||||
{
|
{
|
||||||
/** The type of the final handler called by the asynchronous initiation function.
|
/** The type of the final handler called by the asynchronous initiation function.
|
||||||
|
|||||||
@@ -14,10 +14,10 @@
|
|||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
/** Adapts a @b `MutableBufferSequence` into a @b `Streambuf`.
|
/** Adapts a @b `MutableBufferSequence` into a @b `DynamicBuffer`.
|
||||||
|
|
||||||
This class wraps a @b `MutableBufferSequence` to meet the requirements
|
This class wraps a @b `MutableBufferSequence` to meet the requirements
|
||||||
of @b `Streambuf`. Upon construction the input and output sequences are
|
of @b `DynamicBuffer`. Upon construction the input and output sequences are
|
||||||
empty. A copy of the mutable buffer sequence object is stored; however,
|
empty. A copy of the mutable buffer sequence object is stored; however,
|
||||||
ownership of the underlying memory is not transferred. The caller is
|
ownership of the underlying memory is not transferred. The caller is
|
||||||
responsible for making sure that referenced memory remains valid
|
responsible for making sure that referenced memory remains valid
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace detail {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template <class = void>
|
template<class = void>
|
||||||
std::string const&
|
std::string const&
|
||||||
base64_alphabet()
|
base64_alphabet()
|
||||||
{
|
{
|
||||||
@@ -62,7 +62,7 @@ is_base64(unsigned char c)
|
|||||||
return (std::isalnum(c) || (c == '+') || (c == '/'));
|
return (std::isalnum(c) || (c == '+') || (c == '/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class = void>
|
template<class = void>
|
||||||
std::string
|
std::string
|
||||||
base64_encode (std::uint8_t const* data,
|
base64_encode (std::uint8_t const* data,
|
||||||
std::size_t in_len)
|
std::size_t in_len)
|
||||||
@@ -112,7 +112,7 @@ base64_encode (std::uint8_t const* data,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class = void>
|
template<class = void>
|
||||||
std::string
|
std::string
|
||||||
base64_encode (std::string const& s)
|
base64_encode (std::string const& s)
|
||||||
{
|
{
|
||||||
@@ -120,11 +120,11 @@ base64_encode (std::string const& s)
|
|||||||
std::uint8_t const*> (s.data()), s.size());
|
std::uint8_t const*> (s.data()), s.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class = void>
|
template<class = void>
|
||||||
std::string
|
std::string
|
||||||
base64_decode(std::string const& data)
|
base64_decode(std::string const& data)
|
||||||
{
|
{
|
||||||
int in_len = data.size();
|
auto in_len = data.size();
|
||||||
unsigned char c3[3], c4[4];
|
unsigned char c3[3], c4[4];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
|
|||||||
@@ -54,14 +54,14 @@ public:
|
|||||||
operator()()
|
operator()()
|
||||||
{
|
{
|
||||||
invoke(h_, args_,
|
invoke(h_, args_,
|
||||||
index_sequence_for<Args...> ());
|
index_sequence_for<Args...>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
operator()() const
|
operator()() const
|
||||||
{
|
{
|
||||||
invoke(h_, args_,
|
invoke(h_, args_,
|
||||||
index_sequence_for<Args...> ());
|
index_sequence_for<Args...>());
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <class T>
|
template<class T>
|
||||||
struct empty_base_optimization_decide
|
struct empty_base_optimization_decide
|
||||||
: std::integral_constant <bool,
|
: std::integral_constant <bool,
|
||||||
std::is_empty <T>::value
|
std::is_empty <T>::value
|
||||||
@@ -25,7 +25,7 @@ struct empty_base_optimization_decide
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template <
|
template<
|
||||||
class T,
|
class T,
|
||||||
int UniqueID = 0,
|
int UniqueID = 0,
|
||||||
bool ShouldDeriveFrom =
|
bool ShouldDeriveFrom =
|
||||||
@@ -57,7 +57,7 @@ public:
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <
|
template<
|
||||||
class T,
|
class T,
|
||||||
int UniqueID
|
int UniqueID
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <class R, class C, class ...A>
|
template<class R, class C, class ...A>
|
||||||
auto
|
auto
|
||||||
is_call_possible_test(C&& c, int, A&& ...a)
|
is_call_possible_test(C&& c, int, A&& ...a)
|
||||||
-> decltype(std::is_convertible<
|
-> decltype(std::is_convertible<
|
||||||
@@ -21,7 +21,7 @@ is_call_possible_test(C&& c, int, A&& ...a)
|
|||||||
std::is_same<R, void>::value,
|
std::is_same<R, void>::value,
|
||||||
std::true_type());
|
std::true_type());
|
||||||
|
|
||||||
template <class R, class C, class ...A>
|
template<class R, class C, class ...A>
|
||||||
std::false_type
|
std::false_type
|
||||||
is_call_possible_test(C&& c, long, A&& ...a);
|
is_call_possible_test(C&& c, long, A&& ...a);
|
||||||
|
|
||||||
@@ -30,13 +30,13 @@ is_call_possible_test(C&& c, long, A&& ...a);
|
|||||||
is_call_possible<T, void(std::string)>
|
is_call_possible<T, void(std::string)>
|
||||||
*/
|
*/
|
||||||
/** @{ */
|
/** @{ */
|
||||||
template <class C, class F>
|
template<class C, class F>
|
||||||
struct is_call_possible
|
struct is_call_possible
|
||||||
: std::false_type
|
: std::false_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class C, class R, class ...A>
|
template<class C, class R, class ...A>
|
||||||
struct is_call_possible<C, R(A...)>
|
struct is_call_possible<C, R(A...)>
|
||||||
: decltype(is_call_possible_test<R>(
|
: decltype(is_call_possible_test<R>(
|
||||||
std::declval<C>(), 1, std::declval<A>()...))
|
std::declval<C>(), 1, std::declval<A>()...))
|
||||||
|
|||||||
@@ -281,10 +281,10 @@ finish(sha1_context& ctx, void* digest) noexcept
|
|||||||
ctx.buf[ctx.buflen++] = 0x00;
|
ctx.buf[ctx.buflen++] = 0x00;
|
||||||
std::uint32_t block[BLOCK_INTS];
|
std::uint32_t block[BLOCK_INTS];
|
||||||
sha1::make_block(ctx.buf, block);
|
sha1::make_block(ctx.buf, block);
|
||||||
if (buflen > BLOCK_BYTES - 8)
|
if(buflen > BLOCK_BYTES - 8)
|
||||||
{
|
{
|
||||||
sha1::transform(ctx.digest, block);
|
sha1::transform(ctx.digest, block);
|
||||||
for (size_t i = 0; i < BLOCK_INTS - 2; i++)
|
for(size_t i = 0; i < BLOCK_INTS - 2; i++)
|
||||||
block[i] = 0;
|
block[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class has_get_io_service
|
|||||||
decltype(std::declval<U>().get_io_service()),
|
decltype(std::declval<U>().get_io_service()),
|
||||||
boost::asio::io_service&>>
|
boost::asio::io_service&>>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
public:
|
public:
|
||||||
using type = decltype(check<T>(0));
|
using type = decltype(check<T>(0));
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ public:
|
|||||||
|
|
||||||
/// Write the given data to the stream. Returns the number of bytes written,
|
/// Write the given data to the stream. Returns the number of bytes written,
|
||||||
/// or 0 if an error occurred.
|
/// or 0 if an error occurred.
|
||||||
template <class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
std::size_t
|
std::size_t
|
||||||
write_some(ConstBufferSequence const& buffers,
|
write_some(ConstBufferSequence const& buffers,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ namespace beast {
|
|||||||
caller is still responsible for freeing memory.
|
caller is still responsible for freeing memory.
|
||||||
*/
|
*/
|
||||||
#if GENERATING_DOCS
|
#if GENERATING_DOCS
|
||||||
template <class T, class CompletionHandler>
|
template<class T, class CompletionHandler>
|
||||||
class handler_alloc;
|
class handler_alloc;
|
||||||
#else
|
#else
|
||||||
template <class T, class CompletionHandler>
|
template<class T, class CompletionHandler>
|
||||||
class handler_alloc
|
class handler_alloc
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -46,7 +46,7 @@ private:
|
|||||||
// should produce a compile error if CompletionHandler is not
|
// should produce a compile error if CompletionHandler is not
|
||||||
// constructible from H.
|
// constructible from H.
|
||||||
//
|
//
|
||||||
template <class U, class H>
|
template<class U, class H>
|
||||||
friend class handler_alloc;
|
friend class handler_alloc;
|
||||||
|
|
||||||
CompletionHandler h_;
|
CompletionHandler h_;
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public:
|
|||||||
is_continuation(op->d_->h);
|
is_continuation(op->d_->h);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, read_some_op* op)
|
void asio_handler_invoke(Function&& f, read_some_op* op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ protected:
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
/** A `Streambuf` with a fixed size internal buffer.
|
/** A `DynamicBuffer` with a fixed size internal buffer.
|
||||||
|
|
||||||
@tparam N The number of bytes in the internal buffer.
|
@tparam N The number of bytes in the internal buffer.
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
/** A @b `Streambuf` that uses multiple buffers internally.
|
/** A @b `DynamicBuffer` that uses multiple buffers internally.
|
||||||
|
|
||||||
The implementation uses a sequence of one or more character arrays
|
The implementation uses a sequence of one or more character arrays
|
||||||
of varying sizes. Additional character array objects are appended to
|
of varying sizes. Additional character array objects are appended to
|
||||||
the sequence to accommodate changes in the size of the character
|
the sequence to accommodate changes in the size of the character
|
||||||
sequence.
|
sequence.
|
||||||
|
|
||||||
@note Meets the requirements of @b `Streambuf`.
|
@note Meets the requirements of @b `DynamicBuffer`.
|
||||||
*/
|
*/
|
||||||
using streambuf = basic_streambuf<std::allocator<char>>;
|
using streambuf = basic_streambuf<std::allocator<char>>;
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ protected:
|
|||||||
using list_t = typename boost::intrusive::make_list<
|
using list_t = typename boost::intrusive::make_list<
|
||||||
element, boost::intrusive::constant_time_size<false>>::type;
|
element, boost::intrusive::constant_time_size<false>>::type;
|
||||||
|
|
||||||
using set_t = typename boost::intrusive::make_set<
|
using set_t = typename boost::intrusive::make_multiset<
|
||||||
element, boost::intrusive::constant_time_size<true>,
|
element, boost::intrusive::constant_time_size<true>,
|
||||||
boost::intrusive::compare<less>>::type;
|
boost::intrusive::compare<less>>::type;
|
||||||
|
|
||||||
@@ -117,7 +117,6 @@ protected:
|
|||||||
: set_(std::move(set))
|
: set_(std::move(set))
|
||||||
, list_(std::move(list))
|
, list_(std::move(list))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -244,9 +243,10 @@ public:
|
|||||||
value.
|
value.
|
||||||
|
|
||||||
Field names are stored as-is, but comparison are case-insensitive.
|
Field names are stored as-is, but comparison are case-insensitive.
|
||||||
The container preserves the order of insertion of fields with
|
When the container is iterated, the fields are presented in the order
|
||||||
different names. For fields with the same name, the implementation
|
of insertion. For fields with the same name, the container behaves
|
||||||
concatenates values inserted with duplicate names as per rfc7230.
|
as a std::multiset; there will be a separate value for each occurrence
|
||||||
|
of the field name.
|
||||||
|
|
||||||
@note Meets the requirements of @b `FieldSequence`.
|
@note Meets the requirements of @b `FieldSequence`.
|
||||||
*/
|
*/
|
||||||
@@ -359,27 +359,44 @@ public:
|
|||||||
return set_.size();
|
return set_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns `true` if the specified field exists. */
|
/// Returns `true` if the specified field exists.
|
||||||
bool
|
bool
|
||||||
exists(boost::string_ref const& name) const
|
exists(boost::string_ref const& name) const
|
||||||
{
|
{
|
||||||
return set_.find(name, less{}) != set_.end();
|
return set_.find(name, less{}) != set_.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns an iterator to the case-insensitive matching header. */
|
/// Returns the number of values for the specified field.
|
||||||
|
std::size_t
|
||||||
|
count(boost::string_ref const& name) const;
|
||||||
|
|
||||||
|
/** Returns an iterator to the case-insensitive matching field name.
|
||||||
|
|
||||||
|
If more than one field with the specified name exists, the
|
||||||
|
first field defined by insertion order is returned.
|
||||||
|
*/
|
||||||
iterator
|
iterator
|
||||||
find(boost::string_ref const& name) const;
|
find(boost::string_ref const& name) const;
|
||||||
|
|
||||||
/** Returns the value for a case-insensitive matching header, or "" */
|
/** Returns the value for a case-insensitive matching header, or `""`.
|
||||||
|
|
||||||
|
If more than one field with the specified name exists, the
|
||||||
|
first field defined by insertion order is returned.
|
||||||
|
*/
|
||||||
boost::string_ref
|
boost::string_ref
|
||||||
operator[](boost::string_ref const& name) const;
|
operator[](boost::string_ref const& name) const;
|
||||||
|
|
||||||
/** Clear the contents of the basic_headers. */
|
/// Clear the contents of the basic_headers.
|
||||||
void
|
void
|
||||||
clear() noexcept;
|
clear() noexcept;
|
||||||
|
|
||||||
/** Remove a field.
|
/** Remove a field.
|
||||||
|
|
||||||
|
If more than one field with the specified name exists, all
|
||||||
|
matching fields will be removed.
|
||||||
|
|
||||||
|
@param name The name of the field(s) to remove.
|
||||||
|
|
||||||
@return The number of fields removed.
|
@return The number of fields removed.
|
||||||
*/
|
*/
|
||||||
std::size_t
|
std::size_t
|
||||||
@@ -387,39 +404,57 @@ public:
|
|||||||
|
|
||||||
/** Insert a field value.
|
/** Insert a field value.
|
||||||
|
|
||||||
If a field value already exists the new value will be
|
If a field with the same name already exists, the
|
||||||
extended as per RFC2616 Section 4.2.
|
existing field is untouched and a new field value pair
|
||||||
|
is inserted into the container.
|
||||||
|
|
||||||
|
@param name The name of the field.
|
||||||
|
|
||||||
|
@param value A string holding the value of the field.
|
||||||
*/
|
*/
|
||||||
// VFALCO TODO Consider allowing rvalue references for std::move?
|
|
||||||
void
|
void
|
||||||
insert(boost::string_ref const& name, boost::string_ref value);
|
insert(boost::string_ref const& name, boost::string_ref value);
|
||||||
|
|
||||||
/** Insert a field value.
|
/** Insert a field value.
|
||||||
|
|
||||||
If a field value already exists the new value will be
|
If a field with the same name already exists, the
|
||||||
extended as per RFC2616 Section 4.2.
|
existing field is untouched and a new field value pair
|
||||||
|
is inserted into the container.
|
||||||
|
|
||||||
|
@param name The name of the field
|
||||||
|
|
||||||
|
@param value The value of the field. The object will be
|
||||||
|
converted to a string using `boost::lexical_cast`.
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
typename std::enable_if<
|
typename std::enable_if<
|
||||||
! std::is_constructible<boost::string_ref, T>::value>::type
|
! std::is_constructible<boost::string_ref, T>::value>::type
|
||||||
insert(boost::string_ref name, T const& value)
|
insert(boost::string_ref name, T const& value)
|
||||||
{
|
{
|
||||||
insert(name,
|
insert(name, boost::lexical_cast<std::string>(value));
|
||||||
boost::lexical_cast<std::string>(value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Replace a field value.
|
/** Replace a field value.
|
||||||
|
|
||||||
The current field value, if any, is removed. Then the
|
First removes any values with matching field names, then
|
||||||
specified value is inserted as if by `insert(field, value)`.
|
inserts the new field value.
|
||||||
|
|
||||||
|
@param name The name of the field.
|
||||||
|
|
||||||
|
@param value A string holding the value of the field.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
replace(boost::string_ref const& name, boost::string_ref value);
|
replace(boost::string_ref const& name, boost::string_ref value);
|
||||||
|
|
||||||
/** Replace a field value.
|
/** Replace a field value.
|
||||||
|
|
||||||
The current field value, if any, is removed. Then the
|
First removes any values with matching field names, then
|
||||||
specified value is inserted as if by `insert(field, value)`.
|
inserts the new field value.
|
||||||
|
|
||||||
|
@param name The name of the field
|
||||||
|
|
||||||
|
@param value The value of the field. The object will be
|
||||||
|
converted to a string using `boost::lexical_cast`.
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
typename std::enable_if<
|
typename std::enable_if<
|
||||||
|
|||||||
@@ -482,7 +482,7 @@ private:
|
|||||||
std::declval<error_code&>()),
|
std::declval<error_code&>()),
|
||||||
std::true_type{})>
|
std::true_type{})>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
@@ -501,7 +501,7 @@ private:
|
|||||||
std::declval<error_code&>()),
|
std::declval<error_code&>()),
|
||||||
std::true_type{})>
|
std::true_type{})>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
@@ -520,7 +520,7 @@ private:
|
|||||||
std::declval<error_code&>()),
|
std::declval<error_code&>()),
|
||||||
std::true_type{})>
|
std::true_type{})>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
@@ -539,7 +539,7 @@ private:
|
|||||||
std::declval<error_code&>()),
|
std::declval<error_code&>()),
|
||||||
std::true_type{})>
|
std::true_type{})>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
@@ -557,7 +557,7 @@ private:
|
|||||||
std::declval<error_code&>()),
|
std::declval<error_code&>()),
|
||||||
std::true_type{})>
|
std::true_type{})>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
@@ -575,7 +575,7 @@ private:
|
|||||||
std::declval<error_code&>()),
|
std::declval<error_code&>()),
|
||||||
std::true_type{})>
|
std::true_type{})>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
@@ -594,7 +594,7 @@ private:
|
|||||||
std::declval<error_code&>()),
|
std::declval<error_code&>()),
|
||||||
std::true_type{})>
|
std::true_type{})>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
@@ -613,7 +613,7 @@ private:
|
|||||||
std::declval<error_code&>()),
|
std::declval<error_code&>()),
|
||||||
std::true_type{})>
|
std::true_type{})>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
@@ -630,7 +630,7 @@ private:
|
|||||||
decltype(std::declval<T>().on_headers(
|
decltype(std::declval<T>().on_headers(
|
||||||
std::declval<std::uint64_t>(), std::declval<error_code&>()))>>
|
std::declval<std::uint64_t>(), std::declval<error_code&>()))>>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
@@ -649,7 +649,7 @@ private:
|
|||||||
std::declval<error_code&>()),
|
std::declval<error_code&>()),
|
||||||
std::true_type{})>
|
std::true_type{})>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
@@ -667,7 +667,7 @@ private:
|
|||||||
std::declval<error_code&>()),
|
std::declval<error_code&>()),
|
||||||
std::true_type{})>
|
std::true_type{})>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<C>(0));
|
using type = decltype(check<C>(0));
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class chunk_encode_text
|
|||||||
// Storage for the longest hex string we might need, plus delimiters.
|
// Storage for the longest hex string we might need, plus delimiters.
|
||||||
std::array<char, 2 * sizeof(std::size_t) + 2> buf_;
|
std::array<char, 2 * sizeof(std::size_t) + 2> buf_;
|
||||||
|
|
||||||
template <class OutIter>
|
template<class OutIter>
|
||||||
static
|
static
|
||||||
OutIter
|
OutIter
|
||||||
to_hex(OutIter last, std::size_t n)
|
to_hex(OutIter last, std::size_t n)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class has_content_length_value
|
|||||||
decltype(std::declval<U>().content_length()),
|
decltype(std::declval<U>().content_length()),
|
||||||
std::uint64_t>>
|
std::uint64_t>>
|
||||||
static R check(int);
|
static R check(int);
|
||||||
template <class>
|
template<class>
|
||||||
static std::false_type check(...);
|
static std::false_type check(...);
|
||||||
using type = decltype(check<T>(0));
|
using type = decltype(check<T>(0));
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
|
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
|
||||||
|
|
||||||
#include <beast/http/detail/rfc7230.hpp>
|
#include <beast/http/detail/rfc7230.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
@@ -204,6 +205,18 @@ basic_headers(FwdIt first, FwdIt last)
|
|||||||
insert(first->name(), first->value());
|
insert(first->name(), first->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
std::size_t
|
||||||
|
basic_headers<Allocator>::
|
||||||
|
count(boost::string_ref const& name) const
|
||||||
|
{
|
||||||
|
auto const it = set_.find(name, less{});
|
||||||
|
if(it == set_.end())
|
||||||
|
return 0;
|
||||||
|
auto const last = set_.upper_bound(name, less{});
|
||||||
|
return static_cast<std::size_t>(std::distance(it, last));
|
||||||
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
auto
|
auto
|
||||||
basic_headers<Allocator>::
|
basic_headers<Allocator>::
|
||||||
@@ -221,11 +234,9 @@ boost::string_ref
|
|||||||
basic_headers<Allocator>::
|
basic_headers<Allocator>::
|
||||||
operator[](boost::string_ref const& name) const
|
operator[](boost::string_ref const& name) const
|
||||||
{
|
{
|
||||||
// VFALCO This none object looks sketchy
|
|
||||||
static boost::string_ref const none;
|
|
||||||
auto const it = find(name);
|
auto const it = find(name);
|
||||||
if(it == end())
|
if(it == end())
|
||||||
return none;
|
return {};
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,15 +255,23 @@ std::size_t
|
|||||||
basic_headers<Allocator>::
|
basic_headers<Allocator>::
|
||||||
erase(boost::string_ref const& name)
|
erase(boost::string_ref const& name)
|
||||||
{
|
{
|
||||||
auto const it = set_.find(name, less{});
|
auto it = set_.find(name, less{});
|
||||||
if(it == set_.end())
|
if(it == set_.end())
|
||||||
return 0;
|
return 0;
|
||||||
auto& e = *it;
|
auto const last = set_.upper_bound(name, less{});
|
||||||
set_.erase(set_.iterator_to(e));
|
std::size_t n = 1;
|
||||||
list_.erase(list_.iterator_to(e));
|
for(;;)
|
||||||
alloc_traits::destroy(this->member(), &e);
|
{
|
||||||
alloc_traits::deallocate(this->member(), &e, 1);
|
auto& e = *it++;
|
||||||
return 1;
|
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);
|
||||||
|
if(it == last)
|
||||||
|
break;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
@@ -262,25 +281,10 @@ insert(boost::string_ref const& name,
|
|||||||
boost::string_ref value)
|
boost::string_ref value)
|
||||||
{
|
{
|
||||||
value = detail::trim(value);
|
value = detail::trim(value);
|
||||||
typename set_t::insert_commit_data d;
|
auto const p = alloc_traits::allocate(this->member(), 1);
|
||||||
auto const result =
|
alloc_traits::construct(this->member(), p, name, value);
|
||||||
set_.insert_check(name, less{}, d);
|
set_.insert_before(set_.upper_bound(name, less{}), *p);
|
||||||
if(result.second)
|
list_.push_back(*p);
|
||||||
{
|
|
||||||
auto const p = alloc_traits::allocate(
|
|
||||||
this->member(), 1);
|
|
||||||
alloc_traits::construct(
|
|
||||||
this->member(), p, name, value);
|
|
||||||
list_.push_back(*p);
|
|
||||||
set_.insert_commit(*p, d);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// If field already exists, insert comma
|
|
||||||
// separated value as per RFC2616 section 4.2
|
|
||||||
auto& cur = result.first->data.second;
|
|
||||||
cur.reserve(cur.size() + 1 + value.size());
|
|
||||||
cur.append(1, ',');
|
|
||||||
cur.append(value.data(), value.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#ifndef BEAST_HTTP_IMPL_MESSAGE_V1_IPP
|
#ifndef BEAST_HTTP_IMPL_MESSAGE_V1_IPP
|
||||||
#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP
|
#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP
|
||||||
|
|
||||||
|
#include <beast/core/error.hpp>
|
||||||
#include <beast/http/rfc7230.hpp>
|
#include <beast/http/rfc7230.hpp>
|
||||||
#include <beast/http/detail/has_content_length.hpp>
|
#include <beast/http/detail/has_content_length.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
@@ -87,7 +88,11 @@ prepare_content_length(prepare_info& pi,
|
|||||||
std::true_type)
|
std::true_type)
|
||||||
{
|
{
|
||||||
typename Body::writer w(msg);
|
typename Body::writer w(msg);
|
||||||
//w.init(ec); // VFALCO This is a design problem!
|
// VFALCO This is a design problem!
|
||||||
|
error_code ec;
|
||||||
|
w.init(ec);
|
||||||
|
if(ec)
|
||||||
|
throw system_error{ec};
|
||||||
pi.content_length = w.content_length();
|
pi.content_length = w.content_length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, parse_op* op)
|
void asio_handler_invoke(Function&& f, parse_op* op)
|
||||||
{
|
{
|
||||||
@@ -277,7 +277,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, read_op* op)
|
void asio_handler_invoke(Function&& f, read_op* op)
|
||||||
{
|
{
|
||||||
@@ -412,7 +412,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
|
|||||||
static_assert(is_ReadableBody<Body>::value,
|
static_assert(is_ReadableBody<Body>::value,
|
||||||
"ReadableBody requirements not met");
|
"ReadableBody requirements not met");
|
||||||
error_code ec;
|
error_code ec;
|
||||||
read(stream, dynabuf, msg, ec);
|
beast::http::read(stream, dynabuf, msg, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
throw system_error{ec};
|
throw system_error{ec};
|
||||||
}
|
}
|
||||||
@@ -431,7 +431,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
|
|||||||
static_assert(is_ReadableBody<Body>::value,
|
static_assert(is_ReadableBody<Body>::value,
|
||||||
"ReadableBody requirements not met");
|
"ReadableBody requirements not met");
|
||||||
parser_v1<isRequest, Body, Headers> p;
|
parser_v1<isRequest, Body, Headers> p;
|
||||||
parse(stream, dynabuf, p, ec);
|
beast::http::parse(stream, dynabuf, p, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
return;
|
return;
|
||||||
assert(p.complete());
|
assert(p.complete());
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, write_op* op)
|
void asio_handler_invoke(Function&& f, write_op* op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ namespace http {
|
|||||||
|
|
||||||
enum class parse_error
|
enum class parse_error
|
||||||
{
|
{
|
||||||
|
success = 0,
|
||||||
|
|
||||||
connection_closed,
|
connection_closed,
|
||||||
|
|
||||||
bad_method,
|
bad_method,
|
||||||
|
|||||||
@@ -35,6 +35,37 @@ struct parser_response
|
|||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
|
/** Skip body option.
|
||||||
|
|
||||||
|
The options controls whether or not the parser expects to see a
|
||||||
|
HTTP body, regardless of the presence or absence of certain fields
|
||||||
|
such as Content-Length.
|
||||||
|
|
||||||
|
Depending on the request, some responses do not carry a body.
|
||||||
|
For example, a 200 response to a CONNECT request from a tunneling
|
||||||
|
proxy. In these cases, callers use the @ref skip_body option to
|
||||||
|
inform the parser that no body is expected. The parser will consider
|
||||||
|
the message complete after the all headers have been received.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@code
|
||||||
|
parser_v1<true, empty_body, headers> p;
|
||||||
|
p.set_option(skip_body{true});
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@note Objects of this type are passed to @ref basic_parser_v1::set_option.
|
||||||
|
*/
|
||||||
|
struct skip_body
|
||||||
|
{
|
||||||
|
bool value;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
skip_body(bool v)
|
||||||
|
: value(v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** A parser for producing HTTP/1 messages.
|
/** A parser for producing HTTP/1 messages.
|
||||||
|
|
||||||
This class uses the basic HTTP/1 wire format parser to convert
|
This class uses the basic HTTP/1 wire format parser to convert
|
||||||
@@ -62,6 +93,7 @@ private:
|
|||||||
std::string value_;
|
std::string value_;
|
||||||
message_type m_;
|
message_type m_;
|
||||||
typename message_type::body_type::reader r_;
|
typename message_type::body_type::reader r_;
|
||||||
|
std::uint8_t skip_body_ = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
parser_v1(parser_v1&&) = default;
|
parser_v1(parser_v1&&) = default;
|
||||||
@@ -81,6 +113,13 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the expect body option.
|
||||||
|
void
|
||||||
|
set_option(skip_body const& o)
|
||||||
|
{
|
||||||
|
skip_body_ = o.value ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the parsed message.
|
/** Returns the parsed message.
|
||||||
|
|
||||||
Only valid if `complete()` would return `true`.
|
Only valid if `complete()` would return `true`.
|
||||||
@@ -176,7 +215,7 @@ private:
|
|||||||
{
|
{
|
||||||
flush();
|
flush();
|
||||||
m_.version = 10 * this->http_major() + this->http_minor();
|
m_.version = 10 * this->http_major() + this->http_minor();
|
||||||
return 0;
|
return skip_body_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_request(error_code& ec)
|
void on_request(error_code& ec)
|
||||||
|
|||||||
@@ -30,6 +30,16 @@ namespace http {
|
|||||||
the behavior of the container will be as if a string containing
|
the behavior of the container will be as if a string containing
|
||||||
only characters up to but excluding the first invalid character
|
only characters up to but excluding the first invalid character
|
||||||
was used to construct the list.
|
was used to construct the list.
|
||||||
|
|
||||||
|
@code
|
||||||
|
for(auto const& param : param_list{";level=9;no_context_takeover;bits=15"})
|
||||||
|
{
|
||||||
|
std::cout << ";" << param.first;
|
||||||
|
if(! param.second.empty())
|
||||||
|
std::cout << "=" << param.second;
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
*/
|
*/
|
||||||
class param_list
|
class param_list
|
||||||
{
|
{
|
||||||
@@ -98,6 +108,24 @@ public:
|
|||||||
the behavior of the container will be as if a string containing
|
the behavior of the container will be as if a string containing
|
||||||
only characters up to but excluding the first invalid character
|
only characters up to but excluding the first invalid character
|
||||||
was used to construct the list.
|
was used to construct the list.
|
||||||
|
|
||||||
|
To use this class, construct with the string to be parsed and
|
||||||
|
then use @ref begin and @end, or range-for to iterate each
|
||||||
|
item:
|
||||||
|
|
||||||
|
@code
|
||||||
|
for(auto const& ext : ext_list{"none, 7z;level=9, zip;no_context_takeover;bits=15"})
|
||||||
|
{
|
||||||
|
std::cout << ext.first << "\n";
|
||||||
|
for(auto const& param : ext.second)
|
||||||
|
{
|
||||||
|
std::cout << ";" << param.first;
|
||||||
|
if(! param.second.empty())
|
||||||
|
std::cout << "=" << param.second;
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
*/
|
*/
|
||||||
class ext_list
|
class ext_list
|
||||||
{
|
{
|
||||||
@@ -181,6 +209,15 @@ public:
|
|||||||
the behavior of the container will be as if a string containing
|
the behavior of the container will be as if a string containing
|
||||||
only characters up to but excluding the first invalid character
|
only characters up to but excluding the first invalid character
|
||||||
was used to construct the list.
|
was used to construct the list.
|
||||||
|
|
||||||
|
To use this class, construct with the string to be parsed and
|
||||||
|
then use @ref begin and @end, or range-for to iterate each
|
||||||
|
item:
|
||||||
|
|
||||||
|
@code
|
||||||
|
for(auto const& token : token_list{"apple, pear, banana"})
|
||||||
|
std::cout << token << "\n";
|
||||||
|
@endcode
|
||||||
*/
|
*/
|
||||||
class token_list
|
class token_list
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,71 +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_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
|
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
// BEAST_VERSION / 100 % 1000 is the minor version
|
// BEAST_VERSION / 100 % 1000 is the minor version
|
||||||
// BEAST_VERSION / 100000 is the major version
|
// BEAST_VERSION / 100000 is the major version
|
||||||
//
|
//
|
||||||
#define BEAST_VERSION 100006
|
#define BEAST_VERSION 100000
|
||||||
|
|
||||||
#define BEAST_VERSION_STRING "1.0.0-b6"
|
#define BEAST_VERSION_STRING "1.0.0-b13"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ is_valid(close_code::value code)
|
|||||||
if(v >= 1016 && v <= 2999)
|
if(v >= 1016 && v <= 2999)
|
||||||
return false;
|
return false;
|
||||||
// not used
|
// not used
|
||||||
if(v >= 0 && v <= 999)
|
if(v <= 999)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -136,12 +136,12 @@ write(DynamicBuffer& db, frame_header const& fh)
|
|||||||
if(fh.rsv3)
|
if(fh.rsv3)
|
||||||
b[0] |= 0x10;
|
b[0] |= 0x10;
|
||||||
b[1] = fh.mask ? 0x80 : 0x00;
|
b[1] = fh.mask ? 0x80 : 0x00;
|
||||||
if (fh.len <= 125)
|
if(fh.len <= 125)
|
||||||
{
|
{
|
||||||
b[1] |= fh.len;
|
b[1] |= fh.len;
|
||||||
n = 2;
|
n = 2;
|
||||||
}
|
}
|
||||||
else if (fh.len <= 65535)
|
else if(fh.len <= 65535)
|
||||||
{
|
{
|
||||||
b[1] |= 126;
|
b[1] |= 126;
|
||||||
::new(&b[2]) big_uint16_buf_t{
|
::new(&b[2]) big_uint16_buf_t{
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ mask_inplace_general(
|
|||||||
{
|
{
|
||||||
using boost::asio::buffer_cast;
|
using boost::asio::buffer_cast;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
auto n = buffer_size(b);
|
auto const n = buffer_size(b);
|
||||||
auto p = buffer_cast<std::uint8_t*>(b);
|
auto p = buffer_cast<std::uint8_t*>(b);
|
||||||
for(auto i = n / sizeof(key); i; --i)
|
for(auto i = n / sizeof(key); i; --i)
|
||||||
{
|
{
|
||||||
@@ -122,13 +122,14 @@ mask_inplace_general(
|
|||||||
*p ^= (key >>16); ++p;
|
*p ^= (key >>16); ++p;
|
||||||
*p ^= (key >>24); ++p;
|
*p ^= (key >>24); ++p;
|
||||||
}
|
}
|
||||||
n %= sizeof(key);
|
auto const m =
|
||||||
switch(n)
|
static_cast<std::uint8_t>(n % sizeof(key));
|
||||||
|
switch(m)
|
||||||
{
|
{
|
||||||
case 3: p[2] ^= (key >>16);
|
case 3: p[2] ^= (key >>16);
|
||||||
case 2: p[1] ^= (key >> 8);
|
case 2: p[1] ^= (key >> 8);
|
||||||
case 1: p[0] ^= key;
|
case 1: p[0] ^= key;
|
||||||
key = ror(key, n*8);
|
key = ror(key, m*8);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -144,7 +145,7 @@ mask_inplace_general(
|
|||||||
{
|
{
|
||||||
using boost::asio::buffer_cast;
|
using boost::asio::buffer_cast;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
auto n = buffer_size(b);
|
auto const n = buffer_size(b);
|
||||||
auto p = buffer_cast<std::uint8_t*>(b);
|
auto p = buffer_cast<std::uint8_t*>(b);
|
||||||
for(auto i = n / sizeof(key); i; --i)
|
for(auto i = n / sizeof(key); i; --i)
|
||||||
{
|
{
|
||||||
@@ -157,8 +158,9 @@ mask_inplace_general(
|
|||||||
*p ^= (key >>48); ++p;
|
*p ^= (key >>48); ++p;
|
||||||
*p ^= (key >>56); ++p;
|
*p ^= (key >>56); ++p;
|
||||||
}
|
}
|
||||||
n %= sizeof(key);
|
auto const m =
|
||||||
switch(n)
|
static_cast<std::uint8_t>(n % sizeof(key));
|
||||||
|
switch(m)
|
||||||
{
|
{
|
||||||
case 7: p[6] ^= (key >>16);
|
case 7: p[6] ^= (key >>16);
|
||||||
case 6: p[5] ^= (key >> 8);
|
case 6: p[5] ^= (key >> 8);
|
||||||
@@ -167,7 +169,7 @@ mask_inplace_general(
|
|||||||
case 3: p[2] ^= (key >>16);
|
case 3: p[2] ^= (key >>16);
|
||||||
case 2: p[1] ^= (key >> 8);
|
case 2: p[1] ^= (key >> 8);
|
||||||
case 1: p[0] ^= key;
|
case 1: p[0] ^= key;
|
||||||
key = ror(key, n*8);
|
key = ror(key, m*8);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ utf8_checker_t<_>::write(BufferSequence const& bs)
|
|||||||
{
|
{
|
||||||
using boost::asio::buffer_cast;
|
using boost::asio::buffer_cast;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
for (auto const& b : bs)
|
for(auto const& b : bs)
|
||||||
if(! write(buffer_cast<void const*>(b),
|
if(! write(buffer_cast<void const*>(b),
|
||||||
buffer_size(b)))
|
buffer_size(b)))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ namespace websocket {
|
|||||||
/// Error codes returned from @ref stream operations.
|
/// Error codes returned from @ref stream operations.
|
||||||
enum class error
|
enum class error
|
||||||
{
|
{
|
||||||
|
success = 0,
|
||||||
|
|
||||||
/// Both sides performed a WebSocket close
|
/// Both sides performed a WebSocket close
|
||||||
closed = 1,
|
closed,
|
||||||
|
|
||||||
/// WebSocket connection failed, protocol violation
|
/// WebSocket connection failed, protocol violation
|
||||||
failed,
|
failed,
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, accept_op* op)
|
void asio_handler_invoke(Function&& f, accept_op* op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, close_op* op)
|
void asio_handler_invoke(Function&& f, close_op* op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, handshake_op* op)
|
void asio_handler_invoke(Function&& f, handshake_op* op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, ping_op* op)
|
void asio_handler_invoke(Function&& f, ping_op* op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, read_frame_op* op)
|
void asio_handler_invoke(Function&& f, read_frame_op* op)
|
||||||
{
|
{
|
||||||
@@ -252,7 +252,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
d.state = do_read_fh + 2;
|
d.state = do_read_fh + 2;
|
||||||
if (n == 0)
|
if(n == 0)
|
||||||
{
|
{
|
||||||
bytes_transferred = 0;
|
bytes_transferred = 0;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, read_op* op)
|
void asio_handler_invoke(Function&& f, read_op* op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, response_op* op)
|
void asio_handler_invoke(Function&& f, response_op* op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f,
|
void asio_handler_invoke(Function&& f,
|
||||||
teardown_ssl_op* op)
|
teardown_ssl_op* op)
|
||||||
@@ -129,7 +129,7 @@ operator()(error_code ec, bool again)
|
|||||||
|
|
||||||
template<class AsyncStream>
|
template<class AsyncStream>
|
||||||
void
|
void
|
||||||
teardown(
|
teardown(teardown_tag,
|
||||||
boost::asio::ssl::stream<AsyncStream>& stream,
|
boost::asio::ssl::stream<AsyncStream>& stream,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
@@ -138,7 +138,7 @@ teardown(
|
|||||||
|
|
||||||
template<class AsyncStream, class TeardownHandler>
|
template<class AsyncStream, class TeardownHandler>
|
||||||
void
|
void
|
||||||
async_teardown(
|
async_teardown(teardown_tag,
|
||||||
boost::asio::ssl::stream<AsyncStream>& stream,
|
boost::asio::ssl::stream<AsyncStream>& stream,
|
||||||
TeardownHandler&& handler)
|
TeardownHandler&& handler)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -920,7 +920,7 @@ build_request(boost::string_ref const& host,
|
|||||||
boost::string_ref const& resource, std::string& key)
|
boost::string_ref const& resource, std::string& key)
|
||||||
{
|
{
|
||||||
http::request_v1<http::empty_body> req;
|
http::request_v1<http::empty_body> req;
|
||||||
req.url = "/";
|
req.url = { resource.data(), resource.size() };
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.method = "GET";
|
req.method = "GET";
|
||||||
req.headers.insert("Host", host);
|
req.headers.insert("Host", host);
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f,
|
void asio_handler_invoke(Function&& f,
|
||||||
teardown_tcp_op* op)
|
teardown_tcp_op* op)
|
||||||
@@ -128,7 +128,7 @@ operator()(error_code ec, std::size_t, bool again)
|
|||||||
|
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
teardown(
|
teardown(teardown_tag,
|
||||||
boost::asio::ip::tcp::socket& socket,
|
boost::asio::ip::tcp::socket& socket,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
@@ -151,7 +151,7 @@ teardown(
|
|||||||
template<class TeardownHandler>
|
template<class TeardownHandler>
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
async_teardown(
|
async_teardown(teardown_tag,
|
||||||
boost::asio::ip::tcp::socket& socket,
|
boost::asio::ip::tcp::socket& socket,
|
||||||
TeardownHandler&& handler)
|
TeardownHandler&& handler)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, write_frame_op* op)
|
void asio_handler_invoke(Function&& f, write_frame_op* op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public:
|
|||||||
return op->d_->cont;
|
return op->d_->cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template<class Function>
|
||||||
friend
|
friend
|
||||||
void asio_handler_invoke(Function&& f, write_op* op)
|
void asio_handler_invoke(Function&& f, write_op* op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace websocket {
|
|||||||
*/
|
*/
|
||||||
template<class SyncStream>
|
template<class SyncStream>
|
||||||
void
|
void
|
||||||
teardown(
|
teardown(teardown_tag,
|
||||||
boost::asio::ssl::stream<SyncStream>& stream,
|
boost::asio::ssl::stream<SyncStream>& stream,
|
||||||
error_code& ec);
|
error_code& ec);
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ teardown(
|
|||||||
template<class AsyncStream, class TeardownHandler>
|
template<class AsyncStream, class TeardownHandler>
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
async_teardown(
|
async_teardown(teardown_tag,
|
||||||
boost::asio::ssl::stream<AsyncStream>& stream,
|
boost::asio::ssl::stream<AsyncStream>& stream,
|
||||||
TeardownHandler&& handler);
|
TeardownHandler&& handler);
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,17 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
namespace websocket {
|
namespace websocket {
|
||||||
|
|
||||||
|
/** Tag type used to find teardown and async_teardown overloads
|
||||||
|
|
||||||
|
Overloads of @ref teardown and @async_teardown for user defined
|
||||||
|
types must take a value of type @ref teardown_tag in the first
|
||||||
|
argument in order to be found by the implementation.
|
||||||
|
*/
|
||||||
|
struct teardown_tag {};
|
||||||
|
|
||||||
/** Tear down a connection.
|
/** Tear down a connection.
|
||||||
|
|
||||||
This tears down a connection. The implementation will call
|
This tears down a connection. The implementation will call
|
||||||
@@ -30,7 +39,19 @@ namespace websocket {
|
|||||||
*/
|
*/
|
||||||
template<class Socket>
|
template<class Socket>
|
||||||
void
|
void
|
||||||
teardown(Socket& socket, error_code& ec) = delete;
|
teardown(teardown_tag, Socket& socket, error_code& ec)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If you are trying to use OpenSSL and this goes off, you need to
|
||||||
|
add an include for <beast/websocket/ssl.hpp>.
|
||||||
|
|
||||||
|
If you are creating an instance of beast::websocket::stream with your
|
||||||
|
own user defined type, you must provide an overload of teardown with
|
||||||
|
the corresponding signature (including the teardown_tag).
|
||||||
|
*/
|
||||||
|
static_assert(sizeof(Socket)==-1,
|
||||||
|
"Unknown Socket type in teardown.");
|
||||||
|
}
|
||||||
|
|
||||||
/** Start tearing down a connection.
|
/** Start tearing down a connection.
|
||||||
|
|
||||||
@@ -49,7 +70,8 @@ teardown(Socket& socket, error_code& ec) = delete;
|
|||||||
function signature of the handler must be:
|
function signature of the handler must be:
|
||||||
@code void handler(
|
@code void handler(
|
||||||
error_code const& error // result of operation
|
error_code const& error // result of operation
|
||||||
); @endcode
|
);
|
||||||
|
@endcode
|
||||||
Regardless of whether the asynchronous operation completes
|
Regardless of whether the asynchronous operation completes
|
||||||
immediately or not, the handler will not be invoked from within
|
immediately or not, the handler will not be invoked from within
|
||||||
this function. Invocation of the handler will be performed in a
|
this function. Invocation of the handler will be performed in a
|
||||||
@@ -58,57 +80,19 @@ teardown(Socket& socket, error_code& ec) = delete;
|
|||||||
*/
|
*/
|
||||||
template<class Socket, class TeardownHandler>
|
template<class Socket, class TeardownHandler>
|
||||||
void
|
void
|
||||||
async_teardown(Socket& socket, TeardownHandler&& handler) = delete;
|
async_teardown(teardown_tag, Socket& socket, TeardownHandler&& handler)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If you are trying to use OpenSSL and this goes off, you need to
|
||||||
|
add an include for <beast/websocket/ssl.hpp>.
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
If you are creating an instance of beast::websocket::stream with your
|
||||||
|
own user defined type, you must provide an overload of teardown with
|
||||||
/** Tear down a `boost::asio::ip::tcp::socket`.
|
the corresponding signature (including the teardown_tag).
|
||||||
|
|
||||||
This tears down a connection. The implementation will call
|
|
||||||
the overload of this function based on the `Stream` parameter
|
|
||||||
used to consruct the socket. When `Stream` is a user defined
|
|
||||||
type, and not a `boost::asio::ip::tcp::socket` or any
|
|
||||||
`boost::asio::ssl::stream`, callers are responsible for
|
|
||||||
providing a suitable overload of this function.
|
|
||||||
|
|
||||||
@param socket The socket to tear down.
|
|
||||||
|
|
||||||
@param ec Set to the error if any occurred.
|
|
||||||
*/
|
*/
|
||||||
void
|
static_assert(sizeof(Socket)==-1,
|
||||||
teardown(
|
"Unknown Socket type in async_teardown.");
|
||||||
boost::asio::ip::tcp::socket& socket,
|
}
|
||||||
error_code& ec);
|
|
||||||
|
|
||||||
/** Start tearing down a `boost::asio::ip::tcp::socket`.
|
|
||||||
|
|
||||||
This begins tearing down a connection asynchronously.
|
|
||||||
The implementation will call the overload of this function
|
|
||||||
based on the `Stream` parameter used to consruct the socket.
|
|
||||||
When `Stream` is a user defined type, and not a
|
|
||||||
`boost::asio::ip::tcp::socket` or any `boost::asio::ssl::stream`,
|
|
||||||
callers are responsible for providing a suitable overload
|
|
||||||
of this function.
|
|
||||||
|
|
||||||
@param socket The socket to tear down.
|
|
||||||
|
|
||||||
@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(
|
|
||||||
error_code const& error // result of operation
|
|
||||||
); @endcode
|
|
||||||
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().
|
|
||||||
|
|
||||||
*/
|
|
||||||
template<class TeardownHandler>
|
|
||||||
void
|
|
||||||
async_teardown(
|
|
||||||
boost::asio::ip::tcp::socket& socket,
|
|
||||||
TeardownHandler&& handler);
|
|
||||||
|
|
||||||
} // websocket
|
} // websocket
|
||||||
|
|
||||||
@@ -127,7 +111,7 @@ void
|
|||||||
call_teardown(Socket& socket, error_code& ec)
|
call_teardown(Socket& socket, error_code& ec)
|
||||||
{
|
{
|
||||||
using websocket::teardown;
|
using websocket::teardown;
|
||||||
teardown(socket, ec);
|
teardown(websocket::teardown_tag{}, socket, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Socket, class TeardownHandler>
|
template<class Socket, class TeardownHandler>
|
||||||
@@ -136,12 +120,65 @@ void
|
|||||||
call_async_teardown(Socket& socket, TeardownHandler&& handler)
|
call_async_teardown(Socket& socket, TeardownHandler&& handler)
|
||||||
{
|
{
|
||||||
using websocket::async_teardown;
|
using websocket::async_teardown;
|
||||||
async_teardown(socket,
|
async_teardown(websocket::teardown_tag{}, socket,
|
||||||
std::forward<TeardownHandler>(handler));
|
std::forward<TeardownHandler>(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // websocket_helpers
|
} // websocket_helpers
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace websocket {
|
||||||
|
|
||||||
|
/** Tear down a `boost::asio::ip::tcp::socket`.
|
||||||
|
|
||||||
|
This tears down a connection. The implementation will call
|
||||||
|
the overload of this function based on the `Stream` parameter
|
||||||
|
used to consruct the socket. When `Stream` is a user defined
|
||||||
|
type, and not a `boost::asio::ip::tcp::socket` or any
|
||||||
|
`boost::asio::ssl::stream`, callers are responsible for
|
||||||
|
providing a suitable overload of this function.
|
||||||
|
|
||||||
|
@param socket The socket to tear down.
|
||||||
|
|
||||||
|
@param ec Set to the error if any occurred.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
teardown(teardown_tag,
|
||||||
|
boost::asio::ip::tcp::socket& socket, error_code& ec);
|
||||||
|
|
||||||
|
/** Start tearing down a `boost::asio::ip::tcp::socket`.
|
||||||
|
|
||||||
|
This begins tearing down a connection asynchronously.
|
||||||
|
The implementation will call the overload of this function
|
||||||
|
based on the `Stream` parameter used to consruct the socket.
|
||||||
|
When `Stream` is a user defined type, and not a
|
||||||
|
`boost::asio::ip::tcp::socket` or any `boost::asio::ssl::stream`,
|
||||||
|
callers are responsible for providing a suitable overload
|
||||||
|
of this function.
|
||||||
|
|
||||||
|
@param socket The socket to tear down.
|
||||||
|
|
||||||
|
@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(
|
||||||
|
error_code const& error // result of operation
|
||||||
|
);
|
||||||
|
@endcode
|
||||||
|
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().
|
||||||
|
|
||||||
|
*/
|
||||||
|
template<class TeardownHandler>
|
||||||
|
void
|
||||||
|
async_teardown(teardown_tag,
|
||||||
|
boost::asio::ip::tcp::socket& socket, TeardownHandler&& handler);
|
||||||
|
|
||||||
|
} // websocket
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
#include <beast/websocket/impl/teardown.ipp>
|
#include <beast/websocket/impl/teardown.ipp>
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ elif [[ $(uname -s) == "Linux" ]]; then
|
|||||||
num_proc_units=$(nproc)
|
num_proc_units=$(nproc)
|
||||||
# Physical cores
|
# Physical cores
|
||||||
num_jobs=$(lscpu -p | grep -v '^#' | sort -u -t, -k 2,4 | wc -l)
|
num_jobs=$(lscpu -p | grep -v '^#' | sort -u -t, -k 2,4 | wc -l)
|
||||||
if (("$num_proc_units" < "$num_jobs")); then
|
if ((${num_proc_units} < ${num_jobs})); then
|
||||||
num_jobs=$num_proc_units
|
num_jobs=$num_proc_units
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -82,6 +82,16 @@ function build_beast {
|
|||||||
-j${num_jobs}
|
-j${num_jobs}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function build_beast_cmake {
|
||||||
|
mkdir -p build
|
||||||
|
pushd build > /dev/null
|
||||||
|
cmake -DVARIANT=${VARIANT} ..
|
||||||
|
make -j${num_jobs}
|
||||||
|
mkdir -p ../bin/$VARIANT
|
||||||
|
find . -executable -type f -exec cp {} ../bin/$VARIANT/. \;
|
||||||
|
popd > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
function run_autobahn_test_suite {
|
function run_autobahn_test_suite {
|
||||||
# Run autobahn tests
|
# Run autobahn tests
|
||||||
wsecho=$(find bin -name "websocket-echo" | grep /$VARIANT/)
|
wsecho=$(find bin -name "websocket-echo" | grep /$VARIANT/)
|
||||||
@@ -108,7 +118,11 @@ function run_autobahn_test_suite {
|
|||||||
|
|
||||||
##################################### BUILD ####################################
|
##################################### BUILD ####################################
|
||||||
|
|
||||||
build_beast
|
if [[ ${BUILD_SYSTEM:-} == cmake ]]; then
|
||||||
|
build_beast_cmake
|
||||||
|
else
|
||||||
|
build_beast
|
||||||
|
fi
|
||||||
|
|
||||||
##################################### TESTS ####################################
|
##################################### TESTS ####################################
|
||||||
|
|
||||||
@@ -123,6 +137,7 @@ if [[ $VARIANT == "coverage" ]]; then
|
|||||||
run_tests_with_valgrind
|
run_tests_with_valgrind
|
||||||
run_autobahn_test_suite
|
run_autobahn_test_suite
|
||||||
else
|
else
|
||||||
|
echo "skipping autobahn tests for feature branch build"
|
||||||
run_tests
|
run_tests
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,32 @@ do
|
|||||||
test -x $( type -p ${g}-$GCC_VER )
|
test -x $( type -p ${g}-$GCC_VER )
|
||||||
ln -sv $(type -p ${g}-$GCC_VER) $HOME/bin/${g}
|
ln -sv $(type -p ${g}-$GCC_VER) $HOME/bin/${g}
|
||||||
done
|
done
|
||||||
for c in clang clang++ llvm-symbolizer
|
|
||||||
do
|
if [[ -n ${CLANG_VER:-} ]]; then
|
||||||
test -x $( type -p ${c}-$CLANG_VER )
|
# There are cases where the directory exists, but the exe is not available.
|
||||||
ln -sv $(type -p ${c}-$CLANG_VER) $HOME/bin/${c}
|
# Use this workaround for now.
|
||||||
done
|
if [[ ! -x llvm-${LLVM_VERSION}/bin/llvm-config ]] && [[ -d llvm-${LLVM_VERSION} ]]; then
|
||||||
|
rm -fr llvm-${LLVM_VERSION}
|
||||||
|
fi
|
||||||
|
if [[ ! -d llvm-${LLVM_VERSION} ]]; then
|
||||||
|
mkdir llvm-${LLVM_VERSION}
|
||||||
|
LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-14.04.tar.xz"
|
||||||
|
wget -O - ${LLVM_URL} | tar -Jxvf - --strip 1 -C llvm-${LLVM_VERSION}
|
||||||
|
fi
|
||||||
|
llvm-${LLVM_VERSION}/bin/llvm-config --version;
|
||||||
|
export LLVM_CONFIG="llvm-${LLVM_VERSION}/bin/llvm-config";
|
||||||
|
fi
|
||||||
|
|
||||||
|
# There are cases where the directory exists, but the exe is not available.
|
||||||
|
# Use this workaround for now.
|
||||||
|
if [[ ! -x cmake/bin/cmake && -d cmake ]]; then
|
||||||
|
rm -fr cmake
|
||||||
|
fi
|
||||||
|
if [[ ! -d cmake && ${BUILD_SYSTEM:-} == cmake ]]; then
|
||||||
|
CMAKE_URL="http://www.cmake.org/files/v3.5/cmake-3.5.2-Linux-x86_64.tar.gz"
|
||||||
|
mkdir cmake && wget --no-check-certificate -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
|
||||||
|
fi
|
||||||
|
|
||||||
# NOTE, changed from PWD -> HOME
|
# NOTE, changed from PWD -> HOME
|
||||||
export PATH=$HOME/bin:$PATH
|
export PATH=$HOME/bin:$PATH
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
# Part of Beast
|
# Part of Beast
|
||||||
|
|
||||||
GroupSources(extras/beast beast)
|
GroupSources(extras/beast extras)
|
||||||
GroupSources(include/beast beast)
|
GroupSources(include/beast beast)
|
||||||
GroupSources(test "/")
|
GroupSources(test "/")
|
||||||
|
|
||||||
add_executable (lib-tests
|
add_executable (lib-tests
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
../extras/beast/unit_test/main.cpp
|
../extras/beast/unit_test/main.cpp
|
||||||
core.cpp
|
core.cpp
|
||||||
http.cpp
|
http.cpp
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ unit-test core-tests :
|
|||||||
core/streambuf.cpp
|
core/streambuf.cpp
|
||||||
core/to_string.cpp
|
core/to_string.cpp
|
||||||
core/write_dynabuf.cpp
|
core/write_dynabuf.cpp
|
||||||
core/detail/base64.cpp
|
core/base64.cpp
|
||||||
core/detail/empty_base_optimization.cpp
|
core/empty_base_optimization.cpp
|
||||||
core/detail/get_lowest_layer.cpp
|
core/get_lowest_layer.cpp
|
||||||
core/detail/sha1.cpp
|
core/sha1.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
unit-test http-tests :
|
unit-test http-tests :
|
||||||
@@ -56,11 +56,10 @@ unit-test http-tests :
|
|||||||
http/reason.cpp
|
http/reason.cpp
|
||||||
http/resume_context.cpp
|
http/resume_context.cpp
|
||||||
http/rfc7230.cpp
|
http/rfc7230.cpp
|
||||||
http/status.cpp
|
|
||||||
http/streambuf_body.cpp
|
http/streambuf_body.cpp
|
||||||
http/string_body.cpp
|
http/string_body.cpp
|
||||||
http/write.cpp
|
http/write.cpp
|
||||||
http/detail/chunk_encode.cpp
|
http/chunk_encode.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
unit-test bench-tests :
|
unit-test bench-tests :
|
||||||
@@ -76,10 +75,10 @@ unit-test websocket-tests :
|
|||||||
websocket/rfc6455.cpp
|
websocket/rfc6455.cpp
|
||||||
websocket/stream.cpp
|
websocket/stream.cpp
|
||||||
websocket/teardown.cpp
|
websocket/teardown.cpp
|
||||||
websocket/detail/frame.cpp
|
websocket/frame.cpp
|
||||||
websocket/detail/mask.cpp
|
websocket/mask.cpp
|
||||||
websocket/detail/stream_base.cpp
|
websocket/stream_base.cpp
|
||||||
websocket/detail/utf8_checker.cpp
|
websocket/utf8_checker.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
exe websocket-echo :
|
exe websocket-echo :
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
# Part of Beast
|
# Part of Beast
|
||||||
|
|
||||||
GroupSources(extras/beast beast)
|
GroupSources(extras/beast extras)
|
||||||
GroupSources(include/beast beast)
|
GroupSources(include/beast beast)
|
||||||
GroupSources(test/core "/")
|
GroupSources(test/core "/")
|
||||||
|
|
||||||
add_executable (core-tests
|
add_executable (core-tests
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
../../extras/beast/unit_test/main.cpp
|
../../extras/beast/unit_test/main.cpp
|
||||||
buffer_test.hpp
|
buffer_test.hpp
|
||||||
async_completion.cpp
|
async_completion.cpp
|
||||||
@@ -27,12 +28,12 @@ add_executable (core-tests
|
|||||||
streambuf.cpp
|
streambuf.cpp
|
||||||
to_string.cpp
|
to_string.cpp
|
||||||
write_dynabuf.cpp
|
write_dynabuf.cpp
|
||||||
detail/base64.cpp
|
base64.cpp
|
||||||
detail/empty_base_optimization.cpp
|
empty_base_optimization.cpp
|
||||||
detail/get_lowest_layer.cpp
|
get_lowest_layer.cpp
|
||||||
detail/sha1.cpp
|
sha1.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(core-tests ${Boost_LIBRARIES})
|
target_link_libraries(core-tests ${Boost_LIBRARIES} Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ public:
|
|||||||
check (std::string const& in, std::string const& out)
|
check (std::string const& in, std::string const& out)
|
||||||
{
|
{
|
||||||
auto const encoded = base64_encode (in);
|
auto const encoded = base64_encode (in);
|
||||||
expect (encoded == out);
|
BEAST_EXPECT(encoded == out);
|
||||||
expect (base64_decode (encoded) == in);
|
BEAST_EXPECT(base64_decode (encoded) == in);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -153,10 +153,10 @@ public:
|
|||||||
void
|
void
|
||||||
expect_size(std::size_t n, ConstBufferSequence const& buffers)
|
expect_size(std::size_t n, ConstBufferSequence const& buffers)
|
||||||
{
|
{
|
||||||
expect(test::size_pre(buffers) == n);
|
BEAST_EXPECT(test::size_pre(buffers) == n);
|
||||||
expect(test::size_post(buffers) == n);
|
BEAST_EXPECT(test::size_post(buffers) == n);
|
||||||
expect(test::size_rev_pre(buffers) == n);
|
BEAST_EXPECT(test::size_rev_pre(buffers) == n);
|
||||||
expect(test::size_rev_post(buffers) == n);
|
BEAST_EXPECT(test::size_rev_post(buffers) == n);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U, class V>
|
template<class U, class V>
|
||||||
@@ -173,7 +173,7 @@ public:
|
|||||||
using boost::asio::buffer_cast;
|
using boost::asio::buffer_cast;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
std::string const s = "Hello, world";
|
std::string const s = "Hello, world";
|
||||||
expect(s.size() == 12);
|
BEAST_EXPECT(s.size() == 12);
|
||||||
for(std::size_t i = 1; i < 12; ++i) {
|
for(std::size_t i = 1; i < 12; ++i) {
|
||||||
for(std::size_t x = 1; x < 4; ++x) {
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
for(std::size_t y = 1; y < 4; ++y) {
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
@@ -183,28 +183,28 @@ public:
|
|||||||
sb.commit(buffer_copy(sb.prepare(x), buffer(s.data(), x)));
|
sb.commit(buffer_copy(sb.prepare(x), buffer(s.data(), x)));
|
||||||
sb.commit(buffer_copy(sb.prepare(y), buffer(s.data()+x, y)));
|
sb.commit(buffer_copy(sb.prepare(y), buffer(s.data()+x, y)));
|
||||||
sb.commit(buffer_copy(sb.prepare(z), buffer(s.data()+x+y, z)));
|
sb.commit(buffer_copy(sb.prepare(z), buffer(s.data()+x+y, z)));
|
||||||
expect(to_string(sb.data()) == s);
|
BEAST_EXPECT(to_string(sb.data()) == s);
|
||||||
{
|
{
|
||||||
streambuf sb2(sb);
|
streambuf sb2(sb);
|
||||||
expect(eq(sb, sb2));
|
BEAST_EXPECT(eq(sb, sb2));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
streambuf sb2;
|
streambuf sb2;
|
||||||
sb2 = sb;
|
sb2 = sb;
|
||||||
expect(eq(sb, sb2));
|
BEAST_EXPECT(eq(sb, sb2));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
streambuf sb2(std::move(sb));
|
streambuf sb2(std::move(sb));
|
||||||
expect(to_string(sb2.data()) == s);
|
BEAST_EXPECT(to_string(sb2.data()) == s);
|
||||||
expect_size(0, sb.data());
|
expect_size(0, sb.data());
|
||||||
sb = std::move(sb2);
|
sb = std::move(sb2);
|
||||||
expect(to_string(sb.data()) == s);
|
BEAST_EXPECT(to_string(sb.data()) == s);
|
||||||
expect_size(0, sb2.data());
|
expect_size(0, sb2.data());
|
||||||
}
|
}
|
||||||
self_assign(sb, sb);
|
self_assign(sb, sb);
|
||||||
expect(to_string(sb.data()) == s);
|
BEAST_EXPECT(to_string(sb.data()) == s);
|
||||||
self_assign(sb, std::move(sb));
|
self_assign(sb, std::move(sb));
|
||||||
expect(to_string(sb.data()) == s);
|
BEAST_EXPECT(to_string(sb.data()) == s);
|
||||||
}
|
}
|
||||||
}}}
|
}}}
|
||||||
try
|
try
|
||||||
@@ -226,16 +226,16 @@ public:
|
|||||||
test_allocator<char, false, false, false, false>;
|
test_allocator<char, false, false, false, false>;
|
||||||
using sb_type = basic_streambuf<alloc_type>;
|
using sb_type = basic_streambuf<alloc_type>;
|
||||||
sb_type sb;
|
sb_type sb;
|
||||||
expect(sb.get_allocator().id() == 1);
|
BEAST_EXPECT(sb.get_allocator().id() == 1);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
using alloc_type =
|
using alloc_type =
|
||||||
test_allocator<char, false, false, false, false>;
|
test_allocator<char, false, false, false, false>;
|
||||||
using sb_type = basic_streambuf<alloc_type>;
|
using sb_type = basic_streambuf<alloc_type>;
|
||||||
sb_type sb;
|
sb_type sb;
|
||||||
expect(sb.get_allocator().id() == 2);
|
BEAST_EXPECT(sb.get_allocator().id() == 2);
|
||||||
sb_type sb2(sb);
|
sb_type sb2(sb);
|
||||||
expect(sb2.get_allocator().id() == 2);
|
BEAST_EXPECT(sb2.get_allocator().id() == 2);
|
||||||
sb_type sb3(sb, alloc_type{});
|
sb_type sb3(sb, alloc_type{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,16 +246,16 @@ public:
|
|||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
{
|
{
|
||||||
streambuf sb(2);
|
streambuf sb(2);
|
||||||
expect(buffer_size(sb.prepare(5)) == 5);
|
BEAST_EXPECT(buffer_size(sb.prepare(5)) == 5);
|
||||||
expect(buffer_size(sb.prepare(8)) == 8);
|
BEAST_EXPECT(buffer_size(sb.prepare(8)) == 8);
|
||||||
expect(buffer_size(sb.prepare(7)) == 7);
|
BEAST_EXPECT(buffer_size(sb.prepare(7)) == 7);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
streambuf sb(2);
|
streambuf sb(2);
|
||||||
sb.prepare(2);
|
sb.prepare(2);
|
||||||
expect(test::buffer_count(sb.prepare(5)) == 2);
|
BEAST_EXPECT(test::buffer_count(sb.prepare(5)) == 2);
|
||||||
expect(test::buffer_count(sb.prepare(8)) == 3);
|
BEAST_EXPECT(test::buffer_count(sb.prepare(8)) == 3);
|
||||||
expect(test::buffer_count(sb.prepare(4)) == 2);
|
BEAST_EXPECT(test::buffer_count(sb.prepare(4)) == 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +286,7 @@ public:
|
|||||||
using boost::asio::buffer_cast;
|
using boost::asio::buffer_cast;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
std::string const s = "Hello, world";
|
std::string const s = "Hello, world";
|
||||||
expect(s.size() == 12);
|
BEAST_EXPECT(s.size() == 12);
|
||||||
for(std::size_t i = 1; i < 12; ++i) {
|
for(std::size_t i = 1; i < 12; ++i) {
|
||||||
for(std::size_t x = 1; x < 4; ++x) {
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
for(std::size_t y = 1; y < 4; ++y) {
|
for(std::size_t y = 1; y < 4; ++y) {
|
||||||
@@ -298,78 +298,78 @@ public:
|
|||||||
streambuf sb(i);
|
streambuf sb(i);
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(z);
|
auto d = sb.prepare(z);
|
||||||
expect(buffer_size(d) == z);
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(0);
|
auto d = sb.prepare(0);
|
||||||
expect(buffer_size(d) == 0);
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(y);
|
auto d = sb.prepare(y);
|
||||||
expect(buffer_size(d) == y);
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(x);
|
auto d = sb.prepare(x);
|
||||||
expect(buffer_size(d) == x);
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
sb.commit(buffer_copy(d, buffer(s.data(), x)));
|
sb.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||||
}
|
}
|
||||||
expect(sb.size() == x);
|
BEAST_EXPECT(sb.size() == x);
|
||||||
expect(buffer_size(sb.data()) == sb.size());
|
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(x);
|
auto d = sb.prepare(x);
|
||||||
expect(buffer_size(d) == x);
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(0);
|
auto d = sb.prepare(0);
|
||||||
expect(buffer_size(d) == 0);
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(z);
|
auto d = sb.prepare(z);
|
||||||
expect(buffer_size(d) == z);
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(y);
|
auto d = sb.prepare(y);
|
||||||
expect(buffer_size(d) == y);
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
sb.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
sb.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||||
}
|
}
|
||||||
sb.commit(1);
|
sb.commit(1);
|
||||||
expect(sb.size() == x + y);
|
BEAST_EXPECT(sb.size() == x + y);
|
||||||
expect(buffer_size(sb.data()) == sb.size());
|
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(x);
|
auto d = sb.prepare(x);
|
||||||
expect(buffer_size(d) == x);
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(y);
|
auto d = sb.prepare(y);
|
||||||
expect(buffer_size(d) == y);
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(0);
|
auto d = sb.prepare(0);
|
||||||
expect(buffer_size(d) == 0);
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(z);
|
auto d = sb.prepare(z);
|
||||||
expect(buffer_size(d) == z);
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
sb.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
sb.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||||
}
|
}
|
||||||
sb.commit(2);
|
sb.commit(2);
|
||||||
expect(sb.size() == x + y + z);
|
BEAST_EXPECT(sb.size() == x + y + z);
|
||||||
expect(buffer_size(sb.data()) == sb.size());
|
BEAST_EXPECT(buffer_size(sb.data()) == sb.size());
|
||||||
expect(to_string(sb.data()) == s);
|
BEAST_EXPECT(to_string(sb.data()) == s);
|
||||||
sb.consume(t);
|
sb.consume(t);
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(0);
|
auto d = sb.prepare(0);
|
||||||
expect(buffer_size(d) == 0);
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
}
|
}
|
||||||
expect(to_string(sb.data()) == s.substr(t, std::string::npos));
|
BEAST_EXPECT(to_string(sb.data()) == s.substr(t, std::string::npos));
|
||||||
sb.consume(u);
|
sb.consume(u);
|
||||||
expect(to_string(sb.data()) == s.substr(t + u, std::string::npos));
|
BEAST_EXPECT(to_string(sb.data()) == s.substr(t + u, std::string::npos));
|
||||||
sb.consume(v);
|
sb.consume(v);
|
||||||
expect(to_string(sb.data()) == "");
|
BEAST_EXPECT(to_string(sb.data()) == "");
|
||||||
sb.consume(1);
|
sb.consume(1);
|
||||||
{
|
{
|
||||||
auto d = sb.prepare(0);
|
auto d = sb.prepare(0);
|
||||||
expect(buffer_size(d) == 0);
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}}}}
|
}}}}}
|
||||||
@@ -387,14 +387,14 @@ public:
|
|||||||
sb.prepare(1);
|
sb.prepare(1);
|
||||||
expect_size(3, sb.prepare(3));
|
expect_size(3, sb.prepare(3));
|
||||||
sb.commit(2);
|
sb.commit(2);
|
||||||
expect(test::buffer_count(sb.data()) == 4);
|
BEAST_EXPECT(test::buffer_count(sb.data()) == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testOutputStream()
|
void testOutputStream()
|
||||||
{
|
{
|
||||||
streambuf sb;
|
streambuf sb;
|
||||||
sb << "x";
|
sb << "x";
|
||||||
expect(to_string(sb.data()) == "x");
|
BEAST_EXPECT(to_string(sb.data()) == "x");
|
||||||
}
|
}
|
||||||
|
|
||||||
void testReadSizeHelper()
|
void testReadSizeHelper()
|
||||||
@@ -402,44 +402,44 @@ public:
|
|||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
{
|
{
|
||||||
streambuf sb(10);
|
streambuf sb(10);
|
||||||
expect(read_size_helper(sb, 0) == 0);
|
BEAST_EXPECT(read_size_helper(sb, 0) == 0);
|
||||||
expect(read_size_helper(sb, 1) == 1);
|
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
||||||
expect(read_size_helper(sb, 10) == 10);
|
BEAST_EXPECT(read_size_helper(sb, 10) == 10);
|
||||||
expect(read_size_helper(sb, 20) == 20);
|
BEAST_EXPECT(read_size_helper(sb, 20) == 20);
|
||||||
expect(read_size_helper(sb, 1000) == 512);
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 512);
|
||||||
sb.prepare(3);
|
sb.prepare(3);
|
||||||
sb.commit(3);
|
sb.commit(3);
|
||||||
expect(read_size_helper(sb, 10) == 7);
|
BEAST_EXPECT(read_size_helper(sb, 10) == 7);
|
||||||
expect(read_size_helper(sb, 1000) == 7);
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 7);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
streambuf sb(1000);
|
streambuf sb(1000);
|
||||||
expect(read_size_helper(sb, 0) == 0);
|
BEAST_EXPECT(read_size_helper(sb, 0) == 0);
|
||||||
expect(read_size_helper(sb, 1) == 1);
|
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
||||||
expect(read_size_helper(sb, 1000) == 1000);
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 1000);
|
||||||
expect(read_size_helper(sb, 2000) == 1000);
|
BEAST_EXPECT(read_size_helper(sb, 2000) == 1000);
|
||||||
sb.prepare(3);
|
sb.prepare(3);
|
||||||
expect(read_size_helper(sb, 0) == 0);
|
BEAST_EXPECT(read_size_helper(sb, 0) == 0);
|
||||||
expect(read_size_helper(sb, 1) == 1);
|
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
||||||
expect(read_size_helper(sb, 1000) == 1000);
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 1000);
|
||||||
expect(read_size_helper(sb, 2000) == 1000);
|
BEAST_EXPECT(read_size_helper(sb, 2000) == 1000);
|
||||||
sb.commit(3);
|
sb.commit(3);
|
||||||
expect(read_size_helper(sb, 0) == 0);
|
BEAST_EXPECT(read_size_helper(sb, 0) == 0);
|
||||||
expect(read_size_helper(sb, 1) == 1);
|
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
||||||
expect(read_size_helper(sb, 1000) == 997);
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 997);
|
||||||
expect(read_size_helper(sb, 2000) == 997);
|
BEAST_EXPECT(read_size_helper(sb, 2000) == 997);
|
||||||
sb.consume(2);
|
sb.consume(2);
|
||||||
expect(read_size_helper(sb, 0) == 0);
|
BEAST_EXPECT(read_size_helper(sb, 0) == 0);
|
||||||
expect(read_size_helper(sb, 1) == 1);
|
BEAST_EXPECT(read_size_helper(sb, 1) == 1);
|
||||||
expect(read_size_helper(sb, 1000) == 997);
|
BEAST_EXPECT(read_size_helper(sb, 1000) == 997);
|
||||||
expect(read_size_helper(sb, 2000) == 997);
|
BEAST_EXPECT(read_size_helper(sb, 2000) == 997);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
streambuf sb(2);
|
streambuf sb(2);
|
||||||
expect(test::buffer_count(sb.prepare(2)) == 1);
|
BEAST_EXPECT(test::buffer_count(sb.prepare(2)) == 1);
|
||||||
expect(test::buffer_count(sb.prepare(3)) == 2);
|
BEAST_EXPECT(test::buffer_count(sb.prepare(3)) == 2);
|
||||||
expect(buffer_size(sb.prepare(5)) == 5);
|
BEAST_EXPECT(buffer_size(sb.prepare(5)) == 5);
|
||||||
expect(read_size_helper(sb, 10) == 6);
|
BEAST_EXPECT(read_size_helper(sb, 10) == 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,32 +47,32 @@ public:
|
|||||||
std::list<const_buffer> b6;
|
std::list<const_buffer> b6;
|
||||||
auto bs = buffer_cat(
|
auto bs = buffer_cat(
|
||||||
b1, b2, b3, b4, b5, b6);
|
b1, b2, b3, b4, b5, b6);
|
||||||
expect(buffer_size(bs) == 10);
|
BEAST_EXPECT(buffer_size(bs) == 10);
|
||||||
std::vector<const_buffer> v;
|
std::vector<const_buffer> v;
|
||||||
for(auto iter = make_reverse_iterator(bs.end());
|
for(auto iter = make_reverse_iterator(bs.end());
|
||||||
iter != make_reverse_iterator(bs.begin()); ++iter)
|
iter != make_reverse_iterator(bs.begin()); ++iter)
|
||||||
v.emplace_back(*iter);
|
v.emplace_back(*iter);
|
||||||
expect(buffer_size(bs) == 10);
|
BEAST_EXPECT(buffer_size(bs) == 10);
|
||||||
decltype(bs) bs2(bs);
|
decltype(bs) bs2(bs);
|
||||||
auto bs3(std::move(bs));
|
auto bs3(std::move(bs));
|
||||||
bs = bs2;
|
bs = bs2;
|
||||||
bs3 = std::move(bs2);
|
bs3 = std::move(bs2);
|
||||||
{
|
{
|
||||||
boost::asio::streambuf sb1, sb2;
|
boost::asio::streambuf sb1, sb2;
|
||||||
expect(buffer_size(buffer_cat(
|
BEAST_EXPECT(buffer_size(buffer_cat(
|
||||||
sb1.prepare(5), sb2.prepare(7))) == 12);
|
sb1.prepare(5), sb2.prepare(7))) == 12);
|
||||||
sb1.commit(5);
|
sb1.commit(5);
|
||||||
sb2.commit(7);
|
sb2.commit(7);
|
||||||
expect(buffer_size(buffer_cat(
|
BEAST_EXPECT(buffer_size(buffer_cat(
|
||||||
sb1.data(), sb2.data())) == 12);
|
sb1.data(), sb2.data())) == 12);
|
||||||
}
|
}
|
||||||
for(auto it = bs.begin(); it != bs.end(); ++it)
|
for(auto it = bs.begin(); it != bs.end(); ++it)
|
||||||
{
|
{
|
||||||
decltype(bs)::const_iterator copy;
|
decltype(bs)::const_iterator copy;
|
||||||
copy = it;
|
copy = it;
|
||||||
expect(copy == it);
|
BEAST_EXPECT(copy == it);
|
||||||
copy = copy;
|
copy = copy;
|
||||||
expect(copy == it);
|
BEAST_EXPECT(copy == it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,11 +132,11 @@ public:
|
|||||||
pass();
|
pass();
|
||||||
}
|
}
|
||||||
auto bs2 = bs;
|
auto bs2 = bs;
|
||||||
expect(bs.begin() != bs2.begin());
|
BEAST_EXPECT(bs.begin() != bs2.begin());
|
||||||
expect(bs.end() != bs2.end());
|
BEAST_EXPECT(bs.end() != bs2.end());
|
||||||
decltype(bs)::const_iterator it;
|
decltype(bs)::const_iterator it;
|
||||||
decltype(bs2)::const_iterator it2;
|
decltype(bs2)::const_iterator it2;
|
||||||
expect(it == it2);
|
BEAST_EXPECT(it == it2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
using boost::asio::mutable_buffer;
|
using boost::asio::mutable_buffer;
|
||||||
char buf[12];
|
char buf[12];
|
||||||
std::string const s = "Hello, world";
|
std::string const s = "Hello, world";
|
||||||
expect(s.size() == sizeof(buf));
|
BEAST_EXPECT(s.size() == sizeof(buf));
|
||||||
for(std::size_t i = 1; i < 4; ++i) {
|
for(std::size_t i = 1; i < 4; ++i) {
|
||||||
for(std::size_t j = 1; j < 4; ++j) {
|
for(std::size_t j = 1; j < 4; ++j) {
|
||||||
for(std::size_t x = 1; x < 4; ++x) {
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
@@ -60,83 +60,83 @@ public:
|
|||||||
mutable_buffer{&buf[i], j},
|
mutable_buffer{&buf[i], j},
|
||||||
mutable_buffer{&buf[i+j], k}}};
|
mutable_buffer{&buf[i+j], k}}};
|
||||||
buffers_adapter<decltype(bs)> ba(std::move(bs));
|
buffers_adapter<decltype(bs)> ba(std::move(bs));
|
||||||
expect(ba.max_size() == sizeof(buf));
|
BEAST_EXPECT(ba.max_size() == sizeof(buf));
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(z);
|
auto d = ba.prepare(z);
|
||||||
expect(buffer_size(d) == z);
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(0);
|
auto d = ba.prepare(0);
|
||||||
expect(buffer_size(d) == 0);
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(y);
|
auto d = ba.prepare(y);
|
||||||
expect(buffer_size(d) == y);
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(x);
|
auto d = ba.prepare(x);
|
||||||
expect(buffer_size(d) == x);
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
ba.commit(buffer_copy(d, buffer(s.data(), x)));
|
ba.commit(buffer_copy(d, buffer(s.data(), x)));
|
||||||
}
|
}
|
||||||
expect(ba.size() == x);
|
BEAST_EXPECT(ba.size() == x);
|
||||||
expect(ba.max_size() == sizeof(buf) - x);
|
BEAST_EXPECT(ba.max_size() == sizeof(buf) - x);
|
||||||
expect(buffer_size(ba.data()) == ba.size());
|
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(x);
|
auto d = ba.prepare(x);
|
||||||
expect(buffer_size(d) == x);
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(0);
|
auto d = ba.prepare(0);
|
||||||
expect(buffer_size(d) == 0);
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(z);
|
auto d = ba.prepare(z);
|
||||||
expect(buffer_size(d) == z);
|
BEAST_EXPECT(buffer_size(d) == z);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(y);
|
auto d = ba.prepare(y);
|
||||||
expect(buffer_size(d) == y);
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
ba.commit(buffer_copy(d, buffer(s.data()+x, y)));
|
||||||
}
|
}
|
||||||
ba.commit(1);
|
ba.commit(1);
|
||||||
expect(ba.size() == x + y);
|
BEAST_EXPECT(ba.size() == x + y);
|
||||||
expect(ba.max_size() == sizeof(buf) - (x + y));
|
BEAST_EXPECT(ba.max_size() == sizeof(buf) - (x + y));
|
||||||
expect(buffer_size(ba.data()) == ba.size());
|
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(x);
|
auto d = ba.prepare(x);
|
||||||
expect(buffer_size(d) == x);
|
BEAST_EXPECT(buffer_size(d) == x);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(y);
|
auto d = ba.prepare(y);
|
||||||
expect(buffer_size(d) == y);
|
BEAST_EXPECT(buffer_size(d) == y);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(0);
|
auto d = ba.prepare(0);
|
||||||
expect(buffer_size(d) == 0);
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(z); expect(buffer_size(d) == z);
|
auto d = ba.prepare(z); BEAST_EXPECT(buffer_size(d) == z);
|
||||||
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
ba.commit(buffer_copy(d, buffer(s.data()+x+y, z)));
|
||||||
}
|
}
|
||||||
ba.commit(2);
|
ba.commit(2);
|
||||||
expect(ba.size() == x + y + z);
|
BEAST_EXPECT(ba.size() == x + y + z);
|
||||||
expect(ba.max_size() == 0);
|
BEAST_EXPECT(ba.max_size() == 0);
|
||||||
expect(buffer_size(ba.data()) == ba.size());
|
BEAST_EXPECT(buffer_size(ba.data()) == ba.size());
|
||||||
expect(to_string(ba.data()) == s);
|
BEAST_EXPECT(to_string(ba.data()) == s);
|
||||||
ba.consume(t);
|
ba.consume(t);
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(0);
|
auto d = ba.prepare(0);
|
||||||
expect(buffer_size(d) == 0);
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
}
|
}
|
||||||
expect(to_string(ba.data()) == s.substr(t, std::string::npos));
|
BEAST_EXPECT(to_string(ba.data()) == s.substr(t, std::string::npos));
|
||||||
ba.consume(u);
|
ba.consume(u);
|
||||||
expect(to_string(ba.data()) == s.substr(t + u, std::string::npos));
|
BEAST_EXPECT(to_string(ba.data()) == s.substr(t + u, std::string::npos));
|
||||||
ba.consume(v);
|
ba.consume(v);
|
||||||
expect(to_string(ba.data()) == "");
|
BEAST_EXPECT(to_string(ba.data()) == "");
|
||||||
ba.consume(1);
|
ba.consume(1);
|
||||||
{
|
{
|
||||||
auto d = ba.prepare(0);
|
auto d = ba.prepare(0);
|
||||||
expect(buffer_size(d) == 0);
|
BEAST_EXPECT(buffer_size(d) == 0);
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -158,9 +158,9 @@ public:
|
|||||||
sb_type sb;
|
sb_type sb;
|
||||||
buffers_adapter<
|
buffers_adapter<
|
||||||
sb_type::mutable_buffers_type> ba(sb.prepare(3));
|
sb_type::mutable_buffers_type> ba(sb.prepare(3));
|
||||||
expect(buffer_size(ba.prepare(3)) == 3);
|
BEAST_EXPECT(buffer_size(ba.prepare(3)) == 3);
|
||||||
ba.commit(2);
|
ba.commit(2);
|
||||||
expect(buffer_size(ba.data()) == 2);
|
BEAST_EXPECT(buffer_size(ba.data()) == 2);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
using sb_type = beast::streambuf;
|
using sb_type = beast::streambuf;
|
||||||
@@ -168,13 +168,13 @@ public:
|
|||||||
sb.prepare(3);
|
sb.prepare(3);
|
||||||
buffers_adapter<
|
buffers_adapter<
|
||||||
sb_type::mutable_buffers_type> ba(sb.prepare(8));
|
sb_type::mutable_buffers_type> ba(sb.prepare(8));
|
||||||
expect(buffer_size(ba.prepare(8)) == 8);
|
BEAST_EXPECT(buffer_size(ba.prepare(8)) == 8);
|
||||||
ba.commit(2);
|
ba.commit(2);
|
||||||
expect(buffer_size(ba.data()) == 2);
|
BEAST_EXPECT(buffer_size(ba.data()) == 2);
|
||||||
ba.consume(1);
|
ba.consume(1);
|
||||||
ba.commit(6);
|
ba.commit(6);
|
||||||
ba.consume(2);
|
ba.consume(2);
|
||||||
expect(buffer_size(ba.data()) == 5);
|
BEAST_EXPECT(buffer_size(ba.data()) == 5);
|
||||||
ba.consume(5);
|
ba.consume(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ public:
|
|||||||
void
|
void
|
||||||
expect_size(std::size_t n, ConstBufferSequence const& buffers)
|
expect_size(std::size_t n, ConstBufferSequence const& buffers)
|
||||||
{
|
{
|
||||||
expect(test::size_pre(buffers) == n);
|
BEAST_EXPECT(test::size_pre(buffers) == n);
|
||||||
expect(test::size_post(buffers) == n);
|
BEAST_EXPECT(test::size_post(buffers) == n);
|
||||||
expect(test::size_rev_pre(buffers) == n);
|
BEAST_EXPECT(test::size_rev_pre(buffers) == n);
|
||||||
expect(test::size_rev_post(buffers) == n);
|
BEAST_EXPECT(test::size_rev_post(buffers) == n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testMatrix()
|
void testMatrix()
|
||||||
@@ -43,9 +43,9 @@ public:
|
|||||||
using boost::asio::const_buffer;
|
using boost::asio::const_buffer;
|
||||||
char buf[12];
|
char buf[12];
|
||||||
std::string const s = "Hello, world";
|
std::string const s = "Hello, world";
|
||||||
expect(s.size() == sizeof(buf));
|
BEAST_EXPECT(s.size() == sizeof(buf));
|
||||||
buffer_copy(buffer(buf), buffer(s));
|
buffer_copy(buffer(buf), buffer(s));
|
||||||
expect(to_string(buffer(buf)) == s);
|
BEAST_EXPECT(to_string(buffer(buf)) == s);
|
||||||
for(std::size_t i = 1; i < 4; ++i) {
|
for(std::size_t i = 1; i < 4; ++i) {
|
||||||
for(std::size_t j = 1; j < 4; ++j) {
|
for(std::size_t j = 1; j < 4; ++j) {
|
||||||
for(std::size_t x = 1; x < 4; ++x) {
|
for(std::size_t x = 1; x < 4; ++x) {
|
||||||
@@ -58,24 +58,24 @@ public:
|
|||||||
const_buffer{&buf[i], j},
|
const_buffer{&buf[i], j},
|
||||||
const_buffer{&buf[i+j], k}}};
|
const_buffer{&buf[i+j], k}}};
|
||||||
consuming_buffers<decltype(bs)> cb(bs);
|
consuming_buffers<decltype(bs)> cb(bs);
|
||||||
expect(to_string(cb) == s);
|
BEAST_EXPECT(to_string(cb) == s);
|
||||||
expect_size(s.size(), cb);
|
expect_size(s.size(), cb);
|
||||||
cb.consume(0);
|
cb.consume(0);
|
||||||
expect(eq(cb, consumed_buffers(bs, 0)));
|
BEAST_EXPECT(eq(cb, consumed_buffers(bs, 0)));
|
||||||
expect(to_string(cb) == s);
|
BEAST_EXPECT(to_string(cb) == s);
|
||||||
expect_size(s.size(), cb);
|
expect_size(s.size(), cb);
|
||||||
cb.consume(x);
|
cb.consume(x);
|
||||||
expect(to_string(cb) == s.substr(x));
|
BEAST_EXPECT(to_string(cb) == s.substr(x));
|
||||||
expect(eq(cb, consumed_buffers(bs, x)));
|
BEAST_EXPECT(eq(cb, consumed_buffers(bs, x)));
|
||||||
cb.consume(y);
|
cb.consume(y);
|
||||||
expect(to_string(cb) == s.substr(x+y));
|
BEAST_EXPECT(to_string(cb) == s.substr(x+y));
|
||||||
expect(eq(cb, consumed_buffers(bs, x+y)));
|
BEAST_EXPECT(eq(cb, consumed_buffers(bs, x+y)));
|
||||||
cb.consume(z);
|
cb.consume(z);
|
||||||
expect(to_string(cb) == "");
|
BEAST_EXPECT(to_string(cb) == "");
|
||||||
expect(eq(cb, consumed_buffers(bs, x+y+z)));
|
BEAST_EXPECT(eq(cb, consumed_buffers(bs, x+y+z)));
|
||||||
cb.consume(1);
|
cb.consume(1);
|
||||||
expect(to_string(cb) == "");
|
BEAST_EXPECT(to_string(cb) == "");
|
||||||
expect(eq(cb, consumed_buffers(bs, x+y+z)));
|
BEAST_EXPECT(eq(cb, consumed_buffers(bs, x+y+z)));
|
||||||
}
|
}
|
||||||
}}}}
|
}}}}
|
||||||
}
|
}
|
||||||
@@ -87,10 +87,10 @@ public:
|
|||||||
using boost::asio::null_buffers;
|
using boost::asio::null_buffers;
|
||||||
consuming_buffers<null_buffers> cb(
|
consuming_buffers<null_buffers> cb(
|
||||||
null_buffers{});
|
null_buffers{});
|
||||||
expect(buffer_size(cb) == 0);
|
BEAST_EXPECT(buffer_size(cb) == 0);
|
||||||
consuming_buffers<null_buffers> cb2(
|
consuming_buffers<null_buffers> cb2(
|
||||||
null_buffers{});
|
null_buffers{});
|
||||||
expect(buffer_copy(cb2, cb) == 0);
|
BEAST_EXPECT(buffer_copy(cb2, cb) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testIterator()
|
void testIterator()
|
||||||
@@ -101,7 +101,7 @@ public:
|
|||||||
std::size_t n = 0;
|
std::size_t n = 0;
|
||||||
for(auto it = cb.end(); it != cb.begin(); --it)
|
for(auto it = cb.end(); it != cb.begin(); --it)
|
||||||
++n;
|
++n;
|
||||||
expect(n == 3);
|
BEAST_EXPECT(n == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ public:
|
|||||||
dynabuf_readstream<socket_type, streambuf> srs(ios);
|
dynabuf_readstream<socket_type, streambuf> srs(ios);
|
||||||
dynabuf_readstream<socket_type, streambuf> srs2(std::move(srs));
|
dynabuf_readstream<socket_type, streambuf> srs2(std::move(srs));
|
||||||
srs = std::move(srs2);
|
srs = std::move(srs2);
|
||||||
expect(&srs.get_io_service() == &ios);
|
BEAST_EXPECT(&srs.get_io_service() == &ios);
|
||||||
expect(&srs.get_io_service() == &srs2.get_io_service());
|
BEAST_EXPECT(&srs.get_io_service() == &srs2.get_io_service());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
socket_type sock(ios);
|
socket_type sock(ios);
|
||||||
@@ -63,11 +63,11 @@ public:
|
|||||||
boost::asio::read(srs, buffer(&s[0], s.size()), ec);
|
boost::asio::read(srs, buffer(&s[0], s.size()), ec);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
{
|
{
|
||||||
expect(s == "Hello, world!");
|
BEAST_EXPECT(s == "Hello, world!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect(n < limit);
|
BEAST_EXPECT(n < limit);
|
||||||
|
|
||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
@@ -82,11 +82,11 @@ public:
|
|||||||
boost::asio::read(srs, buffer(&s[0], s.size()), ec);
|
boost::asio::read(srs, buffer(&s[0], s.size()), ec);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
{
|
{
|
||||||
expect(s == "Hello, world!");
|
BEAST_EXPECT(s == "Hello, world!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect(n < limit);
|
BEAST_EXPECT(n < limit);
|
||||||
|
|
||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
@@ -101,11 +101,11 @@ public:
|
|||||||
srs, buffer(&s[0], s.size()), do_yield[ec]);
|
srs, buffer(&s[0], s.size()), do_yield[ec]);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
{
|
{
|
||||||
expect(s == "Hello, world!");
|
BEAST_EXPECT(s == "Hello, world!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect(n < limit);
|
BEAST_EXPECT(n < limit);
|
||||||
|
|
||||||
for(n = 0; n < limit; ++n)
|
for(n = 0; n < limit; ++n)
|
||||||
{
|
{
|
||||||
@@ -121,11 +121,11 @@ public:
|
|||||||
srs, buffer(&s[0], s.size()), do_yield[ec]);
|
srs, buffer(&s[0], s.size()), do_yield[ec]);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
{
|
{
|
||||||
expect(s == "Hello, world!");
|
BEAST_EXPECT(s == "Hello, world!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect(n < limit);
|
BEAST_EXPECT(n < limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user