mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 02:25:52 +00:00
Compare commits
127 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d4fe469c6 | ||
|
|
8b43d67a73 | ||
|
|
128f7cefb1 | ||
|
|
09f9720ebb | ||
|
|
0df1b09a73 | ||
|
|
f432095532 | ||
|
|
e27a38939e | ||
|
|
ffa79ac6a5 | ||
|
|
2e632b1660 | ||
|
|
0b187a6a4e | ||
|
|
6cea5d0838 | ||
|
|
ffc7cf8f6c | ||
|
|
69bc58c5f6 | ||
|
|
f423181b94 | ||
|
|
112a863e73 | ||
|
|
cfde591ac9 | ||
|
|
0c97dda276 | ||
|
|
35f4698aed | ||
|
|
b7e2a3bd5f | ||
|
|
bb61b398a6 | ||
|
|
1e438f51c5 | ||
|
|
60416b18a5 | ||
|
|
4b0a0b0b85 | ||
|
|
f1377d5d30 | ||
|
|
30b6e4e2e5 | ||
|
|
5cf38bf88a | ||
|
|
9e3dadce0d | ||
|
|
73b4c818c5 | ||
|
|
2c2b0eb2f1 | ||
|
|
17726c2cac | ||
|
|
af79c9007e | ||
|
|
3de623bf66 | ||
|
|
7ec58cc554 | ||
|
|
3d6a1781e7 | ||
|
|
ce9238b389 | ||
|
|
2c6b0f3193 | ||
|
|
b4a16b165b | ||
|
|
a8cf5e0a5c | ||
|
|
2fcde0e0b6 | ||
|
|
b45f45dcef | ||
|
|
e823e60ca0 | ||
|
|
74977ab3db | ||
|
|
80dfb7d72d | ||
|
|
c30fe3066a | ||
|
|
0b605b3609 | ||
|
|
9bb337fb1f | ||
|
|
460dd8f186 | ||
|
|
6b0817b7ba | ||
|
|
7698477e86 | ||
|
|
8b60ef9db4 | ||
|
|
209fe8f7a9 | ||
|
|
b514f1aae9 | ||
|
|
f6a0345831 | ||
|
|
ce7e83f763 | ||
|
|
71b42dcec5 | ||
|
|
f5af8b03de | ||
|
|
e01f6e7455 | ||
|
|
b3eada1dc2 | ||
|
|
a3e3b9321e | ||
|
|
c652cf066d | ||
|
|
c218417d1a | ||
|
|
69db2ace58 | ||
|
|
79149b4c0c | ||
|
|
232ec62c75 | ||
|
|
7ca03d3bca | ||
|
|
15a30c745c | ||
|
|
8345475bc3 | ||
|
|
c7de7950c4 | ||
|
|
b6126f219f | ||
|
|
e05bf0844d | ||
|
|
fdff943262 | ||
|
|
a1a8ba7f53 | ||
|
|
d8a5f5b094 | ||
|
|
1ede09760e | ||
|
|
708fc6cd6f | ||
|
|
77999579b5 | ||
|
|
d24bb65639 | ||
|
|
d810f29e99 | ||
|
|
6e3e717876 | ||
|
|
2c87739d6c | ||
|
|
b00b81a861 | ||
|
|
a0a4eedc27 | ||
|
|
c0e9e3df49 | ||
|
|
7028579170 | ||
|
|
84ada74d53 | ||
|
|
be0fb67d8d | ||
|
|
fb60cc9b5b | ||
|
|
3c4d3b10c1 | ||
|
|
d9ef5ef98f | ||
|
|
be9c955506 | ||
|
|
1989b1028f | ||
|
|
0d577d9349 | ||
|
|
7536c53a48 | ||
|
|
e3ff30657c | ||
|
|
698ea58b39 | ||
|
|
a5500721db | ||
|
|
fd4ad29418 | ||
|
|
905c627043 | ||
|
|
8d8907e340 | ||
|
|
6724a63230 | ||
|
|
af4fe24939 | ||
|
|
c1c80dfc52 | ||
|
|
87273e21d8 | ||
|
|
610e51a162 | ||
|
|
e91aacc9a3 | ||
|
|
6e54461f4b | ||
|
|
ef23d72562 | ||
|
|
a1c0d15a1f | ||
|
|
b6a01ea41c | ||
|
|
8425e4558a | ||
|
|
5a688f9236 | ||
|
|
effd8c9737 | ||
|
|
a7c4d682d2 | ||
|
|
e00a6b0e5a | ||
|
|
dc3571184a | ||
|
|
22a375a5f4 | ||
|
|
3337d17fdd | ||
|
|
8ab2236cdd | ||
|
|
0cb6a0f961 | ||
|
|
28ae522ea2 | ||
|
|
c0cf7bd3c1 | ||
|
|
fd7a2835e4 | ||
|
|
3d0314c621 | ||
|
|
8d83aa5c07 | ||
|
|
7ff243ade9 | ||
|
|
2fd0540ed4 | ||
|
|
cdf470e68d |
@@ -9,7 +9,6 @@ url="https://github.com/ripple/rippled"
|
||||
license=('custom:ISC')
|
||||
depends=('protobuf' 'openssl' 'boost-libs')
|
||||
makedepends=('git' 'scons' 'boost')
|
||||
checkdepends=('nodejs')
|
||||
backup=("etc/$pkgname/rippled.cfg")
|
||||
source=("git://github.com/ripple/rippled.git#branch=master")
|
||||
sha512sums=('SKIP')
|
||||
@@ -26,8 +25,6 @@ build() {
|
||||
|
||||
check() {
|
||||
cd "$srcdir/$pkgname"
|
||||
npm install
|
||||
npm test
|
||||
build/rippled --unittest
|
||||
}
|
||||
|
||||
|
||||
@@ -33,16 +33,16 @@ macro(parse_target)
|
||||
if (${cur_component} STREQUAL gcc)
|
||||
if (DEFINED ENV{GNU_CC})
|
||||
set(CMAKE_C_COMPILER $ENV{GNU_CC})
|
||||
elseif ($ENV{CXX} MATCHES .*gcc.*)
|
||||
set(CMAKE_CXX_COMPILER $ENV{CC})
|
||||
elseif ($ENV{CC} MATCHES .*gcc.*)
|
||||
set(CMAKE_C_COMPILER $ENV{CC})
|
||||
else()
|
||||
find_program(CMAKE_C_COMPILER gcc)
|
||||
endif()
|
||||
|
||||
if (DEFINED ENV{GNU_CXX})
|
||||
set(CMAKE_C_COMPILER $ENV{GNU_CXX})
|
||||
set(CMAKE_CXX_COMPILER $ENV{GNU_CXX})
|
||||
elseif ($ENV{CXX} MATCHES .*g\\+\\+.*)
|
||||
set(CMAKE_C_COMPILER $ENV{CC})
|
||||
set(CMAKE_CXX_COMPILER $ENV{CXX})
|
||||
else()
|
||||
find_program(CMAKE_CXX_COMPILER g++)
|
||||
endif()
|
||||
@@ -51,16 +51,16 @@ macro(parse_target)
|
||||
if (${cur_component} STREQUAL clang)
|
||||
if (DEFINED ENV{CLANG_CC})
|
||||
set(CMAKE_C_COMPILER $ENV{CLANG_CC})
|
||||
elseif ($ENV{CXX} MATCHES .*clang.*)
|
||||
set(CMAKE_CXX_COMPILER $ENV{CC})
|
||||
elseif ($ENV{CC} MATCHES .*clang.*)
|
||||
set(CMAKE_C_COMPILER $ENV{CC})
|
||||
else()
|
||||
find_program(CMAKE_C_COMPILER clang)
|
||||
endif()
|
||||
|
||||
if (DEFINED ENV{CLANG_CXX})
|
||||
set(CMAKE_C_COMPILER $ENV{CLANG_CXX})
|
||||
set(CMAKE_CXX_COMPILER $ENV{CLANG_CXX})
|
||||
elseif ($ENV{CXX} MATCHES .*clang.*)
|
||||
set(CMAKE_C_COMPILER $ENV{CC})
|
||||
set(CMAKE_CXX_COMPILER $ENV{CXX})
|
||||
else()
|
||||
find_program(CMAKE_CXX_COMPILER clang++)
|
||||
endif()
|
||||
@@ -105,6 +105,14 @@ macro(parse_target)
|
||||
endif()
|
||||
|
||||
endwhile()
|
||||
# Promote these values to the CACHE, then unset the locals
|
||||
# to prevent shadowing.
|
||||
set(CMAKE_C_COMPILER ${CMAKE_C_COMPILER} CACHE FILEPATH
|
||||
"Path to a program" FORCE)
|
||||
unset(CMAKE_C_COMPILER)
|
||||
set(CMAKE_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE FILEPATH
|
||||
"Path to a program" FORCE)
|
||||
unset(CMAKE_CXX_COMPILER)
|
||||
|
||||
if (release)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
@@ -112,9 +120,25 @@ macro(parse_target)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
# ensure that the unity flags are set and exclusive
|
||||
if (NOT DEFINED unity OR unity)
|
||||
# Default to unity builds
|
||||
set(unity true)
|
||||
set(nonunity false)
|
||||
else()
|
||||
set(unity false)
|
||||
set(nonunity true)
|
||||
endif()
|
||||
|
||||
if (NOT unity)
|
||||
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}Classic)
|
||||
endif()
|
||||
# Promote this value to the CACHE, then unset the local
|
||||
# to prevent shadowing.
|
||||
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE INTERNAL
|
||||
"Choose the type of build, options are in CMAKE_CONFIGURATION_TYPES"
|
||||
FORCE)
|
||||
unset(CMAKE_BUILD_TYPE)
|
||||
endif()
|
||||
|
||||
endmacro()
|
||||
@@ -147,15 +171,13 @@ macro(setup_build_cache)
|
||||
set(CMAKE_CONFIGURATION_TYPES
|
||||
DebugClassic
|
||||
ReleaseClassic)
|
||||
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
|
||||
set(CMAKE_BUILD_TYPE DebugClassic)
|
||||
elseif(${CMAKE_BUILD_TYPE} STREQUAL "Release")
|
||||
set(CMAKE_BUILD_TYPE ReleaseClassic)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Promote this value to the CACHE, then unset the local
|
||||
# to prevent shadowing.
|
||||
set(CMAKE_CONFIGURATION_TYPES
|
||||
${CMAKE_CONFIGURATION_TYPES} CACHE STRING "" FORCE)
|
||||
unset(CMAKE_CONFIGURATION_TYPES)
|
||||
endmacro()
|
||||
|
||||
############################################################
|
||||
@@ -269,11 +291,11 @@ endmacro()
|
||||
|
||||
# Params: Boost components to search for.
|
||||
macro(use_boost)
|
||||
if ((NOT DEFINED BOOST_ROOT) AND (DEFINED ENV{BOOST_ROOT}))
|
||||
set(BOOST_ROOT $ENV{BOOST_ROOT})
|
||||
endif()
|
||||
if(WIN32 OR CYGWIN)
|
||||
# Workaround for MSVC having two boost versions - x86 and x64 on same PC in stage folders
|
||||
if ((NOT DEFINED BOOST_ROOT) AND (DEFINED ENV{BOOST_ROOT}))
|
||||
set(BOOST_ROOT $ENV{BOOST_ROOT})
|
||||
endif()
|
||||
if(DEFINED BOOST_ROOT)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND IS_DIRECTORY ${BOOST_ROOT}/stage64/lib)
|
||||
set(Boost_LIBRARY_DIR ${BOOST_ROOT}/stage64/lib)
|
||||
@@ -487,6 +509,15 @@ macro(setup_build_boilerplate)
|
||||
|
||||
if (is_gcc)
|
||||
add_compile_options(-Wno-unused-but-set-variable -Wno-deprecated)
|
||||
|
||||
# use gold linker if available
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=gold -Wl,--version
|
||||
ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
|
||||
if ("${LD_VERSION}" MATCHES "GNU gold")
|
||||
append_flags(CMAKE_EXE_LINKER_FLAGS -fuse-ld=gold)
|
||||
endif ()
|
||||
unset(LD_VERSION)
|
||||
endif()
|
||||
|
||||
# Generator expressions are not supported in add_definitions, use set_property instead
|
||||
@@ -502,6 +533,15 @@ macro(setup_build_boilerplate)
|
||||
APPEND
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
$<$<OR:$<BOOL:${profile}>,$<CONFIG:Release>,$<CONFIG:ReleaseClassic>>:NDEBUG>)
|
||||
else()
|
||||
# CMAKE_CXX_FLAGS_RELEASE is created by CMake for most / all generators
|
||||
# with defaults including /DNDEBUG or -DNDEBUG, and that value is stored
|
||||
# in the cache. Override that locally so that the cache value will be
|
||||
# avaiable if "assert" is ever changed.
|
||||
STRING(REGEX REPLACE "[-/]DNDEBUG" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
STRING(REGEX REPLACE "[-/]DNDEBUG" "" CMAKE_CXX_FLAGS_RELEASECLASSIC "${CMAKE_CXX_FLAGS_RELEASECLASSIC}")
|
||||
STRING(REGEX REPLACE "[-/]DNDEBUG" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
||||
STRING(REGEX REPLACE "[-/]DNDEBUG" "" CMAKE_C_FLAGS_RELEASECLASSIC "${CMAKE_C_FLAGS_RELEASECLASSIC}")
|
||||
endif()
|
||||
|
||||
if (NOT WIN32)
|
||||
@@ -520,11 +560,19 @@ macro(setup_build_boilerplate)
|
||||
add_compile_options(
|
||||
-Wno-redeclared-class-member -Wno-mismatched-tags -Wno-deprecated-register)
|
||||
add_definitions(-DBOOST_ASIO_HAS_STD_ARRAY)
|
||||
|
||||
# use ldd linker if available
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=lld -Wl,--version
|
||||
ERROR_QUIET OUTPUT_VARIABLE LD_VERSION)
|
||||
if ("${LD_VERSION}" MATCHES "LLD")
|
||||
append_flags(CMAKE_EXE_LINKER_FLAGS -fuse-ld=lld)
|
||||
endif ()
|
||||
unset(LD_VERSION)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
add_definitions(-DBEAST_COMPILE_OBJECTIVE_CPP=1
|
||||
-DNO_LOG_UNHANDLED_EXCEPTIONS)
|
||||
add_definitions(-DBEAST_COMPILE_OBJECTIVE_CPP=1)
|
||||
add_compile_options(
|
||||
-Wno-deprecated -Wno-deprecated-declarations -Wno-unused-variable -Wno-unused-function)
|
||||
endif()
|
||||
|
||||
@@ -117,18 +117,18 @@ parser.add_argument(
|
||||
help='Add a prefix for unit tests',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--nonpm', '-n',
|
||||
action='store_true',
|
||||
help='Do not run npm tests',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--clean', '-c',
|
||||
action='store_true',
|
||||
help='delete all build artifacts after testing',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--quiet', '-q',
|
||||
action='store_true',
|
||||
help='Reduce output where possible (unit tests)',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'scons_args',
|
||||
default=(),
|
||||
@@ -192,9 +192,12 @@ def run_tests(args):
|
||||
|
||||
print('Unit tests for', target)
|
||||
testflag = '--unittest'
|
||||
quiet = ''
|
||||
if ARGS.test:
|
||||
testflag += ('=' + ARGS.test)
|
||||
resultcode, lines = shell(executable, (testflag,))
|
||||
if ARGS.quiet:
|
||||
quiet = '-q'
|
||||
resultcode, lines = shell(executable, (testflag, quiet,))
|
||||
|
||||
if resultcode:
|
||||
if not ARGS.verbose:
|
||||
@@ -203,15 +206,6 @@ def run_tests(args):
|
||||
if not ARGS.keep_going:
|
||||
break
|
||||
|
||||
if not ARGS.nonpm:
|
||||
print('npm tests for', target)
|
||||
resultcode, lines = shell('npm', ('test', '--rippled=' + executable,))
|
||||
if resultcode:
|
||||
if not ARGS.verbose:
|
||||
print('ERROR:\n', *lines, sep='')
|
||||
failed.append([target, 'npm'])
|
||||
if not ARGS.keep_going:
|
||||
break
|
||||
return failed
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# This script builds boost with the correct ABI flags for ubuntu
|
||||
#
|
||||
|
||||
version=59
|
||||
version=63
|
||||
patch=0
|
||||
|
||||
if hash lsb_release 2>/dev/null; then
|
||||
|
||||
@@ -25,7 +25,7 @@ if [ ${ubuntu_release} == "12.04" ]; then
|
||||
add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||
apt-get update
|
||||
apt-get -y upgrade
|
||||
apt-get -y install curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties boost1.57-all-dev nodejs g++-5 g++-4.9
|
||||
apt-get -y install curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties boost1.57-all-dev g++-5 g++-4.9
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 99 --slave /usr/bin/g++ g++ /usr/bin/g++-5
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 99 --slave /usr/bin/g++ g++ /usr/bin/g++-4.9
|
||||
exit 0
|
||||
@@ -33,21 +33,25 @@ fi
|
||||
|
||||
if [ ${ubuntu_release} == "14.04" ] || [ ${ubuntu_release} == "15.04" ]; then
|
||||
apt-get install python-software-properties
|
||||
echo "deb [arch=amd64] https://mirrors.ripple.com/ubuntu/ trusty stable contrib" | sudo tee /etc/apt/sources.list.d/ripple.list
|
||||
echo "deb [arch=amd64] https://mirrors.ripple.com/ubuntu/ trusty stable contrib" | sudo tee /etc/apt/sources.list.d/ripple.list
|
||||
wget -O- -q https://mirrors.ripple.com/mirrors.ripple.com.gpg.key | sudo apt-key add -
|
||||
add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||
apt-get update
|
||||
apt-get -y upgrade
|
||||
apt-get -y install curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties boost-all-dev nodejs g++-5 g++-4.9
|
||||
apt-get -y install curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties boost-all-dev g++-5 g++-4.9
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 99 --slave /usr/bin/g++ g++ /usr/bin/g++-5
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 99 --slave /usr/bin/g++ g++ /usr/bin/g++-4.9
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ${ubuntu_release} == "16.04" ] || [ ${ubuntu_release} == "15.10" ]; then
|
||||
# Test if 0th parameter has a version number greater than or equal to the 1st param
|
||||
function version_check() { test "$(printf '%s\n' "$@" | sort -V | tail -n 1)" == "$1"; }
|
||||
|
||||
# this should work for versions greater than 15.10
|
||||
if version_check ${ubuntu_release} 15.10; then
|
||||
apt-get update
|
||||
apt-get -y upgrade
|
||||
apt-get -y install python-software-properties curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties libboost-all-dev nodejs
|
||||
apt-get -y install python-software-properties curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties libboost-all-dev
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ software components:
|
||||
* (Optional) [Python and Scons](README.md#optional-install-python-and-scons)
|
||||
* [OpenSSL Library](README.md#install-openssl)
|
||||
* [Boost library](README.md#build-boost)
|
||||
* [Node.js](README.md#install-nodejs)
|
||||
|
||||
## Install Software
|
||||
|
||||
@@ -242,9 +241,7 @@ and then choose the **Build->Build Solution** menu item.
|
||||
|
||||
# Unit Tests (Recommended)
|
||||
|
||||
## Internal
|
||||
|
||||
The internal rippled unit tests are written in C++ and are part
|
||||
The rippled unit tests are written in C++ and are part
|
||||
of the rippled executable.
|
||||
|
||||
From a Windows console, run the unit tests:
|
||||
@@ -255,108 +252,4 @@ From a Windows console, run the unit tests:
|
||||
|
||||
Substitute the correct path to the executable to test different builds.
|
||||
|
||||
## External
|
||||
|
||||
The external rippled unit tests are written in Javascript using Node.js,
|
||||
and utilize the mocha unit test framework. To run the unit tests, it
|
||||
will be necessary to perform the following steps:
|
||||
|
||||
### Install Node.js
|
||||
|
||||
[Install Node.js](http://nodejs.org/download/). We recommend the Windows
|
||||
installer (**.msi** file) as it takes care of updating the *PATH* environment
|
||||
variable so that scripts can find the command. On Windows systems,
|
||||
**Node.js** comes with **npm**. A separate installation of **npm**
|
||||
is not necessary.
|
||||
|
||||
### Create node_modules
|
||||
|
||||
Open a windows console. From the root of your local rippled repository
|
||||
directory, invoke **npm** to bring in the necessary components:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
If you get an error that looks like
|
||||
|
||||
```
|
||||
Error: ENOENT, stat 'C:\Users\username\AppData\Roaming\npm'
|
||||
```
|
||||
|
||||
simply create the indicated folder and try again.
|
||||
|
||||
### Create a test config.js
|
||||
|
||||
From a *bash* shell (installed with Git for Windows), copy the
|
||||
example configuration file into the appropriate location:
|
||||
|
||||
```
|
||||
cp test/config-example.js test/config.js
|
||||
```
|
||||
|
||||
Edit your version of test/config.js to reflect the correct path to the rippled executable:
|
||||
|
||||
```
|
||||
exports.default_server_config = {
|
||||
// Where to find the binary.
|
||||
rippled_path: path.resolve(__dirname, "../build/msvc.debug/rippled.exe")
|
||||
};
|
||||
```
|
||||
|
||||
Also in **test/config.js**, change any occurrences of the
|
||||
IP address *0.0.0.0* to *127.0.0.1*.
|
||||
|
||||
### Run Tests
|
||||
|
||||
From a windows console, run the unit tests:
|
||||
|
||||
```
|
||||
npm test
|
||||
```
|
||||
|
||||
Alternatively, run an individual test using mocha:
|
||||
|
||||
```
|
||||
sh
|
||||
node_modules/mocha/bin/mocha test/account_tx-test.js
|
||||
```
|
||||
|
||||
* NOTE: The version of ripple-lib provided by the npm install
|
||||
facility is usually slightly behind the develop branch of the
|
||||
authoritative ripple-lib repository. Therefore, some tests might fail.
|
||||
|
||||
### Development ripple-lib
|
||||
|
||||
To use the latest branch of **ripple-lib** during the unit tests,
|
||||
first clone the repository in a new location outside of your rippled
|
||||
repository. Then update the submodules. After, run **npm install**
|
||||
to set up the **node_modules** directory. Finally, install the
|
||||
**grunt** command line tools required to run **grunt** and
|
||||
build **ripple-lib**.
|
||||
|
||||
```
|
||||
git clone git@github.com:ripple/ripple-lib.git
|
||||
cd ripple-lib
|
||||
git submodule update --init
|
||||
npm install
|
||||
npm install -g grunt-cli
|
||||
grunt
|
||||
```
|
||||
|
||||
Now link this version of **ripple-lib** into the global packages:
|
||||
|
||||
```
|
||||
sudo npm link
|
||||
```
|
||||
|
||||
To make rippled use the newly linked global **ripple-lib** package
|
||||
instead of the one installed under **node_modules**, change
|
||||
directories to the local rippled repository and delete the old
|
||||
**ripple-lib** then link to the new one:
|
||||
|
||||
```
|
||||
sh
|
||||
rm -rf node_modules/ripple-lib
|
||||
npm link ripple-lib
|
||||
```
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,6 @@ these software components:
|
||||
* [Homebrew](http://brew.sh/)
|
||||
* [Git](http://git-scm.com/)
|
||||
* [Scons](http://www.scons.org/)
|
||||
* [Node.js](http://nodejs.org/download/)
|
||||
|
||||
## Install Software
|
||||
|
||||
@@ -175,68 +174,4 @@ rippled builds a set of unit tests into the server executable. To run these unit
|
||||
tests after building, pass the `--unittest` option to the compiled `rippled`
|
||||
executable. The executable will exit after running the unit tests.
|
||||
|
||||
## System Tests (Recommended)
|
||||
|
||||
The external rippled system tests are written in Javascript using Node.js, and
|
||||
utilize the buster system test framework. To run the system tests, it will be
|
||||
necessary to perform the following steps:
|
||||
|
||||
### Install Node.js
|
||||
|
||||
Install [Node.js](http://nodejs.org/download/). We recommend the macos
|
||||
installer (`.pkg` file) since it takes care of updating the `PATH`
|
||||
environment variable so that scripts can find the command. On macos systems,
|
||||
`Node.js` comes with `npm`. A separate installation of `npm` is not
|
||||
necessary.
|
||||
|
||||
### Create node_modules
|
||||
|
||||
From the root of your local rippled repository, invoke `npm` to
|
||||
bring in the necessary components:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Run Tests
|
||||
|
||||
```
|
||||
npm test
|
||||
```
|
||||
|
||||
### Development ripple-lib
|
||||
|
||||
If you want to use the latest branch of `ripple-lib` during the system tests:
|
||||
|
||||
1. clone the repository in a new location outside of your rippled repository.
|
||||
2. update the submodules in that repo.
|
||||
3. run `npm install` to set up the `node_modules` directory.
|
||||
4. install the `grunt` command line tools required to run `grunt` and build `ripple-lib`.
|
||||
|
||||
i.e.:
|
||||
|
||||
```
|
||||
git clone https://github.com/ripple/rippled.git
|
||||
cd ripple-lib
|
||||
git submodule update --init
|
||||
npm install
|
||||
npm install -g grunt-cli
|
||||
grunt
|
||||
```
|
||||
|
||||
Now link this version of `ripple-lib` into the global packages:
|
||||
|
||||
```
|
||||
sudo npm link
|
||||
```
|
||||
|
||||
To make rippled use the newly linked global `ripple-lib` package instead of
|
||||
the one installed under `node_modules`, change directories to the local
|
||||
rippled repository and delete the old `ripple-lib` then link to the new
|
||||
one:
|
||||
|
||||
```
|
||||
rm -rf node_modules/ripple-lib
|
||||
npm link ripple-lib
|
||||
```
|
||||
|
||||
|
||||
107
CMakeLists.txt
107
CMakeLists.txt
@@ -52,7 +52,22 @@
|
||||
|
||||
############################################################
|
||||
|
||||
#########################################################
|
||||
# CMAKE_C_COMPILER and CMAKE_CXX_COMPILER must be defined
|
||||
# before the project statement; However, the project
|
||||
# statement will clear CMAKE_BUILD_TYPE. CACHE variables,
|
||||
# along with the order of this code, are used to work
|
||||
# around these constraints.
|
||||
#
|
||||
# Don't put any code above or in this block, unless it
|
||||
# has similar constraints.
|
||||
cmake_minimum_required(VERSION 3.1.0)
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/Builds/CMake")
|
||||
include(CMakeFuncs)
|
||||
set(openssl_min 1.0.2)
|
||||
parse_target()
|
||||
project(rippled)
|
||||
#########################################################
|
||||
|
||||
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
|
||||
set(dir "build")
|
||||
@@ -82,22 +97,8 @@ if("${CMAKE_GENERATOR}" MATCHES "Visual Studio" AND
|
||||
-G\"${CMAKE_GENERATOR} Win64\"")
|
||||
endif()
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/Builds/CMake")
|
||||
include(CMakeFuncs)
|
||||
|
||||
set(openssl_min 1.0.2)
|
||||
|
||||
parse_target()
|
||||
|
||||
if (NOT DEFINED unity)
|
||||
set(unity true)
|
||||
set(nonunity false)
|
||||
endif()
|
||||
|
||||
setup_build_cache()
|
||||
|
||||
project(rippled)
|
||||
|
||||
if(nonunity)
|
||||
get_cmake_property(allvars VARIABLES)
|
||||
string(REGEX MATCHALL "[^;]*(DEBUG|RELEASE)[^;]*" matchvars "${allvars}")
|
||||
@@ -195,11 +196,10 @@ json.cpp
|
||||
protocol.cpp
|
||||
rpcx.cpp
|
||||
shamap.cpp
|
||||
server.cpp
|
||||
test.cpp)
|
||||
server.cpp)
|
||||
|
||||
prepend(test_unity_srcs
|
||||
src/unity/
|
||||
src/test/unity/
|
||||
app_test_unity.cpp
|
||||
basics_test_unity.cpp
|
||||
beast_test_unity.cpp
|
||||
@@ -214,11 +214,11 @@ resource_test_unity.cpp
|
||||
rpc_test_unity.cpp
|
||||
server_test_unity.cpp
|
||||
shamap_test_unity.cpp
|
||||
test_unity.cpp)
|
||||
support_unity.cpp)
|
||||
|
||||
list(APPEND rippled_src_unity ${beast_unity_srcs} ${ripple_unity_srcs} ${test_unity_srcs})
|
||||
|
||||
add_with_props(rippled_src_unity src/unity/nodestore_test_unity.cpp
|
||||
add_with_props(rippled_src_unity src/test/unity/nodestore_test_unity.cpp
|
||||
-I"${CMAKE_SOURCE_DIR}/"src/rocksdb2/include
|
||||
-I"${CMAKE_SOURCE_DIR}/"src/snappy/snappy
|
||||
-I"${CMAKE_SOURCE_DIR}/"src/snappy/config
|
||||
@@ -235,7 +235,7 @@ add_with_props(rippled_src_unity src/ripple/unity/soci_ripple.cpp ${soci_extra_i
|
||||
list(APPEND ripple_unity_srcs ${beast_unity_srcs} ${test_unity_srcs}
|
||||
src/ripple/unity/nodestore.cpp
|
||||
src/ripple/unity/soci_ripple.cpp
|
||||
src/unity/nodestore_test_unity.cpp)
|
||||
src/test/unity/nodestore_test_unity.cpp)
|
||||
|
||||
############################################################
|
||||
|
||||
@@ -266,8 +266,7 @@ foreach(curdir
|
||||
protocol
|
||||
rpc
|
||||
server
|
||||
shamap
|
||||
test)
|
||||
shamap)
|
||||
file(GLOB_RECURSE cursrcs src/ripple/${curdir}/*.cpp)
|
||||
list(APPEND rippled_src_nonunity "${cursrcs}")
|
||||
list(APPEND non_unity_srcs "${cursrcs}")
|
||||
@@ -284,7 +283,28 @@ add_with_props(rippled_src_nonunity "${nodestore_srcs}"
|
||||
|
||||
list(APPEND non_unity_srcs "${nodestore_srcs}")
|
||||
|
||||
file(GLOB_RECURSE test_srcs src/test/*.cpp)
|
||||
# unit test sources
|
||||
foreach(curdir
|
||||
app
|
||||
basics
|
||||
beast
|
||||
conditions
|
||||
core
|
||||
json
|
||||
ledger
|
||||
nodestore
|
||||
overlay
|
||||
peerfinder
|
||||
protocol
|
||||
resource
|
||||
rpc
|
||||
server
|
||||
shamap
|
||||
jtx)
|
||||
file(GLOB_RECURSE cursrcs src/test/${curdir}/*.cpp)
|
||||
list(APPEND test_srcs "${cursrcs}")
|
||||
endforeach()
|
||||
|
||||
add_with_props(rippled_src_nonunity "${test_srcs}"
|
||||
-I"${CMAKE_SOURCE_DIR}/"src/rocksdb2/include
|
||||
-I"${CMAKE_SOURCE_DIR}/"src/snappy/snappy
|
||||
@@ -364,8 +384,7 @@ foreach(cursrc
|
||||
src/ripple/unity/lz4.c
|
||||
src/ripple/unity/protobuf.cpp
|
||||
src/ripple/unity/ripple.proto.cpp
|
||||
src/ripple/unity/resource.cpp
|
||||
src/ripple/unity/websocket02.cpp)
|
||||
src/ripple/unity/resource.cpp)
|
||||
|
||||
add_with_props(rippled_src_all ${cursrc}
|
||||
${rocks_db_system_header}
|
||||
@@ -440,15 +459,45 @@ set_property(TARGET ${other_target} PROPERTY EXCLUDE_FROM_DEFAULT_BUILD true)
|
||||
find_program(
|
||||
B2_EXE
|
||||
NAMES b2
|
||||
PATHS ENV BOOST_ROOT
|
||||
HINTS ${BOOST_ROOT}
|
||||
PATHS ${BOOST_ROOT}
|
||||
DOC "Location of the b2 build executable from Boost")
|
||||
if(${B2_EXE} STREQUAL "b2-NOTFOUND")
|
||||
if(${B2_EXE} STREQUAL "B2_EXE-NOTFOUND")
|
||||
message(WARNING
|
||||
"Boost b2 executable not found. docs target will not be buildable")
|
||||
elseif(NOT BOOST_ROOT)
|
||||
if(Boost_INCLUDE_DIRS)
|
||||
set(BOOST_ROOT ${Boost_INCLUDE_DIRS})
|
||||
else()
|
||||
get_filename_component(BOOST_ROOT ${B2_EXE} DIRECTORY)
|
||||
endif()
|
||||
endif()
|
||||
# The value for BOOST_ROOT will be determined based on
|
||||
# 1) The environment BOOST_ROOT
|
||||
# 2) The Boost_INCLUDE_DIRS found by `get_boost`
|
||||
# 3) The folder the `b2` executable is found in.
|
||||
# If those checks don't yield the correct path, BOOST_ROOT
|
||||
# can be defined on the cmake command line:
|
||||
# cmake <path> -DBOOST_ROOT=<boost_path>
|
||||
if(BOOST_ROOT)
|
||||
set(B2_PARAMS "-sBOOST_ROOT=${BOOST_ROOT}")
|
||||
endif()
|
||||
|
||||
# Find bash to help Windows avoid file association problems
|
||||
find_program(
|
||||
BASH_EXE
|
||||
NAMES bash sh
|
||||
DOC "Location of the bash shell executable"
|
||||
)
|
||||
if(${BASH_EXE} STREQUAL "BASH_EXE-NOTFOUND")
|
||||
message(WARNING
|
||||
"Unable to find bash executable. docs target may not be buildable")
|
||||
set(BASH_EXE "")
|
||||
endif()
|
||||
|
||||
add_custom_target(docs
|
||||
COMMAND "./makeqbk.sh"
|
||||
COMMAND ${B2_EXE}
|
||||
COMMAND ${CMAKE_COMMAND} -E env "PATH=$ENV{PATH} " ${BASH_EXE} ./makeqbk.sh
|
||||
COMMAND ${B2_EXE} ${B2_PARAMS}
|
||||
BYPRODUCTS "${CMAKE_SOURCE_DIR}/docs/html/index.html"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/docs"
|
||||
SOURCES "${doc_srcs}"
|
||||
|
||||
@@ -67,8 +67,6 @@ ISC license. See the LICENSE file for more details.
|
||||
| ./Builds| Platform or IDE-specific project files. |
|
||||
| ./doc | Documentation and example configuration files. |
|
||||
| ./src | Source code. |
|
||||
| ./test | Javascript / Mocha tests. |
|
||||
|
||||
|
||||
Some of the directories under `src` are external repositories inlined via
|
||||
git-subtree. See the corresponding README for more details.
|
||||
|
||||
207
RELEASENOTES.md
207
RELEASENOTES.md
@@ -4,8 +4,215 @@ This document contains the release notes for `rippled`, the reference server
|
||||
implementation of the Ripple protocol. To learn more about how to build and
|
||||
run a `rippled` server, visit https://ripple.com/build/rippled-setup/
|
||||
|
||||
If you are using Red Hat Enterprise Linux 7 or CentOS 7, you can [update using `yum`](https://ripple.com/build/rippled-setup/#updating-rippled). For other platforms, please [compile from source](https://wiki.ripple.com/Rippled_build_instructions).
|
||||
|
||||
|
||||
# Releases
|
||||
|
||||
## Version 0.60.0
|
||||
|
||||
The `rippled` 0.60.0 release introduces several enhancements that improve the reliability and scalability of the Ripple Consensus Ledger (RCL), including features that add ledger interoperability by improving Interledger Protocol compatibility. Ripple recommends that all server operators upgrade to version 0.60.0 by Thursday, 2017-03-30, for service continuity.
|
||||
|
||||
Highlights of this release include:
|
||||
|
||||
- `Escrow` (previously called `SusPay`) which permits users to cryptographically escrow XRP on RCL with an expiration date, and optionally a hashlock crypto-condition. Ripple expects Escrow to be enabled via an Amendment named [`Escrow`](https://ripple.com/build/amendments/#escrow) on Thursday, 2017-03-30. See below for details.
|
||||
- Dynamic UNL Lite, which allows `rippled` to automatically adjust which validators it trusts based on recommended lists from trusted publishers.
|
||||
|
||||
**New and Updated Features**
|
||||
|
||||
- Add `Escrow` support (#2039)
|
||||
- Dynamize trusted validator list and quorum (#1842)
|
||||
- Simplify fee handling during transaction submission (#1992)
|
||||
- Publish server stream when fee changes (#2016)
|
||||
- Replace manifest with validator token (#1975)
|
||||
- Add validator key revocations (#2019)
|
||||
- Add `SecretKey` comparison operator (#2004)
|
||||
- Reduce `LEDGER_MIN_CONSENSUS` (#2013)
|
||||
- Update libsecp256k1 and Beast B30 (#1983)
|
||||
- Make `Config` extensible via lambda (#1993)
|
||||
- WebSocket permessage-deflate integration (#1995)
|
||||
- Do not close socket on a foreign thread (#2014)
|
||||
- Update build scripts to support latest boost and ubuntu distros (#1997)
|
||||
- Handle protoc targets in scons ninja build (#2022)
|
||||
- Specify syntax version for ripple.proto file (#2007)
|
||||
- Eliminate protocol header dependency (#1962)
|
||||
- Use gnu gold or clang lld linkers if available (#2031)
|
||||
- Add tests for `lookupLedger` (#1989)
|
||||
- Add unit test for `get_counts` RPC method (#2011)
|
||||
- Add test for `transaction_entry` request (#2017)
|
||||
- Unit tests of RPC "sign" (#2010)
|
||||
- Add failure only unit test reporter (#2018)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Enforce rippling constraints during payments (#2049)
|
||||
- Fix limiting step re-execute bug (#1936)
|
||||
- Make "wss" work the same as "wss2" (#2033)
|
||||
- Config test uses unique directories for each test (#1984)
|
||||
- Check for malformed public key on payment channel (#2027)
|
||||
- Send a websocket ping before timing out in server (#2035)
|
||||
|
||||
|
||||
## Version 0.50.3
|
||||
|
||||
The `rippled` 0.50.3 release corrects a reported exploit that would allow a combination of trust lines and order books in a payment path to bypass the blocking effect of the [`NoRipple`](https://ripple.com/build/understanding-the-noripple-flag/) flag. Ripple recommends that all server operators immediately upgrade to version 0.50.3.
|
||||
|
||||
**New and Updated Features**
|
||||
|
||||
This release has no new features.
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
Correct a reported exploit that would allow a combination of trust lines and order books in a payment path to bypass the blocking effect of the “NoRipple” flag.
|
||||
|
||||
|
||||
## Version 0.50.2
|
||||
|
||||
The `rippled` 0.50.2 release adjusts the default TLS cipher list and corrects a flaw that would not allow an SSL handshake to properly complete if the port was configured using the `wss` keyword. Ripple recommends upgrading to 0.50.2 only if server operators are running rippled servers that accept client connections over TLS.
|
||||
|
||||
**New and Updated Features**
|
||||
|
||||
This release has no new features.
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
Adjust the default cipher list and correct a flaw that would not allow an SSL handshake to properly complete if the port was configured using the `wss` keyword (#1985)
|
||||
|
||||
|
||||
## Version 0.50.0
|
||||
|
||||
The `rippled` 0.50.0 release includes TickSize, which allows gateways to set a "tick size" for assets they issue to help promote faster price discovery and deeper liquidity, as well as reduce transaction spam and ledger churn on RCL. Ripple expects TickSize to be enabled via an Amendment called TickSize on Tuesday, 2017-02-21.
|
||||
|
||||
You can [update to the new version](https://ripple.com/build/rippled-setup/#updating-rippled) on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please [compile the new version from source](https://wiki.ripple.com/Rippled_build_instructions).
|
||||
|
||||
**New and Updated Features**
|
||||
|
||||
**Tick Size**
|
||||
|
||||
Currently, offers on RCL can differ by as little as one part in a quadrillion. This means that there is essentially no value to placing an offer early, as an offer placed later at a microscopically better price gets priority over it. The [TickSize](https://ripple.com/build/amendments/#ticksize) Amendment solves this problem by introducing a minimum tick size that a price must move for an offer to be considered to be at a better price. The tick size is controlled by the issuers of the assets involved.
|
||||
|
||||
This change lets issuers quantize the exchange rates of offers to use a specified number of significant digits. Gateways must enable a TickSize on their account for this feature to benefit them. A single AccountSet transaction may set a `TickSize` parameter. Legal values are 0 and 3-15 inclusive. Zero removes the setting. 3-15 allow that many decimal digits of precision in the pricing of offers for assets issued by this account. It will still be possible to place an offer to buy or sell any amount of an asset and the offer will still keep that amount as exactly as it does now. If an offer involves two assets that each have a tick size, the smaller number of significant figures (larger ticks) controls.
|
||||
|
||||
For asset pairs with XRP, the tick size imposed, if any, is the tick size of the issuer of the non-XRP asset. For asset pairs without XRP, the tick size imposed, if any, is the smaller of the two issuer's configured tick sizes.
|
||||
|
||||
The tick size is imposed by rounding the offer quality down to the nearest tick and recomputing the non-critical side of the offer. For a buy, the amount offered is rounded down. For a sell, the amount charged is rounded up.
|
||||
|
||||
The primary expected benefit of the TickSize amendment is the reduction of bots fighting over the tip of the order book, which means:
|
||||
- Quicker price discovery as outpricing someone by a microscopic amount is made impossible (currently bots can spend hours outbidding each other with no significant price movement)
|
||||
- A reduction in offer creation and cancellation spam
|
||||
- Traders can't outbid by a microscopic amount
|
||||
- More offers left on the books as priority
|
||||
|
||||
We also expect larger tick sizes to benefit market makers in the following ways:
|
||||
- They increase the delta between the fair market value and the trade price, ultimately reducing spreads
|
||||
- They prevent market makers from consuming each other's offers due to slight changes in perceived fair market value, which promotes liquidity
|
||||
- They promote faster price discovery by reducing the back and forths required to move the price by traders who don't want to move the price more than they need to
|
||||
- They reduce transaction spam by reducing fighting over the tip of the order book and reducing the need to change offers due to slight price changes
|
||||
- They reduce ledger churn and metadata sizes by reducing the number of indexes each order book must have
|
||||
- They allow the order book as presented to traders to better reflect the actual book since these presentations are inevitably aggregated into ticks
|
||||
|
||||
**Hardened TLS configuration**
|
||||
|
||||
This release updates the default TLS configuration for rippled. The new release supports only 2048-bit DH parameters and defines a new default set of modern ciphers to use, removing support for ciphers and hash functions that are no longer considered secure.
|
||||
|
||||
Server administrators who wish to have different settings can configure custom global and per-port cipher suites in the configuration file using the `ssl_ciphers` directive.
|
||||
|
||||
**0.50.0 Change Log**
|
||||
|
||||
Remove websocketpp support (#1910)
|
||||
|
||||
Increase OpenSSL requirements & harden default TLS cipher suites (#1913)
|
||||
|
||||
Move test support sources out of ripple directory (#1916)
|
||||
|
||||
Enhance ledger header RPC commands (#1918)
|
||||
|
||||
Add support for tick sizes (#1922)
|
||||
|
||||
Port discrepancy-test.coffee to c++ (#1930)
|
||||
|
||||
Remove redundant call to `clearNeedNetworkLedger` (#1931)
|
||||
|
||||
Port freeze-test.coffee to C++ unit test. (#1934)
|
||||
|
||||
Fix CMake docs target to work if `BOOST_ROOT` is not set (#1937)
|
||||
|
||||
Improve setup for account_tx paging test (#1942)
|
||||
|
||||
Eliminate npm tests (#1943)
|
||||
|
||||
Port uniport js test to cpp (#1944)
|
||||
|
||||
Enable amendments in genesis ledger (#1944)
|
||||
|
||||
Trim ledger data in Discrepancy_test (#1948)
|
||||
|
||||
Add `current_ledger` field to `fee` result (#1949)
|
||||
|
||||
Cleanup unit test support code (#1953)
|
||||
|
||||
Add ledger save / load tests (#1955)
|
||||
|
||||
Remove unused websocket files (#1957)
|
||||
|
||||
Update RPC handler role/usage (#1966)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
Validator's manifest not forwarded beyond directly connected peers (#1919)
|
||||
|
||||
**Upcoming Features**
|
||||
|
||||
We expect the previously announced Suspended Payments feature, which introduces new transaction types to the Ripple protocol that will permit users to cryptographically escrow XRP on RCL, to be enabled via the [SusPay](https://ripple.com/build/amendments/#suspay) Amendment on Tuesday, 2017-02-21.
|
||||
|
||||
Also, we expect support for crypto-conditions, which are signature-like structures that can be used with suspended payments to support ILP integration, to be included in the next rippled release scheduled for March.
|
||||
|
||||
Lastly, we do not have an update on the previously announced changes to the hash tree structure that rippled uses to represent a ledger, called [SHAMapV2](https://ripple.com/build/amendments/#shamapv2). At the time of activation, this amendment will require brief scheduled allowable unavailability while the changes to the hash tree structure are computed by the network. We will keep the community updated as we progress towards this date (TBA).
|
||||
|
||||
|
||||
## Version 0.40.1
|
||||
|
||||
The `rippled` 0.40.1 release increases SQLite database limits in all rippled servers. Ripple recommends upgrading to 0.40.1 only if server operators are running rippled servers with full-history of the ledger. There are no new or updated features in the 0.40.1 release.
|
||||
|
||||
You can update to the new version on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please compile the new version from source.
|
||||
|
||||
**New and Updated Features**
|
||||
|
||||
This release has no new features.
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
Increase SQLite database limits to prevent full-history servers from crashing when restarting. (#1961)
|
||||
|
||||
## Version 0.40.0
|
||||
|
||||
The `rippled` 0.40.0 release includes Suspended Payments, a new transaction type on the Ripple network that functions similar to an escrow service, which permits users cryptographically escrow XRP on RCL with an expiration date. Ripple expects Suspended Payments to be enabled via an Amendment named [SusPay](https://ripple.com/build/amendments/#suspay) on Tuesday, 2017-01-17.
|
||||
|
||||
You can update to the new version on Red Hat Enterprise Linux 7 or CentOS 7 using yum. For other platforms, please compile the new version from source.
|
||||
|
||||
**New and Updated Features**
|
||||
|
||||
Previously, Ripple announced the introduction of Payment Channels during the release of rippled version 0.33.0, which permit scalable, off-ledger checkpoints of high volume, low value payments flowing in a single direction. This was the first step in a multi-phase effort to make RCL more scalable and to support Interledger Protocol (ILP). Ripple expects Payment Channels to be enabled via an Amendment called [PayChan](https://ripple.com/build/amendments/#paychan) on a future date to be determined.
|
||||
|
||||
In the second phase towards making RCL more scalable and compatible with ILP, Ripple is introducing Suspended Payments, a new transaction type on the Ripple network that functions similar to an escrow service, which permits users to cryptographically escrow XRP on RCL with an expiration date. Ripple expects Suspended Payments to be enabled via an Amendment named [SusPay](https://ripple.com/build/amendments/#suspay) on Tuesday, 2017-01-17.
|
||||
|
||||
A Suspended Payment can be created, which deducts the funds from the sending account. It can then be either fulfilled or canceled. It can only be fulfilled if the fulfillment transaction makes it into a ledger with a CloseTime lower than the expiry date of the transaction. It can be canceled with a transaction that makes it into a ledger with a CloseTime greater than the expiry date of the transaction.
|
||||
|
||||
In the third phase towards making RCL more scalable and compatible with ILP, Ripple plans to introduce additional library support for crypto-conditions, which are distributable event descriptions written in a standard format that describe how to recognize a fulfillment message without saying exactly what the fulfillment is. Fulfillments are cryptographically verifiable messages that prove an event occurred. If you transmit a fulfillment, then everyone who has the condition can agree that the condition has been met. Fulfillment requires the submission of a signature that matches the condition (message hash and public key). This format supports multiple algorithms, including different hash functions and cryptographic signing schemes. Crypto-conditions can be nested in multiple levels, with each level possibly having multiple signatures.
|
||||
|
||||
Lastly, we do not have an update on the previously announced changes to the hash tree structure that rippled uses to represent a ledger, called [SHAMapV2](https://ripple.com/build/amendments/#shamapv2). This will require brief scheduled allowable downtime while the changes to the hash tree structure are propagated by the network. We will keep the community updated as we progress towards this date (TBA).
|
||||
|
||||
Consensus refactor (#1874)
|
||||
|
||||
Bug Fixes
|
||||
|
||||
Correct an issue in payment flow code that did not remove an unfunded offer (#1860)
|
||||
|
||||
Sign validator manifests with both ephemeral and master keys (#1865)
|
||||
|
||||
Correctly parse multi-buffer JSON messages (#1862)
|
||||
|
||||
|
||||
## Version 0.33.0
|
||||
|
||||
The `rippled` 0.33.0 release includes an improved version of the payment code, which we expect to be activated via Amendment on Wednesday, 2016-10-20 with the name [Flow](https://ripple.com/build/amendments/#flow). We are also introducing XRP Payment Channels, a new structure in the ledger designed to support [Interledger Protocol](https://interledger.org/) trust lines as balances get substantial, which we expect to be activated via Amendment on a future date (TBA) with the name [PayChan](https://ripple.com/build/amendments/#paychan). Lastly, we will be introducing changes to the hash tree structure that rippled uses to represent a ledger, which we expect to be available via Amendment on a future date (TBA) with the name [SHAMapV2](https://ripple.com/build/amendments/#shamapv2).
|
||||
|
||||
73
SConstruct
73
SConstruct
@@ -123,9 +123,9 @@ import time
|
||||
import glob
|
||||
import SCons.Action
|
||||
|
||||
if (platform.architecture()[0] != '64bit'):
|
||||
if (not platform.machine().endswith('64')):
|
||||
print('Warning: Detected {} architecture. Rippled requires a 64-bit OS.'.format(
|
||||
platform.architecture()[0]));
|
||||
platform.machine()));
|
||||
|
||||
sys.path.append(os.path.join('src', 'ripple', 'beast', 'site_scons'))
|
||||
sys.path.append(os.path.join('src', 'ripple', 'site_scons'))
|
||||
@@ -392,8 +392,6 @@ def config_base(env):
|
||||
env.Prepend(LIBPATH=['%s/lib' % openssl])
|
||||
except:
|
||||
pass
|
||||
if not 'vcxproj' in COMMAND_LINE_TARGETS:
|
||||
env.Append(CPPDEFINES=['NO_LOG_UNHANDLED_EXCEPTIONS'])
|
||||
|
||||
# handle command-line arguments
|
||||
profile_jemalloc = ARGUMENTS.get('profile-jemalloc')
|
||||
@@ -554,6 +552,13 @@ def config_env(toolchain, variant, env):
|
||||
if toolchain == 'clang':
|
||||
env.Append(CCFLAGS=['-Wno-redeclared-class-member'])
|
||||
env.Append(CPPDEFINES=['BOOST_ASIO_HAS_STD_ARRAY'])
|
||||
try:
|
||||
ldd_ver = subprocess.check_output([env['CLANG_CXX'], '-fuse-ld=lld', '-Wl,--version'],
|
||||
stderr=subprocess.STDOUT).strip()
|
||||
# have lld
|
||||
env.Append(LINKFLAGS=['-fuse-ld=lld'])
|
||||
except:
|
||||
pass
|
||||
|
||||
env.Append(CXXFLAGS=[
|
||||
'-frtti',
|
||||
@@ -573,7 +578,6 @@ def config_env(toolchain, variant, env):
|
||||
env.Append(CCFLAGS=[
|
||||
'-Wno-deprecated',
|
||||
'-Wno-deprecated-declarations',
|
||||
'-Wno-unused-variable',
|
||||
'-Wno-unused-function',
|
||||
])
|
||||
else:
|
||||
@@ -586,11 +590,17 @@ def config_env(toolchain, variant, env):
|
||||
'-D_GLIBCXX_USE_CXX11_ABI' : 0
|
||||
})
|
||||
if toolchain == 'gcc':
|
||||
|
||||
env.Append(CCFLAGS=[
|
||||
'-Wno-unused-but-set-variable',
|
||||
'-Wno-deprecated',
|
||||
])
|
||||
try:
|
||||
ldd_ver = subprocess.check_output([env['GNU_CXX'], '-fuse-ld=gold', '-Wl,--version'],
|
||||
stderr=subprocess.STDOUT).strip()
|
||||
# have ld.gold
|
||||
env.Append(LINKFLAGS=['-fuse-ld=gold'])
|
||||
except:
|
||||
pass
|
||||
|
||||
boost_libs = [
|
||||
# resist the temptation to alphabetize these. coroutine
|
||||
@@ -949,14 +959,10 @@ def get_classic_sources(toolchain):
|
||||
append_sources(result, *list_sources('src/ripple/rpc', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/shamap', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/server', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/test', '.cpp'))
|
||||
append_sources(result,
|
||||
'src/test/BasicNetwork_test.cpp',
|
||||
'src/test/Env_test.cpp',
|
||||
'src/test/WSClient_test.cpp')
|
||||
append_sources(result, *list_sources('src/test/app', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/basics', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/beast', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/conditions', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/core', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/json', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/ledger', '.cpp'))
|
||||
@@ -967,7 +973,9 @@ def get_classic_sources(toolchain):
|
||||
append_sources(result, *list_sources('src/test/rpc', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/server', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/shamap', '.cpp'))
|
||||
|
||||
append_sources(result, *list_sources('src/test/jtx', '.cpp'))
|
||||
|
||||
|
||||
if use_shp(toolchain):
|
||||
cc_flags = {'CCFLAGS': ['--system-header-prefix=rocksdb2']}
|
||||
else:
|
||||
@@ -1013,22 +1021,21 @@ def get_unity_sources(toolchain):
|
||||
'src/ripple/unity/rpcx.cpp',
|
||||
'src/ripple/unity/shamap.cpp',
|
||||
'src/ripple/unity/server.cpp',
|
||||
'src/ripple/unity/test.cpp',
|
||||
'src/unity/app_test_unity.cpp',
|
||||
'src/unity/basics_test_unity.cpp',
|
||||
'src/unity/beast_test_unity.cpp',
|
||||
'src/unity/core_test_unity.cpp',
|
||||
'src/unity/conditions_test_unity.cpp',
|
||||
'src/unity/json_test_unity.cpp',
|
||||
'src/unity/ledger_test_unity.cpp',
|
||||
'src/unity/overlay_test_unity.cpp',
|
||||
'src/unity/peerfinder_test_unity.cpp',
|
||||
'src/unity/protocol_test_unity.cpp',
|
||||
'src/unity/resource_test_unity.cpp',
|
||||
'src/unity/rpc_test_unity.cpp',
|
||||
'src/unity/server_test_unity.cpp',
|
||||
'src/unity/shamap_test_unity.cpp',
|
||||
'src/unity/test_unity.cpp'
|
||||
'src/test/unity/app_test_unity.cpp',
|
||||
'src/test/unity/basics_test_unity.cpp',
|
||||
'src/test/unity/beast_test_unity.cpp',
|
||||
'src/test/unity/core_test_unity.cpp',
|
||||
'src/test/unity/conditions_test_unity.cpp',
|
||||
'src/test/unity/json_test_unity.cpp',
|
||||
'src/test/unity/ledger_test_unity.cpp',
|
||||
'src/test/unity/overlay_test_unity.cpp',
|
||||
'src/test/unity/peerfinder_test_unity.cpp',
|
||||
'src/test/unity/protocol_test_unity.cpp',
|
||||
'src/test/unity/resource_test_unity.cpp',
|
||||
'src/test/unity/rpc_test_unity.cpp',
|
||||
'src/test/unity/server_test_unity.cpp',
|
||||
'src/test/unity/shamap_test_unity.cpp',
|
||||
'src/test/unity/support_unity.cpp'
|
||||
)
|
||||
|
||||
if use_shp(toolchain):
|
||||
@@ -1039,7 +1046,7 @@ def get_unity_sources(toolchain):
|
||||
append_sources(
|
||||
result,
|
||||
'src/ripple/unity/nodestore.cpp',
|
||||
'src/unity/nodestore_test_unity.cpp',
|
||||
'src/test/unity/nodestore_test_unity.cpp',
|
||||
CPPPATH=[
|
||||
'src/rocksdb2/include',
|
||||
'src/snappy/snappy',
|
||||
@@ -1162,7 +1169,6 @@ for tu_style in ['classic', 'unity']:
|
||||
'src/ripple/unity/protobuf.cpp',
|
||||
'src/ripple/unity/ripple.proto.cpp',
|
||||
'src/ripple/unity/resource.cpp',
|
||||
'src/ripple/unity/websocket02.cpp',
|
||||
**cc_flags
|
||||
)
|
||||
|
||||
@@ -1238,7 +1244,8 @@ for tu_style in ['classic', 'unity']:
|
||||
if should_build_ninja(tu_style, toolchain, variant):
|
||||
print('Generating ninja: {}:{}:{}'.format(tu_style, toolchain, variant))
|
||||
scons_to_ninja.GenerateNinjaFile(
|
||||
[object_builder.env] + object_builder.child_envs,
|
||||
# add base env last to ensure protoc targets are added
|
||||
[object_builder.env] + object_builder.child_envs + [base],
|
||||
dest_file='build.ninja')
|
||||
|
||||
for key, value in aliases.iteritems():
|
||||
@@ -1275,10 +1282,10 @@ def do_count(target, source, env):
|
||||
path = os.path.join(parent, path)
|
||||
r = os.path.splitext(path)
|
||||
if r[1] in suffixes:
|
||||
if r[0].endswith('.test'):
|
||||
if r[0].endswith('_test'):
|
||||
yield os.path.normpath(path)
|
||||
return list(_iter(base))
|
||||
testfiles = list_testfiles(os.path.join('src', 'ripple'), env.get('CPPSUFFIXES'))
|
||||
testfiles = list_testfiles(os.path.join('src', 'test'), env.get('CPPSUFFIXES'))
|
||||
lines = 0
|
||||
for f in testfiles:
|
||||
lines = lines + sum(1 for line in open(f))
|
||||
|
||||
18
appveyor.yml
18
appveyor.yml
@@ -69,6 +69,7 @@ install:
|
||||
echo "Download from $env:RIPPLED_DEPS_URL"
|
||||
Start-FileDownload "$env:RIPPLED_DEPS_URL"
|
||||
7z x "$($env:RIPPLED_DEPS_PATH).zip" -oC:\ -y > $null
|
||||
if ($LastExitCode -ne 0) { throw "7z failed" }
|
||||
}
|
||||
|
||||
# Newer DEPS include a versions file.
|
||||
@@ -92,6 +93,7 @@ build_script:
|
||||
if ($env:build -eq "scons") {
|
||||
# Build with scons
|
||||
scons $env:target -j%NUMBER_OF_PROCESSORS%
|
||||
if ($LastExitCode -ne 0) { throw "scons build failed" }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -102,14 +104,15 @@ build_script:
|
||||
New-Item -ItemType Directory -Force -Path "build/$cmake_target"
|
||||
Push-Location "build/$cmake_target"
|
||||
cmake -G"Visual Studio 14 2015 Win64" -Dtarget="$cmake_target" ../..
|
||||
if ($LastExitCode -ne 0) { throw "CMake failed" }
|
||||
cmake --build . --config $env:buildconfig -- -m
|
||||
if ($LastExitCode -ne 0) { throw "CMake build failed" }
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
after_build:
|
||||
- ps: |
|
||||
if ($env:build -eq "scons") {
|
||||
# Put our executable in a place where npm test can find it.
|
||||
cp build/$($env:target)/rippled.exe build
|
||||
ls build
|
||||
$exe="build/rippled"
|
||||
@@ -122,11 +125,10 @@ after_build:
|
||||
|
||||
test_script:
|
||||
- ps: |
|
||||
# Run the rippled unit tests
|
||||
& $exe --unittest
|
||||
|
||||
# Run the rippled integration tests
|
||||
& npm install --progress=false
|
||||
& npm test --rippled="$exe"
|
||||
|
||||
& {
|
||||
# Run the rippled unit tests
|
||||
& $exe --unittest --quiet --unittest-log
|
||||
# https://connect.microsoft.com/PowerShell/feedback/details/751703/option-to-stop-script-if-command-line-exe-fails
|
||||
if ($LastExitCode -ne 0) { throw "Unit tests failed" }
|
||||
}
|
||||
|
||||
|
||||
@@ -43,11 +43,11 @@ rm -f build/${APP}
|
||||
ldd $APP_PATH
|
||||
|
||||
if [[ ${APP} == "rippled" ]]; then
|
||||
export APP_ARGS="--unittest"
|
||||
export APP_ARGS="--unittest --quiet --unittest-log"
|
||||
# Only report on src/ripple files
|
||||
export LCOV_FILES="*/src/ripple/*"
|
||||
# Exclude */src/ripple/test directory
|
||||
export LCOV_EXCLUDE_FILES="*/src/ripple/test/*"
|
||||
# Nothing to explicitly exclude
|
||||
export LCOV_EXCLUDE_FILES="LCOV_NO_EXCLUDE"
|
||||
else
|
||||
: ${APP_ARGS:=}
|
||||
: ${LCOV_FILES:="*/src/*"}
|
||||
@@ -70,7 +70,7 @@ gdb -return-child-result -quiet -batch \
|
||||
-ex run \
|
||||
-ex "thread apply all backtrace full" \
|
||||
-ex "quit" \
|
||||
--args $APP_PATH --unittest
|
||||
--args $APP_PATH --unittest --quiet --unittest-log
|
||||
|
||||
if [[ $TARGET == "coverage" ]]; then
|
||||
# Create test coverage data file
|
||||
@@ -89,8 +89,4 @@ if [[ $TARGET == "coverage" ]]; then
|
||||
codecov -X gcov # don't even try and look for .gcov files ;)
|
||||
fi
|
||||
|
||||
if [[ ${APP} == "rippled" ]]; then
|
||||
# Run NPM tests
|
||||
npm install --progress=false
|
||||
npm test --rippled=$APP_PATH
|
||||
fi
|
||||
|
||||
|
||||
@@ -53,11 +53,6 @@ if [ -x $HOME/bin/g++ ]; then
|
||||
$HOME/bin/g++ -v
|
||||
fi
|
||||
|
||||
# Avoid `spurious errors` caused by ~/.npm permission issues
|
||||
# Does it already exist? Who owns? What permissions?
|
||||
ls -lah ~/.npm || mkdir ~/.npm
|
||||
# Make sure we own it
|
||||
chown -Rc $USER ~/.npm
|
||||
pip install --user https://github.com/codecov/codecov-python/archive/master.zip
|
||||
|
||||
bash bin/sh/install-boost.sh
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import base64, os, random, struct, sys
|
||||
import base64, binascii, json, os, random, struct, sys
|
||||
import ed25519
|
||||
import ecdsa
|
||||
import hashlib
|
||||
@@ -188,9 +188,14 @@ def perform_check(s, print=print):
|
||||
|
||||
def perform_sign(
|
||||
seq, validation_pk_human, validation_sk_human, master_sk_human, print=print):
|
||||
print('[validation_manifest]')
|
||||
print(wrap(get_signature(
|
||||
int(seq), validation_pk_human, validation_sk_human, master_sk_human)))
|
||||
manifest = get_signature(
|
||||
int(seq), validation_pk_human, validation_sk_human, master_sk_human)
|
||||
|
||||
print('[validator_token]')
|
||||
print(wrap(base64.b64encode(json.dumps({
|
||||
"validation_secret_key": binascii.b2a_hex(Base58.decode_version(validation_sk_human)[1]),
|
||||
"manifest": manifest},
|
||||
separators=(',', ':')))))
|
||||
|
||||
def perform_verify(
|
||||
seq, validation_pk_human, master_pk_human, signature, print=print):
|
||||
|
||||
@@ -104,12 +104,7 @@ n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3
|
||||
n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
|
||||
n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
|
||||
[validation_quorum]
|
||||
3
|
||||
|
||||
[validation_seed]
|
||||
{validation_seed}
|
||||
#vaidation_public_key: {validation_public_key}
|
||||
#validation_public_key: {validation_public_key}
|
||||
|
||||
# Other rippled's trusting this validator need this key
|
||||
[validator_keys]
|
||||
@@ -122,8 +117,8 @@ n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
expire = 1
|
||||
auto_connect = 1
|
||||
|
||||
[validation_manifest]
|
||||
{validation_manifest}
|
||||
[validator_token]
|
||||
{validator_token}
|
||||
|
||||
[rpc_startup]
|
||||
{{ "command": "log_level", "severity": "debug" }}
|
||||
@@ -204,7 +199,7 @@ def sign_manifest(seq, validation_pk, master_secret):
|
||||
result = []
|
||||
for l in r.splitlines():
|
||||
l.strip()
|
||||
if not l or l == '[validation_manifest]':
|
||||
if not l or l == '[validator_token]':
|
||||
continue
|
||||
result.append(l)
|
||||
return '\n'.join(result)
|
||||
@@ -433,7 +428,7 @@ def new_config_ephemeral_key(
|
||||
if rm_dbs and os.path.exists(db_dir):
|
||||
shutil.rmtree(db_dir)
|
||||
os.makedirs(db_dir)
|
||||
# replace the validation_manifest section with `signed`
|
||||
# replace the validator_token section with `signed`
|
||||
bak = config_file + '.bak'
|
||||
if is_windows() and os.path.isfile(bak):
|
||||
os.remove(bak)
|
||||
@@ -443,7 +438,7 @@ def new_config_ephemeral_key(
|
||||
with open(config_file, 'w') as out:
|
||||
for l in src:
|
||||
sl = l.strip()
|
||||
if not in_manifest and sl == '[validation_manifest]':
|
||||
if not in_manifest and sl == '[validator_token]':
|
||||
in_manifest = True
|
||||
elif in_manifest:
|
||||
if sl.startswith('[') or sl.startswith('#'):
|
||||
@@ -542,7 +537,7 @@ def get_configs(manifest_seq):
|
||||
sibling_ip = '127.0.0.1'
|
||||
sibling_port = port_nums[sibling_index][1]
|
||||
d = {
|
||||
'validation_manifest': s,
|
||||
'validator_token': s,
|
||||
'all_validator_keys': all_validator_keys,
|
||||
'node_db_type': node_db_type,
|
||||
'node_db_path': node_db_path,
|
||||
|
||||
@@ -45,7 +45,6 @@ RESULT = {
|
||||
'websocket_public_port': '5206',
|
||||
'peer_ip': '0.0.0.0',
|
||||
'rpc_port': '5205',
|
||||
'validation_quorum': '3',
|
||||
'websocket_ip': '127.0.0.1'}
|
||||
|
||||
FULL = """
|
||||
@@ -131,10 +130,6 @@ n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3
|
||||
n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
|
||||
n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
|
||||
# Ditto.
|
||||
[validation_quorum]
|
||||
3
|
||||
|
||||
[validation_seed]
|
||||
sh1T8T9yGuV7Jb6DPhqSzdU2s5LcV
|
||||
|
||||
|
||||
@@ -141,9 +141,13 @@ class test_Sign(TestCase):
|
||||
Sign.perform_sign(self.SEQUENCE, public, private, private, print=self.print)
|
||||
self.assertEquals(
|
||||
self.results,
|
||||
[[['[validation_manifest]'], {}],
|
||||
[['JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2dnZ2dnZ2\n'
|
||||
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkYwRAIgXyobHA8sDQxmDJNLE6HIaARlzvcd79/wT068\n'
|
||||
'e113gUkCIHkI540JQT2LHwAD7/y3wFE5X3lEXMfgZRkpLZTxkpticBJAzo5VrUEr0U47sHvu\n'
|
||||
'IjbrINLCTM6pAScA899G9kpMWexbXv1ceIbTP5JH1HyQmsZsROTeHR0irojvYgx7JLaiAA=='],
|
||||
[[['[validator_token]'], {}],
|
||||
[['eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiNmI2YjZiNmI2YjZiNmI2YjZiNmI2Yj\n'
|
||||
'ZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YjZiNmI2YiIsIm1hbmlm\n'
|
||||
'ZXN0IjoiSkFBQUFCZHhJZTJESUtVWmQ5akRqS2lra254bkRmV0NIa1NYWVpSZUZlbn\n'
|
||||
'ZzbW9WQ2RJdzZuTWhBbloyZG5aMmRuWjJkbloyZG5aMmRuWjJkbloyZG5aMmRuWjJk\n'
|
||||
'bloyZG5aMmRrWXdSQUlnWHlvYkhBOHNEUXhtREpOTEU2SElhQVJsenZjZDc5L3dUMD\n'
|
||||
'Y4ZTExM2dVa0NJSGtJNTQwSlFUMkxId0FENy95M3dGRTVYM2xFWE1mZ1pSa3BMWlR4\n'
|
||||
'a3B0aWNCSkF6bzVWclVFcjBVNDdzSHZ1SWpicklOTENUTTZwQVNjQTg5OUc5a3BNV2\n'
|
||||
'V4Ylh2MWNlSWJUUDVKSDFIeVFtc1pzUk9UZUhSMGlyb2p2WWd4N0pMYWlBQT09In0='],
|
||||
{}]])
|
||||
|
||||
@@ -21,8 +21,4 @@ test:
|
||||
- scons clang.debug
|
||||
override:
|
||||
# Execute unit tests under gdb
|
||||
- gdb -return-child-result -quiet -batch -ex "set env MALLOC_CHECK_=3" -ex "set print thread-events off" -ex run -ex "thread apply all backtrace full" -ex "quit" --args build/clang.debug/rippled --unittest
|
||||
- npm install --progress=false
|
||||
- |
|
||||
echo "exports.default_server_config = {\"rippled_path\" : \"$HOME/rippled/build/clang.debug/rippled\"};" > test/config.js
|
||||
- npm test
|
||||
- gdb -return-child-result -quiet -batch -ex "set env MALLOC_CHECK_=3" -ex "set print thread-events off" -ex run -ex "thread apply all backtrace full" -ex "quit" --args build/clang.debug/rippled --unittest --quiet --unittest-log
|
||||
|
||||
@@ -8,7 +8,7 @@ Validators use two types of key pairs: *master keys* and *ephemeral
|
||||
keys*. Ephemeral keys are used to sign and verify validations. Master keys are
|
||||
used to sign and verify manifests that change ephemeral keys. The master secret
|
||||
key should be tightly controlled. The ephemeral secret key needs to be present
|
||||
in the config file.
|
||||
in the config file in the form of a token.
|
||||
|
||||
## Validator Keys
|
||||
|
||||
@@ -28,10 +28,9 @@ Sample output:
|
||||
paamfhAn5m1NM4UUu5mmvVaHQy8Fb65bkpbaNrvKwX3YMKdjzi2
|
||||
```
|
||||
|
||||
The first value is the master public key. Add the public key to the config
|
||||
for this validator. A one-word comment must be added after the key (for example
|
||||
*ThisServersName*). Any other rippled trusting the validator needs to add the
|
||||
master public key to its config. Only add keys received from trusted sources.
|
||||
The first value is the master public key. Any other rippled trusting the
|
||||
validator needs to add the master public key to its config. Only add keys
|
||||
received from trusted sources.
|
||||
|
||||
The second value is the corresponding master secret key. **DO NOT INSTALL THIS
|
||||
IN THE CONFIG**. The master secret key will be used to sign manifests that
|
||||
@@ -63,17 +62,6 @@ Sample output:
|
||||
}
|
||||
```
|
||||
|
||||
Add the `validation_seed` value (the ephemeral secret key) to this validator's
|
||||
config. It is recommended to add the ephemeral public key and the sequence
|
||||
number as a comment as well (sequence numbers are be explained below):
|
||||
|
||||
```
|
||||
[validation_seed]
|
||||
sh8bLqqkGBknGcsgRTrFMxcciwytm
|
||||
# validation_public_key: n9LtZ9haqYMbzJ92cDd3pu3Lko6uEznrXuYea3ehuhVcwDHF5coX
|
||||
# sequence number: 1
|
||||
```
|
||||
|
||||
A manifest is a signed message used to inform other servers of this validator's
|
||||
ephemeral public key. A manifest contains a sequence number, the new ephemeral
|
||||
public key, and it is signed with both the ephemeral and master secret keys.
|
||||
@@ -95,15 +83,18 @@ For example:
|
||||
Sample output:
|
||||
|
||||
```
|
||||
[validation_manifest]
|
||||
JAAAAAFxIe3t8rIb4Ba8JHI97CbwpxmTq0LhN/7ZAbsNaSwrbHaypHMhAzTuu07YGOvVvB3+
|
||||
aS0jhP+q0TVgTjGJKhx+yTY1Da3ddkYwRAIgDkmIt3dPNsfeCH3ApMZgpwqG4JwtIlKEymqK
|
||||
S7v+VqkCIFQXg20ZMpXXT86vmLdlmPspgeUN1scWsuFoPYUUJywycBJAl93+/bZbfZ4quTeM
|
||||
5y80/OSIcVoWPcHajwrAl68eiAW4MVFeJXvShXNfnT+XsxMjDh0VpOkhvyp971i1MgjBAA==
|
||||
```
|
||||
[validator_token]
|
||||
eyJ2YWxpZGF0aW9uX3ByaXZhdGVfa2V5IjoiN2VkMWM2ZDVmMTBhOGUyYWNmZWE0OW
|
||||
NkNzE5ZjhiZjZhMWI1Yjg2M2Q3N2QxMDE1MjVkNGQxOWU4ZWYwNjU1OSIsIm1hbmlm
|
||||
ZXN0IjoiSkFBQUFBRnhJZTNVZ3lXb3QwdFpSTFBNbDQ1dit5YkdPanJYNkE5c1JIcU
|
||||
lJWUlZSTZjREhuTWhBNlNqWWZnWnJsTHFXU2UrNzlWUkZnOWJEeVZKNDMvYmV6Zkxu
|
||||
dWkxVzhQdWRrWXdSQUlnY09KWmVpdmFaOW1abmM4Y1N4bUlOVGVYSUlKOE5oTXprRD
|
||||
lrWThseGRkc0NJRk1OU3k5Qmo4VHNQWlV4NzNwYUJ0RmxpaDZWOTlSRXNnU3V6Wlhr
|
||||
BXMHNWTVZXR09QUnY0Ylg2dDVmYi9haUtoNkZyRVdtYk5YeXpRNmI5TGhDQT09In0=
|
||||
```
|
||||
|
||||
Copy this to the config for this validator. Don't forget to update the comment
|
||||
noting the sequence number.
|
||||
Copy this to the config for this validator. It is recommended to add the
|
||||
sequence number as a comment as well.
|
||||
|
||||
## Revoking a key
|
||||
|
||||
|
||||
@@ -260,7 +260,54 @@
|
||||
# If you need a certificate chain, specify the path to the
|
||||
# certificate chain here. The chain may include the end certificate.
|
||||
#
|
||||
# ssl_ciphers = <cipherlist>
|
||||
#
|
||||
# Control the ciphers which the server will support over SSL on the port,
|
||||
# specified using the OpenSSL "cipher list format".
|
||||
#
|
||||
# NOTE If unspecified, rippled will automatically configure a modern
|
||||
# cipher suite. This default suite should be widely supported.
|
||||
#
|
||||
# You should not modify this string unless you have a specific
|
||||
# reason and cryptographic expertise. Incorrect modification may
|
||||
# keep rippled from connecting to other instances of rippled or
|
||||
# prevent RPC and WebSocket clients from connecting.
|
||||
#
|
||||
# WebSocket permessage-deflate extension options
|
||||
#
|
||||
# These settings configure the optional permessage-deflate extension
|
||||
# options and may appear on any port configuration entry. They are meaningful
|
||||
# only to ports which have enabled a WebSocket protocol.
|
||||
#
|
||||
# permessage_deflate = <flag>
|
||||
#
|
||||
# Determines if permessage_deflate extension negotiations are enabled.
|
||||
# When enabled, clients may request the extension and the server will
|
||||
# offer the enabled extension in response.
|
||||
#
|
||||
# client_max_window_bits = [9..15]
|
||||
# server_max_window_bits = [9..15]
|
||||
# client_no_context_takeover = <flag>
|
||||
# server_no_context_takeover = <flag>
|
||||
#
|
||||
# These optional settings control options related to the permessage-deflate
|
||||
# extension negotiation. For precise definitions of these fields please see
|
||||
# the RFC 7692, "Compression Extensions for WebSocket":
|
||||
# https://tools.ietf.org/html/rfc7692
|
||||
#
|
||||
# compress_level = [0..9]
|
||||
#
|
||||
# When set, determines the amount of compression attempted, where 0 is
|
||||
# the least amount and 9 is the most amount. Higher levels require more
|
||||
# CPU resources. Levels 1 through 3 use a fast compression algorithm,
|
||||
# while levels 4 through 9 use a more compact algorithm which uses more
|
||||
# CPU resources. If unspecified, a default of 3 is used.
|
||||
#
|
||||
# memory_level = [1..9]
|
||||
#
|
||||
# When set, determines the relative amount of memory used to hold
|
||||
# intermediate compression data. Higher numbers can give better compression
|
||||
# ratios at the cost of higher memory and CPU resources.
|
||||
#
|
||||
# [rpc_startup]
|
||||
#
|
||||
@@ -499,8 +546,7 @@
|
||||
#
|
||||
# These settings affect the behavior of the server instance with respect
|
||||
# to Ripple payment protocol level activities such as validating and
|
||||
# closing ledgers, establishing a quorum, or adjusting fees in response
|
||||
# to server overloads.
|
||||
# closing ledgers or adjusting fees in response to server overloads.
|
||||
#
|
||||
#
|
||||
#
|
||||
@@ -554,17 +600,42 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# [validator_token]
|
||||
#
|
||||
# This is an alternative to [validation_seed] that allows rippled to perform
|
||||
# validation without having to store the validator keys on the network
|
||||
# connected server. The field should contain a single token in the form of a
|
||||
# base64-encoded blob.
|
||||
# An external tool is available for generating validator keys and tokens.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [validator_key_revocation]
|
||||
#
|
||||
# If a validator's secret key has been compromised, a revocation must be
|
||||
# generated and added to this field. The revocation notifies peers that it is
|
||||
# no longer safe to trust the revoked key. The field should contain a single
|
||||
# revocation in the form of a base64-encoded blob.
|
||||
# An external tool is available for generating and revoking validator keys.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [validators_file]
|
||||
#
|
||||
# Path or name of a file that contains the validation public keys of nodes
|
||||
# to always accept as validators as well as the minimum number of validators
|
||||
# needed to accept consensus.
|
||||
#
|
||||
# The contents of the file should include a [validators] and a
|
||||
# [validation_quorum] entry. [validators] should be followed by
|
||||
# a list of validation public keys of nodes, one per line, optionally
|
||||
# followed by a comment separated by whitespace.
|
||||
# [validation_quorum] should be followed by a number.
|
||||
# The contents of the file should include a [validators] and/or
|
||||
# [validator_list_sites] and [validator_list_keys] entries.
|
||||
# [validators] should be followed by a list of validation public keys of
|
||||
# nodes, one per line.
|
||||
# [validator_list_sites] should be followed by a list of URIs each serving a
|
||||
# list of recommended validators.
|
||||
# [validator_list_keys] should be followed by a list of keys belonging to
|
||||
# trusted validator list publishers. Validator lists fetched from configured
|
||||
# sites will only be considered if the list is accompanied by a valid
|
||||
# signature from a trusted publisher key.
|
||||
#
|
||||
# Specify the file by its name or path.
|
||||
# Unless an absolute path is specified, it will be considered relative to
|
||||
@@ -576,14 +647,12 @@
|
||||
#
|
||||
# Example content:
|
||||
# [validators]
|
||||
# n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1
|
||||
# n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2
|
||||
# n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3
|
||||
# n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
|
||||
# n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
# n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
|
||||
# n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
|
||||
# n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
|
||||
# n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
|
||||
# n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
|
||||
#
|
||||
# [validation_quorum]
|
||||
# 3
|
||||
#
|
||||
#
|
||||
# [path_search]
|
||||
@@ -974,7 +1043,7 @@ pool.ntp.org
|
||||
[ips]
|
||||
r.ripple.com 51235
|
||||
|
||||
# File containing validation quorum and trusted validator keys.
|
||||
# File containing trusted validator keys or validator list publishers.
|
||||
# Unless an absolute path is specified, it will be considered relative to the
|
||||
# folder in which the rippled.cfg file is located.
|
||||
[validators_file]
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
# [validators]
|
||||
#
|
||||
# List of the validation public keys of nodes to always accept as validators.
|
||||
# A comment may, optionally, be associated with each entry, separated by
|
||||
# whitespace from the validation public key.
|
||||
#
|
||||
# The latest list of recommended validators can be obtained from
|
||||
# https://ripple.com/ripple.txt
|
||||
@@ -23,26 +21,34 @@
|
||||
#
|
||||
# Examples:
|
||||
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
|
||||
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
|
||||
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt
|
||||
#
|
||||
# [validator_list_sites]
|
||||
#
|
||||
# List of URIs serving lists of recommended validators.
|
||||
#
|
||||
# [validation_quorum]
|
||||
# Examples:
|
||||
# https://ripple.com/validators
|
||||
# http://127.0.0.1:8000
|
||||
#
|
||||
# Sets the minimum number of trusted validations a ledger must have before
|
||||
# the server considers it fully validated. Note that if you are validating,
|
||||
# your validation counts.
|
||||
# [validator_list_keys]
|
||||
#
|
||||
# List of keys belonging to trusted validator list publishers.
|
||||
# Validator lists fetched from configured sites will only be considered
|
||||
# if the list is accompanied by a valid signature from a trusted
|
||||
# publisher key.
|
||||
# Validator list keys should be hex-encoded.
|
||||
#
|
||||
# Examples:
|
||||
# ed499d732bded01504a7407c224412ef550cc1ade638a4de4eb88af7c36cb8b282
|
||||
# 0202d3f36a801349f3be534e3f64cfa77dede6e1b6310a0b48f40f20f955cec945
|
||||
# 02dd8b7075f64d77d9d2bdb88da364f29fcd975f9ea6f21894abcc7564efda8054
|
||||
#
|
||||
|
||||
# Public keys of the validators that this rippled instance trusts.
|
||||
[validators]
|
||||
n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1
|
||||
n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2
|
||||
n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3
|
||||
n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4
|
||||
n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
|
||||
# The number of validators rippled needs to accept a consensus.
|
||||
# Don't change this unless you know what you're doing.
|
||||
[validation_quorum]
|
||||
3
|
||||
n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
|
||||
n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
|
||||
n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
|
||||
n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS
|
||||
n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA
|
||||
|
||||
@@ -105,6 +105,10 @@ WARN_LOGFILE =
|
||||
INPUT = \
|
||||
\
|
||||
../src/ripple/protocol/STObject.h \
|
||||
../src/ripple/protocol/JsonFields.h \
|
||||
../src/test/support/AbstractClient.h \
|
||||
../src/test/support/JSONRPCClient.h \
|
||||
../src/test/support/WSClient.h \
|
||||
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
|
||||
31
package.json
31
package.json
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"name": "rippled",
|
||||
"version": "0.0.1",
|
||||
"description": "Rippled Server",
|
||||
"private": true,
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"dependencies": {
|
||||
"assert-diff": "^1.0.1",
|
||||
"async": "~0.2.9",
|
||||
"babel": "^5.8.21",
|
||||
"coffee-script": "^1.8.0",
|
||||
"deep-equal": "0.0.0",
|
||||
"extend": "~1.2.0",
|
||||
"lodash": "^3.5.0",
|
||||
"mocha": "^2.1.0",
|
||||
"request": "^2.47.0",
|
||||
"ripple-lib": "0.13.0-rc6.0",
|
||||
"simple-jsonrpc": "~0.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"pretest": "node test/pretest.js",
|
||||
"test": "mocha test/websocket-test.js test/server-test.js test/*-test.{js,coffee}"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/ripple/rippled.git"
|
||||
},
|
||||
"readmeFilename": "README.md"
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
sudo: false
|
||||
language: cpp
|
||||
|
||||
env:
|
||||
@@ -10,27 +11,31 @@ env:
|
||||
# to boost's .tar.gz.
|
||||
- LCOV_ROOT=$HOME/lcov
|
||||
- VALGRIND_ROOT=$HOME/valgrind-install
|
||||
- BOOST_ROOT=$HOME/boost_1_60_0
|
||||
- BOOST_URL='http://downloads.sourceforge.net/project/boost/boost/1.60.0/boost_1_60_0.tar.gz?r=https%3A%2F%2Fsourceforge.net%2Fprojects%2Fboost%2Ffiles%2Fboost%2F1.60.0%2Fboost_1_60_0.tar.gz&ts=1460417589&use_mirror=netix'
|
||||
packages: &gcc5_pkgs
|
||||
- gcc-5
|
||||
- g++-5
|
||||
- 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
|
||||
- BOOST_ROOT=$HOME/boost_1_61_0
|
||||
- BOOST_URL='http://sourceforge.net/projects/boost/files/boost/1.61.0/boost_1_61_0.tar.gz'
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages:
|
||||
- gcc-5
|
||||
- g++-5
|
||||
- python-software-properties
|
||||
- libssl-dev
|
||||
- libffi-dev
|
||||
- libstdc++6
|
||||
- binutils-gold
|
||||
# Provides a backtrace if the unittests crash
|
||||
- gdb
|
||||
# Needed for installing valgrind
|
||||
- subversion
|
||||
- automake
|
||||
- autotools-dev
|
||||
- libc6-dbg
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# GCC/Coverage/Autobahn
|
||||
# GCC/Coverage/Autobahn (if master or develop branch)
|
||||
- compiler: gcc
|
||||
env:
|
||||
- GCC_VER=5
|
||||
@@ -38,10 +43,6 @@ matrix:
|
||||
- ADDRESS_MODEL=64
|
||||
- BUILD_SYSTEM=cmake
|
||||
- PATH=$PWD/cmake/bin:$PATH
|
||||
addons: &ao_gcc5
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: *gcc5_pkgs
|
||||
|
||||
# Clang/UndefinedBehaviourSanitizer
|
||||
- compiler: clang
|
||||
@@ -54,7 +55,6 @@ matrix:
|
||||
- BUILD_SYSTEM=cmake
|
||||
- PATH=$PWD/cmake/bin:$PATH
|
||||
- PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
||||
addons: *ao_gcc5
|
||||
|
||||
# Clang/AddressSanitizer
|
||||
- compiler: clang
|
||||
@@ -64,7 +64,6 @@ matrix:
|
||||
- CLANG_VER=3.8
|
||||
- ADDRESS_MODEL=64
|
||||
- PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
||||
addons: *ao_gcc5
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@@ -77,7 +76,7 @@ before_install:
|
||||
- scripts/install-dependencies.sh
|
||||
|
||||
script:
|
||||
- scripts/build-and-test.sh
|
||||
- travis_retry scripts/build-and-test.sh
|
||||
|
||||
after_script:
|
||||
- cat nohup.out || echo "nohup.out already deleted"
|
||||
|
||||
@@ -1,3 +1,274 @@
|
||||
1.0.0-b30
|
||||
|
||||
WebSocket
|
||||
|
||||
* Fix race in pings during reads
|
||||
* Fix race in close frames during reads
|
||||
* Fix race when write suspends
|
||||
* Allow concurrent websocket async ping and writes
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b29
|
||||
|
||||
* Fix compilation error in non-template class
|
||||
* Document type-pun in buffer_cat
|
||||
* Correctly check ostream modifier (/extras)
|
||||
|
||||
HTTP
|
||||
|
||||
* Fix Body requirements doc
|
||||
* Fix illegal HTTP characters accepted as hex zero
|
||||
* Fix Writer return value documentation
|
||||
|
||||
WebSocket
|
||||
|
||||
* Fix race in writes during reads
|
||||
* Fix doc link typo
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b28
|
||||
|
||||
* Split out and rename test stream classes
|
||||
* Restyle async result constructions
|
||||
* Fix HTTP split parse edge case
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b27
|
||||
|
||||
* Tidy up tests and docs
|
||||
* Add documentation building instructions
|
||||
|
||||
API Changes:
|
||||
|
||||
* Invoke callback on pings and pongs
|
||||
* Move basic_streambuf to streambuf.hpp
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b26
|
||||
|
||||
* Tidy up warnings and tests
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b25
|
||||
|
||||
* Fixes for WebSocket echo server
|
||||
* Fix 32-bit arm7 warnings
|
||||
* Remove unnecessary include
|
||||
* WebSocket server examples and test tidying
|
||||
* Fix deflate setup bug
|
||||
|
||||
API Changes:
|
||||
|
||||
* Better handler_ptr
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b24
|
||||
|
||||
* bjam use clang on MACOSX
|
||||
* Simplify Travis package install specification
|
||||
* Add optional yield_to arguments
|
||||
* Make decorator copyable
|
||||
* Add WebSocket permessage-deflate extension support
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b23
|
||||
|
||||
* Tune websocket echo server for performance
|
||||
* Add file and line number to thrown exceptions
|
||||
* Better logging in async echo server
|
||||
* Add copy special members
|
||||
* Fix message constructor and special members
|
||||
* Travis CI improvements
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b22
|
||||
|
||||
* Fix broken Intellisense
|
||||
* Implement the Asio deallocation-before-invocation guarantee
|
||||
* Add handler helpers
|
||||
* Avoid copies in handler_alloc
|
||||
* Update README.md example programs
|
||||
* Fix websocket stream read documentation
|
||||
* Disable Boost.Coroutine deprecation warning
|
||||
* Update documentation examples
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b21
|
||||
|
||||
* Remove extraneous includes
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b20
|
||||
|
||||
ZLib
|
||||
|
||||
* Add ZLib module
|
||||
|
||||
API Changes:
|
||||
|
||||
* Rename HTTP identifiers
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b19
|
||||
|
||||
* Boost library min/max guidance
|
||||
* Improvements to code coverage
|
||||
* Use boost::lexical_cast instead of std::to_string
|
||||
* Fix prepare_buffers value_type
|
||||
* Fix consuming_buffers value_type
|
||||
* Better buffer_cat
|
||||
|
||||
HTTP
|
||||
|
||||
* Make chunk_encode public
|
||||
* Add write, async_write, operator<< for message_headers
|
||||
* Add read, async_read for message_headers
|
||||
* Fix with_body example
|
||||
|
||||
WebSocket
|
||||
|
||||
* Optimize utf8 validation
|
||||
* Optimize mask operations
|
||||
|
||||
API Changes:
|
||||
|
||||
* Refactor message and message_headers declarations
|
||||
* prepared_buffers is private
|
||||
* consume_buffers is removed
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b18
|
||||
|
||||
* Increase optimization settings for MSVC builds
|
||||
|
||||
HTTP
|
||||
|
||||
* Check invariants in parse_op:
|
||||
* Clean up message docs
|
||||
|
||||
WebSocket
|
||||
|
||||
* Write buffer option does not change capacity
|
||||
* Close connection during async_read on close frame
|
||||
* Add pong, async pong to stream
|
||||
|
||||
Core
|
||||
|
||||
* Meet DynamicBuffer requirements for static_streambuf
|
||||
* Fix write_frame masking and auto-fragment handling
|
||||
|
||||
Extras
|
||||
|
||||
* unit_test::suite fixes:
|
||||
- New overload of fail() specifies file and line
|
||||
- BEAST_EXPECTS only evaluates the reason string on a failure
|
||||
* Add zlib module
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b17
|
||||
|
||||
* Change implicit to default value in example
|
||||
* Tidy up some declarations
|
||||
* Fix basic_streambuf::capacity
|
||||
* Add basic_streambuf::alloc_size
|
||||
* Parser callbacks may not throw
|
||||
* Fix Reader concept doc typo
|
||||
* Add is_Reader trait
|
||||
* Tidy up basic_headers for documentation
|
||||
* Tidy up documentation
|
||||
* Add basic_parser_v1::reset
|
||||
* Fix handling of body_what::pause in basic_parser_v1
|
||||
* Add headers_parser
|
||||
* Engaged invokable is destructible
|
||||
* Improve websocket example in README.md
|
||||
* Refactor read_size_helper
|
||||
|
||||
API Changes:
|
||||
|
||||
* Added init() to Reader requirements
|
||||
* Reader must be nothrow constructible
|
||||
* Reader is now constructed right before reading the body
|
||||
- The message passed on construction is filled in
|
||||
* Rework HTTP concepts:
|
||||
- Writer uses write instead of operator()
|
||||
- Refactor traits to use void_t
|
||||
- Remove is_ReadableBody, is_WritableBody
|
||||
- Add has_reader, has_writer, is_Reader, is_Writer
|
||||
- More friendly compile errors on failed concept checks
|
||||
* basic_parser_v1 requires all callbacks present
|
||||
* on_headers parser callback now returns void
|
||||
* on_body_what is a new required parser callback returning body_what
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b16
|
||||
|
||||
* Make value optional in param-list
|
||||
* Frame processing routines are member functions
|
||||
* Fix on_headers called twice from basic_parser_v1
|
||||
* Constrain parser_v1 constructor
|
||||
* Improve first line serialization
|
||||
* Add pause option to on_headers interface
|
||||
* Refactor base_parser_v1 callback traits:
|
||||
* Refine Parser concept
|
||||
* Relax ForwardIterator requirements in FieldSequence
|
||||
* Fix websocket failure testing
|
||||
* Refine Writer concept and fix exemplar in documentation
|
||||
|
||||
API Changes:
|
||||
|
||||
* Rename mask_buffer_size to write_buffer_size
|
||||
* Make auto_fragment a boolean option
|
||||
|
||||
The message class hierarchy is refactored (breaking change):
|
||||
|
||||
* One message class now models both HTTP/1 and HTTP/2 messages
|
||||
* message_v1, request_v1, response_v1 removed
|
||||
* New classes basic_request and basic_response model
|
||||
messages without the body.
|
||||
|
||||
Error resolution: Callers should use message, request,
|
||||
and response instead of message_v1, request_v1, and
|
||||
response_v1 respectively.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b15
|
||||
|
||||
* rfc7230 section 3.3.2 compliance
|
||||
* Add HTTPS example
|
||||
* Add Secure WebSocket example
|
||||
* Fix message_v1 constructor
|
||||
* Tidy up DynamicBuffer requirements
|
||||
* Tidy up error types and headers
|
||||
* Fix handling empty HTTP headers in parser_v1
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b14
|
||||
|
||||
* Add missing rebind to handler_alloc
|
||||
* Fix error handling in http server examples
|
||||
* Fix CMake scripts for MinGW
|
||||
* Use BOOST_ASSERT
|
||||
* Better WebSocket decorator
|
||||
* Update and tidy documentation
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b13
|
||||
|
||||
* dstream improvements
|
||||
|
||||
@@ -6,21 +6,52 @@ project (Beast)
|
||||
|
||||
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
if (WIN32)
|
||||
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")
|
||||
if (MSVC)
|
||||
# /wd4244 /wd4127
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /MP /W4 /wd4100 /bigobj /D _WIN32_WINNT=0x0601 /D _SCL_SECURE_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
||||
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /Oi /Ot /GL /MT")
|
||||
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Oi /Ot /MT")
|
||||
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
||||
set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
|
||||
# for RelWithDebInfo builds, disable incremental linking
|
||||
# since CMake sets it ON by default for that build type and it
|
||||
# causes warnings
|
||||
string (REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" replacement_flags
|
||||
${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO})
|
||||
set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO ${replacement_flags})
|
||||
|
||||
else()
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
find_package(Boost REQUIRED COMPONENTS coroutine context thread filesystem program_options system)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||
link_directories(${Boost_LIBRARY_DIR})
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads)
|
||||
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wpedantic")
|
||||
"${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter")
|
||||
endif()
|
||||
|
||||
add_definitions ("-DBOOST_COROUTINES_NO_DEPRECATION_WARNING")
|
||||
|
||||
if (APPLE AND NOT DEFINED ENV{OPENSSL_ROOT_DIR})
|
||||
find_program(HOMEBREW brew)
|
||||
if (NOT HOMEBREW STREQUAL "HOMEBREW-NOTFOUND")
|
||||
execute_process(COMMAND brew --prefix openssl
|
||||
OUTPUT_VARIABLE OPENSSL_ROOT_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(OpenSSL)
|
||||
|
||||
if (MINGW)
|
||||
link_libraries(${Boost_LIBRARIES} ws2_32 mswsock)
|
||||
endif()
|
||||
|
||||
if ("${VARIANT}" STREQUAL "coverage")
|
||||
@@ -53,7 +84,6 @@ function(DoGroupSources curdir rootdir folder)
|
||||
source_group("" FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
||||
else()
|
||||
string(REGEX REPLACE ^${rootdir} ${folder} groupname ${curdir})
|
||||
#set(groupname ${curdir})
|
||||
string(REPLACE "/" "\\" groupname ${groupname})
|
||||
source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
||||
endif()
|
||||
@@ -67,6 +97,29 @@ endfunction()
|
||||
include_directories (extras)
|
||||
include_directories (include)
|
||||
|
||||
set(ZLIB_SOURCES
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/crc32.h
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/deflate.h
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/inffast.h
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/inffixed.h
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/inflate.h
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/inftrees.h
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/trees.h
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/zlib.h
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/zutil.h
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/adler32.c
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/compress.c
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/crc32.c
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/deflate.c
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/infback.c
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/inffast.c
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/inflate.c
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/inftrees.c
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/trees.c
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/uncompr.c
|
||||
${PROJECT_SOURCE_DIR}/test/zlib/zlib-1.2.8/zutil.c
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE BEAST_INCLUDES
|
||||
${PROJECT_SOURCE_DIR}/include/beast/*.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/beast/*.ipp
|
||||
@@ -78,7 +131,14 @@ file(GLOB_RECURSE EXTRAS_INCLUDES
|
||||
)
|
||||
|
||||
add_subdirectory (examples)
|
||||
if (NOT OPENSSL_FOUND)
|
||||
message("OpenSSL not found. Not building examples/ssl")
|
||||
else()
|
||||
add_subdirectory (examples/ssl)
|
||||
endif()
|
||||
|
||||
add_subdirectory (test)
|
||||
add_subdirectory (test/core)
|
||||
add_subdirectory (test/http)
|
||||
add_subdirectory (test/websocket)
|
||||
add_subdirectory (test/zlib)
|
||||
|
||||
@@ -37,7 +37,7 @@ else if [ os.name ] = HAIKU
|
||||
if [ os.name ] = NT
|
||||
{
|
||||
lib ssl : : <name>ssleay32 ;
|
||||
lib crypto : : <name>libeay32 ;
|
||||
lib crypto : : <name>libeay32 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -45,6 +45,11 @@ else
|
||||
lib crypto ;
|
||||
}
|
||||
|
||||
if [ os.name ] = MACOSX
|
||||
{
|
||||
using clang : : ;
|
||||
}
|
||||
|
||||
variant coverage
|
||||
:
|
||||
debug
|
||||
@@ -87,20 +92,20 @@ project beast
|
||||
<library>/boost/coroutine//boost_coroutine
|
||||
<library>/boost/filesystem//boost_filesystem
|
||||
<library>/boost/program_options//boost_program_options
|
||||
# <library>ssl
|
||||
# <library>crypto
|
||||
<define>BOOST_ALL_NO_LIB=1
|
||||
<define>BOOST_SYSTEM_NO_DEPRECATED=1
|
||||
<threading>multi
|
||||
<link>static
|
||||
<runtime-link>shared
|
||||
<debug-symbols>on
|
||||
<toolset>gcc:<cxxflags>-std=c++11
|
||||
<toolset>gcc:<cxxflags>-Wno-unused-variable
|
||||
<toolset>gcc:<cxxflags>-Wno-unused-parameter
|
||||
<toolset>clang:<cxxflags>-std=c++11
|
||||
<toolset>clang:<cxxflags>-Wno-unused-parameter
|
||||
<toolset>gcc:<cxxflags>-Wno-unused-variable # Temporary until we can figure out -isystem
|
||||
<toolset>clang:<cxxflags>-Wno-unused-variable # Temporary until we can figure out -isystem
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
||||
<toolset>msvc:<cxxflags>-bigobj
|
||||
<toolset>msvc:<cxxflags>"/wd4100 /bigobj"
|
||||
<toolset>msvc,<variant>release:<cxxflags>"/Ob2 /Oi /Ot"
|
||||
<os>LINUX:<define>_XOPEN_SOURCE=600
|
||||
<os>LINUX:<define>_GNU_SOURCE=1
|
||||
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
||||
@@ -113,12 +118,7 @@ project beast
|
||||
<os>NT,<toolset>gcc:<library>ws2_32
|
||||
<os>NT,<toolset>gcc:<library>mswsock
|
||||
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
|
||||
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
|
||||
<os>HPUX:<library>ipv6
|
||||
<os>QNXNTO:<library>socket
|
||||
<os>HAIKU:<library>network
|
||||
: usage-requirements
|
||||
<include>.
|
||||
:
|
||||
build-dir bin
|
||||
;
|
||||
|
||||
@@ -8,20 +8,15 @@
|
||||
(https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/) [![License]
|
||||
(https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)
|
||||
|
||||
# HTTP and WebSocket implementations built on Boost.Asio
|
||||
# HTTP and WebSocket built on Boost.Asio in C++11
|
||||
|
||||
---
|
||||
|
||||
## CppCon 2016
|
||||
## Appearances
|
||||
|
||||
I will be giving a lightning talk on Beast at CppCon 2016 in Bellevue,
|
||||
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
|
||||
| <a href="http://cppcast.com/2017/01/vinnie-falco/">CppCast 2017</a> | <a href="https://raw.githubusercontent.com/vinniefalco/Beast/master/doc/images/CppCon2016.pdf">CppCon 2016</a> |
|
||||
| ------------ | ----------- |
|
||||
| <a href="http://cppcast.com/2017/01/vinnie-falco/"><img width="180" height="180" alt="Vinnie Falco" src="https://avatars1.githubusercontent.com/u/1503976?v=3&u=76c56d989ef4c09625256662eca2775df78a16ad&s=180"></a> | <a href="https://www.youtube.com/watch?v=uJZgRcvPFwI"><img width="320" height = "180" alt="Beast" src="https://raw.githubusercontent.com/vinniefalco/Beast/master/doc/images/CppCon2016.png"></a> |
|
||||
|
||||
---
|
||||
|
||||
@@ -96,7 +91,7 @@ using the `git subtree` or `git submodule` commands). Then, edit your
|
||||
build scripts to add the `include/` directory to the list of paths checked
|
||||
by the C++ compiler when searching for includes. Beast `#include` lines
|
||||
will look like this:
|
||||
```
|
||||
```C++
|
||||
#include <beast/http.hpp>
|
||||
#include <beast/websocket.hpp>
|
||||
```
|
||||
@@ -137,6 +132,7 @@ The files in the repository are laid out thusly:
|
||||
./
|
||||
bin/ Holds executables and project files
|
||||
bin64/ Holds 64-bit Windows executables and project files
|
||||
doc/ Source code and scripts for the documentation
|
||||
include/ Add this to your compiler includes
|
||||
beast/
|
||||
extras/ Additional APIs, may change
|
||||
@@ -171,14 +167,14 @@ int main()
|
||||
// WebSocket connect and send message using beast
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
ws.handshake(host, "/");
|
||||
ws.write(boost::asio::buffer("Hello, world!"));
|
||||
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||
|
||||
// Receive WebSocket message, print and close using beast
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(beast::websocket::close_code::normal);
|
||||
std::cout << to_string(sb.data()) << "\n";
|
||||
std::cout << beast::to_string(sb.data()) << "\n";
|
||||
}
|
||||
```
|
||||
|
||||
@@ -186,6 +182,7 @@ Example HTTP program:
|
||||
```C++
|
||||
#include <beast/http.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@@ -200,18 +197,19 @@ int main()
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||
|
||||
// Send HTTP request using beast
|
||||
beast::http::request_v1<beast::http::empty_body> req;
|
||||
beast::http::request<beast::http::empty_body> req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
||||
req.headers.replace("User-Agent", "Beast");
|
||||
req.fields.replace("Host", host + ":" +
|
||||
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||
req.fields.replace("User-Agent", "Beast");
|
||||
beast::http::prepare(req);
|
||||
beast::http::write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
beast::streambuf sb;
|
||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
||||
beast::http::response<beast::http::streambuf_body> resp;
|
||||
beast::http::read(sock, sb, resp);
|
||||
std::cout << resp;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ Core:
|
||||
* Complete allocator testing in basic_streambuf
|
||||
|
||||
WebSocket:
|
||||
* Minimize sizeof(websocket::stream)
|
||||
* Move check for message size limit to account for compression
|
||||
* more invokable unit test coverage
|
||||
* More control over the HTTP request and response during handshakes
|
||||
* optimized versions of key/masking, choose prepared_key size
|
||||
|
||||
22
src/beast/doc/Dockerfile
Normal file
22
src/beast/doc/Dockerfile
Normal file
@@ -0,0 +1,22 @@
|
||||
FROM ubuntu:16.04
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install build-essential g++ git libbz2-dev wget python-dev
|
||||
|
||||
# Install Boost
|
||||
ENV BOOST_SHA 440a59f8bc4023dbe6285c9998b0f7fa288468b889746b1ef00e8b36c559dce1
|
||||
RUN wget https://sourceforge.net/projects/boost/files/boost/1.62.0/boost_1_62_0.tar.gz
|
||||
RUN echo "$BOOST_SHA boost_1_62_0.tar.gz" | sha256sum -c
|
||||
RUN tar xzf boost_1_62_0.tar.gz
|
||||
RUN cd boost_1_62_0 && ./bootstrap.sh --prefix=/usr/local
|
||||
RUN cd boost_1_62_0 && ./b2 install
|
||||
ENV BOOST_ROOT=/boost_1_62_0
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get -y install doxygen
|
||||
RUN apt-get -y install xsltproc
|
||||
|
||||
CMD cd /opt/beast/doc && \
|
||||
chmod +x makeqbk.sh && \
|
||||
./makeqbk.sh && \
|
||||
$BOOST_ROOT/b2
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
# Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -15,15 +15,15 @@ using boostbook ;
|
||||
using quickbook ;
|
||||
using doxygen ;
|
||||
|
||||
xml beast_boostbook : master.qbk ;
|
||||
import quickbook ;
|
||||
|
||||
path-constant out : . ;
|
||||
path-constant here : . ;
|
||||
|
||||
install stylesheets
|
||||
:
|
||||
$(broot)/doc/src/boostbook.css
|
||||
:
|
||||
<location>$(out)/html
|
||||
<location>$(here)/html
|
||||
;
|
||||
|
||||
explicit stylesheets ;
|
||||
@@ -35,7 +35,7 @@ install images
|
||||
images/body.png
|
||||
images/message.png
|
||||
:
|
||||
<location>$(out)/html/images
|
||||
<location>$(here)/html/images
|
||||
;
|
||||
|
||||
explicit images ;
|
||||
@@ -44,40 +44,54 @@ install callouts
|
||||
:
|
||||
[ glob $(broot)/doc/src/images/callouts/*.png ]
|
||||
:
|
||||
<location>$(out)/html/images/callouts
|
||||
<location>$(here)/html/images/callouts
|
||||
;
|
||||
|
||||
explicit callout ;
|
||||
|
||||
boostbook doc
|
||||
install examples
|
||||
:
|
||||
beast_boostbook
|
||||
[ glob
|
||||
../examples/*.cpp
|
||||
../examples/*.hpp
|
||||
../examples/ssl/*.cpp
|
||||
../examples/ssl/*.hpp
|
||||
]
|
||||
:
|
||||
<xsl:param>chapter.autolabel=0
|
||||
<xsl:param>boost.image.src=images/beast.png
|
||||
<xsl:param>boost.image.alt="Beast Logo"
|
||||
<xsl:param>boost.image.w=2400
|
||||
<xsl:param>boost.image.h=80
|
||||
<xsl:param>boost.root=$(broot)
|
||||
<xsl:param>chapter.autolabel=0
|
||||
<xsl:param>chunk.first.sections=1 # Chunk the first top-level section?
|
||||
<xsl:param>chunk.section.depth=8 # Depth to which sections should be chunked
|
||||
<xsl:param>generate.section.toc.level=1 # Control depth of TOC generation in sections
|
||||
<xsl:param>toc.max.depth=2 # How many levels should be created for each TOC?
|
||||
<xsl:param>toc.section.depth=2 # How deep should recursive sections appear in the TOC?
|
||||
:
|
||||
<location>temp
|
||||
<dependency>stylesheets
|
||||
<dependency>images
|
||||
<location>$(here)/html/examples
|
||||
;
|
||||
|
||||
#explicit doc ;
|
||||
# <xsl:param>nav.layout=none
|
||||
# <format>html:<xsl:param>location=../bin/doc/html
|
||||
# <xsl:param>generate.toc="chapter nop section nop"
|
||||
# <xsl:param>root.filename=index
|
||||
# <xsl:param>output-root="../bin/html"
|
||||
explicit examples ;
|
||||
|
||||
xml doc
|
||||
:
|
||||
master.qbk
|
||||
:
|
||||
<location>temp
|
||||
<include>$(broot)/tools/boostbook/dtd
|
||||
;
|
||||
|
||||
boostbook boostdoc
|
||||
:
|
||||
doc
|
||||
:
|
||||
<xsl:param>boost.root=$(broot)
|
||||
<xsl:param>boost.image.src=images/beast.png
|
||||
<xsl:param>boost.image.alt="Beast Logo"
|
||||
<xsl:param>boost.image.w=1330
|
||||
<xsl:param>boost.image.h=80
|
||||
<xsl:param>chapter.autolabel=0
|
||||
<xsl:param>chunk.section.depth=8 # Depth to which sections should be chunked
|
||||
<xsl:param>chunk.first.sections=1 # Chunk the first top-level section?
|
||||
<xsl:param>toc.section.depth=8 # How deep should recursive sections appear in the TOC?
|
||||
<xsl:param>toc.max.depth=8 # How many levels should be created for each TOC?
|
||||
<xsl:param>generate.section.toc.level=8 # Control depth of TOC generation in sections
|
||||
<xsl:param>generate.toc="chapter nop section nop"
|
||||
<include>$(broot)/tools/boostbook/dtd
|
||||
:
|
||||
<location>temp
|
||||
<dependency>examples
|
||||
<dependency>images
|
||||
<dependency>stylesheets
|
||||
;
|
||||
|
||||
#[include reference.qbk]
|
||||
#[xinclude index.xml]
|
||||
72
src/beast/doc/README.md
Normal file
72
src/beast/doc/README.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Building documentation
|
||||
|
||||
## Specifying Files
|
||||
|
||||
To specify the source files for which to build documentation, modify `INPUT`
|
||||
and its related fields in `doc/source.dox`. Note that the `INPUT` paths are
|
||||
relative to the `doc/` directory.
|
||||
|
||||
## Install Dependencies
|
||||
|
||||
### Windows
|
||||
|
||||
Install these dependencies:
|
||||
|
||||
1. Install [Doxygen](http://www.stack.nl/~dimitri/doxygen/download.html)
|
||||
2. Download the following zip files from [xsltproc](https://www.zlatkovic.com/pub/libxml/)
|
||||
(Alternate download: ftp://ftp.zlatkovic.com/libxml/),
|
||||
and extract the `bin\` folder contents into any folder in your path.
|
||||
* iconv
|
||||
* libxml2
|
||||
* libxslt
|
||||
* zlib
|
||||
3. Download [Boost](http://www.boost.org/users/download/)
|
||||
1. Extract the compressed file contents to your (new) `$BOOST_ROOT` location.
|
||||
2. Open a command prompt or shell in the `$BOOST_ROOT`.
|
||||
3. `./bootstrap.bat`
|
||||
4. If it is not already there, add your `$BOOST_ROOT` to your environment `$PATH`.
|
||||
|
||||
### MacOS
|
||||
|
||||
1. Install doxygen:
|
||||
* Use homebrew to install: `brew install doxygen`. The executable will be
|
||||
installed in `/usr/local/bin` which is already in your path.
|
||||
* Alternatively, install from here: [doxygen](http://www.stack.nl/~dimitri/doxygen/download.html).
|
||||
You'll then need to make doxygen available to your command line. You can
|
||||
do this by adding a symbolic link from `/usr/local/bin` to the doxygen
|
||||
executable. For example, `$ ln -s /Applications/Doxygen.app/Contents/Resources/doxygen /usr/local/bin/doxygen`
|
||||
2. Install [Boost](http://www.boost.org/users/download/)
|
||||
1. Extract the compressed file contents to your (new) `$BOOST_ROOT` location.
|
||||
2. Open a command prompt or shell in the `$BOOST_ROOT`.
|
||||
3. `$ ./bootstrap.bat`
|
||||
4. If it is not already there, add your `$BOOST_ROOT` to your environment
|
||||
`$PATH`. This makes the `b2` command available to the command line.
|
||||
3. That should be all that's required. In OS X 10.11, at least, libxml2 and
|
||||
libxslt come pre-installed.
|
||||
|
||||
### Linux
|
||||
|
||||
1. Install [Docker](https://docs.docker.com/engine/installation/)
|
||||
2. Build Docker image. From the Beast root folder:
|
||||
```
|
||||
sudo docker build -t beast-docs doc/
|
||||
```
|
||||
|
||||
## Do it
|
||||
|
||||
### Windows & MacOS
|
||||
|
||||
From the Beast root folder:
|
||||
```
|
||||
cd doc
|
||||
./makeqbk.sh && b2
|
||||
```
|
||||
The output will be in `doc/html`.
|
||||
|
||||
### Linux
|
||||
|
||||
From the Beast root folder:
|
||||
```
|
||||
sudo docker run -v $PWD:/opt/beast --rm beast-docs
|
||||
```
|
||||
The output will be in `doc/html`.
|
||||
@@ -1,48 +1,56 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:design Design choices]
|
||||
[section:design Design Choices]
|
||||
|
||||
[block '''
|
||||
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||
<member><link linkend="beast.design.http">HTTP FAQ</link></member>
|
||||
<member><link linkend="beast.design.websocket">WebSocket FAQ</link></member>
|
||||
<member><link linkend="beast.design.websocketpp">Comparison to Zaphoyd Studios WebSocket++</link></member>
|
||||
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||
''']
|
||||
|
||||
The implementations are driven by business needs of cryptocurrency server
|
||||
applications (e.g. [@https://ripple.com Ripple]) written in C++. These
|
||||
needs were not met by existing solutions so Beast was written from scratch
|
||||
as a solution. Beast's design philosophy avoid flaws exhibited by other
|
||||
as a solution. Beast's design philosophy avoids flaws exhibited by other
|
||||
libraries:
|
||||
|
||||
* Don't try to do too much.
|
||||
|
||||
* Don't sacrifice performance.
|
||||
|
||||
* Don't do too much, otherwise interfaces become rigid.
|
||||
* Mimic Boost.Asio; familiarity breeds confidence.
|
||||
|
||||
* Symmetric interfaces (client and server the same, or close to it).
|
||||
* Role-symmetric interfaces; client and server the same (or close to it).
|
||||
|
||||
* Emulate Boost.Asio interfaces as much as possible, since Asio is
|
||||
proven and it is familiar to users.
|
||||
* Leave important decisions to the user, such as allocating memory or
|
||||
managing flow control.
|
||||
|
||||
* Let library users make the important decisions such as how to
|
||||
allocate memory or how to leverage flow control.
|
||||
|
||||
Beast uses the [link beast.types.DynamicBuffer [*`DynamicBuffer`]] concept
|
||||
presented in the Netwoking TS, and relies heavily on the Boost.Asio
|
||||
[*`ConstBufferSequence`] and [*`MutableBufferSequence`] concepts for passing
|
||||
buffers to functions. The authors have found the dynamic buffer and buffer
|
||||
sequence interfaces to be optimal for interacting with Asio, and for other
|
||||
tasks such as incremental parsing of data in buffers (for example, parsing
|
||||
websocket frames stored in a [link beast.ref.static_streambuf `static_streambuf`]).
|
||||
Beast uses the __DynamicBuffer__ concept presented in the Networking TS
|
||||
(__N4588__), and relies heavily on the Boost.Asio __ConstBufferSequence__
|
||||
and __MutableBufferSequence__ concepts for passing buffers to functions.
|
||||
The authors have found the dynamic buffer and buffer sequence interfaces to
|
||||
be optimal for interacting with Asio, and for other tasks such as incremental
|
||||
parsing of data in buffers (for example, parsing websocket frames stored
|
||||
in a [link beast.ref.static_streambuf `static_streambuf`]).
|
||||
|
||||
During the development of Beast the authors have studied other software
|
||||
packages and in particular the comments left during the Boost Review process
|
||||
of other packages offering similar functionality. In this section we attempt
|
||||
to address those issues.
|
||||
of other packages offering similar functionality. In this section and the
|
||||
FAQs that follow we attempt to answer those questions that are also applicable
|
||||
to Beast.
|
||||
|
||||
[variablelist
|
||||
[[
|
||||
"I would also like to see instances of this library being used
|
||||
in production. That would give some evidence that the design
|
||||
works in practice.""
|
||||
works in practice."
|
||||
][
|
||||
Beast.HTTP and Beast.WebSocket are production ready and currently
|
||||
running on public servers receiving traffic and handling millions of
|
||||
@@ -56,25 +64,26 @@ to address those issues.
|
||||
]
|
||||
|
||||
|
||||
[section:http HTTP]
|
||||
|
||||
For HTTP we to model the message to maximize flexibility of implementation
|
||||
[section:http HTTP FAQ]
|
||||
|
||||
For HTTP we model the message to maximize flexibility of implementation
|
||||
strategies while allowing familiar verbs such as [*`read`] and [*`write`].
|
||||
The HTTP interface is further driven by the needs of the WebSocket module,
|
||||
as a WebSocket session requires a HTTP Upgrade handshake exchange at the
|
||||
start. Other design goals:
|
||||
|
||||
* Don't try to invent a complete web server or client
|
||||
* Keep it simple.
|
||||
|
||||
* Have simple free functions to send and receive messages.
|
||||
* Stay low level; don't invent a whole web server or client.
|
||||
|
||||
* Allow the message object to be customized,
|
||||
* Allow for customizations, if the user needs it.
|
||||
|
||||
[variablelist
|
||||
|
||||
[[
|
||||
"Some more advanced examples, e.g. including TLS with client/server
|
||||
certificates would help.""
|
||||
certificates would help."
|
||||
][
|
||||
The HTTP interface doesn't try to reinvent the wheel, it just uses
|
||||
the `boost::asio::ip::tcp::socket` or `boost::asio::ssl::stream` that
|
||||
@@ -94,7 +103,7 @@ start. Other design goals:
|
||||
]]
|
||||
|
||||
[[
|
||||
"Cookies? Forms/File Uploads?""
|
||||
"Cookies? Forms/File Uploads?"
|
||||
][
|
||||
Cookies, or managing these types of HTTP headers in general, is the
|
||||
responsibility of higher levels. Beast.HTTP just tries to get complete
|
||||
@@ -107,7 +116,7 @@ start. Other design goals:
|
||||
|
||||
[[
|
||||
"...supporting TLS (is this a feature? If not this would be a show-stopper),
|
||||
etc.
|
||||
etc."
|
||||
][
|
||||
Beast.HTTP does not provide direct facilities for implementing TLS
|
||||
connections; however, the interfaces already existing on the
|
||||
@@ -126,17 +135,24 @@ start. Other design goals:
|
||||
over Asio. Such an implementation should serve as a building block upon
|
||||
which higher abstractions such as the aforementioned HTTP service or
|
||||
cgi-gateway can be built.
|
||||
|
||||
One of the example programs implements a simple HTTP server that
|
||||
delivers files from the filesystem.
|
||||
]]
|
||||
|
||||
[[
|
||||
"You should send a 100-continue to ask for the rest of the body if required."
|
||||
][
|
||||
These behaviors are best left to the calling software. A future library
|
||||
can build on Beast.HTTP to provide these behaviors.
|
||||
The Beast interface needs to support this functionality (by allowing this
|
||||
special case of partial message parsing and serialization). Specifically,
|
||||
it should let callers read the request up to just before the body,
|
||||
and let callers write the request up to just before the body. However,
|
||||
making use of this behavior should be up to callers (since Beast is low
|
||||
level).
|
||||
]]
|
||||
|
||||
[[
|
||||
"What about HTTP/2?""
|
||||
"What about HTTP/2?"
|
||||
][
|
||||
Many reviewers feel that HTTP/2 support is an essential feature of
|
||||
a HTTP library. The authors agree that HTTP/2 is important but also
|
||||
@@ -145,13 +161,13 @@ start. Other design goals:
|
||||
and 1.1.
|
||||
|
||||
The Beast.HTTP message model is suitable for HTTP/2 and can be re-used.
|
||||
The IEFT HTTP Working Group adopted message compatiblity with HTTP/1.x
|
||||
The IETF HTTP Working Group adopted message compatiblity with HTTP/1.x
|
||||
as an explicit goal. A parser can simply emit full headers after
|
||||
decoding the compressed HTTP/2 headers. The stream ID is not logicaly
|
||||
decoding the compressed HTTP/2 headers. The stream ID is not logically
|
||||
part of the message but rather message metadata and should be
|
||||
communicated out-of-band (see below). HTTP/2 sessions begin with a
|
||||
traditional HTTP/1.1 Upgrade similar in fashion to the WebSocket
|
||||
upgrade. A HTTP/2 implementation can use existing Beast.HTTP primitives
|
||||
upgrade. An HTTP/2 implementation can use existing Beast.HTTP primitives
|
||||
to perform this handshake.
|
||||
|
||||
Free functions for HTTP/2 sessions are not possible because of the
|
||||
@@ -167,10 +183,50 @@ start. Other design goals:
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:websocket WebSocket FAQ]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[
|
||||
What about message compression?
|
||||
][
|
||||
Beast WebSocket supports the permessage-deflate extension described in
|
||||
[@https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-00 draft-ietf-hybi-permessage-compression-00].
|
||||
The library comes with a header-only, C++11 port of ZLib's "deflate" codec
|
||||
used in the implementation of the permessage-deflate extension.
|
||||
]]
|
||||
|
||||
[[
|
||||
Where is the TLS/SSL interface?
|
||||
][
|
||||
The `websocket::stream` wraps the socket or stream that you provide
|
||||
(for example, a `boost::asio::ip::tcp::socket` or a
|
||||
`boost::asio::ssl::stream`). You establish your TLS connection using the
|
||||
interface on `ssl::stream` like shown in all of the Asio examples, then
|
||||
construct your `websocket::stream` around it. It works perfectly fine;
|
||||
Beast.WebSocket doesn't try to reinvent the wheel or put a fresh coat of
|
||||
interface paint on the `ssl::stream`.
|
||||
|
||||
The WebSocket implementation [*does] provide support for shutting down
|
||||
the TLS connection through the use of the ADL compile-time virtual functions
|
||||
[link beast.ref.websocket__teardown `teardown`] and
|
||||
[link beast.ref.websocket__async_teardown `async_teardown`]. These will
|
||||
properly close the connection as per rfc6455 and overloads are available
|
||||
for TLS streams. Callers may provide their own overloads of these functions
|
||||
for user-defined next layer types.
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:websocket WebSocket]
|
||||
|
||||
|
||||
[section:websocketpp Comparison to Zaphoyd Studios WebSocket++]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -208,21 +264,19 @@ start. Other design goals:
|
||||
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).
|
||||
(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].
|
||||
__AsyncReadStream__, __AsyncWriteStream__, __SyncReadStream__, __SyncWriteStream__.
|
||||
|
||||
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
|
||||
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
|
||||
@@ -283,8 +337,7 @@ start. Other design goals:
|
||||
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.
|
||||
through the __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
|
||||
@@ -314,7 +367,7 @@ start. Other design goals:
|
||||
|
||||
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
|
||||
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
|
||||
@@ -378,29 +431,27 @@ start. Other design goals:
|
||||
|
||||
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
|
||||
aggregation and 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
|
||||
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`).
|
||||
__DynamicBuffer__ (modeled after `boost::asio::streambuf`).
|
||||
|
||||
Beast comes with the class `beast::basic_streambuf`, an efficient
|
||||
implementation of the [*DynamicBuffer] concept which makes use of multiple
|
||||
Beast comes with the class __basic_streambuf__, an efficient
|
||||
implementation of the __DynamicBuffer__ concept which makes use of multiple
|
||||
allocated octet arrays. If an incoming message is broken up into
|
||||
multiple pieces, no reallocation occurs. Instead, new allocations are
|
||||
appended to the sequence when existing allocations are filled. Beast
|
||||
does not impose any particular memory management model on callers. The
|
||||
`basic_streambuf` provided by beast supports standard allocators through
|
||||
a template argument. Use the [*DynamicBuffer] that comes with beast,
|
||||
__basic_streambuf__ provided by beast supports standard allocators through
|
||||
a template argument. Use the __DynamicBuffer__ that comes with beast,
|
||||
customize the allocator if you desire, or provide your own type that
|
||||
meets the
|
||||
[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/basic_streambuf.hpp#L21 concept requirements].
|
||||
meets the requirements.
|
||||
|
||||
[table
|
||||
[
|
||||
@@ -596,44 +647,8 @@ start. Other design goals:
|
||||
]
|
||||
]]
|
||||
|
||||
[[
|
||||
What about message compression?
|
||||
][
|
||||
The author is currently porting ZLib 1.2.8 to modern, header-only C++11
|
||||
that does not use macros or try to support ancient architectures. This
|
||||
deflate implementation will be available as its own individually
|
||||
usable interface, and also will be used to power Beast WebSocket's
|
||||
permessage-deflate implementation, due Q4 of 2016.
|
||||
|
||||
However, Beast currently has sufficient functionality that users can
|
||||
begin taking advantage of the WebSocket protocol using this library
|
||||
immediately.
|
||||
]]
|
||||
|
||||
[[
|
||||
Where is the TLS/SSL interface?
|
||||
][
|
||||
The `websocket::stream` wraps the socket or stream that you provide
|
||||
(for example, a `boost::asio::ip::tcp::socket` or a
|
||||
`boost::asio::ssl::stream`). You establish your TLS connection using the
|
||||
interface on `ssl::stream` like shown in all of the Asio examples, they
|
||||
construct your `websocket::stream` around it. It works perfectly fine;
|
||||
Beast.WebSocket doesn't try to reinvent the wheel or put a fresh coat of
|
||||
interface paint on the `ssl::stream`.
|
||||
|
||||
The WebSocket implementation [*does] provides support for shutting down
|
||||
the TLS connection through the use of the ADL compile-time virtual functions
|
||||
[link beast.ref.websocket__teardown `teardown`] and
|
||||
[link beast.ref.websocket__async_teardown `async_teardown`]. These will
|
||||
properly close the connection as per rfc6455 and overloads are available
|
||||
for TLS streams. Callers may provide their own overloads of these functions
|
||||
for user-defined next layer types.
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
136
src/beast/doc/examples.qbk
Normal file
136
src/beast/doc/examples.qbk
Normal file
@@ -0,0 +1,136 @@
|
||||
[/
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:example Examples]
|
||||
|
||||
These usage examples are intended to quickly impress upon readers the
|
||||
flavor of the library. They are complete programs which may be built
|
||||
and run. Source code and build scripts for these programs may be found
|
||||
in the examples directory.
|
||||
|
||||
[heading HTTP GET]
|
||||
|
||||
Use HTTP to request the root page from a website and print the response:
|
||||
|
||||
```
|
||||
#include <beast/http.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Normal boost::asio setup
|
||||
std::string const host = "boost.org";
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::ip::tcp::resolver r{ios};
|
||||
boost::asio::ip::tcp::socket sock{ios};
|
||||
boost::asio::connect(sock,
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||
|
||||
// Send HTTP request using beast
|
||||
beast::http::request<beast::http::empty_body> req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.fields.replace("Host", host + ":" +
|
||||
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||
req.fields.replace("User-Agent", "Beast");
|
||||
beast::http::prepare(req);
|
||||
beast::http::write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
beast::streambuf sb;
|
||||
beast::http::response<beast::http::streambuf_body> resp;
|
||||
beast::http::read(sock, sb, resp);
|
||||
std::cout << resp;
|
||||
}
|
||||
```
|
||||
[heading WebSocket]
|
||||
|
||||
Establish a WebSocket connection, send a message and receive the reply:
|
||||
```
|
||||
#include <beast/core/to_string.hpp>
|
||||
#include <beast/websocket.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Normal boost::asio setup
|
||||
std::string const host = "echo.websocket.org";
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::ip::tcp::resolver r{ios};
|
||||
boost::asio::ip::tcp::socket sock{ios};
|
||||
boost::asio::connect(sock,
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||
|
||||
// WebSocket connect and send message using beast
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
ws.handshake(host, "/");
|
||||
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||
|
||||
// Receive WebSocket message, print and close using beast
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(beast::websocket::close_code::normal);
|
||||
std::cout << beast::to_string(sb.data()) << "\n";
|
||||
}
|
||||
```
|
||||
|
||||
[heading WebSocket Echo Server]
|
||||
|
||||
This example demonstrates both synchronous and asynchronous
|
||||
WebSocket server implementations.
|
||||
|
||||
* [@examples/websocket_async_echo_server.hpp]
|
||||
* [@examples/websocket_sync_echo_server.hpp]
|
||||
* [@examples/websocket_echo.cpp]
|
||||
|
||||
[heading Secure WebSocket]
|
||||
|
||||
Establish a WebSocket connection over an encrypted TLS connection,
|
||||
send a message and receive the reply. Requires OpenSSL to build.
|
||||
|
||||
* [@examples/websocket_ssl_example.cpp]
|
||||
|
||||
[heading HTTPS GET]
|
||||
|
||||
This example demonstrates sending and receiving HTTP messages
|
||||
over a TLS connection. Requires OpenSSL to build.
|
||||
|
||||
* [@examples/http_ssl_example.cpp]
|
||||
|
||||
[heading HTTP Crawl]
|
||||
|
||||
This example retrieves the page at each of the most popular domains
|
||||
as measured by Alexa.
|
||||
|
||||
* [@examples/http_crawl.cpp]
|
||||
|
||||
[heading HTTP Server]
|
||||
|
||||
This example demonstrates both synchronous and asynchronous server
|
||||
implementations. It also provides an example of implementing a [*Body]
|
||||
type, in `file_body`.
|
||||
|
||||
* [@examples/file_body.hpp]
|
||||
* [@examples/http_async_server.hpp]
|
||||
* [@examples/http_sync_server.hpp]
|
||||
* [@examples/http_server.cpp]
|
||||
|
||||
[heading Listings]
|
||||
|
||||
These are stand-alone listings of the HTTP and WebSocket examples.
|
||||
|
||||
* [@examples/http_example.cpp]
|
||||
* [@examples/websocket_example.cpp]
|
||||
|
||||
[endsect]
|
||||
@@ -1,142 +1,207 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:http HTTP]
|
||||
[/
|
||||
ideas:
|
||||
- complete send request walkthrough (client)
|
||||
- complete receive response walkthrough (client)
|
||||
- complete receive request walkthrough (server)
|
||||
- complete send response walkthrough (server)
|
||||
|
||||
Beast.HTTP offers programmers simple and performant models of HTTP messages and
|
||||
- Introduce concepts from simple to complex
|
||||
- Smooth progression of new ideas building on the previous ideas
|
||||
|
||||
- do we show a simplified message with collapsed fields?
|
||||
- do we introduce `header` or `message` first?
|
||||
|
||||
|
||||
contents:
|
||||
Message (and header, fields)
|
||||
Create request
|
||||
Create response
|
||||
Algorithms
|
||||
Write
|
||||
Read
|
||||
Parse
|
||||
Examples
|
||||
Send Request
|
||||
Receive Response
|
||||
Receive Request
|
||||
Send Response
|
||||
Advanced
|
||||
Responding to HEAD
|
||||
Expect: 100-continue
|
||||
Body (user defined)
|
||||
|
||||
|
||||
section beast.http.examples Examples
|
||||
|
||||
note
|
||||
In the example code which follows, `socket` refers to an object of type
|
||||
`boost::asio::ip::tcp::socket` which is currently connected to a remote peer.
|
||||
]
|
||||
|
||||
|
||||
|
||||
[section:http Using HTTP]
|
||||
|
||||
[block '''
|
||||
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||
<member><link linkend="beast.http.message">Message</link></member>
|
||||
<member><link linkend="beast.http.fields">Fields</link></member>
|
||||
<member><link linkend="beast.http.body">Body</link></member>
|
||||
<member><link linkend="beast.http.algorithms">Algorithms</link></member>
|
||||
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||
''']
|
||||
|
||||
Beast offers programmers simple and performant models of HTTP messages and
|
||||
their associated operations including synchronous and asynchronous reading and
|
||||
writing of messages in the HTTP/1 wire format using Boost.Asio.
|
||||
|
||||
The HTTP protocol is described fully in
|
||||
[@https://tools.ietf.org/html/rfc7230 rfc7230]
|
||||
|
||||
|
||||
|
||||
[section:motivation Motivation]
|
||||
|
||||
The HTTP protocol is pervasive in network applications. As C++ is a logical
|
||||
choice for high performance network servers, there is great utility in solid
|
||||
building blocks for manipulating, sending, and receiving HTTP messages
|
||||
compliant with the Hypertext Transfer Protocol and the supplements that
|
||||
follow. Unfortunately reliable implementations or industry standards do not
|
||||
exist in C++.
|
||||
|
||||
Beast.HTTP is built on Boost.Asio and uses its own robust header-only HTTP/1
|
||||
message parser modeled after the nodejs http-parser (written in C). A proposal
|
||||
to add networking functionality to the C++ standard library, based on
|
||||
Boost.Asio, is under consideration by the standards committee. Since the final
|
||||
approved networking interface for the C++ standard library will likely closely
|
||||
resemble the current interface of Boost.Asio, it is logical for Beast.HTTP to
|
||||
use Boost.Asio as its network transport.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:scope Scope]
|
||||
|
||||
This library is designed to be a building block for creating higher level
|
||||
libraries. It is not designed to be end-user facing. There is no convenient
|
||||
class that implements the core of a web server, nor is there a convenient
|
||||
class to quickly perform common operations such as fetching a file or
|
||||
connecting and retrieving a document from a secure connection. These
|
||||
use-cases are important, but this library does not try to do that. Instead,
|
||||
it offers primitives that can be used to build those user-facing algorithms.
|
||||
|
||||
A HTTP message (referred to hereafter as "message") contains request or
|
||||
response specific attributes, a series of zero or more name/value pairs
|
||||
(collectively termed "headers"), and a series of octets called the message
|
||||
body which may be zero in length. The HTTP protocol defines the client and
|
||||
server roles: clients send messages called requests and servers send back
|
||||
messages called responses. `http::message` models both requests and responses.
|
||||
Beast aims to offer this functionality:
|
||||
|
||||
* [*Model]: Provide a universal HTTP message class model.
|
||||
|
||||
* [*Build]: Construct a new message and manipulate its contents.
|
||||
|
||||
* [*Parse]: Deserialize a message from a network or memory stream in HTTP/1 wire format.
|
||||
|
||||
* [*Serialize]: Serialize a message into a network or memory stream in HTTP/1 wire format.
|
||||
|
||||
[note The documentation which follows assumes familiarity with
|
||||
both Boost.Asio and the HTTP protocol specification described in
|
||||
[@https://tools.ietf.org/html/rfc7230 rfc7230] ]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:usage Usage]
|
||||
writing of messages and headers in the HTTP/1 wire format using Boost.Asio.
|
||||
|
||||
[note
|
||||
Sample code and identifiers mentioned in this section are written
|
||||
as if the following declarations are in effect:
|
||||
The following documentation assumes familiarity with both Boost.Asio
|
||||
and the HTTP protocol specification described in __rfc7230__. Sample code
|
||||
and identifiers mentioned in this section are written as if the following
|
||||
declarations are in effect:
|
||||
```
|
||||
#include <beast/core.hpp>
|
||||
#include <beast/http.hpp>
|
||||
using namespace beast;
|
||||
using namespace beast::http;
|
||||
```
|
||||
]
|
||||
|
||||
|
||||
|
||||
In the paragraphs that follow we describe the available interfaces for
|
||||
performing typical operations such as interacting with a HTTP server
|
||||
or handling simple requests. Subsequent sections cover the message model
|
||||
and its customization points in more depth, for advanced applications.
|
||||
|
||||
[heading Declarations]
|
||||
|
||||
To do anything, a message must be declared. The message class template
|
||||
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
|
||||
kind of container used to represent the message body. Here we will
|
||||
declare a HTTP/1 request that has a `std::string` for the body container:
|
||||
[section:message Message]
|
||||
|
||||
The HTTP protocol defines the client and server roles: clients send messages
|
||||
called requests and servers send back messages called responses. A HTTP message
|
||||
(referred to hereafter as "message") contains request or response specific
|
||||
attributes (contained in the "Start Line"), a series of zero or more name/value
|
||||
pairs (collectively termed "Fields"), and an optional series of octets called
|
||||
the message body which may be zero in length. The start line for a HTTP request
|
||||
includes a string called the method, a string called the URL, and a version
|
||||
number indicating HTTP/1.0 or HTTP/1.1. For a response, the start line contains
|
||||
an integer status code and a string called the reason phrase. Alternatively, a
|
||||
HTTP message can be viewed as two parts: a header, followed by a body.
|
||||
|
||||
[note
|
||||
The Reason-Phrase is obsolete as of rfc7230.
|
||||
]
|
||||
|
||||
The __header__ class template models the header for HTTP/1 and HTTP/2 messages.
|
||||
This class template is a family of specializations, one for requests and one
|
||||
for responses, depending on the [*`isRequest`] template value.
|
||||
The [*`Fields`] template type determines the type of associative container
|
||||
used to store the field values. The provided __basic_fields__ class template
|
||||
and __fields__ type alias are typical choices for the [*`Fields`] type, but
|
||||
advanced applications may supply user defined types which meet the requirements.
|
||||
The __message__ class template models the header and optional body for HTTP/1
|
||||
and HTTP/2 requests and responses. It is derived from the __header__ class
|
||||
template with the same shared template parameters, and adds the `body` data
|
||||
member. The message class template requires an additional template argument
|
||||
type [*`Body`]. This type controls the container used to represent the body,
|
||||
if any, as well as the algorithms needed to serialize and parse bodies of
|
||||
that type.
|
||||
|
||||
This illustration shows the declarations and members of the __header__ and
|
||||
__message__ class templates, as well as the inheritance relationship:
|
||||
|
||||
[$images/message.png [width 650px] [height 390px]]
|
||||
|
||||
For notational convenience, these template type aliases are provided which
|
||||
supply typical choices for the [*`Fields`] type:
|
||||
```
|
||||
http::message_v1<true, http::string_body> req;
|
||||
using request_header = header<true, fields>;
|
||||
using response_header = header<false, fields>;
|
||||
|
||||
template<class Body, class Fields = fields>
|
||||
using request = message<true, Body, Fields>;
|
||||
|
||||
template<class Body, class Fields = fields>
|
||||
using response = message<false, Body, Fields>;
|
||||
```
|
||||
|
||||
Two type aliases are provided for notational convenience when declaring
|
||||
HTTP/1 messages. These two statements declare a request and a response
|
||||
respectively:
|
||||
```
|
||||
http::request_v1<http::string_body> req;
|
||||
http::response_v1<http::string_body> resp;
|
||||
```
|
||||
The code examples below show how to create and fill in a request and response
|
||||
object:
|
||||
|
||||
[heading Members]
|
||||
|
||||
Message objects are default constructible, with public access to data members.
|
||||
Request and response objects have some common members, and some members unique
|
||||
to the message type. These statements set all the members in each message:
|
||||
```
|
||||
http::request_v1<http::string_body> req;
|
||||
[table Create Message
|
||||
[[HTTP Request] [HTTP Response]]
|
||||
[[
|
||||
```
|
||||
request<empty_body> req;
|
||||
req.version = 11; // HTTP/1.1
|
||||
req.method = "GET";
|
||||
req.url = "/index.html";
|
||||
req.version = 11; // HTTP/1.1
|
||||
req.headers.insert("User-Agent", "hello_world");
|
||||
req.body = "";
|
||||
req.url = "/index.htm"
|
||||
req.fields.insert("Accept", "text/html");
|
||||
req.fields.insert("Connection", "keep-alive");
|
||||
req.fields.insert("User-Agent", "Beast");
|
||||
```
|
||||
][
|
||||
```
|
||||
response<string_body> res;
|
||||
res.version = 11; // HTTP/1.1
|
||||
res.status = 200;
|
||||
res.reason = "OK";
|
||||
res.fields.insert("Sever", "Beast");
|
||||
res.fields.insert("Content-Length", 4);
|
||||
res.body = "****";
|
||||
```
|
||||
]]]
|
||||
|
||||
http::response_v1<http::string_body> resp;
|
||||
resp.status = 404;
|
||||
resp.reason = "Not Found";
|
||||
resp.version = 10; // HTTP/1.0
|
||||
resp.headers.insert("Server", "Beast.HTTP");
|
||||
resp.body = "The requested resource was not found.";
|
||||
```
|
||||
In the serialized format of a HTTP message, the header is represented as a
|
||||
series of text lines ending in CRLF (`"\r\n"`). The end of the header is
|
||||
indicated by a line containing only CRLF. Here are examples of serialized HTTP
|
||||
request and response objects. The objects created above will produce these
|
||||
results when serialized. Note that only the response has a body:
|
||||
|
||||
[heading Headers]
|
||||
[table Serialized HTTP Request and Response
|
||||
[[HTTP Request] [HTTP Response]]
|
||||
[[
|
||||
```
|
||||
GET /index.htm HTTP/1.1\r\n
|
||||
Accept: text/html\r\n
|
||||
Connection: keep-alive\r\n
|
||||
User-Agent: Beast\r\n
|
||||
\r\n
|
||||
```
|
||||
][
|
||||
```
|
||||
200 OK HTTP/1.1\r\n
|
||||
Server: Beast\r\n
|
||||
Content-Length: 4\r\n
|
||||
\r\n
|
||||
****
|
||||
```
|
||||
]]]
|
||||
|
||||
The `message::headers` member is a container for setting the field/value
|
||||
pairs in the message. These statements change the values of the headers
|
||||
in the message passed:
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
[section:fields Fields]
|
||||
|
||||
The [*`Fields`] type represents a container that can set or retrieve the
|
||||
fields in a message. Beast provides the
|
||||
[link beast.ref.http__basic_fields `basic_fields`] class which serves
|
||||
the needs for most users. It supports modification and inspection of values.
|
||||
The field names are not case-sensitive.
|
||||
|
||||
These statements change the values of the headers in the message passed:
|
||||
```
|
||||
template<class Body>
|
||||
void set_fields(http::request_v1<Body>& req)
|
||||
void set_fields(request<Body>& req)
|
||||
{
|
||||
if(! req.exists("User-Agent"))
|
||||
req.insert("User-Agent", "myWebClient");
|
||||
@@ -148,17 +213,24 @@ in the message passed:
|
||||
}
|
||||
```
|
||||
|
||||
[heading Body]
|
||||
User defined [*`Fields`] types are possible. To support serialization, the
|
||||
type must meet the requirements of __FieldSequence__. To support parsing using
|
||||
the provided parser, the type must provide the `insert` member function.
|
||||
|
||||
The `message::body` member represents the message body. Depending on the
|
||||
`Body` template argument type, this could be a writable container. The
|
||||
following types, provided by the library, are suitable choices for the
|
||||
`Body` type:
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:body Body]
|
||||
|
||||
The message [*`Body`] template parameter controls both the type of the data
|
||||
member of the resulting message object, and the algorithms used during parsing
|
||||
and serialization. Beast provides three very common [*`Body`] types:
|
||||
|
||||
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
|
||||
Used in GET requests where there is no message body. Example:
|
||||
```
|
||||
http::request_v1<http::empty_body> req;
|
||||
request<empty_body> req;
|
||||
req.version = 11;
|
||||
req.method = "GET";
|
||||
req.url = "/index.html";
|
||||
@@ -170,36 +242,77 @@ or response with simple text in the message body (such as an error message).
|
||||
Has the same insertion complexity of `std::string`. This is the type of body
|
||||
used in the examples:
|
||||
```
|
||||
http::response_v1<http::string_body> resp;
|
||||
static_assert(std::is_same<decltype(resp.body), std::string>::value);
|
||||
resp.body = "Here is the data you requested";
|
||||
response<string_body> res;
|
||||
static_assert(std::is_same<decltype(res.body), std::string>::value);
|
||||
res.body = "Here is the data you requested";
|
||||
```
|
||||
|
||||
* [link beast.ref.http__streambuf_body [*`streambuf_body`:]] A body with a
|
||||
`value_type` of [link beast.ref.streambuf `streambuf`]: an efficient storage
|
||||
object which uses multiple octet arrays of varying lengths to represent data.
|
||||
|
||||
[heading Sockets]
|
||||
[heading Advanced]
|
||||
|
||||
The library provides simple free functions modeled after Boost.Asio to
|
||||
send and receive messages on TCP/IP sockets, SSL streams, or any object
|
||||
which meets the Boost.Asio type requirements (SyncReadStream, SyncWriteStream,
|
||||
AsyncReadStream, and AsyncWriteStream depending on the types of operations
|
||||
performed). To send messages synchronously, use one of the `http:write`
|
||||
functions:
|
||||
User-defined types are possible for the message body, where the type meets the
|
||||
[link beast.ref.Body [*`Body`]] requirements. This simplified class declaration
|
||||
shows the customization points available to user-defined body types:
|
||||
|
||||
[$images/body.png [width 510px] [height 210px]]
|
||||
|
||||
* [*`value_type`]: Determines the type of the
|
||||
[link beast.ref.http__message.body `message::body`] member. If this
|
||||
type defines default construction, move, copy, or swap, then message objects
|
||||
declared with this [*`Body`] will have those operations defined.
|
||||
|
||||
* [*`reader`]: An optional nested type meeting the requirements of
|
||||
[link beast.ref.Reader [*`Reader`]]. If present, this defines the algorithm
|
||||
used for parsing bodies of this type.
|
||||
|
||||
* [*`writer`]: An optional nested type meeting the requirements of
|
||||
[link beast.ref.Writer [*`Writer`]]. If present, this defines the algorithm
|
||||
used for serializing bodies of this type.
|
||||
|
||||
The examples included with this library provide a Body implementation that
|
||||
serializing message bodies that come from a file.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:algorithms Algorithms]
|
||||
|
||||
Algorithms are provided to serialize and deserialize HTTP/1 messages on
|
||||
streams.
|
||||
|
||||
* [link beast.ref.http__read [*read]]: Deserialize a HTTP/1 __header__ or __message__ from a stream.
|
||||
* [link beast.ref.http__write [*write]]: Serialize a HTTP/1 __header__ or __message__ to a stream.
|
||||
|
||||
Asynchronous versions of these algorithms are also available:
|
||||
|
||||
* [link beast.ref.http__async_read [*async_read]]: Deserialize a HTTP/1 __header__ or __message__ asynchronously from a stream.
|
||||
* [link beast.ref.http__async_write [*async_write]]: Serialize a HTTP/1 __header__ or __message__ asynchronously to a stream.
|
||||
|
||||
[heading Using Sockets]
|
||||
|
||||
The free function algorithms are modeled after Boost.Asio to send and receive
|
||||
messages on TCP/IP sockets, SSL streams, or any object which meets the
|
||||
Boost.Asio type requirements (__SyncReadStream__, __SyncWriteStream__,
|
||||
__AsyncReadStream__, and __AsyncWriteStream__ depending on the types of
|
||||
operations performed). To send messages synchronously, use one of the
|
||||
[link beast.ref.http__write `write`] functions:
|
||||
```
|
||||
void send_request(boost::asio::ip::tcp::socket& sock)
|
||||
{
|
||||
http::request<http::empty_body> req;
|
||||
request<empty_body> req;
|
||||
req.version = 11;
|
||||
req.method = "GET";
|
||||
req.url = "/index.html";
|
||||
...
|
||||
http::write(sock, req); // Throws exception on error
|
||||
write(sock, req); // Throws exception on error
|
||||
...
|
||||
// Alternatively
|
||||
boost::system::error:code ec;
|
||||
http::write(sock, req, ec);
|
||||
write(sock, req, ec);
|
||||
if(ec)
|
||||
std::cerr << "error writing http message: " << ec.message();
|
||||
}
|
||||
@@ -209,27 +322,27 @@ An asynchronous interface is available:
|
||||
```
|
||||
void handle_write(boost::system::error_code);
|
||||
...
|
||||
http::request_v1<http::empty_body> req;
|
||||
request<empty_body> req;
|
||||
...
|
||||
http::async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
|
||||
async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
|
||||
```
|
||||
|
||||
When the implementation reads messages from a socket, it can read bytes lying
|
||||
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
|
||||
store and re-use these extra bytes on subsequent messages, the read interface
|
||||
requires an additional parameter: a [link beast.types.DynamicBuffer [*`DynamicBuffer`]]
|
||||
requires an additional parameter: a [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]
|
||||
object. This example reads a message from the socket, with the extra bytes
|
||||
stored in the streambuf parameter for use in a subsequent call to read:
|
||||
```
|
||||
boost::asio::streambuf sb;
|
||||
...
|
||||
http::response_v1<http::string_body> resp;
|
||||
http::read(sock, sb, resp); // Throws exception on error
|
||||
response<string_body> res;
|
||||
read(sock, sb, res); // Throws exception on error
|
||||
...
|
||||
// Alternatively
|
||||
boost::system::error:code ec;
|
||||
http::read(sock, sb, resp, ec);
|
||||
read(sock, sb, res, ec);
|
||||
if(ec)
|
||||
std::cerr << "error reading http message: " << ec.message();
|
||||
```
|
||||
@@ -241,116 +354,28 @@ called:
|
||||
void handle_read(boost::system::error_code);
|
||||
...
|
||||
boost::asio::streambuf sb;
|
||||
http::response_v1<http::string_body> resp;
|
||||
response<string_body> res;
|
||||
...
|
||||
http::async_read(sock, resp, std::bind(&handle_read, std::placeholders::_1));
|
||||
async_read(sock, res, std::bind(&handle_read, std::placeholders::_1));
|
||||
```
|
||||
|
||||
An alternative to using a `boost::asio::streambuf` is to use a
|
||||
[link beast.ref.streambuf `beast::streambuf`], which meets the requirements of
|
||||
[*`DynamicBuffer`] and is optimized for performance:
|
||||
__streambuf__, which meets the requirements of __DynamicBuffer__ and
|
||||
is optimized for performance:
|
||||
```
|
||||
void handle_read(boost::system::error_code);
|
||||
...
|
||||
beast::streambuf sb;
|
||||
http::response_v1<http::string_body> resp;
|
||||
http::read(sock, sb, resp);
|
||||
response<string_body> res;
|
||||
read(sock, sb, res);
|
||||
```
|
||||
|
||||
The `read` implementation can use any object meeting the requirements of
|
||||
[link beast.types.DynamicBuffer [*`DynamicBuffer`]], allowing callers to define custom
|
||||
__DynamicBuffer__, allowing callers to define custom
|
||||
memory management strategies used by the implementation.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:advanced Advanced]
|
||||
|
||||
The spectrum of hardware and software platforms which perform these typical
|
||||
HTTP operations is vast, ranging from powerful servers in large datacenters
|
||||
to tiny resource-limited embedded devices. No single concrete implementation
|
||||
of a class intended to model messages can efficiently serve all needs.
|
||||
For example, an object that minimizes resources during parsing may not be
|
||||
able to edit and change headers dynamically. A message that represents the
|
||||
message body as a disk file may support sending but not parsing. Many efficient
|
||||
and correct models of messages exist, supporting some or all of the
|
||||
operations listed above.
|
||||
|
||||
[heading Message model]
|
||||
|
||||
The message class template and provided Body types are suitable for casual
|
||||
library users. This section explains the message model for advanced users
|
||||
who wish to take control over aspects of the implementation. We introduce
|
||||
customization points for the header and body via class template arguments.
|
||||
This illustration shows more detail about the
|
||||
[link beast.ref.http__message [*`message`]] class template (boilerplate
|
||||
present in the actual declaration has been removed for clarity):
|
||||
|
||||
[$images/message.png [width 580px] [height 225px]]
|
||||
|
||||
The default constructor, move special members, and copy special members are
|
||||
all defaulted. A message is movable, copyable, or default constructible based
|
||||
on the capabilities of its template arguments.
|
||||
|
||||
Messages modeled in this fashion are ['complete], containing all of the
|
||||
information required to perform the supported set of operations. They are
|
||||
['first-class types], returnable from functions and composable. HTTP
|
||||
requests and responses are distinct types, allowing functions to be
|
||||
overloaded on the type of message.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:headers Headers Type]
|
||||
|
||||
The `Headers` type represents the field/value pairs present in every HTTP
|
||||
message. These types implement the
|
||||
[link beast.types.FieldSequence [*`FieldSequence`]]
|
||||
concept. The value type of a field sequence is an object meeting the
|
||||
requirements of [link beast.types.Field [*`Field`]]. The implementation can
|
||||
serialize any instance of `Headers` that meets the field sequence requirements.
|
||||
This example shows a function which returns `true` if the specified field
|
||||
sequence has a connect field:
|
||||
```
|
||||
template<class FieldSequence>
|
||||
bool
|
||||
has_connect(FieldSequence const& fs)
|
||||
{
|
||||
return std::find_if(fs.begin(), fs.end(),
|
||||
[&](auto const& field)
|
||||
{
|
||||
return ci_equal(field.name(), "Connect");
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:body Body Type]
|
||||
|
||||
The `Body` template argument in the `message` class must meet the
|
||||
[link beast.types.Body [*`Body`] requirements]. It provides customization
|
||||
of the data member in the message, the algorithm for parsing, and the
|
||||
algorithm for serialization:
|
||||
|
||||
[$images/body.png [width 510px] [height 210px]]
|
||||
|
||||
Instances of the optional nested types `writer` and `reader` perform
|
||||
serialization and deserialization of the message body. If either or
|
||||
both of these types are present, the message becomes serializable, parsable,
|
||||
or both. They model [link beast.types.Reader [*`Reader`]] and
|
||||
[link beast.types.Writer [*`Writer`]] respectively.
|
||||
|
||||
For specialized applications, users may implement their own types which
|
||||
meet the requirements. The examples included with this library provide a
|
||||
Body implementation used to serve files in a HTTP server.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
BIN
src/beast/doc/images/CppCon2016.pdf
Normal file
BIN
src/beast/doc/images/CppCon2016.pdf
Normal file
Binary file not shown.
BIN
src/beast/doc/images/CppCon2016.png
Normal file
BIN
src/beast/doc/images/CppCon2016.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 145 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 30 KiB |
Binary file not shown.
@@ -2,12 +2,13 @@
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "boostbook.dtd">
|
||||
|
||||
<!--
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
|
||||
<section id="index">
|
||||
<section id="beast.index">
|
||||
<title>Index</title>
|
||||
<index/>
|
||||
</section>
|
||||
|
||||
4
src/beast/doc/makeqbk.sh
Normal file → Executable file
4
src/beast/doc/makeqbk.sh
Normal file → Executable file
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
# Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
[library Beast
|
||||
[quickbook 1.6]
|
||||
[copyright 2013 - 2016 Vinnie Falco]
|
||||
[purpose C++ Library]
|
||||
[copyright 2013 - 2017 Vinnie Falco]
|
||||
[purpose Networking Protocol Library]
|
||||
[license
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -22,174 +22,86 @@
|
||||
[template mdash[] '''— ''']
|
||||
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
|
||||
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
|
||||
[def __POSIX__ /POSIX/]
|
||||
[def __Windows__ /Windows/]
|
||||
[def __accept__ [@http://www.opengroup.org/onlinepubs/000095399/functions/accept.html `accept()`]]
|
||||
[def __connect__ [@http://www.opengroup.org/onlinepubs/000095399/functions/connect.html `connect()`]]
|
||||
[def __getpeername__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getpeername.html `getpeername()`]]
|
||||
[def __getsockname__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getsockname.html `getsockname()`]]
|
||||
[def __getsockopt__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getsockopt.html `getsockopt()`]]
|
||||
[def __ioctl__ [@http://www.opengroup.org/onlinepubs/000095399/functions/ioctl.html `ioctl()`]]
|
||||
[def __recvfrom__ [@http://www.opengroup.org/onlinepubs/000095399/functions/recvfrom.html `recvfrom()`]]
|
||||
[def __sendto__ [@http://www.opengroup.org/onlinepubs/000095399/functions/sendto.html `sendto()`]]
|
||||
[def __setsockopt__ [@http://www.opengroup.org/onlinepubs/000095399/functions/setsockopt.html `setsockopt()`]]
|
||||
[def __socket__ [@http://www.opengroup.org/onlinepubs/000095399/functions/socket.html `socket()`]]
|
||||
|
||||
[def __N4588__ [@http://cplusplus.github.io/networking-ts/draft.pdf [*N4588]]]
|
||||
[def __rfc6455__ [@https://tools.ietf.org/html/rfc6455 rfc6455]]
|
||||
[def __rfc7230__ [@https://tools.ietf.org/html/rfc7230 rfc7230]]
|
||||
|
||||
[def __asio_handler_invoke__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]]
|
||||
[def __asio_handler_allocate__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]]
|
||||
[def __void_or_deduced__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]]
|
||||
|
||||
[section:intro Introduction]
|
||||
[def __AsyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]]
|
||||
[def __AsyncWriteStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]]
|
||||
[def __CompletionHandler__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]]
|
||||
[def __ConstBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]]
|
||||
[def __Handler__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/Handler.html [*Handler]]]
|
||||
[def __MutableBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]]
|
||||
[def __SyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]]
|
||||
[def __SyncWriteStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]]
|
||||
|
||||
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:
|
||||
[def __Body__ [link beast.ref.Body [*`Body`]]]
|
||||
[def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]]
|
||||
[def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]]
|
||||
[def __Parser__ [link beast.ref.Parser [*`Parser`]]]
|
||||
|
||||
* [*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.
|
||||
|
||||
|
||||
|
||||
[section:requirements Requirements]
|
||||
|
||||
Beast requires:
|
||||
|
||||
* [*C++11.] A minimum of C++11 is needed.
|
||||
* [*Boost.] Beast is built on Boost, especially Boost.Asio.
|
||||
* [*OpenSSL.] If using TLS/Secure sockets (optional).
|
||||
|
||||
[note Tested compilers: msvc-14+, gcc 5+, clang 3.6+]
|
||||
|
||||
The library is [*header-only]. It is not necessary to add any .cpp files,
|
||||
or to edit your existing build script or project file except to provide
|
||||
that the include/ directory for beast is searched for include files.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:example Examples]
|
||||
|
||||
These usage examples are intended to quickly impress upon readers the
|
||||
flavor of the library. They are complete programs which may be built
|
||||
and run. Source code and build scripts for these programs may be found
|
||||
in the examples directory.
|
||||
|
||||
Use HTTP to request the root page from a website and print the response:
|
||||
```
|
||||
#include <beast/http.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Normal boost::asio setup
|
||||
std::string const host = "boost.org";
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::ip::tcp::resolver r{ios};
|
||||
boost::asio::ip::tcp::socket sock{ios};
|
||||
boost::asio::connect(sock,
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||
|
||||
// Send HTTP request using beast
|
||||
beast::http::request_v1<beast::http::empty_body> req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
||||
req.headers.replace("User-Agent", "Beast");
|
||||
beast::http::prepare(req);
|
||||
beast::http::write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
beast::streambuf sb;
|
||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
||||
beast::http::read(sock, sb, resp);
|
||||
std::cout << resp;
|
||||
}
|
||||
```
|
||||
|
||||
Establish a WebSocket connection, send a message and receive the reply:
|
||||
```
|
||||
#include <beast/core/to_string.hpp>
|
||||
#include <beast/websocket.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main()
|
||||
{
|
||||
// Normal boost::asio setup
|
||||
std::string const host = "echo.websocket.org";
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::ip::tcp::resolver r{ios};
|
||||
boost::asio::ip::tcp::socket sock{ios};
|
||||
boost::asio::connect(sock,
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||
|
||||
// WebSocket connect and send message using beast
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
ws.handshake(host, "/");
|
||||
ws.write(boost::asio::buffer("Hello, world!"));
|
||||
|
||||
// Receive WebSocket message, print and close using beast
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(beast::websocket::close_code::normal);
|
||||
std::cout << to_string(sb.data()) << "\n";
|
||||
}
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:credits Credits]
|
||||
|
||||
Boost.Asio is the inspiration behind which all of the interfaces and
|
||||
implementation strategies are built. Some parts of the documentation are
|
||||
written to closely resemble the wording and presentation of Boost.Asio
|
||||
documentation. Credit goes to Christopher Kohloff for the wonderful
|
||||
Asio library and the ideas upon which Beast is built.
|
||||
|
||||
Beast would not be possible without the considerable time and patience
|
||||
contributed by David Schwartz, Edward Hennis, Howard Hinnant, Miguel Portilla,
|
||||
Nikolaos Bougalis, Scott Determan, Scott Schurr, and Ripple Labs for
|
||||
supporting its development.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]]
|
||||
[def __fields__ [link beast.ref.http__fields `fields`]]
|
||||
[def __header__ [link beast.ref.http__header `header`]]
|
||||
[def __message__ [link beast.ref.http__message `message`]]
|
||||
[def __streambuf__ [link beast.ref.streambuf `streambuf`]]
|
||||
[def __basic_streambuf__ [link beast.ref.basic_streambuf `basic_streambuf`]]
|
||||
|
||||
Beast is a cross-platform, header-only C++ library built on Boost.Asio that
|
||||
provides implementations of the HTTP and WebSocket protocols.
|
||||
|
||||
[variablelist
|
||||
[[
|
||||
[link beast.overview Overview]
|
||||
][
|
||||
An introduction with features, requirements, and credits.
|
||||
]]
|
||||
[[
|
||||
[link beast.http Using HTTP]
|
||||
][
|
||||
How to use Beast's HTTP interfaces in your applications.
|
||||
]]
|
||||
[[
|
||||
[link beast.websocket Using WebSocket]
|
||||
][
|
||||
How to use Beast's WebSocket interfaces in your applications.
|
||||
]]
|
||||
[[
|
||||
[link beast.example Examples]
|
||||
][
|
||||
Examples that illustrate the use of Beast in more complex applications.
|
||||
]]
|
||||
[[
|
||||
[link beast.design Design]
|
||||
][
|
||||
Design rationale, answers to review questions, and
|
||||
other library comparisons.
|
||||
]]
|
||||
[[
|
||||
[link beast.ref Reference]
|
||||
][
|
||||
Detailed class and function reference.
|
||||
]]
|
||||
[[
|
||||
[link beast.index Index]
|
||||
][
|
||||
Book-style text index of Beast documentation.
|
||||
]]
|
||||
]
|
||||
|
||||
[include overview.qbk]
|
||||
[include http.qbk]
|
||||
[include websocket.qbk]
|
||||
[include examples.qbk]
|
||||
[include design.qbk]
|
||||
|
||||
[section:types Type Requirements]
|
||||
[section:ref Reference]
|
||||
[xinclude quickref.xml]
|
||||
[include types/Body.qbk]
|
||||
[include types/BufferSequence.qbk]
|
||||
[include types/DynamicBuffer.qbk]
|
||||
@@ -199,13 +111,7 @@ supporting its development.
|
||||
[include types/Reader.qbk]
|
||||
[include types/Streams.qbk]
|
||||
[include types/Writer.qbk]
|
||||
[include reference.qbk]
|
||||
[endsect]
|
||||
|
||||
[include design.qbk]
|
||||
[section:quickref Quick Reference]
|
||||
[xinclude quickref.xml]
|
||||
[endsect]
|
||||
[include reference.qbk]
|
||||
[section:idx Index]
|
||||
[xinclude index.xml]
|
||||
[endsect]
|
||||
|
||||
114
src/beast/doc/overview.qbk
Normal file
114
src/beast/doc/overview.qbk
Normal file
@@ -0,0 +1,114 @@
|
||||
[/
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:overview Introduction]
|
||||
|
||||
Beast is a header-only, cross-platform C++ library built on Boost.Asio and
|
||||
parts of Boost, containing two modules implementing widely used network
|
||||
protocols. Beast offers a universal HTTP message model, plus algorithms for
|
||||
parsing and serializing HTTP/1 messages. Beast.WebSocket provides a complete
|
||||
implementation of the WebSocket protocol. Their design achieves these goals:
|
||||
|
||||
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
|
||||
used to build clients, servers, or both.
|
||||
|
||||
* [*Ease of Use.] HTTP messages are modeled using simple, readily
|
||||
accessible objects. Functions and classes used to send and receive HTTP
|
||||
or WebSocket messages are designed to resemble Boost.Asio as closely as
|
||||
possible. Users familiar with Boost.Asio will be immediately comfortable
|
||||
using this library.
|
||||
|
||||
* [*Flexibility.] Interfaces do not mandate specific implementation
|
||||
strategies; important decisions such as buffer or thread management are
|
||||
left to users of the library.
|
||||
|
||||
* [*Performance.] The implementation performs competitively, making it a
|
||||
realistic choice for building high performance network servers.
|
||||
|
||||
* [*Scalability.] Development of network applications that scale to thousands
|
||||
of concurrent connections is possible with the implementation.
|
||||
|
||||
* [*Basis for further abstraction.] The interfaces facilitate the
|
||||
development of other libraries that provide higher levels of abstraction.
|
||||
|
||||
The HTTP portion of Beast is designed to be a low-level building block for
|
||||
creating higher level libraries. It implements only the HTTP protocol, and
|
||||
does not handle domain specific features (for example: cookies, redirects, or
|
||||
deflate content encodings).
|
||||
|
||||
[heading Requirements]
|
||||
|
||||
Beast requires:
|
||||
|
||||
* [*C++11.] A minimum of C++11 is needed.
|
||||
* [*Boost.] Beast is built on Boost, especially Boost.Asio.
|
||||
* [*OpenSSL.] If using TLS/Secure sockets (optional).
|
||||
|
||||
[note Tested compilers: msvc-14+, gcc 5+, clang 3.6+]
|
||||
|
||||
The library is [*header-only]. It is not necessary to add any .cpp files,
|
||||
or to add commands to your build script for building Beast. To link your
|
||||
program successfully, you'll need to add the Boost.System library to link
|
||||
with. If you use coroutines you'll also need the Boost.Coroutine library.
|
||||
Please visit the Boost documentation for instructions on how to do this for
|
||||
your particular build system.
|
||||
|
||||
[heading Motivation]
|
||||
|
||||
Beast is built on Boost.Asio. A proposal to add networking functionality to the
|
||||
C++ standard library, based on Boost.Asio, is under consideration by the
|
||||
committee and on track for standardization. Since the final approved networking
|
||||
interface for the C++ standard library will likely closely resemble the current
|
||||
interface of Boost.Asio, the choice of Boost.Asio as the network transport
|
||||
layer is prudent.
|
||||
|
||||
The HTTP protocol is pervasive in network applications. As C++ is a logical
|
||||
choice for high performance network servers, there is great utility in solid
|
||||
building blocks for manipulating, sending, and receiving HTTP messages
|
||||
compliant with the Hypertext Transfer Protocol and the supplements that
|
||||
follow. Unfortunately reliable implementations or industry standards do not
|
||||
exist in C++. The development of higher level libraries is stymied by the
|
||||
lack of a common set of low-level algorithms and types for interacting with
|
||||
the HTTP protocol.
|
||||
|
||||
Today's web applications increasingly rely on alternatives to standard HTTP
|
||||
to achieve performance and/or responsiveness. While WebSocket implementations
|
||||
are widely available in common web development languages such as Javascript,
|
||||
good implementations in C++ are scarce. A survey of existing C++ WebSocket
|
||||
solutions reveals interfaces which lack symmetry, impose performance penalties,
|
||||
and needlessly restrict implementation strategies.
|
||||
|
||||
Beast.WebSocket takes advantage of Boost.Asio's extensible asynchronous
|
||||
model, handler allocation, and handler invocation hooks. Calls to
|
||||
Beast.WebSocket asynchronous initiation functions allow callers the choice
|
||||
of using a completion handler, stackful or stackless coroutines, futures,
|
||||
or user defined customizations (for example, Boost.Fiber). The
|
||||
implementation uses handler invocation hooks (__asio_handler_invoke__),
|
||||
providing execution guarantees on composed operations in a manner identical
|
||||
to Boost.Asio. The implementation also uses handler allocation hooks
|
||||
(__asio_handler_allocate__) when allocating memory internally for composed
|
||||
operations.
|
||||
|
||||
There is no need for inheritance or virtual members in a
|
||||
[link beast.ref.websocket__stream `websocket::stream`].
|
||||
All operations are templated and transparent to the compiler, allowing for
|
||||
maximum inlining and optimization.
|
||||
|
||||
[heading Credits]
|
||||
|
||||
Boost.Asio is the inspiration behind which all of the interfaces and
|
||||
implementation strategies are built. Some parts of the documentation are
|
||||
written to closely resemble the wording and presentation of Boost.Asio
|
||||
documentation. Credit goes to Christopher Kohlhoff for the wonderful
|
||||
Asio library and the ideas upon which Beast is built.
|
||||
|
||||
Beast would not be possible without the considerable time and patience
|
||||
contributed by David Schwartz, Edward Hennis, Howard Hinnant, Miguel Portilla,
|
||||
Nikolaos Bougalis, Scott Determan, Scott Schurr, and Ripple Labs for
|
||||
supporting its development.
|
||||
|
||||
[endsect]
|
||||
@@ -2,7 +2,7 @@
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "boostbook.dtd">
|
||||
|
||||
<!--
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -16,10 +16,10 @@
|
||||
<colspec colname="d"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry valign="center" namest="a" nameend="b">
|
||||
<entry valign="center" namest="a" nameend="c">
|
||||
<bridgehead renderas="sect2">HTTP</bridgehead>
|
||||
</entry>
|
||||
<entry valign="center" namest="c" nameend="d">
|
||||
<entry valign="center" namest="d" nameend="d">
|
||||
<bridgehead renderas="sect2">WebSocket</bridgehead>
|
||||
</entry>
|
||||
</row>
|
||||
@@ -30,53 +30,82 @@
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__basic_dynabuf_body">basic_dynabuf_body</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_headers">basic_headers</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_fields">basic_fields</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member>
|
||||
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
|
||||
<member><link linkend="beast.ref.http__headers">headers</link></member>
|
||||
<member><link linkend="beast.ref.http__fields">fields</link></member>
|
||||
<member><link linkend="beast.ref.http__header">header</link></member>
|
||||
<member><link linkend="beast.ref.http__header_parser_v1">header_parser_v1</link></member>
|
||||
<member><link linkend="beast.ref.http__message">message</link></member>
|
||||
<member><link linkend="beast.ref.http__parser_v1">parser_v1</link></member>
|
||||
<member><link linkend="beast.ref.http__request">request</link></member>
|
||||
<member><link linkend="beast.ref.http__request_header">request_header</link></member>
|
||||
<member><link linkend="beast.ref.http__response">response</link></member>
|
||||
<member><link linkend="beast.ref.http__response_header">response_header</link></member>
|
||||
<member><link linkend="beast.ref.http__resume_context">resume_context</link></member>
|
||||
<member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member>
|
||||
<member><link linkend="beast.ref.http__string_body">string_body</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<bridgehead renderas="sect3">rfc7230</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
||||
<member><link linkend="beast.ref.http__headers_max_size">headers_max_size</link></member>
|
||||
<member><link linkend="beast.ref.http__skip_body">skip_body</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Parser">is_Parser</link></member>
|
||||
<member><link linkend="beast.ref.http__is_ReadableBody">is_ReadableBody</link></member>
|
||||
<member><link linkend="beast.ref.http__is_WritableBody">is_WritableBody</link></member>
|
||||
|
||||
<member><link linkend="beast.ref.http__ext_list">ext_list</link></member>
|
||||
<member><link linkend="beast.ref.http__param_list">param_list</link></member>
|
||||
<member><link linkend="beast.ref.http__token_list">token_list</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
|
||||
<member><link linkend="beast.ref.http__async_read">async_read</link></member>
|
||||
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
|
||||
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
|
||||
<member><link linkend="beast.ref.http__chunk_encode">chunk_encode</link></member>
|
||||
<member><link linkend="beast.ref.http__chunk_encode_final">chunk_encode_final</link></member>
|
||||
<member><link linkend="beast.ref.http__swap">swap</link></member>
|
||||
<member><link linkend="beast.ref.http__is_keep_alive">is_keep_alive</link></member>
|
||||
<member><link linkend="beast.ref.http__is_upgrade">is_upgrade</link></member>
|
||||
<member><link linkend="beast.ref.http__operator_ls_">operator<<</link></member>
|
||||
<member><link linkend="beast.ref.http__parse">parse</link></member>
|
||||
<member><link linkend="beast.ref.http__prepare">prepare</link></member>
|
||||
<member><link linkend="beast.ref.http__read">read</link></member>
|
||||
<member><link linkend="beast.ref.http__swap">swap</link></member>
|
||||
<member><link linkend="beast.ref.http__reason_string">reason_string</link></member>
|
||||
<member><link linkend="beast.ref.http__with_body">with_body</link></member>
|
||||
<member><link linkend="beast.ref.http__write">write</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Parser">is_Parser</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Reader">is_Reader</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Writer">is_Writer</link></member>
|
||||
<member><link linkend="beast.ref.http__has_reader">has_reader</link></member>
|
||||
<member><link linkend="beast.ref.http__has_writer">has_writer</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__header_max_size">header_max_size</link></member>
|
||||
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
||||
<member><link linkend="beast.ref.http__skip_body">skip_body</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__body_what">body_what</link></member>
|
||||
<member><link linkend="beast.ref.http__connection">connection</link></member>
|
||||
<member><link linkend="beast.ref.http__no_content_length">no_content_length</link></member>
|
||||
<member><link linkend="beast.ref.http__parse_error">parse_error</link></member>
|
||||
<member><link linkend="beast.ref.http__parse_flag">parse_flag</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.types.Body">Body</link></member>
|
||||
<member><link linkend="beast.types.Field">Field</link></member>
|
||||
<member><link linkend="beast.types.FieldSequence">FieldSequence</link></member>
|
||||
<member><link linkend="beast.types.Parser">Parser</link></member>
|
||||
<member><link linkend="beast.types.Reader">Reader</link></member>
|
||||
<member><link linkend="beast.types.Writer">Writer</link></member>
|
||||
<member><link linkend="beast.ref.Body">Body</link></member>
|
||||
<member><link linkend="beast.ref.Field">Field</link></member>
|
||||
<member><link linkend="beast.ref.FieldSequence">FieldSequence</link></member>
|
||||
<member><link linkend="beast.ref.Parser">Parser</link></member>
|
||||
<member><link linkend="beast.ref.Reader">Reader</link></member>
|
||||
<member><link linkend="beast.ref.Writer">Writer</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
@@ -88,24 +117,23 @@
|
||||
<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>
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__auto_fragment_size">auto_fragment_size</link></member>
|
||||
<member><link linkend="beast.ref.websocket__decorate">decorate</link></member>
|
||||
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</link></member>
|
||||
<member><link linkend="beast.ref.websocket__mask_buffer_size">mask_buffer_size</link></member>
|
||||
<member><link linkend="beast.ref.websocket__message_type">message_type</link></member>
|
||||
<member><link linkend="beast.ref.websocket__pong_callback">pong_callback</link></member>
|
||||
<member><link linkend="beast.ref.websocket__read_buffer_size">read_buffer_size</link></member>
|
||||
<member><link linkend="beast.ref.websocket__read_message_max">read_message_max</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__async_teardown">async_teardown</link></member>
|
||||
<member><link linkend="beast.ref.websocket__teardown">teardown</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__auto_fragment">auto_fragment</link></member>
|
||||
<member><link linkend="beast.ref.websocket__decorate">decorate</link></member>
|
||||
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</link></member>
|
||||
<member><link linkend="beast.ref.websocket__message_type">message_type</link></member>
|
||||
<member><link linkend="beast.ref.websocket__permessage_deflate">permessage_deflate</link></member>
|
||||
<member><link linkend="beast.ref.websocket__ping_callback">ping_callback</link></member>
|
||||
<member><link linkend="beast.ref.websocket__read_buffer_size">read_buffer_size</link></member>
|
||||
<member><link linkend="beast.ref.websocket__read_message_max">read_message_max</link></member>
|
||||
<member><link linkend="beast.ref.websocket__write_buffer_size">write_buffer_size</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__close_code">close_code</link></member>
|
||||
@@ -121,11 +149,15 @@
|
||||
<colspec colname="b"/>
|
||||
<colspec colname="c"/>
|
||||
<colspec colname="d"/>
|
||||
<colspec colname="e"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry valign="center" namest="a" nameend="d">
|
||||
<bridgehead renderas="sect2">Core</bridgehead>
|
||||
</entry>
|
||||
<entry valign="center" namest="e" nameend="e">
|
||||
<bridgehead renderas="sect2">ZLib</bridgehead>
|
||||
</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -138,9 +170,12 @@
|
||||
<member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member>
|
||||
<member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member>
|
||||
<member><link linkend="beast.ref.dynabuf_readstream">dynabuf_readstream</link></member>
|
||||
<member><link linkend="beast.ref.errc">errc</link></member>
|
||||
<member><link linkend="beast.ref.error_category">error_category</link></member>
|
||||
<member><link linkend="beast.ref.error_code">error_code</link></member>
|
||||
<member><link linkend="beast.ref.error_condition">error_condition</link></member>
|
||||
<member><link linkend="beast.ref.handler_alloc">handler_alloc</link></member>
|
||||
<member><link linkend="beast.ref.prepared_buffers">prepared_buffers</link></member>
|
||||
<member><link linkend="beast.ref.handler_ptr">handler_ptr</link></member>
|
||||
<member><link linkend="beast.ref.static_streambuf">static_streambuf</link></member>
|
||||
<member><link linkend="beast.ref.static_streambuf_n">static_streambuf_n</link></member>
|
||||
<member><link linkend="beast.ref.static_string">static_string</link></member>
|
||||
@@ -153,18 +188,15 @@
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.bind_handler">bind_handler</link></member>
|
||||
<member><link linkend="beast.ref.buffer_cat">buffer_cat</link></member>
|
||||
<member><link linkend="beast.ref.consumed_buffers">consumed_buffers</link></member>
|
||||
<member><link linkend="beast.ref.prepare_buffer">prepare_buffer</link></member>
|
||||
<member><link linkend="beast.ref.prepare_buffers">prepare_buffers</link></member>
|
||||
<member><link linkend="beast.ref.to_string">to_string</link></member>
|
||||
|
||||
<member><link linkend="beast.ref.write">write</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
|
||||
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
|
||||
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
|
||||
<member><link linkend="beast.ref.is_AsyncStream">is_AsyncStream</link></member>
|
||||
@@ -181,11 +213,29 @@
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.types.streams.AsyncStream">AsyncStream</link></member>
|
||||
<member><link linkend="beast.types.BufferSequence">BufferSequence</link></member>
|
||||
<member><link linkend="beast.types.DynamicBuffer">DynamicBuffer</link></member>
|
||||
<member><link linkend="beast.types.streams.Stream">Stream</link></member>
|
||||
<member><link linkend="beast.types.streams.SyncStream">SyncStream</link></member>
|
||||
<member><link linkend="beast.ref.streams.AsyncStream">AsyncStream</link></member>
|
||||
<member><link linkend="beast.ref.BufferSequence">BufferSequence</link></member>
|
||||
<member><link linkend="beast.ref.DynamicBuffer">DynamicBuffer</link></member>
|
||||
<member><link linkend="beast.ref.streams.Stream">Stream</link></member>
|
||||
<member><link linkend="beast.ref.streams.SyncStream">SyncStream</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.zlib__deflate_stream">deflate_stream</link></member>
|
||||
<member><link linkend="beast.ref.zlib__inflate_stream">inflate_stream</link></member>
|
||||
<member><link linkend="beast.ref.zlib__z_params">z_params</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.zlib__deflate_upper_bound">deflate_upper_bound</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.zlib__error">error</link></member>
|
||||
<member><link linkend="beast.ref.zlib__Flush">Flush</link></member>
|
||||
<member><link linkend="beast.ref.zlib__Strategy">Strategy</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
@@ -25,14 +25,12 @@
|
||||
-->
|
||||
<xsl:template match="/doxygen">
|
||||
<xsl:text>[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:ref Reference]
|
||||
|
||||
</xsl:text>
|
||||
<xsl:for-each select="
|
||||
compounddef[@kind = 'class' or @kind = 'struct'] |
|
||||
@@ -59,7 +57,6 @@
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:for-each>
|
||||
<xsl:text>
[endsect]</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
<!--========== Utilities ==========-->
|
||||
@@ -165,7 +162,7 @@
|
||||
<xsl:text>``['implementation-defined]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$type='void_or_deduced'">
|
||||
<xsl:text>``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]``</xsl:text>
|
||||
<xsl:text>__void_or_deduced__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="$type"/>
|
||||
@@ -198,6 +195,18 @@
|
||||
select="concat(substring-before($name, '::'), '__', substring-after($name, '::'))"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="substring($name, string-length($name) - 1) = '<<'">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
select="concat(substring-before($name, '<<'), '_ls_')"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="substring($name, string-length($name) - 1) = '>>'">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
select="concat(substring-before($name, '>>'), '_rs_')"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, '=')">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
@@ -270,10 +279,10 @@
|
||||
select="concat(substring-before($name, '*'), '_star_', substring-after($name, '*'))"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, '~')">
|
||||
<xsl:when test="starts-with($name, '~')">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
select="concat(substring-before($name, '~'), '_', substring-after($name, '~'))"/>
|
||||
select="concat(substring-after($name, '~'), '_dtor_')"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, ' ')">
|
||||
@@ -1055,10 +1064,26 @@
|
||||
</xsl:for-each>
|
||||
<xsl:text>]
</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="count(sectiondef[@kind='public-attrib' or @kind='public-static-attrib']) > 0">
|
||||
<xsl:if test="count(sectiondef[@kind='public-static-attrib']) > 0">
|
||||
<xsl:text>[heading Static Data Members]
</xsl:text>
|
||||
<xsl:text>[table
 [[Name][Description]]
</xsl:text>
|
||||
<xsl:for-each select="sectiondef[@kind='public-static-attrib']/memberdef" mode="class-table">
|
||||
<xsl:sort select="name"/>
|
||||
<xsl:text> [
</xsl:text>
|
||||
<xsl:text> [[link beast.ref.</xsl:text>
|
||||
<xsl:value-of select="$class-id"/>.<xsl:value-of select="name"/>
|
||||
<xsl:text> [*</xsl:text>
|
||||
<xsl:value-of select="name"/>
|
||||
<xsl:text>]]]
 [
 </xsl:text>
|
||||
<xsl:value-of select="briefdescription"/>
|
||||
<xsl:text>
 ]
 ]
</xsl:text>
|
||||
</xsl:for-each>
|
||||
<xsl:text>]
</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="count(sectiondef[@kind='public-attrib']) > 0">
|
||||
<xsl:text>[heading Data Members]
</xsl:text>
|
||||
<xsl:text>[table
 [[Name][Description]]
</xsl:text>
|
||||
<xsl:for-each select="sectiondef[@kind='public-attrib' or @kind='public-static-attrib']/memberdef" mode="class-table">
|
||||
<xsl:for-each select="sectiondef[@kind='public-attrib']/memberdef" mode="class-table">
|
||||
<xsl:sort select="name"/>
|
||||
<xsl:text> [
</xsl:text>
|
||||
<xsl:text> [[link beast.ref.</xsl:text>
|
||||
@@ -1528,47 +1553,53 @@
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="type = 'class AsyncStream'">
|
||||
<xsl:text>class ``[link beast.types.streams.AsyncStream [*AsyncStream]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.streams.AsyncStream [*AsyncStream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class AsyncReadStream'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]``</xsl:text>
|
||||
<xsl:text>class __AsyncReadStream__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class AsyncWriteStream'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]``</xsl:text>
|
||||
<xsl:text>class __AsyncWriteStream__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class Body'">
|
||||
<xsl:text>class ``[link beast.types.Body [*Body]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.Body [*Body]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class BufferSequence'">
|
||||
<xsl:text>class ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="(type = 'class' or type = 'class...') and declname = 'BufferSequence'">
|
||||
<xsl:value-of select="type"/>
|
||||
<xsl:text> ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||
<xsl:text> ``[link beast.ref.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'CompletionHandler' or type = 'class CompletionHandler'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]``</xsl:text>
|
||||
<xsl:text>class __CompletionHandler__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'ConstBufferSequence' or type = 'class ConstBufferSequence'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]``</xsl:text>
|
||||
<xsl:text>class __ConstBufferSequence__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'DynamicBuffer' or type = 'class DynamicBuffer'">
|
||||
<xsl:text>class ``[link beast.types.DynamicBuffer [*DynamicBuffer]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.DynamicBuffer [*DynamicBuffer]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Handler' or type = 'class Handler'">
|
||||
<xsl:text>class __Handler__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'MutableBufferSequence' or type = 'class MutableBufferSequence'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]``</xsl:text>
|
||||
<xsl:text>class __MutableBufferSequence__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Parser' or type = 'class Parser'">
|
||||
<xsl:text>class ``[link beast.ref.Parser [*Parser]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Stream' or type = 'class Stream'">
|
||||
<xsl:text>class ``[link beast.types.streams.Stream [*Stream]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.streams.Stream [*Stream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class SyncStream'">
|
||||
<xsl:text>class ``[link beast.types.streams.SyncStream [*SyncStream]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.streams.SyncStream [*SyncStream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'SyncReadStream' or type = 'class SyncReadStream'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]``</xsl:text>
|
||||
<xsl:text>class __SyncReadStream__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'SyncWriteStream' or type = 'class SyncWriteStream'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]``</xsl:text>
|
||||
<xsl:text>class __SyncWriteStream__</xsl:text>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="declname = 'T'">
|
||||
@@ -1682,6 +1713,14 @@
|
||||
</xsl:choose>
|
||||
<xsl:text>```
</xsl:text>
|
||||
<xsl:for-each select="../memberdef[name = $unqualified-name]">
|
||||
<xsl:if test="position() > 1">
|
||||
<xsl:text>
</xsl:text>
|
||||
<xsl:if test=" not(briefdescription = preceding-sibling::*/briefdescription)">
|
||||
<xsl:text>```
</xsl:text>
|
||||
<xsl:apply-templates select="briefdescription" mode="markup"/>
|
||||
<xsl:text>```
</xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:if>
|
||||
<xsl:variable name="stripped-type">
|
||||
<xsl:call-template name="cleanup-type">
|
||||
<xsl:with-param name="name" select="type"/>
|
||||
|
||||
@@ -107,52 +107,8 @@ INPUT = \
|
||||
../include/beast/core \
|
||||
../include/beast/http \
|
||||
../include/beast/websocket \
|
||||
../include/beast/doc_debug.hpp \
|
||||
|
||||
../include/beast/async_completion.hpp \
|
||||
../include/beast/basic_streambuf.hpp \
|
||||
../include/beast/bind_handler.hpp \
|
||||
../include/beast/buffer_cat.hpp \
|
||||
../include/beast/buffers_adapter.hpp \
|
||||
../include/beast/consuming_buffers.hpp \
|
||||
../include/beast/handler_alloc.hpp \
|
||||
../include/beast/http.hpp \
|
||||
../include/beast/placeholders.hpp \
|
||||
../include/beast/prepare_buffers.hpp \
|
||||
../include/beast/static_streambuf.hpp \
|
||||
../include/beast/streambuf.hpp \
|
||||
../include/beast/streambuf_readstream.hpp \
|
||||
../include/beast/to_string.hpp \
|
||||
../include/beast/type_check.hpp \
|
||||
../include/beast/websocket.hpp \
|
||||
../include/beast/write_streambuf.hpp \
|
||||
../include/beast/http/basic_headers.hpp \
|
||||
../include/beast/http/basic_parser_v1.hpp \
|
||||
../include/beast/http/body_writer.hpp \
|
||||
../include/beast/http/chunk_encode.hpp \
|
||||
../include/beast/http/empty_body.hpp \
|
||||
../include/beast/http/error.hpp \
|
||||
../include/beast/http/fields.hpp \
|
||||
../include/beast/http/headers.hpp \
|
||||
../include/beast/http/message.hpp \
|
||||
../include/beast/http/message_v1.hpp \
|
||||
../include/beast/http/method.hpp \
|
||||
../include/beast/http/parse_error.hpp \
|
||||
../include/beast/http/parser.hpp \
|
||||
../include/beast/http/read.hpp \
|
||||
../include/beast/http/resume_context.hpp \
|
||||
../include/beast/http/rfc2616.hpp \
|
||||
../include/beast/http/streambuf_body.hpp \
|
||||
../include/beast/http/string_body.hpp \
|
||||
../include/beast/http/type_check.hpp \
|
||||
../include/beast/http/write.hpp \
|
||||
../include/beast/websocket/error.hpp \
|
||||
../include/beast/websocket/option.hpp \
|
||||
../include/beast/websocket/rfc6455.hpp \
|
||||
../include/beast/websocket/ssl.hpp \
|
||||
../include/beast/websocket/static_string.hpp \
|
||||
../include/beast/websocket/stream.hpp \
|
||||
../include/beast/websocket/teardown.hpp \
|
||||
../include/beast/zlib \
|
||||
../extras/beast/doc_debug.hpp
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS =
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:Body Body]
|
||||
[section:Body Body requirements]
|
||||
|
||||
A [*Body] type is supplied as a template argument to the __message__ class. It
|
||||
controls both the type of the data member of the resulting message object, and
|
||||
the algorithms used during parsing and serialization.
|
||||
|
||||
In this table:
|
||||
|
||||
@@ -23,25 +27,20 @@ In this table:
|
||||
]
|
||||
]
|
||||
[
|
||||
[`X:value_type{}`]
|
||||
[]
|
||||
[`DefaultConstructible`]
|
||||
]
|
||||
[
|
||||
[`Body::reader`]
|
||||
[`X::reader`]
|
||||
[]
|
||||
[
|
||||
If present, a type meeting the requirements of
|
||||
[link beast.types.Reader [*`Reader`]].
|
||||
[link beast.ref.Reader [*`Reader`]].
|
||||
Provides an implementation to parse the body.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`Body::writer`]
|
||||
[`X::writer`]
|
||||
[]
|
||||
[
|
||||
If present, a type meeting the requirements of
|
||||
[link beast.types.Writer [*`Writer`]].
|
||||
[link beast.ref.Writer [*`Writer`]].
|
||||
Provides an implementation to serialize the body.
|
||||
]
|
||||
]
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:BufferSequence BufferSequence]
|
||||
[section:BufferSequence BufferSequence requirements]
|
||||
|
||||
A `BufferSequence` is a type meeting either of the following requirements:
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:DynamicBuffer DynamicBuffer]
|
||||
[section:DynamicBuffer DynamicBuffer requirements]
|
||||
|
||||
A dynamic buffer encapsulates memory storage that may be automatically resized
|
||||
as required, where the memory is divided into an input sequence followed by an
|
||||
@@ -27,7 +27,7 @@ implementation strategies:
|
||||
|
||||
* A sequence of one or more octet arrays of varying sizes. Additional octet
|
||||
array objects are appended to the sequence to accommodate changes in the
|
||||
size of the character sequence. This is the implementation approached
|
||||
size of the character sequence. This is the implementation approach
|
||||
currently offered by [link beast.ref.basic_streambuf `basic_streambuf`].
|
||||
|
||||
In the table below:
|
||||
@@ -88,7 +88,7 @@ In the table below:
|
||||
]
|
||||
[
|
||||
[`a.prepare(n)`]
|
||||
[`X:mutable_buffers_type`]
|
||||
[`X::mutable_buffers_type`]
|
||||
[
|
||||
Returns a mutable buffer sequence u representing the output sequence,
|
||||
and where `buffer_size(u) == n`. The dynamic buffer reallocates memory
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:Field Field]
|
||||
[section:Field Field requirements]
|
||||
|
||||
A [*`Field`] represents a single HTTP header field/value pair.
|
||||
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:FieldSequence FieldSequence]
|
||||
[section:FieldSequence FieldSequence requirements]
|
||||
|
||||
A [*`FieldSequence`] is an iterable container whose value type meets
|
||||
the requirements of [link beast.types.Field [*`Field`]].
|
||||
A [*FieldSequence] is an iterable container whose value type meets
|
||||
the requirements of [link beast.ref.Field [*Field]]. Objects that meet
|
||||
these requirements become serializable by the implementation.
|
||||
|
||||
In this table:
|
||||
|
||||
* `X` denotes a type that meets the requirements of [*`FieldSequence`].
|
||||
* `X` denotes a type that meets the requirements of [*FieldSequence].
|
||||
|
||||
* `a` is a value of type `X`.
|
||||
* `c` is a value of type `X const`.
|
||||
|
||||
[table FieldSequence requirements
|
||||
[[operation][type][semantics, pre/post-conditions]]
|
||||
@@ -22,25 +23,33 @@ In this table:
|
||||
[`X::value_type`]
|
||||
[]
|
||||
[
|
||||
A type that meets the requirements of `Field`.
|
||||
A type that meets the requirements of [link beast.ref.Field [*Field]].
|
||||
]
|
||||
]
|
||||
[
|
||||
[`X::const_iterator`]
|
||||
[]
|
||||
[
|
||||
A type that meets the requirements of `ForwardIterator`.
|
||||
An iterator type whose `reference` type meets the
|
||||
requirements of [link beast.ref.Field [*Field]], and which
|
||||
satisfies all the requirements of [*ForwardIterator],
|
||||
except that:
|
||||
|
||||
[ordered_list
|
||||
[there is no requirement that `operator->` is provided, and]
|
||||
[there is no requirement that `reference` be a reference type.]
|
||||
]
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.begin()`]
|
||||
[`c.begin()`]
|
||||
[`X::const_iterator`]
|
||||
[
|
||||
Returns an iterator to the beginning of the field sequence.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.end()`]
|
||||
[`c.end()`]
|
||||
[`X::const_iterator`]
|
||||
[
|
||||
Returns an iterator to the end of the field sequence.
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:Parser Parser]
|
||||
[section:Parser Parser requirements]
|
||||
|
||||
A [*`Parser`] is used to deserialize HTTP/1 messages from [link beast.types.streams streams].
|
||||
Objects of this type are used with [link beast.ref.http__parse http::parse] and
|
||||
[link beast.ref.http__async_parse http::async_parse].
|
||||
A [*Parser] is used to deserialize objects from
|
||||
[link beast.ref.streams streams]. Objects of this type are used with
|
||||
[link beast.ref.http__parse http::parse] and
|
||||
[link beast.ref.http__async_parse http::async_parse]. The definition of
|
||||
an object, and the predicate defining when the parse is complete, are
|
||||
determined by the implementation.
|
||||
|
||||
In this table:
|
||||
|
||||
* `X` denotes a type meeting the requirements of [*`Parser`].
|
||||
* `X` denotes a type meeting the requirements of [*Parser].
|
||||
|
||||
* `a` denotes a value of type `X`.
|
||||
|
||||
* `b` is a value meeting the requirements of [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConvertibleToConstBuffer.html [*`ConvertibleToConstBuffer`]].
|
||||
* `b` is a value meeting the requirements of __ConstBufferSequence__.
|
||||
|
||||
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
||||
|
||||
@@ -27,18 +30,18 @@ In this table:
|
||||
[`a.complete()`]
|
||||
[`bool`]
|
||||
[
|
||||
Returns `true` when a complete HTTP/1 message has been parsed.
|
||||
Returns `true` when parsing is complete.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.write(b, ec)`]
|
||||
[`std::size_t`]
|
||||
[
|
||||
Parses the octets in the specified input buffer sequentially until
|
||||
an error occurs, the end of the buffer is reached, or a complete
|
||||
HTTP/1 message has been parsed. If an error occurs, `ec` is set
|
||||
to the error code and parsing stops. This function returns the
|
||||
number of bytes consumed from the input buffer.
|
||||
Sequentially parses the octets in the specified input buffer sequence
|
||||
until an error occurs, the end of the buffer is reached, or parsing is
|
||||
complete. Upon success, this function returns the number of bytes used
|
||||
from the input. If an error occurs, `ec` is set to the error code and
|
||||
parsing stops.
|
||||
]
|
||||
]
|
||||
[
|
||||
@@ -48,9 +51,9 @@ In this table:
|
||||
Indicates to the parser that no more octets will be available.
|
||||
Typically this function is called when the end of stream is reached.
|
||||
For example, if a call to `boost::asio::ip::tcp::socket::read_some`
|
||||
generates a `boost::asio::error::eof` error. Some HTTP/1 messages
|
||||
determine the end of the message body by an end of file marker or
|
||||
closing of the connection.
|
||||
generates a `boost::asio::error::eof` error. Some objects, such as
|
||||
certain HTTP/1 messages, determine the end of the message body by
|
||||
an end of file marker or closing of the connection.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:Reader Reader]
|
||||
[section:Reader Reader requirements]
|
||||
|
||||
Parser implementations will construct the corresponding `reader` object
|
||||
during the parse. This customization point allows the Body to determine
|
||||
the strategy for storing incoming message body data.
|
||||
Parsers provided by the implementation will construct the corresponding
|
||||
`reader` object during parsing. This customization point allows the
|
||||
Body to determine the strategy for storing incoming message body data.
|
||||
|
||||
In this table:
|
||||
|
||||
@@ -17,15 +17,14 @@ In this table:
|
||||
|
||||
* `a` denotes a value of type `X`.
|
||||
|
||||
* `p` is any pointer.
|
||||
|
||||
* `n` is a value convertible to `std::size_t`.
|
||||
|
||||
* `ec` is a value of type `error_code&`.
|
||||
* `p` is a `void const*` to valid memory of at least `n` bytes.
|
||||
|
||||
* `m` denotes a value of type `message const&` where
|
||||
`std::is_same<decltype(m.body), Body::value_type>:value == true`
|
||||
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
||||
|
||||
* `m` denotes a value of type `message&` where
|
||||
`std::is_same<decltype(m.body), Body::value_type>::value == true`.
|
||||
|
||||
[table Reader requirements
|
||||
[[operation] [type] [semantics, pre/post-conditions]]
|
||||
@@ -33,22 +32,38 @@ In this table:
|
||||
[`X a(m);`]
|
||||
[]
|
||||
[
|
||||
`a` is constructible from `m`. The lifetime of `m` is
|
||||
guaranteed to end no earlier than after `a` is destroyed.
|
||||
`a` is constructible from `m`. The lifetime of `m` is guaranteed
|
||||
to end no earlier than after `a` is destroyed. The constructor
|
||||
will be called after all headers have been stored in `m`, and
|
||||
before any body data is deserialized. This function must be
|
||||
`noexcept`.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.init(ec)`]
|
||||
[`void`]
|
||||
[
|
||||
Called immediately after construction. If the function sets
|
||||
an error code in `ec`, the parse is aborted and the error is
|
||||
propagated to the caller. This function must be `noexcept`.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.write(p, n, ec)`]
|
||||
[`void`]
|
||||
[
|
||||
Deserializes the input sequence into the body.
|
||||
If `ec` is set, the deserialization is aborted and the error
|
||||
is returned to the caller.
|
||||
Deserializes the input sequence into the body. If `ec` is set,
|
||||
the deserialization is aborted and the error is propagated to
|
||||
the caller. If the message headers specify a chunked transfer
|
||||
encoding, the reader will receive the decoded version of the
|
||||
body. This function must be `noexcept`.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[note Definitions for required `Reader` member functions should be declared
|
||||
inline so the generated code becomes part of the implementation. ]
|
||||
[note
|
||||
Definitions for required `Reader` member functions should be declared
|
||||
inline so the generated code can become part of the implementation.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:streams Streams]
|
||||
[section:streams Streams requirements]
|
||||
|
||||
Stream types represent objects capable of performing synchronous or
|
||||
asynchronous I/O. They are based on concepts from `boost::asio`.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:Writer Writer]
|
||||
[section:Writer Writer requirements]
|
||||
|
||||
A `Writer` serializes the message body. The implementation creates an instance
|
||||
of this type when serializing a message, and calls into it zero or more times
|
||||
@@ -28,13 +28,13 @@ In this table:
|
||||
* `m` denotes a value of type `message const&` where
|
||||
`std::is_same<decltype(m.body), Body::value_type>:value == true`.
|
||||
|
||||
* `rc` is an object of type [link beast.ref.http__resume_context resume_context].
|
||||
* `rc` is an object of type [link beast.ref.http__resume_context `resume_context`].
|
||||
|
||||
* `ec` is a value of type `error_code&`.
|
||||
* `ec` is a value of type [link beast.ref.error_code `error_code&`]
|
||||
|
||||
* `wf` is a [*write function]: a function object of unspecified type provided
|
||||
by the implementation which accepts any value meeting the requirements
|
||||
of `ConstBufferSequence` as its single parameter.
|
||||
of __ConstBufferSequence__ as its single parameter.
|
||||
|
||||
[table Writer requirements
|
||||
[[operation] [type] [semantics, pre/post-conditions]]
|
||||
@@ -42,17 +42,18 @@ In this table:
|
||||
[`X a(m);`]
|
||||
[]
|
||||
[
|
||||
`a` is constructible from `m`. The lifetime of `m` is
|
||||
guaranteed to end no earlier than after `a` is destroyed.
|
||||
`a` is constructible from `m`. The lifetime of `m` is guaranteed
|
||||
to end no earlier than after `a` is destroyed. This function must
|
||||
be `noexcept`.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.init(ec)`]
|
||||
[`void`]
|
||||
[
|
||||
Called immediately after construction.
|
||||
If `ec` is set, the serialization is aborted and the error
|
||||
is propagated to the caller.
|
||||
Called immediately after construction. If the function sets an
|
||||
error code in `ec`, the serialization is aborted and the error
|
||||
is propagated to the caller. This function must be `noexcept`.
|
||||
]
|
||||
]
|
||||
[
|
||||
@@ -67,31 +68,33 @@ In this table:
|
||||
the serialized message body will be sent unmodified, with the
|
||||
error `boost::asio::error::eof` returned to the caller, to notify
|
||||
they should close the connection to indicate the end of the message.
|
||||
This function must be `noexcept`.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a(rc, ec, wf)`]
|
||||
[`a.write(rc, ec, wf)`]
|
||||
[`boost::tribool`]
|
||||
[
|
||||
Called repeatedly after `init` succeeds.
|
||||
`wf` is a function object which takes as its single parameter,
|
||||
any value meeting the requirements of `ConstBufferSequence`.
|
||||
Buffers provided by the `writer` to this [*write function] must
|
||||
remain valid until the next member function of `writer` is
|
||||
Called repeatedly after `init` succeeds. `wf` is a function object
|
||||
which takes as its single parameter any value meeting the requirements
|
||||
of __ConstBufferSequence__. Buffers provided to this write function
|
||||
must remain valid until the next member function of `writer` is
|
||||
invoked (which may be the destructor). This function returns `true`
|
||||
to indicate all message body data has been written, or `false`
|
||||
if there is more body data. If the return value is
|
||||
`boost::indeterminate`, the implementation will suspend the operation
|
||||
until the writer invokes `rc`. It is the writers responsibility when
|
||||
returning `boost::indeterminate`, to acquire ownership of the
|
||||
`resume_context` via move construction and eventually call it or else
|
||||
undefined behavior results.
|
||||
to indicate all message body data has been written, or `false` if
|
||||
there is more body data. If the return value is `boost::indeterminate`,
|
||||
the implementation will suspend the operation until the writer invokes
|
||||
`rc`. It is the writers responsibility when returning
|
||||
`boost::indeterminate`, to acquire ownership of `rc` via move
|
||||
construction and eventually call it or else undefined behavior
|
||||
results. This function must be `noexcept`.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[note Definitions for required `Writer` member functions should be declared
|
||||
inline so the generated code becomes part of the implementation. ]
|
||||
[note
|
||||
Definitions for required `Writer` member functions should be declared
|
||||
inline so the generated code can become part of the implementation.
|
||||
]
|
||||
|
||||
Exemplar:
|
||||
```
|
||||
@@ -109,7 +112,7 @@ public:
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
explicit
|
||||
writer(message<isRequest, Body, Headers> const& msg);
|
||||
writer(message<isRequest, Body, Headers> const& msg) noexcept;
|
||||
|
||||
/** Initialize the writer.
|
||||
|
||||
@@ -119,7 +122,7 @@ public:
|
||||
@param ec Contains the error code if any errors occur.
|
||||
*/
|
||||
void
|
||||
init(error_code& ec);
|
||||
init(error_code& ec) noexcept;
|
||||
|
||||
/** Returns the content length.
|
||||
|
||||
@@ -128,8 +131,8 @@ public:
|
||||
use chunk-encoding or terminate the connection to indicate the end
|
||||
of the message.
|
||||
*/
|
||||
std::size_t
|
||||
content_length() const;
|
||||
std::uint64_t
|
||||
content_length() noexcept;
|
||||
|
||||
/** Write zero or one buffer representing the message body.
|
||||
|
||||
@@ -164,7 +167,8 @@ public:
|
||||
the writer must guarantee that the buffers remain valid until the
|
||||
next member function is invoked, which may be the destructor.
|
||||
|
||||
@return `true` if there is data, `false` when done,
|
||||
@return `true` if there is no more data to send,
|
||||
`false` when there may be more data,
|
||||
boost::indeterminate to suspend.
|
||||
|
||||
@note Undefined behavior if the callee takes ownership
|
||||
@@ -172,7 +176,10 @@ public:
|
||||
*/
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, WriteFunction&& write);
|
||||
write(
|
||||
resume_context&&,
|
||||
error_code&,
|
||||
WriteFunction&& wf) noexcept;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -7,6 +7,21 @@
|
||||
|
||||
[section:websocket WebSocket]
|
||||
|
||||
[block '''
|
||||
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||
<member><link linkend="beast.websocket.creation">Creation</link></member>
|
||||
<member><link linkend="beast.websocket.connections">Making connections</link></member>
|
||||
<member><link linkend="beast.websocket.handshaking">Handshaking</link></member>
|
||||
<member><link linkend="beast.websocket.messages">Messages</link></member>
|
||||
<member><link linkend="beast.websocket.frames">Frames</link></member>
|
||||
<member><link linkend="beast.websocket.control">Control Frames</link></member>
|
||||
<member><link linkend="beast.websocket.buffers">Buffers</link></member>
|
||||
<member><link linkend="beast.websocket.async">Asynchronous interface</link></member>
|
||||
<member><link linkend="beast.websocket.io_service">The io_service</link></member>
|
||||
<member><link linkend="beast.websocket.threads">Thread Safety</link></member>
|
||||
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||
''']
|
||||
|
||||
The WebSocket Protocol enables two-way communication between a client
|
||||
running untrusted code in a controlled environment to a remote host that has
|
||||
opted-in to communications from that code. The protocol consists of an opening
|
||||
@@ -22,48 +37,12 @@ C++ approach.
|
||||
The WebSocket protocol is described fully in
|
||||
[@https://tools.ietf.org/html/rfc6455 rfc6455]
|
||||
|
||||
[note
|
||||
The following documentation assumes familiarity with both
|
||||
Boost.Asio and the WebSocket protocol specification described in __rfc6455__.
|
||||
]
|
||||
|
||||
|
||||
[section:motivation Motivation]
|
||||
|
||||
Today's web applications increasingly rely on alternatives to standard HTTP
|
||||
to achieve performance and/or responsiveness. While WebSocket implementations
|
||||
are widely available in common web development languages such as Javascript,
|
||||
good implementations in C++ are scarce. A survey of existing C++ WebSocket
|
||||
solutions reveals interfaces which lack symmetry, impose performance penalties,
|
||||
and needlessly restrict implementation strategies.
|
||||
|
||||
Beast.WebSocket is built on Boost.Asio, a robust cross platform networking
|
||||
framework that is part of Boost and also offered as a standalone library.
|
||||
A proposal to add networking functionality to the C++ standard library,
|
||||
based on Boost.Asio, is under consideration by the standards committee.
|
||||
Since the final approved networking interface for the C++ standard library
|
||||
will likely closely resemble the current interface of Boost.Asio, it is
|
||||
logical for Beast.WebSocket to use Boost.Asio as its network transport.
|
||||
|
||||
Beast.WebSocket takes advantage of Boost.Asio's extensible asynchronous
|
||||
model, handler allocation, and handler invocation hooks. Calls to
|
||||
Beast.WebSocket asynchronous initiation functions allow callers the choice
|
||||
of using a completion handler, stackful or stackless coroutines, futures,
|
||||
or user defined customizations (for example, Boost.Fiber). The
|
||||
implementation uses handler invocation hooks
|
||||
([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]),
|
||||
providing execution guarantees on composed operations in a manner
|
||||
identical to Boost.Asio. The implementation also uses handler allocation hooks
|
||||
([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`])
|
||||
when allocating memory internally for composed operations.
|
||||
|
||||
There is no need for inheritance or virtual members in a
|
||||
[link beast.ref.websocket__stream `beast::websocket::stream`].
|
||||
All operations are templated and transparent to the compiler, allowing for
|
||||
maximum inlining and optimization.
|
||||
|
||||
[note The documentation which follows assumes familiarity with
|
||||
both Boost.Asio and the WebSocket protocol specification described in
|
||||
[@https://tools.ietf.org/html/rfc6455 rfc6455] ]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:creation Creation]
|
||||
@@ -71,15 +50,15 @@ both Boost.Asio and the WebSocket protocol specification described in
|
||||
The interface to Beast's WebSocket implementation is a single template
|
||||
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
|
||||
wraps a "next layer" object. The next layer object must meet the requirements
|
||||
of [link beast.types.streams.SyncStream [*`SyncReadStream`]] if synchronous
|
||||
of [link beast.ref.streams.SyncStream [*`SyncReadStream`]] if synchronous
|
||||
operations are performed, or
|
||||
[link beast.types.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
||||
[link beast.ref.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
||||
operations are performed, or both. Arguments supplied during construction are
|
||||
passed to next layer's constructor. Here we declare a websocket stream over
|
||||
a TCP/IP socket with ownership of the socket:
|
||||
```
|
||||
boost::asio::io_service ios;
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||
```
|
||||
|
||||
[heading Using SSL]
|
||||
@@ -92,8 +71,8 @@ argument when constructing the stream.
|
||||
#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);
|
||||
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
|
||||
@@ -108,7 +87,7 @@ to wrap an object that already exists. This socket can be moved in:
|
||||
```
|
||||
boost::asio::ip::tcp::socket&& sock;
|
||||
...
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(std::move(sock));
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{std::move(sock)};
|
||||
```
|
||||
|
||||
Or, the wrapper can be constructed with a non-owning reference. In
|
||||
@@ -117,35 +96,37 @@ underlying socket being wrapped:
|
||||
```
|
||||
boost::asio::ip::tcp::socket sock;
|
||||
...
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
```
|
||||
|
||||
The layer being wrapped can be accessed through the websocket's "next layer",
|
||||
permitting callers to interact directly with its interface.
|
||||
```
|
||||
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);
|
||||
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};
|
||||
...
|
||||
ws.next_layer().shutdown(); // ssl::stream shutdown
|
||||
```
|
||||
|
||||
[important Initiating read and write operations on the next layer while
|
||||
websocket operations are being performed can break invariants, and
|
||||
result in undefined behavior. ]
|
||||
[warning
|
||||
Initiating read and write operations on the next layer while
|
||||
stream operations are being performed can break invariants, and
|
||||
result in undefined behavior.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:connecting Making connections]
|
||||
[section:connections Making connections]
|
||||
|
||||
Connections are established by using the interfaces which already exist
|
||||
for the next layer. For example, making an outgoing connection:
|
||||
```
|
||||
std::string const host = "mywebapp.com";
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::ip::tcp::resolver r(ios);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
boost::asio::ip::tcp::resolver r{ios};
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||
boost::asio::connect(ws.next_layer(),
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"}));
|
||||
```
|
||||
@@ -154,12 +135,14 @@ Accepting an incoming connection:
|
||||
```
|
||||
void do_accept(boost::asio::ip::tcp::acceptor& acceptor)
|
||||
{
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(acceptor.get_io_service());
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{acceptor.get_io_service()};
|
||||
acceptor.accept(ws.next_layer());
|
||||
}
|
||||
```
|
||||
|
||||
[note Examples use synchronous interfaces for clarity of exposition. ]
|
||||
[note
|
||||
Examples use synchronous interfaces for clarity of exposition.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -171,16 +154,17 @@ A WebSocket session begins when one side sends the HTTP Upgrade request
|
||||
for websocket, and the other side sends an appropriate HTTP response
|
||||
indicating that the request was accepted and that the connection has
|
||||
been upgraded. The HTTP Upgrade request must include the Host HTTP field,
|
||||
and the URI of the resource to request. `handshake` is used to send the
|
||||
and the URI of the resource to request.
|
||||
[link beast.ref.websocket__stream.handshake `handshake`] is used to send the
|
||||
request with the required host and resource strings.
|
||||
```
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||
...
|
||||
ws.set_option(beast::websocket::keep_alive(true));
|
||||
ws.handshake("ws.example.com:80", "/cgi-bin/bitcoin-prices");
|
||||
```
|
||||
|
||||
The [link beast.ref.websocket__stream `beast::websocket::stream`] automatically
|
||||
The [link beast.ref.websocket__stream `stream`] automatically
|
||||
handles receiving and processing the HTTP response to the handshake request.
|
||||
The call to handshake is successful if a HTTP response is received with the
|
||||
101 "Switching Protocols" status code. On failure, an error is returned or an
|
||||
@@ -190,7 +174,7 @@ open for a subsequent handshake attempt
|
||||
Performing a handshake for an incoming websocket upgrade request operates
|
||||
similarly. If the handshake fails, an error is returned or exception thrown:
|
||||
```
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||
...
|
||||
ws.accept();
|
||||
```
|
||||
@@ -205,7 +189,7 @@ void do_accept(boost::asio::ip::tcp::socket& sock)
|
||||
boost::asio::streambuf sb;
|
||||
boost::asio::read_until(sock, sb, "\r\n\r\n");
|
||||
...
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
ws.accept(sb.data());
|
||||
...
|
||||
}
|
||||
@@ -218,10 +202,10 @@ void do_accept(boost::asio::ip::tcp::socket& sock)
|
||||
{
|
||||
boost::asio::streambuf sb;
|
||||
beast::http::request<http::empty_body> request;
|
||||
beast::http::read(sock, request);
|
||||
beast::http::read(sock, sb, request);
|
||||
if(beast::http::is_upgrade(request))
|
||||
{
|
||||
websocket::stream<ip::tcp::socket&> ws(sock);
|
||||
websocket::stream<ip::tcp::socket&> ws{sock};
|
||||
ws.accept(request);
|
||||
...
|
||||
}
|
||||
@@ -242,17 +226,19 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
||||
{
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode::value op;
|
||||
ws.read(sb);
|
||||
ws.read(op, sb);
|
||||
|
||||
ws.set_option(beast::websocket::message_type(op));
|
||||
ws.set_option(beast::websocket::message_type{op});
|
||||
ws.write(sb.data());
|
||||
sb.consume(sb.size());
|
||||
}
|
||||
```
|
||||
|
||||
[important Calls to [link beast.ref.websocket__stream.set_option `set_option`]
|
||||
must be made from the same implicit or explicit strand as that used to perform
|
||||
other operations. ]
|
||||
[important
|
||||
Calls to [link beast.ref.websocket__stream.set_option `set_option`]
|
||||
must be made from the same implicit or explicit strand as that used
|
||||
to perform other operations.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -280,9 +266,9 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
||||
if(fi.fin)
|
||||
break;
|
||||
}
|
||||
ws.set_option(beast::websocket::message_type(fi.op));
|
||||
ws.set_option(beast::websocket::message_type{fi.op});
|
||||
beast::consuming_buffers<
|
||||
beast::streambuf::const_buffers_type> cb(sb.data());
|
||||
beast::streambuf::const_buffers_type> cb{sb.data()};
|
||||
for(;;)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
@@ -305,66 +291,111 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
||||
|
||||
|
||||
|
||||
[section:controlframes Control frames]
|
||||
[section:control Control Frames]
|
||||
|
||||
During read operations, the implementation automatically reads and processes
|
||||
WebSocket control frames such as ping, pong, and close. Pings are replied
|
||||
to as soon as possible, pongs are delivered to the pong callback. The receipt
|
||||
of a close frame initiates the WebSocket close procedure, eventually resulting
|
||||
in the error code [link beast.ref.websocket__error `error::closed`] being
|
||||
delivered to the caller in a subsequent read operation, assuming no other error
|
||||
Control frames are small (less than 128 bytes) messages entirely contained
|
||||
in an individual WebSocket frame. They may be sent at any time by either
|
||||
peer on an established connection, and can appear in between continuation
|
||||
frames for a message. There are three types of control frames: ping, pong,
|
||||
and close.
|
||||
|
||||
A sent ping indicates a request that the sender wants to receive a pong. A
|
||||
pong is a response to a ping. Pongs may be sent unsolicited, at any time.
|
||||
One use for an unsolicited pong is to inform the remote peer that the
|
||||
session is still active after a long period of inactivity. A close frame
|
||||
indicates that the remote peer wishes to close the WebSocket connection.
|
||||
The connection is considered gracefully closed when each side has sent
|
||||
and received a close frame.
|
||||
|
||||
During read operations, Beast automatically reads and processes control
|
||||
frames. Pings are replied to as soon as possible with a pong, received
|
||||
ping and pongs are delivered to the ping callback. The receipt of a close
|
||||
frame initiates the WebSocket close procedure, eventually resulting in the
|
||||
error code [link beast.ref.websocket__error `error::closed`] being delivered
|
||||
to the caller in a subsequent read operation, assuming no other error
|
||||
takes place.
|
||||
|
||||
To ensure timely delivery of control frames, large messages are broken up
|
||||
into smaller sized frames. The implementation chooses the size and number
|
||||
of the frames making up the message. The automatic fragment size option
|
||||
gives callers control over the size of these frames:
|
||||
A consequence of this automatic behavior is that caller-initiated read
|
||||
operations can cause socket writes. However, these writes will not
|
||||
compete with caller-initiated write operations. For the purposes of
|
||||
correctness with respect to the stream invariants, caller-initiated
|
||||
read operations still only count as a read. This means that callers can
|
||||
have a simultaneously active read, write, and ping operation in progress,
|
||||
while the implementation also automatically handles control frames.
|
||||
|
||||
[heading Ping and Pong Frames]
|
||||
|
||||
Ping and pong messages are control frames which may be sent at any time
|
||||
by either peer on an established WebSocket connection. They are sent
|
||||
using the functions
|
||||
[link beast.ref.websocket__stream.ping `ping`] and
|
||||
[link beast.ref.websocket__stream.pong `pong`].
|
||||
|
||||
To be notified of ping and pong control frames, callers may register a
|
||||
"ping callback" using [link beast.ref.websocket__stream.set_option `set_option`].
|
||||
The object provided with this option should be callable with the following
|
||||
signature:
|
||||
```
|
||||
void on_ping(bool is_pong, ping_data const& payload);
|
||||
...
|
||||
ws.set_option(beast::websocket::auto_fragment_size(8192));
|
||||
ws.set_option(ping_callback{&on_ping});
|
||||
```
|
||||
|
||||
When a ping callback is registered, all pings and pongs received through
|
||||
either synchronous read functions or asynchronous read functions will
|
||||
invoke the ping callback, with the value of `is_pong` set to `true` if a
|
||||
pong was received else `false` if a ping was received. The payload of
|
||||
the ping or pong control frame is passed in the payload argument.
|
||||
|
||||
Unlike regular completion handlers used in calls to asynchronous initiation
|
||||
functions, the ping callback only needs to be set once. The callback is not
|
||||
reset when a ping or pong is received. The same callback is used for both
|
||||
synchronous and asynchronous reads. The ping callback is passive; in order
|
||||
to receive pings and pongs, a synchronous or asynchronous stream read
|
||||
function must be active.
|
||||
|
||||
[note
|
||||
When an asynchronous read function receives a ping or pong, the
|
||||
ping callback is invoked in the same manner as that used to invoke
|
||||
the final completion handler of the corresponding read function.
|
||||
]
|
||||
|
||||
[heading Close Frames]
|
||||
|
||||
The WebSocket protocol defines a procedure and control message for initiating
|
||||
a close of the session. Handling of close initiated by the remote end of the
|
||||
connection is performed automatically. To manually initiate a close, use
|
||||
[link beast.ref.websocket__stream.close `close`]:
|
||||
the [link beast.ref.websocket__stream.close `close`] function:
|
||||
```
|
||||
ws.close();
|
||||
```
|
||||
|
||||
[note To receive the [link beast.ref.websocket__error `error::closed`]
|
||||
error, a read operation is required. ]
|
||||
When the remote peer initiates a close by sending a close frame, Beast
|
||||
will handle it for you by causing the next read to return `error::closed`.
|
||||
When this error code is delivered, it indicates to the application that
|
||||
the WebSocket connection has been closed cleanly, and that the TCP/IP
|
||||
connection has been closed. After initiating a close, it is necessary to
|
||||
continue reading messages until receiving the error `error::closed`. This
|
||||
is because the remote peer may still be sending message and control frames
|
||||
before it receives and responds to the close frame.
|
||||
|
||||
[endsect]
|
||||
[important
|
||||
To receive the [link beast.ref.websocket__error `error::closed`]
|
||||
error, a read operation is required.
|
||||
]
|
||||
|
||||
[heading Auto-fragment]
|
||||
|
||||
|
||||
[section:pongs Pong messages]
|
||||
|
||||
To receive pong control frames, callers may register a "pong callback" using
|
||||
[link beast.ref.websocket__stream.set_option `set_option`]:
|
||||
|
||||
the following signature:
|
||||
To ensure timely delivery of control frames, large messages can be broken up
|
||||
into smaller sized frames. The automatic fragment option turns on this
|
||||
feature, and the write buffer size option determines the maximum size of
|
||||
the fragments:
|
||||
```
|
||||
void on_pong(ping_data const& payload);
|
||||
...
|
||||
ws.set_option(pong_callback{&on_pong});
|
||||
ws.set_option(beast::websocket::auto_fragment{true});
|
||||
ws.set_option(beast::websocket::write_buffer_size{16384});
|
||||
```
|
||||
|
||||
When a pong callback is registered, any pongs received through either
|
||||
synchronous read functions or asynchronous read functions will invoke the
|
||||
pong callback, passing the payload in the pong message as the argument.
|
||||
|
||||
Unlike regular completion handlers used in calls to asynchronous initiation
|
||||
functions, the pong callback only needs to be set once. The callback is not
|
||||
reset when a pong is received. The same callback is used for both synchronous
|
||||
and asynchronous reads. The pong callback is passive; in order to receive
|
||||
pongs, a synchronous or asynchronous stream read function must be active.
|
||||
|
||||
[note When an asynchronous read function receives a pong, the the pong callback
|
||||
is invoked in the same manner as that used to invoke the final completion
|
||||
handler of the corresponding read function.]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -373,7 +404,7 @@ handler of the corresponding read function.]
|
||||
|
||||
Because calls to read data may return a variable amount of bytes, the
|
||||
interface to calls that read data require an object that meets the requirements
|
||||
of [link beast.types.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on
|
||||
of [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on
|
||||
[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
|
||||
|
||||
The implementation does not perform queueing or buffering of messages. If
|
||||
@@ -429,7 +460,7 @@ use or require threads.
|
||||
|
||||
|
||||
|
||||
[section:safety Thread Safety]
|
||||
[section:threads Thread Safety]
|
||||
|
||||
Like a regular asio socket, a [link beast.ref.websocket__stream `stream`] is
|
||||
not thread safe. Callers are responsible for synchronizing operations on the
|
||||
|
||||
@@ -41,6 +41,17 @@ if (NOT WIN32)
|
||||
target_link_libraries(http-example ${Boost_LIBRARIES} Threads::Threads)
|
||||
endif()
|
||||
|
||||
add_executable (websocket-echo
|
||||
${BEAST_INCLUDES}
|
||||
websocket_async_echo_server.hpp
|
||||
websocket_sync_echo_server.hpp
|
||||
websocket_echo.cpp
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(websocket-echo ${Boost_LIBRARIES} Threads::Threads)
|
||||
endif()
|
||||
|
||||
add_executable (websocket-example
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
#
|
||||
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
# Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
|
||||
import os ;
|
||||
|
||||
exe http-crawl :
|
||||
http_crawl.cpp
|
||||
urls_large_data.cpp
|
||||
@@ -20,7 +18,10 @@ exe http-example :
|
||||
http_example.cpp
|
||||
;
|
||||
|
||||
exe websocket-echo :
|
||||
websocket_echo.cpp
|
||||
;
|
||||
|
||||
exe websocket-example :
|
||||
websocket_example.cpp
|
||||
;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,9 +8,12 @@
|
||||
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -34,8 +37,8 @@ struct file_body
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
writer(message<isRequest, file_body, Headers> const& m) noexcept
|
||||
template<bool isRequest, class Fields>
|
||||
writer(message<isRequest, file_body, Fields> const& m) noexcept
|
||||
: path_(m.body)
|
||||
{
|
||||
}
|
||||
@@ -58,14 +61,15 @@ struct file_body
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
content_length() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
write(resume_context&&, error_code&,
|
||||
WriteFunction&& wf) noexcept
|
||||
{
|
||||
if(size_ - offset_ < sizeof(buf_))
|
||||
buf_len_ = static_cast<std::size_t>(
|
||||
@@ -75,7 +79,7 @@ struct file_body
|
||||
auto const nread = fread(buf_, 1, sizeof(buf_), file_);
|
||||
(void)nread;
|
||||
offset_ += buf_len_;
|
||||
write(boost::asio::buffer(buf_, buf_len_));
|
||||
wf(boost::asio::buffer(buf_, buf_len_));
|
||||
return offset_ >= size_;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "mime_type.hpp"
|
||||
|
||||
#include <beast/http.hpp>
|
||||
#include <beast/core/handler_helpers.hpp>
|
||||
#include <beast/core/handler_ptr.hpp>
|
||||
#include <beast/core/placeholders.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
@@ -32,8 +34,8 @@ class http_async_server
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
using req_type = request_v1<string_body>;
|
||||
using resp_type = response_v1<file_body>;
|
||||
using req_type = request<string_body>;
|
||||
using resp_type = response<file_body>;
|
||||
|
||||
std::mutex m_;
|
||||
bool log_ = true;
|
||||
@@ -85,32 +87,26 @@ public:
|
||||
|
||||
private:
|
||||
template<class Stream, class Handler,
|
||||
bool isRequest, class Body, class Headers>
|
||||
bool isRequest, class Body, class Fields>
|
||||
class write_op
|
||||
{
|
||||
using alloc_type =
|
||||
handler_alloc<char, Handler>;
|
||||
|
||||
struct data
|
||||
{
|
||||
Stream& s;
|
||||
message_v1<isRequest, Body, Headers> m;
|
||||
Handler h;
|
||||
bool cont;
|
||||
Stream& s;
|
||||
message<isRequest, Body, Fields> m;
|
||||
|
||||
template<class DeducedHandler>
|
||||
data(DeducedHandler&& h_, Stream& s_,
|
||||
message_v1<isRequest, Body, Headers>&& m_)
|
||||
: s(s_)
|
||||
data(Handler& handler, Stream& s_,
|
||||
message<isRequest, Body, Fields>&& m_)
|
||||
: cont(beast_asio_helpers::
|
||||
is_continuation(handler))
|
||||
, 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_;
|
||||
handler_ptr<data, Handler> d_;
|
||||
|
||||
public:
|
||||
write_op(write_op&&) = default;
|
||||
@@ -118,9 +114,8 @@ private:
|
||||
|
||||
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)...))
|
||||
: d_(std::forward<DeducedHandler>(h),
|
||||
s, std::forward<Args>(args)...)
|
||||
{
|
||||
(*this)(error_code{}, false);
|
||||
}
|
||||
@@ -135,23 +130,23 @@ private:
|
||||
beast::http::async_write(d.s, d.m, std::move(*this));
|
||||
return;
|
||||
}
|
||||
d.h(ec);
|
||||
d_.invoke(ec);
|
||||
}
|
||||
|
||||
friend
|
||||
void* asio_handler_allocate(
|
||||
std::size_t size, write_op* op)
|
||||
{
|
||||
return boost_asio_handler_alloc_helpers::
|
||||
allocate(size, op->d_->h);
|
||||
return beast_asio_helpers::
|
||||
allocate(size, op->d_.handler());
|
||||
}
|
||||
|
||||
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);
|
||||
return beast_asio_helpers::
|
||||
deallocate(p, size, op->d_.handler());
|
||||
}
|
||||
|
||||
friend
|
||||
@@ -164,22 +159,22 @@ private:
|
||||
friend
|
||||
void asio_handler_invoke(Function&& f, write_op* op)
|
||||
{
|
||||
return boost_asio_handler_invoke_helpers::
|
||||
invoke(f, op->d_->h);
|
||||
return beast_asio_helpers::
|
||||
invoke(f, op->d_.handler());
|
||||
}
|
||||
};
|
||||
|
||||
template<class Stream,
|
||||
bool isRequest, class Body, class Headers,
|
||||
bool isRequest, class Body, class Fields,
|
||||
class DeducedHandler>
|
||||
static
|
||||
void
|
||||
async_write(Stream& stream, message_v1<
|
||||
isRequest, Body, Headers>&& msg,
|
||||
async_write(Stream& stream, message<
|
||||
isRequest, Body, Fields>&& msg,
|
||||
DeducedHandler&& handler)
|
||||
{
|
||||
write_op<Stream, typename std::decay<DeducedHandler>::type,
|
||||
isRequest, Body, Headers>{std::forward<DeducedHandler>(
|
||||
isRequest, Body, Fields>{std::forward<DeducedHandler>(
|
||||
handler), stream, std::move(msg)};
|
||||
}
|
||||
|
||||
@@ -236,12 +231,12 @@ private:
|
||||
path = server_.root_ + path;
|
||||
if(! boost::filesystem::exists(path))
|
||||
{
|
||||
response_v1<string_body> res;
|
||||
response<string_body> res;
|
||||
res.status = 404;
|
||||
res.reason = "Not Found";
|
||||
res.version = req_.version;
|
||||
res.headers.insert("Server", "http_async_server");
|
||||
res.headers.insert("Content-Type", "text/html");
|
||||
res.fields.insert("Server", "http_async_server");
|
||||
res.fields.insert("Content-Type", "text/html");
|
||||
res.body = "The file '" + path + "' was not found";
|
||||
prepare(res);
|
||||
async_write(sock_, std::move(res),
|
||||
@@ -249,32 +244,35 @@ private:
|
||||
asio::placeholders::error));
|
||||
return;
|
||||
}
|
||||
resp_type res;
|
||||
res.status = 200;
|
||||
res.reason = "OK";
|
||||
res.version = req_.version;
|
||||
res.headers.insert("Server", "http_async_server");
|
||||
res.headers.insert("Content-Type", mime_type(path));
|
||||
res.body = path;
|
||||
try
|
||||
{
|
||||
resp_type res;
|
||||
res.status = 200;
|
||||
res.reason = "OK";
|
||||
res.version = req_.version;
|
||||
res.fields.insert("Server", "http_async_server");
|
||||
res.fields.insert("Content-Type", mime_type(path));
|
||||
res.body = path;
|
||||
prepare(res);
|
||||
async_write(sock_, std::move(res),
|
||||
std::bind(&peer::on_write, shared_from_this(),
|
||||
asio::placeholders::error));
|
||||
}
|
||||
catch(std::exception const& e)
|
||||
{
|
||||
res = {};
|
||||
response<string_body> 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.fields.insert("Server", "http_async_server");
|
||||
res.fields.insert("Content-Type", "text/html");
|
||||
res.body =
|
||||
std::string{"An internal error occurred"} + e.what();
|
||||
prepare(res);
|
||||
async_write(sock_, std::move(res),
|
||||
std::bind(&peer::on_write, shared_from_this(),
|
||||
asio::placeholders::error));
|
||||
}
|
||||
async_write(sock_, std::move(res),
|
||||
std::bind(&peer::on_write, shared_from_this(),
|
||||
asio::placeholders::error));
|
||||
}
|
||||
|
||||
void on_write(error_code ec)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/http.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using namespace beast::http;
|
||||
@@ -35,21 +36,21 @@ int main(int, char const*[])
|
||||
ip::tcp::socket sock(ios);
|
||||
connect(sock, it);
|
||||
auto ep = sock.remote_endpoint();
|
||||
request_v1<empty_body> req;
|
||||
request<empty_body> req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.headers.insert("Host", host +
|
||||
std::string(":") + std::to_string(ep.port()));
|
||||
req.headers.insert("User-Agent", "beast/http");
|
||||
req.fields.insert("Host", host + std::string(":") +
|
||||
boost::lexical_cast<std::string>(ep.port()));
|
||||
req.fields.insert("User-Agent", "beast/http");
|
||||
prepare(req);
|
||||
write(sock, req);
|
||||
response_v1<string_body> res;
|
||||
response<string_body> res;
|
||||
streambuf sb;
|
||||
beast::http::read(sock, sb, res);
|
||||
std::cout << res;
|
||||
}
|
||||
catch(boost::system::system_error const& ec)
|
||||
catch(beast::system_error const& ec)
|
||||
{
|
||||
std::cerr << host << ": " << ec.what();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <beast/http.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@@ -21,18 +22,19 @@ int main()
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||
|
||||
// Send HTTP request using beast
|
||||
beast::http::request_v1<beast::http::empty_body> req;
|
||||
beast::http::request<beast::http::empty_body> req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
||||
req.headers.replace("User-Agent", "Beast");
|
||||
req.fields.replace("Host", host + ":" +
|
||||
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||
req.fields.replace("User-Agent", "Beast");
|
||||
beast::http::prepare(req);
|
||||
beast::http::write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
beast::streambuf sb;
|
||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
||||
beast::http::response<beast::http::streambuf_body> resp;
|
||||
beast::http::read(sock, sb, resp);
|
||||
std::cout << resp;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -20,34 +20,26 @@ int main(int ac, char const* av[])
|
||||
po::options_description desc("Options");
|
||||
|
||||
desc.add_options()
|
||||
("root,r", po::value<std::string>()->implicit_value("."),
|
||||
("root,r", po::value<std::string>()->default_value("."),
|
||||
"Set the root directory for serving files")
|
||||
("port,p", po::value<std::uint16_t>()->implicit_value(8080),
|
||||
("port,p", po::value<std::uint16_t>()->default_value(8080),
|
||||
"Set the port number for the server")
|
||||
("ip", po::value<std::string>()->implicit_value("0.0.0.0"),
|
||||
("ip", po::value<std::string>()->default_value("0.0.0.0"),
|
||||
"Set the IP address to bind to, \"0.0.0.0\" for all")
|
||||
("threads,n", po::value<std::size_t>()->implicit_value(4),
|
||||
("threads,n", po::value<std::size_t>()->default_value(4),
|
||||
"Set the number of threads to use")
|
||||
("sync,s", "Launch a synchronous server")
|
||||
;
|
||||
po::variables_map vm;
|
||||
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||
|
||||
std::string root = ".";
|
||||
if(vm.count("root"))
|
||||
root = vm["root"].as<std::string>();
|
||||
std::string root = vm["root"].as<std::string>();
|
||||
|
||||
std::uint16_t port = 8080;
|
||||
if(vm.count("port"))
|
||||
port = vm["port"].as<std::uint16_t>();
|
||||
std::uint16_t port = vm["port"].as<std::uint16_t>();
|
||||
|
||||
std::string ip = "0.0.0.0";
|
||||
if(vm.count("ip"))
|
||||
ip = vm["ip"].as<std::string>();
|
||||
std::string ip = vm["ip"].as<std::string>();
|
||||
|
||||
std::size_t threads = 4;
|
||||
if(vm.count("threads"))
|
||||
threads = vm["threads"].as<std::size_t>();
|
||||
std::size_t threads = vm["threads"].as<std::size_t>();
|
||||
|
||||
bool sync = vm.count("sync") > 0;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "file_body.hpp"
|
||||
#include "mime_type.hpp"
|
||||
|
||||
#include <beast/http.hpp>
|
||||
#include <beast/core/placeholders.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <cstdint>
|
||||
@@ -19,6 +21,7 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <iostream>
|
||||
@@ -32,8 +35,8 @@ class http_sync_server
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
using req_type = request_v1<string_body>;
|
||||
using resp_type = response_v1<file_body>;
|
||||
using req_type = request<string_body>;
|
||||
using resp_type = response<file_body>;
|
||||
|
||||
bool log_ = true;
|
||||
std::mutex m_;
|
||||
@@ -161,44 +164,48 @@ private:
|
||||
path = root_ + path;
|
||||
if(! boost::filesystem::exists(path))
|
||||
{
|
||||
response_v1<string_body> res;
|
||||
response<string_body> res;
|
||||
res.status = 404;
|
||||
res.reason = "Not Found";
|
||||
res.version = req.version;
|
||||
res.headers.insert("Server", "http_sync_server");
|
||||
res.headers.insert("Content-Type", "text/html");
|
||||
res.fields.insert("Server", "http_sync_server");
|
||||
res.fields.insert("Content-Type", "text/html");
|
||||
res.body = "The file '" + path + "' was not found";
|
||||
prepare(res);
|
||||
write(sock, res, ec);
|
||||
if(ec)
|
||||
break;
|
||||
return;
|
||||
}
|
||||
resp_type res;
|
||||
res.status = 200;
|
||||
res.reason = "OK";
|
||||
res.version = req.version;
|
||||
res.headers.insert("Server", "http_sync_server");
|
||||
res.headers.insert("Content-Type", mime_type(path));
|
||||
res.body = path;
|
||||
try
|
||||
{
|
||||
resp_type res;
|
||||
res.status = 200;
|
||||
res.reason = "OK";
|
||||
res.version = req.version;
|
||||
res.fields.insert("Server", "http_sync_server");
|
||||
res.fields.insert("Content-Type", mime_type(path));
|
||||
res.body = path;
|
||||
prepare(res);
|
||||
write(sock, res, ec);
|
||||
if(ec)
|
||||
break;
|
||||
}
|
||||
catch(std::exception const& e)
|
||||
{
|
||||
res = {};
|
||||
response<string_body> 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.fields.insert("Server", "http_sync_server");
|
||||
res.fields.insert("Content-Type", "text/html");
|
||||
res.body =
|
||||
std::string{"An internal error occurred"} + e.what();
|
||||
std::string{"An internal error occurred: "} + e.what();
|
||||
prepare(res);
|
||||
write(sock, res, ec);
|
||||
if(ec)
|
||||
break;
|
||||
}
|
||||
write(sock, res, ec);
|
||||
if(ec)
|
||||
break;
|
||||
}
|
||||
fail(id, ec);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
32
src/beast/examples/ssl/CMakeLists.txt
Normal file
32
src/beast/examples/ssl/CMakeLists.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
# Part of Beast
|
||||
|
||||
GroupSources(extras/beast extras)
|
||||
GroupSources(include/beast beast)
|
||||
|
||||
GroupSources(examples/ssl "/")
|
||||
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
add_executable (http-ssl-example
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
http_ssl_example.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(http-ssl-example ${OPENSSL_LIBRARIES})
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(http-ssl-example ${Boost_LIBRARIES} Threads::Threads)
|
||||
endif()
|
||||
|
||||
add_executable (websocket-ssl-example
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
websocket_ssl_example.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(websocket-ssl-example ${OPENSSL_LIBRARIES})
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(websocket-ssl-example ${Boost_LIBRARIES} Threads::Threads)
|
||||
endif()
|
||||
54
src/beast/examples/ssl/Jamfile.v2
Normal file
54
src/beast/examples/ssl/Jamfile.v2
Normal file
@@ -0,0 +1,54 @@
|
||||
#
|
||||
# Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
|
||||
import os ;
|
||||
|
||||
if [ os.name ] = SOLARIS
|
||||
{
|
||||
lib socket ;
|
||||
lib nsl ;
|
||||
}
|
||||
else if [ os.name ] = NT
|
||||
{
|
||||
lib ws2_32 ;
|
||||
lib mswsock ;
|
||||
}
|
||||
else if [ os.name ] = HPUX
|
||||
{
|
||||
lib ipv6 ;
|
||||
}
|
||||
else if [ os.name ] = HAIKU
|
||||
{
|
||||
lib network ;
|
||||
}
|
||||
|
||||
if [ os.name ] = NT
|
||||
{
|
||||
lib ssl : : <name>ssleay32 ;
|
||||
lib crypto : : <name>libeay32 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
lib ssl ;
|
||||
lib crypto ;
|
||||
}
|
||||
|
||||
project
|
||||
: requirements
|
||||
<library>ssl
|
||||
<library>crypto
|
||||
;
|
||||
|
||||
exe http-ssl-example
|
||||
:
|
||||
http_ssl_example.cpp
|
||||
;
|
||||
|
||||
exe websocket-ssl-example
|
||||
:
|
||||
websocket_ssl_example.cpp
|
||||
;
|
||||
58
src/beast/examples/ssl/http_ssl_example.cpp
Normal file
58
src/beast/examples/ssl/http_ssl_example.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <beast/http.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::asio::connect;
|
||||
using socket = boost::asio::ip::tcp::socket;
|
||||
using resolver = boost::asio::ip::tcp::resolver;
|
||||
using io_service = boost::asio::io_service;
|
||||
namespace ssl = boost::asio::ssl;
|
||||
|
||||
// Normal boost::asio setup
|
||||
std::string const host = "github.com";
|
||||
io_service ios;
|
||||
resolver r{ios};
|
||||
socket sock{ios};
|
||||
connect(sock, r.resolve(resolver::query{host, "https"}));
|
||||
|
||||
// Perform SSL handshaking
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
ssl::stream<socket&> stream{sock, ctx};
|
||||
stream.set_verify_mode(ssl::verify_none);
|
||||
stream.handshake(ssl::stream_base::client);
|
||||
|
||||
// Send HTTP request over SSL using Beast
|
||||
beast::http::request<beast::http::empty_body> req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.fields.insert("Host", host + ":" +
|
||||
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||
req.fields.insert("User-Agent", "Beast");
|
||||
beast::http::prepare(req);
|
||||
beast::http::write(stream, req);
|
||||
|
||||
// Receive and print HTTP response using Beast
|
||||
beast::streambuf sb;
|
||||
beast::http::response<beast::http::streambuf_body> resp;
|
||||
beast::http::read(stream, sb, resp);
|
||||
std::cout << resp;
|
||||
|
||||
// Shut down SSL on the stream
|
||||
boost::system::error_code ec;
|
||||
stream.shutdown(ec);
|
||||
if(ec && ec != boost::asio::error::eof)
|
||||
std::cout << "error: " << ec.message();
|
||||
}
|
||||
49
src/beast/examples/ssl/websocket_ssl_example.cpp
Normal file
49
src/beast/examples/ssl/websocket_ssl_example.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <beast/core/to_string.hpp>
|
||||
#include <beast/websocket.hpp>
|
||||
#include <beast/websocket/ssl.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::asio::connect;
|
||||
using socket = boost::asio::ip::tcp::socket;
|
||||
using resolver = boost::asio::ip::tcp::resolver;
|
||||
using io_service = boost::asio::io_service;
|
||||
namespace ssl = boost::asio::ssl;
|
||||
|
||||
// Normal boost::asio setup
|
||||
std::string const host = "echo.websocket.org";
|
||||
io_service ios;
|
||||
resolver r{ios};
|
||||
socket sock{ios};
|
||||
connect(sock, r.resolve(resolver::query{host, "https"}));
|
||||
|
||||
// Perform SSL handshaking
|
||||
using stream_type = ssl::stream<socket&>;
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
stream_type stream{sock, ctx};
|
||||
stream.set_verify_mode(ssl::verify_none);
|
||||
stream.handshake(ssl::stream_base::client);
|
||||
|
||||
// Secure WebSocket connect and send message using Beast
|
||||
beast::websocket::stream<stream_type&> ws{stream};
|
||||
ws.handshake(host, "/");
|
||||
ws.write(boost::asio::buffer("Hello, world!"));
|
||||
|
||||
// Receive Secure WebSocket message, print and close using Beast
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(beast::websocket::close_code::normal);
|
||||
std::cout << to_string(sb.data()) << "\n";
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
375
src/beast/examples/websocket_async_echo_server.hpp
Normal file
375
src/beast/examples/websocket_async_echo_server.hpp
Normal file
@@ -0,0 +1,375 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef WEBSOCKET_ASYNC_ECHO_SERVER_HPP
|
||||
#define WEBSOCKET_ASYNC_ECHO_SERVER_HPP
|
||||
|
||||
#include <beast/core/placeholders.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/websocket/stream.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace websocket {
|
||||
|
||||
/** Asynchronous WebSocket echo client/server
|
||||
*/
|
||||
class async_echo_server
|
||||
{
|
||||
public:
|
||||
using error_code = beast::error_code;
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
|
||||
private:
|
||||
struct identity
|
||||
{
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
true, Body, Fields>& req) const
|
||||
{
|
||||
req.fields.replace("User-Agent", "async_echo_client");
|
||||
}
|
||||
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
false, Body, Fields>& resp) const
|
||||
{
|
||||
resp.fields.replace("Server", "async_echo_server");
|
||||
}
|
||||
};
|
||||
|
||||
/** A container of type-erased option setters.
|
||||
*/
|
||||
template<class NextLayer>
|
||||
class options_set
|
||||
{
|
||||
// workaround for std::function bug in msvc
|
||||
struct callable
|
||||
{
|
||||
virtual ~callable() = default;
|
||||
virtual void operator()(
|
||||
beast::websocket::stream<NextLayer>&) = 0;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class callable_impl : public callable
|
||||
{
|
||||
T t_;
|
||||
|
||||
public:
|
||||
template<class U>
|
||||
callable_impl(U&& u)
|
||||
: t_(std::forward<U>(u))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(beast::websocket::stream<NextLayer>& ws)
|
||||
{
|
||||
t_(ws);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Opt>
|
||||
class lambda
|
||||
{
|
||||
Opt opt_;
|
||||
|
||||
public:
|
||||
lambda(lambda&&) = default;
|
||||
lambda(lambda const&) = default;
|
||||
|
||||
lambda(Opt const& opt)
|
||||
: opt_(opt)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(beast::websocket::stream<NextLayer>& ws) const
|
||||
{
|
||||
ws.set_option(opt_);
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<std::type_index,
|
||||
std::unique_ptr<callable>> list_;
|
||||
|
||||
public:
|
||||
template<class Opt>
|
||||
void
|
||||
set_option(Opt const& opt)
|
||||
{
|
||||
std::unique_ptr<callable> p;
|
||||
p.reset(new callable_impl<lambda<Opt>>{opt});
|
||||
list_[std::type_index{
|
||||
typeid(Opt)}] = std::move(p);
|
||||
}
|
||||
|
||||
void
|
||||
set_options(beast::websocket::stream<NextLayer>& ws)
|
||||
{
|
||||
for(auto const& op : list_)
|
||||
(*op.second)(ws);
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream* log_;
|
||||
boost::asio::io_service ios_;
|
||||
socket_type sock_;
|
||||
endpoint_type ep_;
|
||||
boost::asio::ip::tcp::acceptor acceptor_;
|
||||
std::vector<std::thread> thread_;
|
||||
boost::optional<boost::asio::io_service::work> work_;
|
||||
options_set<socket_type> opts_;
|
||||
|
||||
public:
|
||||
async_echo_server(async_echo_server const&) = delete;
|
||||
async_echo_server& operator=(async_echo_server const&) = delete;
|
||||
|
||||
/** Constructor.
|
||||
|
||||
@param log A pointer to a stream to log to, or `nullptr`
|
||||
to disable logging.
|
||||
|
||||
@param threads The number of threads in the io_service.
|
||||
*/
|
||||
async_echo_server(std::ostream* log,
|
||||
std::size_t threads)
|
||||
: log_(log)
|
||||
, sock_(ios_)
|
||||
, acceptor_(ios_)
|
||||
, work_(ios_)
|
||||
{
|
||||
opts_.set_option(
|
||||
beast::websocket::decorate(identity{}));
|
||||
thread_.reserve(threads);
|
||||
for(std::size_t i = 0; i < threads; ++i)
|
||||
thread_.emplace_back(
|
||||
[&]{ ios_.run(); });
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
*/
|
||||
~async_echo_server()
|
||||
{
|
||||
work_ = boost::none;
|
||||
error_code ec;
|
||||
ios_.dispatch(
|
||||
[&]{ acceptor_.close(ec); });
|
||||
for(auto& t : thread_)
|
||||
t.join();
|
||||
}
|
||||
|
||||
/** Return the listening endpoint.
|
||||
*/
|
||||
endpoint_type
|
||||
local_endpoint() const
|
||||
{
|
||||
return acceptor_.local_endpoint();
|
||||
}
|
||||
|
||||
/** Set a websocket option.
|
||||
|
||||
The option will be applied to all new connections.
|
||||
|
||||
@param opt The option to apply.
|
||||
*/
|
||||
template<class Opt>
|
||||
void
|
||||
set_option(Opt const& opt)
|
||||
{
|
||||
opts_.set_option(opt);
|
||||
}
|
||||
|
||||
/** Open a listening port.
|
||||
|
||||
@param ep The address and port to bind to.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
void
|
||||
open(endpoint_type const& ep, error_code& ec)
|
||||
{
|
||||
acceptor_.open(ep.protocol(), ec);
|
||||
if(ec)
|
||||
return fail("open", ec);
|
||||
acceptor_.set_option(
|
||||
boost::asio::socket_base::reuse_address{true});
|
||||
acceptor_.bind(ep, ec);
|
||||
if(ec)
|
||||
return fail("bind", ec);
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
if(ec)
|
||||
return fail("listen", ec);
|
||||
acceptor_.async_accept(sock_, ep_,
|
||||
std::bind(&async_echo_server::on_accept, this,
|
||||
beast::asio::placeholders::error));
|
||||
}
|
||||
|
||||
private:
|
||||
class peer
|
||||
{
|
||||
struct data
|
||||
{
|
||||
async_echo_server& server;
|
||||
endpoint_type ep;
|
||||
int state = 0;
|
||||
beast::websocket::stream<socket_type> ws;
|
||||
boost::asio::io_service::strand strand;
|
||||
beast::websocket::opcode op;
|
||||
beast::streambuf db;
|
||||
std::size_t id;
|
||||
|
||||
data(async_echo_server& server_,
|
||||
endpoint_type const& ep_,
|
||||
socket_type&& sock_)
|
||||
: server(server_)
|
||||
, ep(ep_)
|
||||
, ws(std::move(sock_))
|
||||
, strand(ws.get_io_service())
|
||||
, id([]
|
||||
{
|
||||
static std::atomic<std::size_t> n{0};
|
||||
return ++n;
|
||||
}())
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// VFALCO This could be unique_ptr in [Net.TS]
|
||||
std::shared_ptr<data> d_;
|
||||
|
||||
public:
|
||||
peer(peer&&) = default;
|
||||
peer(peer const&) = default;
|
||||
peer& operator=(peer&&) = delete;
|
||||
peer& operator=(peer const&) = delete;
|
||||
|
||||
template<class... Args>
|
||||
explicit
|
||||
peer(async_echo_server& server,
|
||||
endpoint_type const& ep, socket_type&& sock,
|
||||
Args&&... args)
|
||||
: d_(std::make_shared<data>(server, ep,
|
||||
std::forward<socket_type>(sock),
|
||||
std::forward<Args>(args)...))
|
||||
{
|
||||
auto& d = *d_;
|
||||
d.server.opts_.set_options(d.ws);
|
||||
run();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
auto& d = *d_;
|
||||
d.ws.async_accept(std::move(*this));
|
||||
}
|
||||
|
||||
void operator()(error_code ec, std::size_t)
|
||||
{
|
||||
(*this)(ec);
|
||||
}
|
||||
|
||||
void operator()(error_code ec)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
auto& d = *d_;
|
||||
switch(d.state)
|
||||
{
|
||||
// did accept
|
||||
case 0:
|
||||
if(ec)
|
||||
return fail("async_accept", ec);
|
||||
|
||||
// start
|
||||
case 1:
|
||||
if(ec)
|
||||
return fail("async_handshake", ec);
|
||||
d.db.consume(d.db.size());
|
||||
// read message
|
||||
d.state = 2;
|
||||
d.ws.async_read(d.op, d.db,
|
||||
d.strand.wrap(std::move(*this)));
|
||||
return;
|
||||
|
||||
// got message
|
||||
case 2:
|
||||
if(ec == beast::websocket::error::closed)
|
||||
return;
|
||||
if(ec)
|
||||
return fail("async_read", ec);
|
||||
// write message
|
||||
d.state = 1;
|
||||
d.ws.set_option(
|
||||
beast::websocket::message_type(d.op));
|
||||
d.ws.async_write(d.db.data(),
|
||||
d.strand.wrap(std::move(*this)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
fail(std::string what, error_code ec)
|
||||
{
|
||||
auto& d = *d_;
|
||||
if(d.server.log_)
|
||||
if(ec != beast::websocket::error::closed)
|
||||
d.server.fail("[#" + std::to_string(d.id) +
|
||||
" " + boost::lexical_cast<std::string>(d.ep) +
|
||||
"] " + what, ec);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
fail(std::string what, error_code ec)
|
||||
{
|
||||
if(log_)
|
||||
{
|
||||
static std::mutex m;
|
||||
std::lock_guard<std::mutex> lock{m};
|
||||
(*log_) << what << ": " <<
|
||||
ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_accept(error_code ec)
|
||||
{
|
||||
if(! acceptor_.is_open())
|
||||
return;
|
||||
if(ec == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
if(ec)
|
||||
fail("accept", ec);
|
||||
peer{*this, ep_, std::move(sock_)};
|
||||
acceptor_.async_accept(sock_, ep_,
|
||||
std::bind(&async_echo_server::on_accept, this,
|
||||
beast::asio::placeholders::error));
|
||||
}
|
||||
};
|
||||
|
||||
} // websocket
|
||||
|
||||
#endif
|
||||
56
src/beast/examples/websocket_echo.cpp
Normal file
56
src/beast/examples/websocket_echo.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include "websocket_async_echo_server.hpp"
|
||||
#include "websocket_sync_echo_server.hpp"
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
#include <iostream>
|
||||
|
||||
/// Block until SIGINT or SIGTERM is received.
|
||||
void
|
||||
sig_wait()
|
||||
{
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::signal_set signals(
|
||||
ios, SIGINT, SIGTERM);
|
||||
signals.async_wait(
|
||||
[&](boost::system::error_code const&, int)
|
||||
{
|
||||
});
|
||||
ios.run();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace beast::websocket;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
|
||||
beast::error_code ec;
|
||||
|
||||
permessage_deflate pmd;
|
||||
pmd.client_enable = true;
|
||||
pmd.server_enable = true;
|
||||
pmd.compLevel = 3;
|
||||
|
||||
websocket::async_echo_server s1{&std::cout, 1};
|
||||
s1.set_option(read_message_max{64 * 1024 * 1024});
|
||||
s1.set_option(auto_fragment{false});
|
||||
s1.set_option(pmd);
|
||||
s1.open(endpoint_type{
|
||||
address_type::from_string("127.0.0.1"), 6000 }, ec);
|
||||
|
||||
websocket::sync_echo_server s2{&std::cout};
|
||||
s2.set_option(read_message_max{64 * 1024 * 1024});
|
||||
s2.set_option(auto_fragment{false});
|
||||
s2.set_option(pmd);
|
||||
s2.open(endpoint_type{
|
||||
address_type::from_string("127.0.0.1"), 6001 }, ec);
|
||||
|
||||
sig_wait();
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -24,12 +24,12 @@ int main()
|
||||
// WebSocket connect and send message using beast
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
ws.handshake(host, "/");
|
||||
ws.write(boost::asio::buffer("Hello, world!"));
|
||||
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||
|
||||
// Receive WebSocket message, print and close using beast
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(beast::websocket::close_code::normal);
|
||||
std::cout << to_string(sb.data()) << "\n";
|
||||
std::cout << beast::to_string(sb.data()) << "\n";
|
||||
}
|
||||
|
||||
326
src/beast/examples/websocket_sync_echo_server.hpp
Normal file
326
src/beast/examples/websocket_sync_echo_server.hpp
Normal file
@@ -0,0 +1,326 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef WEBSOCKET_SYNC_ECHO_SERVER_HPP
|
||||
#define WEBSOCKET_SYNC_ECHO_SERVER_HPP
|
||||
|
||||
#include <beast/core/placeholders.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/websocket.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace websocket {
|
||||
|
||||
/** Synchronous WebSocket echo client/server
|
||||
*/
|
||||
class sync_echo_server
|
||||
{
|
||||
public:
|
||||
using error_code = beast::error_code;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
private:
|
||||
struct identity
|
||||
{
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
true, Body, Fields>& req) const
|
||||
{
|
||||
req.fields.replace("User-Agent", "sync_echo_client");
|
||||
}
|
||||
|
||||
template<class Body, class Fields>
|
||||
void
|
||||
operator()(beast::http::message<
|
||||
false, Body, Fields>& resp) const
|
||||
{
|
||||
resp.fields.replace("Server", "sync_echo_server");
|
||||
}
|
||||
};
|
||||
|
||||
/** A container of type-erased option setters.
|
||||
*/
|
||||
template<class NextLayer>
|
||||
class options_set
|
||||
{
|
||||
// workaround for std::function bug in msvc
|
||||
struct callable
|
||||
{
|
||||
virtual ~callable() = default;
|
||||
virtual void operator()(
|
||||
beast::websocket::stream<NextLayer>&) = 0;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class callable_impl : public callable
|
||||
{
|
||||
T t_;
|
||||
|
||||
public:
|
||||
template<class U>
|
||||
callable_impl(U&& u)
|
||||
: t_(std::forward<U>(u))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(beast::websocket::stream<NextLayer>& ws)
|
||||
{
|
||||
t_(ws);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Opt>
|
||||
class lambda
|
||||
{
|
||||
Opt opt_;
|
||||
|
||||
public:
|
||||
lambda(lambda&&) = default;
|
||||
lambda(lambda const&) = default;
|
||||
|
||||
lambda(Opt const& opt)
|
||||
: opt_(opt)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(beast::websocket::stream<NextLayer>& ws) const
|
||||
{
|
||||
ws.set_option(opt_);
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<std::type_index,
|
||||
std::unique_ptr<callable>> list_;
|
||||
|
||||
public:
|
||||
template<class Opt>
|
||||
void
|
||||
set_option(Opt const& opt)
|
||||
{
|
||||
std::unique_ptr<callable> p;
|
||||
p.reset(new callable_impl<lambda<Opt>>{opt});
|
||||
list_[std::type_index{
|
||||
typeid(Opt)}] = std::move(p);
|
||||
}
|
||||
|
||||
void
|
||||
set_options(beast::websocket::stream<NextLayer>& ws)
|
||||
{
|
||||
for(auto const& op : list_)
|
||||
(*op.second)(ws);
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream* log_;
|
||||
boost::asio::io_service ios_;
|
||||
socket_type sock_;
|
||||
endpoint_type ep_;
|
||||
boost::asio::ip::tcp::acceptor acceptor_;
|
||||
std::thread thread_;
|
||||
options_set<socket_type> opts_;
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
|
||||
@param log A pointer to a stream to log to, or `nullptr`
|
||||
to disable logging.
|
||||
*/
|
||||
sync_echo_server(std::ostream* log)
|
||||
: log_(log)
|
||||
, sock_(ios_)
|
||||
, acceptor_(ios_)
|
||||
{
|
||||
opts_.set_option(
|
||||
beast::websocket::decorate(identity{}));
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
*/
|
||||
~sync_echo_server()
|
||||
{
|
||||
if(thread_.joinable())
|
||||
{
|
||||
error_code ec;
|
||||
ios_.dispatch(
|
||||
[&]{ acceptor_.close(ec); });
|
||||
thread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the listening endpoint.
|
||||
*/
|
||||
endpoint_type
|
||||
local_endpoint() const
|
||||
{
|
||||
return acceptor_.local_endpoint();
|
||||
}
|
||||
|
||||
/** Set a websocket option.
|
||||
|
||||
The option will be applied to all new connections.
|
||||
|
||||
@param opt The option to apply.
|
||||
*/
|
||||
template<class Opt>
|
||||
void
|
||||
set_option(Opt const& opt)
|
||||
{
|
||||
opts_.set_option(opt);
|
||||
}
|
||||
|
||||
/** Open a listening port.
|
||||
|
||||
@param ep The address and port to bind to.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
void
|
||||
open(endpoint_type const& ep, error_code& ec)
|
||||
{
|
||||
acceptor_.open(ep.protocol(), ec);
|
||||
if(ec)
|
||||
return fail("open", ec);
|
||||
acceptor_.set_option(
|
||||
boost::asio::socket_base::reuse_address{true});
|
||||
acceptor_.bind(ep, ec);
|
||||
if(ec)
|
||||
return fail("bind", ec);
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
if(ec)
|
||||
return fail("listen", ec);
|
||||
acceptor_.async_accept(sock_, ep_,
|
||||
std::bind(&sync_echo_server::on_accept, this,
|
||||
beast::asio::placeholders::error));
|
||||
thread_ = std::thread{[&]{ ios_.run(); }};
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
fail(std::string what, error_code ec)
|
||||
{
|
||||
if(log_)
|
||||
{
|
||||
static std::mutex m;
|
||||
std::lock_guard<std::mutex> lock{m};
|
||||
(*log_) << what << ": " <<
|
||||
ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fail(std::string what, error_code ec,
|
||||
int id, endpoint_type const& ep)
|
||||
{
|
||||
if(log_)
|
||||
if(ec != beast::websocket::error::closed)
|
||||
fail("[#" + std::to_string(id) + " " +
|
||||
boost::lexical_cast<std::string>(ep) +
|
||||
"] " + what, ec);
|
||||
}
|
||||
|
||||
void
|
||||
on_accept(error_code ec)
|
||||
{
|
||||
if(ec == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
if(ec)
|
||||
return fail("accept", ec);
|
||||
struct lambda
|
||||
{
|
||||
std::size_t id;
|
||||
endpoint_type ep;
|
||||
sync_echo_server& self;
|
||||
boost::asio::io_service::work work;
|
||||
// Must be destroyed before work otherwise the
|
||||
// io_service could be destroyed before the socket.
|
||||
socket_type sock;
|
||||
|
||||
lambda(sync_echo_server& self_,
|
||||
endpoint_type const& ep_,
|
||||
socket_type&& sock_)
|
||||
: id([]
|
||||
{
|
||||
static std::atomic<std::size_t> n{0};
|
||||
return ++n;
|
||||
}())
|
||||
, ep(ep_)
|
||||
, self(self_)
|
||||
, work(sock_.get_io_service())
|
||||
, sock(std::move(sock_))
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
self.do_peer(id, ep, std::move(sock));
|
||||
}
|
||||
};
|
||||
std::thread{lambda{*this, ep_, std::move(sock_)}}.detach();
|
||||
acceptor_.async_accept(sock_, ep_,
|
||||
std::bind(&sync_echo_server::on_accept, this,
|
||||
beast::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void
|
||||
do_peer(std::size_t id,
|
||||
endpoint_type const& ep, socket_type&& sock)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
using boost::asio::buffer_copy;
|
||||
beast::websocket::stream<
|
||||
socket_type> ws{std::move(sock)};
|
||||
opts_.set_options(ws);
|
||||
error_code ec;
|
||||
ws.accept(ec);
|
||||
if(ec)
|
||||
{
|
||||
fail("accept", ec, id, ep);
|
||||
return;
|
||||
}
|
||||
for(;;)
|
||||
{
|
||||
beast::websocket::opcode op;
|
||||
beast::streambuf sb;
|
||||
ws.read(op, sb, ec);
|
||||
if(ec)
|
||||
{
|
||||
auto const s = ec.message();
|
||||
break;
|
||||
}
|
||||
ws.set_option(beast::websocket::message_type{op});
|
||||
ws.write(sb.data(), ec);
|
||||
if(ec)
|
||||
break;
|
||||
}
|
||||
if(ec && ec != beast::websocket::error::closed)
|
||||
{
|
||||
fail("read", ec, id, ep);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // websocket
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -13,11 +13,9 @@
|
||||
namespace beast {
|
||||
namespace test {
|
||||
|
||||
enum error
|
||||
enum class error
|
||||
{
|
||||
success = 0,
|
||||
|
||||
fail_error
|
||||
fail_error = 1
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
@@ -79,14 +77,15 @@ inline
|
||||
error_code
|
||||
make_error_code(error ev)
|
||||
{
|
||||
return error_code{static_cast<int>(ev),
|
||||
detail::get_error_category()};
|
||||
return error_code{
|
||||
static_cast<std::underlying_type<error>::type>(ev),
|
||||
detail::get_error_category()};
|
||||
}
|
||||
|
||||
/** A countdown to simulated failure.
|
||||
|
||||
On the Nth operation, the class will fail with the specified
|
||||
error code, or the default error code of @ref fail_error.
|
||||
error code, or the default error code of @ref error::fail_error.
|
||||
*/
|
||||
class fail_counter
|
||||
{
|
||||
@@ -102,7 +101,7 @@ public:
|
||||
*/
|
||||
explicit
|
||||
fail_counter(std::size_t n,
|
||||
error_code ev = make_error_code(fail_error))
|
||||
error_code ev = make_error_code(error::fail_error))
|
||||
: n_(n)
|
||||
, ec_(ev)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -113,7 +113,7 @@ public:
|
||||
{
|
||||
async_completion<
|
||||
ReadHandler, void(error_code, std::size_t)
|
||||
> completion(handler);
|
||||
> completion{handler};
|
||||
next_layer_.get_io_service().post(
|
||||
bind_handler(completion.handler, ec, 0));
|
||||
return completion.result.get();
|
||||
@@ -150,7 +150,7 @@ public:
|
||||
{
|
||||
async_completion<
|
||||
WriteHandler, void(error_code, std::size_t)
|
||||
> completion(handler);
|
||||
> completion{handler};
|
||||
next_layer_.get_io_service().post(
|
||||
bind_handler(completion.handler, ec, 0));
|
||||
return completion.result.get();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,8 +9,6 @@
|
||||
#define BEAST_TEST_SIG_WAIT_HPP
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
namespace beast {
|
||||
namespace test {
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_TEST_STRING_STREAM_HPP
|
||||
#define BEAST_TEST_STRING_STREAM_HPP
|
||||
#ifndef BEAST_TEST_STRING_ISTREAM_HPP
|
||||
#define BEAST_TEST_STRING_ISTREAM_HPP
|
||||
|
||||
#include <beast/core/async_completion.hpp>
|
||||
#include <beast/core/bind_handler.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/prepare_buffer.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <string>
|
||||
@@ -23,16 +25,21 @@ namespace test {
|
||||
discarded, and when data is read it comes from a string provided
|
||||
at construction.
|
||||
*/
|
||||
class string_stream
|
||||
class string_istream
|
||||
{
|
||||
std::string s_;
|
||||
boost::asio::const_buffer cb_;
|
||||
boost::asio::io_service& ios_;
|
||||
std::size_t read_max_;
|
||||
|
||||
public:
|
||||
string_stream(boost::asio::io_service& ios,
|
||||
std::string s)
|
||||
string_istream(boost::asio::io_service& ios,
|
||||
std::string s, std::size_t read_max =
|
||||
(std::numeric_limits<std::size_t>::max)())
|
||||
: s_(std::move(s))
|
||||
, cb_(boost::asio::buffer(s_))
|
||||
, ios_(ios)
|
||||
, read_max_(read_max)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -59,9 +66,9 @@ public:
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = boost::asio::buffer_copy(
|
||||
buffers, boost::asio::buffer(s_));
|
||||
buffers, prepare_buffer(read_max_, cb_));
|
||||
if(n > 0)
|
||||
s_.erase(0, n);
|
||||
cb_ = cb_ + n;
|
||||
else
|
||||
ec = boost::asio::error::eof;
|
||||
return n;
|
||||
@@ -81,7 +88,7 @@ public:
|
||||
else
|
||||
ec = boost::asio::error::eof;
|
||||
async_completion<ReadHandler,
|
||||
void(error_code, std::size_t)> completion(handler);
|
||||
void(error_code, std::size_t)> completion{handler};
|
||||
ios_.post(bind_handler(
|
||||
completion.handler, ec, n));
|
||||
return completion.result.get();
|
||||
@@ -113,7 +120,7 @@ public:
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
async_completion<WriteHandler,
|
||||
void(error_code, std::size_t)> completion(handler);
|
||||
void(error_code, std::size_t)> completion{handler};
|
||||
ios_.post(bind_handler(completion.handler,
|
||||
error_code{}, boost::asio::buffer_size(buffers)));
|
||||
return completion.result.get();
|
||||
118
src/beast/extras/beast/test/string_ostream.hpp
Normal file
118
src/beast/extras/beast/test/string_ostream.hpp
Normal file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_TEST_STRING_OSTREAM_HPP
|
||||
#define BEAST_TEST_STRING_OSTREAM_HPP
|
||||
|
||||
#include <beast/core/async_completion.hpp>
|
||||
#include <beast/core/bind_handler.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace test {
|
||||
|
||||
class string_ostream
|
||||
{
|
||||
boost::asio::io_service& ios_;
|
||||
|
||||
public:
|
||||
std::string str;
|
||||
|
||||
explicit
|
||||
string_ostream(boost::asio::io_service& ios)
|
||||
: ios_(ios)
|
||||
{
|
||||
}
|
||||
|
||||
boost::asio::io_service&
|
||||
get_io_service()
|
||||
{
|
||||
return ios_;
|
||||
}
|
||||
|
||||
template<class MutableBufferSequence>
|
||||
std::size_t
|
||||
read_some(MutableBufferSequence const& buffers)
|
||||
{
|
||||
error_code ec;
|
||||
auto const n = read_some(buffers, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
return n;
|
||||
}
|
||||
|
||||
template<class MutableBufferSequence>
|
||||
std::size_t
|
||||
read_some(MutableBufferSequence const& buffers,
|
||||
error_code& ec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class MutableBufferSequence, class ReadHandler>
|
||||
typename async_completion<ReadHandler,
|
||||
void(error_code, std::size_t)>::result_type
|
||||
async_read_some(MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler)
|
||||
{
|
||||
async_completion<ReadHandler,
|
||||
void(error_code, std::size_t)> completion{handler};
|
||||
ios_.post(bind_handler(completion.handler,
|
||||
error_code{}, 0));
|
||||
return completion.result.get();
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(ConstBufferSequence const& buffers)
|
||||
{
|
||||
error_code ec;
|
||||
auto const n = write_some(buffers, ec);
|
||||
if(ec)
|
||||
throw system_error{ec};
|
||||
return n;
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(
|
||||
ConstBufferSequence const& buffers, error_code&)
|
||||
{
|
||||
auto const n = buffer_size(buffers);
|
||||
using boost::asio::buffer_size;
|
||||
using boost::asio::buffer_cast;
|
||||
str.reserve(str.size() + n);
|
||||
for(auto const& buffer : buffers)
|
||||
str.append(buffer_cast<char const*>(buffer),
|
||||
buffer_size(buffer));
|
||||
return n;
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
async_write_some(ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
error_code ec;
|
||||
auto const bytes_transferred = write_some(buffers, ec);
|
||||
async_completion<
|
||||
WriteHandler, void(error_code, std::size_t)
|
||||
> completion{handler};
|
||||
get_io_service().post(
|
||||
bind_handler(completion.handler, ec, bytes_transferred));
|
||||
return completion.result.get();
|
||||
}
|
||||
};
|
||||
|
||||
} // test
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -21,9 +21,9 @@ namespace test {
|
||||
|
||||
/** Mix-in to support tests using asio coroutines.
|
||||
|
||||
Derive from this class and use yield_to to launch test functions
|
||||
inside coroutines. This is handy for testing asynchronous asio
|
||||
code.
|
||||
Derive from this class and use yield_to to launch test
|
||||
functions inside coroutines. This is handy for testing
|
||||
asynchronous asio code.
|
||||
*/
|
||||
class enable_yield_to
|
||||
{
|
||||
@@ -72,12 +72,32 @@ public:
|
||||
Function will be called with this signature:
|
||||
|
||||
@code
|
||||
void f(yield_context);
|
||||
void f(args..., yield_context);
|
||||
@endcode
|
||||
|
||||
@param f The Callable object to invoke.
|
||||
|
||||
@param args Optional arguments forwarded to the callable object.
|
||||
*/
|
||||
template<class Function>
|
||||
#if GENERATING_DOCS
|
||||
template<class F, class... Args>
|
||||
void
|
||||
yield_to(Function&& f);
|
||||
yield_to(F&& f, Args&&... args);
|
||||
#else
|
||||
template<class F>
|
||||
void
|
||||
yield_to(F&& f);
|
||||
|
||||
template<class Function, class Arg, class... Args>
|
||||
void
|
||||
yield_to(Function&& f, Arg&& arg, Args&&... args)
|
||||
{
|
||||
yield_to(std::bind(f,
|
||||
std::forward<Arg>(arg),
|
||||
std::forward<Args>(args)...,
|
||||
std::placeholders::_1));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<class Function>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
: std::basic_ostream<CharT, Traits>(&buf_)
|
||||
, buf_(os)
|
||||
{
|
||||
if(os.flags() && std::ios::unitbuf)
|
||||
if(os.flags() & std::ios::unitbuf)
|
||||
std::unitbuf(*this);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <beast/unit_test/amount.hpp>
|
||||
#include <beast/unit_test/recorder.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
@@ -214,7 +215,8 @@ reporter<_>::fmtdur(typename clock_type::duration const& d)
|
||||
using namespace std::chrono;
|
||||
auto const ms = duration_cast<milliseconds>(d);
|
||||
if(ms < seconds{1})
|
||||
return std::to_string(ms.count()) + "ms";
|
||||
return boost::lexical_cast<std::string>(
|
||||
ms.count()) + "ms";
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::setprecision(1) <<
|
||||
(ms.count()/1000.) << "s";
|
||||
@@ -243,7 +245,7 @@ on_case_begin(std::string const& name)
|
||||
{
|
||||
case_results_ = case_results(name);
|
||||
os_ << suite_results_.name <<
|
||||
(case_results_.name.empty() ? "" :
|
||||
(case_results_.name.empty() ? "" :
|
||||
(" " + case_results_.name)) << std::endl;
|
||||
}
|
||||
|
||||
@@ -281,7 +283,6 @@ reporter<_>::
|
||||
on_log(std::string const& s)
|
||||
{
|
||||
os_ << s;
|
||||
os_.flush();
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,7 +9,7 @@
|
||||
#define BEAST_UNIT_TEST_RUNNER_H_INCLUDED
|
||||
|
||||
#include <beast/unit_test/suite_info.hpp>
|
||||
#include <cassert>
|
||||
#include <boost/assert.hpp>
|
||||
#include <mutex>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
@@ -185,7 +185,7 @@ runner::run(suite_info const& s)
|
||||
on_suite_begin(s);
|
||||
s.run(*this);
|
||||
// Forgot to call pass or fail.
|
||||
assert(cond_);
|
||||
BOOST_ASSERT(cond_);
|
||||
on_case_end();
|
||||
on_suite_end();
|
||||
return failed_;
|
||||
@@ -239,9 +239,9 @@ runner::testcase(std::string const& name)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
// Name may not be empty
|
||||
assert(default_ || ! name.empty());
|
||||
BOOST_ASSERT(default_ || ! name.empty());
|
||||
// Forgot to call pass or fail
|
||||
assert(default_ || cond_);
|
||||
BOOST_ASSERT(default_ || cond_);
|
||||
if(! default_)
|
||||
on_case_end();
|
||||
default_ = false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <beast/unit_test/runner.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -17,6 +18,27 @@
|
||||
namespace beast {
|
||||
namespace unit_test {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class String>
|
||||
static
|
||||
std::string
|
||||
make_reason(String const& reason,
|
||||
char const* file, int line)
|
||||
{
|
||||
std::string s(reason);
|
||||
if(! s.empty())
|
||||
s.append(": ");
|
||||
namespace fs = boost::filesystem;
|
||||
s.append(fs::path{file}.filename().string());
|
||||
s.append("(");
|
||||
s.append(boost::lexical_cast<std::string>(line));
|
||||
s.append(")");
|
||||
return s;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
class thread;
|
||||
|
||||
enum abort_t
|
||||
@@ -112,7 +134,7 @@ private:
|
||||
}
|
||||
|
||||
/** Open a new testcase.
|
||||
|
||||
|
||||
A testcase is a series of evaluated test conditions. A test
|
||||
suite may have multiple test cases. A test is associated with
|
||||
the last opened testcase. When the test first runs, a default
|
||||
@@ -178,11 +200,21 @@ public:
|
||||
|
||||
/** Record a failure.
|
||||
|
||||
@param reason
|
||||
@param reason Optional text added to the output on a failure.
|
||||
|
||||
@param file The source code file where the test failed.
|
||||
|
||||
@param line The source code line number where the test failed.
|
||||
*/
|
||||
/** @{ */
|
||||
template<class String>
|
||||
void
|
||||
fail(String const& reason, char const* file, int line);
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
fail(std::string const& reason = "");
|
||||
/** @} */
|
||||
|
||||
/** Evaluate a test condition.
|
||||
|
||||
@@ -206,25 +238,25 @@ public:
|
||||
bool
|
||||
expect(Condition const& shouldBeTrue)
|
||||
{
|
||||
return expect(shouldBeTrue, {});
|
||||
return expect(shouldBeTrue, "");
|
||||
}
|
||||
|
||||
template<class Condition>
|
||||
template<class Condition, class String>
|
||||
bool
|
||||
expect(Condition const& shouldBeTrue, std::string const& reason);
|
||||
expect(Condition const& shouldBeTrue, String const& reason);
|
||||
|
||||
template<class Condition>
|
||||
bool
|
||||
expect(Condition const& shouldBeTrue,
|
||||
char const* file, int line)
|
||||
{
|
||||
return expect(shouldBeTrue, {}, file, line);
|
||||
return expect(shouldBeTrue, "", file, line);
|
||||
}
|
||||
|
||||
template<class Condition>
|
||||
template<class Condition, class String>
|
||||
bool
|
||||
expect(Condition const& shouldBeTrue,
|
||||
std::string const& reason, char const* file, int line);
|
||||
String const& reason, char const* file, int line);
|
||||
/** @} */
|
||||
|
||||
//
|
||||
@@ -320,10 +352,7 @@ public:
|
||||
{
|
||||
auto const& name = ss_.str();
|
||||
if(! name.empty())
|
||||
{
|
||||
suite_.log.flush();
|
||||
suite_.runner_->testcase(name);
|
||||
}
|
||||
}
|
||||
|
||||
scoped_testcase(suite& self, std::stringstream& ss)
|
||||
@@ -362,7 +391,6 @@ suite::testcase_t::operator()(
|
||||
std::string const& name, abort_t abort)
|
||||
{
|
||||
suite_.abort_ = abort == abort_on_fail;
|
||||
suite_.log.flush();
|
||||
suite_.runner_->testcase(name);
|
||||
}
|
||||
|
||||
@@ -402,11 +430,11 @@ operator()(runner& r)
|
||||
}
|
||||
}
|
||||
|
||||
template<class Condition>
|
||||
template<class Condition, class String>
|
||||
bool
|
||||
suite::
|
||||
expect(
|
||||
Condition const& shouldBeTrue, std::string const& reason)
|
||||
Condition const& shouldBeTrue, String const& reason)
|
||||
{
|
||||
if(shouldBeTrue)
|
||||
{
|
||||
@@ -417,26 +445,18 @@ expect(
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class Condition>
|
||||
template<class Condition, class String>
|
||||
bool
|
||||
suite::
|
||||
expect(Condition const& shouldBeTrue,
|
||||
std::string const& reason, char const* file, int line)
|
||||
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);
|
||||
fail(detail::make_reason(reason, file, line));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -535,6 +555,14 @@ fail(std::string const& reason)
|
||||
}
|
||||
}
|
||||
|
||||
template<class String>
|
||||
void
|
||||
suite::
|
||||
fail(String const& reason, char const* file, int line)
|
||||
{
|
||||
fail(detail::make_reason(reason, file, line));
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
suite::
|
||||
@@ -583,7 +611,8 @@ run(runner& r)
|
||||
|
||||
If the condition is false, the file and line number are reported.
|
||||
*/
|
||||
#define BEAST_EXPECTS(cond, reason) expect(cond, reason, __FILE__, __LINE__)
|
||||
#define BEAST_EXPECTS(cond, reason) ((cond) ? (pass(), true) : \
|
||||
(fail((reason), __FILE__, __LINE__), false))
|
||||
#endif
|
||||
|
||||
} // unit_test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <beast/unit_test/suite_info.hpp>
|
||||
#include <beast/unit_test/detail/const_container.hpp>
|
||||
#include <cassert>
|
||||
#include <boost/assert.hpp>
|
||||
#include <typeindex>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
@@ -57,13 +57,13 @@ suite_list::insert(
|
||||
std::string s;
|
||||
s = std::string(library) + "." + module + "." + name;
|
||||
auto const result(names_.insert(s));
|
||||
assert(result.second); // Duplicate name
|
||||
BOOST_ASSERT(result.second); // Duplicate name
|
||||
}
|
||||
|
||||
{
|
||||
auto const result(classes_.insert(
|
||||
std::type_index(typeid(Suite))));
|
||||
assert(result.second); // Duplicate type
|
||||
BOOST_ASSERT(result.second); // Duplicate type
|
||||
}
|
||||
#endif
|
||||
cont().emplace(make_suite_info<Suite>(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user