Compare commits
178 Commits
0.33.0-hf1
...
0.50.0-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
ef23d72562 | ||
|
|
a1c0d15a1f | ||
|
|
b6a01ea41c | ||
|
|
8425e4558a | ||
|
|
5a688f9236 | ||
|
|
effd8c9737 | ||
|
|
a7c4d682d2 | ||
|
|
e00a6b0e5a | ||
|
|
dc3571184a | ||
|
|
22a375a5f4 | ||
|
|
3337d17fdd | ||
|
|
8ab2236cdd | ||
|
|
0cb6a0f961 | ||
|
|
28ae522ea2 | ||
|
|
c0cf7bd3c1 | ||
|
|
fd7a2835e4 | ||
|
|
3d0314c621 | ||
|
|
8d83aa5c07 | ||
|
|
7ff243ade9 | ||
|
|
2fd0540ed4 | ||
|
|
cdf470e68d | ||
|
|
7fc780dd70 | ||
|
|
4d7b1a3b61 | ||
|
|
9a9dffa4ff | ||
|
|
51e7f595bb | ||
|
|
293e520efc | ||
|
|
9e960ff6b8 | ||
|
|
0a8e690917 | ||
|
|
cf60d4c30e | ||
|
|
8f2480225b | ||
|
|
44167a6bcb | ||
|
|
db95808206 | ||
|
|
fd901f8081 | ||
|
|
b6ce0aa75a | ||
|
|
b712125bc0 | ||
|
|
d69b16895c | ||
|
|
d198b439fd | ||
|
|
83aa5517c0 | ||
|
|
5711e7caa9 | ||
|
|
8d0c93691d | ||
|
|
d8d0cb17ba | ||
|
|
47a919faf0 | ||
|
|
d572de769b | ||
|
|
810a6b0f30 | ||
|
|
665ad180cb | ||
|
|
361917e902 | ||
|
|
4b261b12a4 | ||
|
|
afd4b45036 | ||
|
|
47adc728db | ||
|
|
7e39d645b9 | ||
|
|
35504f1723 | ||
|
|
61d9dda4e0 | ||
|
|
38ca9d4a97 | ||
|
|
f37aa1d6c8 | ||
|
|
db13ddf844 | ||
|
|
bf642404c7 | ||
|
|
d53d5cfc42 | ||
|
|
bbf52056f9 | ||
|
|
b8cae2dfaf | ||
|
|
795ee8bb5e | ||
|
|
cfcd618aa6 | ||
|
|
19258cf980 | ||
|
|
cdaafeb4b6 | ||
|
|
7688a97d95 | ||
|
|
027b289c91 | ||
|
|
b55edfa8f0 | ||
|
|
7d46d153c6 | ||
|
|
96b17749af | ||
|
|
f27348c4d5 | ||
|
|
c6923dcf88 | ||
|
|
f456355da2 | ||
|
|
97806b42c4 | ||
|
|
ed02b0717e | ||
|
|
2963e91752 | ||
|
|
aa11effdd6 | ||
|
|
6e9c15af92 | ||
|
|
0ddeb29c35 | ||
|
|
a7630aaa55 | ||
|
|
1d15af6afd | ||
|
|
dd0075f2b8 | ||
|
|
4b0d8b630c | ||
|
|
b421559a47 | ||
|
|
05e7373086 | ||
|
|
bb0b97f46b | ||
|
|
3b639afac2 | ||
|
|
bd93ecbd6b | ||
|
|
79159ffd87 | ||
|
|
231a5ae6fb | ||
|
|
45249e8746 | ||
|
|
e6ed9ae4d8 | ||
|
|
aca6db5601 | ||
|
|
8e9f9599b8 | ||
|
|
71d7d87bf3 | ||
|
|
7ffef30f1c | ||
|
|
7c90b9ef88 | ||
|
|
4bb74196c0 | ||
|
|
35fa20a110 | ||
|
|
633cf86ad8 | ||
|
|
66ce8779e8 | ||
|
|
a9b3042d7e | ||
|
|
4df24c0e8e | ||
|
|
9a988963e9 | ||
|
|
5be33a650d | ||
|
|
5b09dc731f | ||
|
|
51d7e7336f | ||
|
|
ad9be4dbf6 | ||
|
|
2f9a8440c2 | ||
|
|
a40dd2690a | ||
|
|
104f12a9e2 | ||
|
|
e499743cdd | ||
|
|
241795cd73 | ||
|
|
411b2534ed | ||
|
|
253f138aff | ||
|
|
dadbab4c0f | ||
|
|
d9017a3f76 | ||
|
|
aedfaab93d | ||
|
|
d263d4d449 | ||
|
|
b39e4817e5 | ||
|
|
4dfa250a34 | ||
|
|
8a6908c072 | ||
|
|
d8fe737ad7 | ||
|
|
61023c3f4a | ||
|
|
b607d47bd3 | ||
|
|
878c0f2a19 | ||
|
|
19dd983d2b | ||
|
|
c15751ced6 | ||
|
|
a55d9aa4c3 | ||
|
|
037d52114a | ||
|
|
3ff56eb071 | ||
|
|
9e8a5a5765 | ||
|
|
461a8ea846 | ||
|
|
8d9c0daa9d | ||
|
|
1537527927 | ||
|
|
8204d9524e | ||
|
|
07bf106cd3 | ||
|
|
225b5a1204 | ||
|
|
054d5de877 | ||
|
|
5349bcc1c5 | ||
|
|
17fd2ef2e2 | ||
|
|
e199c0555c | ||
|
|
42557b800c | ||
|
|
ef2330d477 | ||
|
|
f8a1ec0348 | ||
|
|
8375ae647e | ||
|
|
69da298aa7 | ||
|
|
6765507cc4 | ||
|
|
e2c67a1666 | ||
|
|
6397025435 | ||
|
|
2a448065da | ||
|
|
5c7130e4fd | ||
|
|
bbad20c66f | ||
|
|
c4c8a620c8 |
5
.gitignore
vendored
@@ -1,5 +1,9 @@
|
|||||||
# .gitignore
|
# .gitignore
|
||||||
|
|
||||||
|
bin/boostbook_catalog.xml
|
||||||
|
bin/config.log
|
||||||
|
bin/project-cache.jam
|
||||||
|
|
||||||
# Ignore vim swap files.
|
# Ignore vim swap files.
|
||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
@@ -89,3 +93,4 @@ Builds/VisualStudio2015/*.sdf
|
|||||||
|
|
||||||
# MSVC
|
# MSVC
|
||||||
*.pdb
|
*.pdb
|
||||||
|
.vs/
|
||||||
|
|||||||
12
.gitmodules
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[submodule "docs/docca"]
|
||||||
|
path = docs/docca
|
||||||
|
url = https://github.com/vinniefalco/docca.git
|
||||||
|
[submodule "src/nudb/extras/beast"]
|
||||||
|
path = src/nudb/extras/beast
|
||||||
|
url = https://github.com/vinniefalco/Beast.git
|
||||||
|
[submodule "src/nudb/extras/rocksdb"]
|
||||||
|
path = src/nudb/extras/rocksdb
|
||||||
|
url = https://github.com/facebook/rocksdb.git
|
||||||
|
[submodule "src/nudb/doc/docca"]
|
||||||
|
path = src/nudb/doc/docca
|
||||||
|
url = https://github.com/vinniefalco/docca.git
|
||||||
48
.travis.yml
@@ -11,51 +11,57 @@ env:
|
|||||||
# to boost's .tar.gz.
|
# to boost's .tar.gz.
|
||||||
- LCOV_ROOT=$HOME/lcov
|
- LCOV_ROOT=$HOME/lcov
|
||||||
- BOOST_ROOT=$HOME/boost_1_60_0
|
- 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'
|
- BOOST_URL='http://sourceforge.net/projects/boost/files/boost/1.60.0/boost_1_60_0.tar.gz'
|
||||||
|
|
||||||
packages: &gcc5_pkgs
|
addons:
|
||||||
- gcc-5
|
apt:
|
||||||
- g++-5
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
- python-software-properties
|
packages:
|
||||||
- protobuf-compiler
|
- gcc-5
|
||||||
- libprotobuf-dev
|
- g++-5
|
||||||
- libssl-dev
|
- python-software-properties
|
||||||
- libstdc++6
|
- protobuf-compiler
|
||||||
- binutils-gold
|
- libprotobuf-dev
|
||||||
# Provides a backtrace if the unittests crash
|
- libssl-dev
|
||||||
- gdb
|
- libstdc++6
|
||||||
|
- binutils-gold
|
||||||
|
# Provides a backtrace if the unittests crash
|
||||||
|
- gdb
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
# Default BUILD is "scons".
|
||||||
|
|
||||||
- compiler: gcc
|
- compiler: gcc
|
||||||
env: GCC_VER=5 TARGET=debug.nounity
|
env: GCC_VER=5 BUILD=cmake TARGET=debug.nounity PATH=$PWD/cmake/bin:$PATH
|
||||||
addons: &ao_gcc5
|
|
||||||
apt:
|
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
|
||||||
packages: *gcc5_pkgs
|
|
||||||
|
|
||||||
- compiler: gcc
|
- compiler: gcc
|
||||||
env: GCC_VER=5 TARGET=coverage
|
env: GCC_VER=5 TARGET=coverage
|
||||||
addons: *ao_gcc5
|
|
||||||
|
|
||||||
- compiler: clang
|
- compiler: clang
|
||||||
env: GCC_VER=5 TARGET=debug CLANG_VER=3.8 PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
env: GCC_VER=5 TARGET=debug CLANG_VER=3.8 PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
||||||
addons: *ao_gcc5
|
|
||||||
|
|
||||||
- compiler: clang
|
- compiler: clang
|
||||||
env: GCC_VER=5 TARGET=debug.nounity CLANG_VER=3.8 PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
env: GCC_VER=5 TARGET=debug.nounity CLANG_VER=3.8 PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
||||||
addons: *ao_gcc5
|
|
||||||
|
# The clang cmake builds do not link.
|
||||||
|
# - compiler: clang
|
||||||
|
# env: GCC_VER=5 BUILD=cmake TARGET=debug CLANG_VER=3.8 PATH=$PWD/llvm-$LLVM_VERSION/bin:$PWD/cmake/bin:$PATH
|
||||||
|
|
||||||
|
# - compiler: clang
|
||||||
|
# env: GCC_VER=5 BUILD=cmake TARGET=debug.nounity CLANG_VER=3.8 PATH=$PWD/llvm-$LLVM_VERSION/bin:$PWD/cmake/bin:$PATH
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $BOOST_ROOT
|
- $BOOST_ROOT
|
||||||
- llvm-$LLVM_VERSION
|
- llvm-$LLVM_VERSION
|
||||||
|
- cmake
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- bin/ci/ubuntu/install-dependencies.sh
|
- bin/ci/ubuntu/install-dependencies.sh
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- bin/ci/ubuntu/build-and-test.sh
|
- travis_retry bin/ci/ubuntu/build-and-test.sh
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ url="https://github.com/ripple/rippled"
|
|||||||
license=('custom:ISC')
|
license=('custom:ISC')
|
||||||
depends=('protobuf' 'openssl' 'boost-libs')
|
depends=('protobuf' 'openssl' 'boost-libs')
|
||||||
makedepends=('git' 'scons' 'boost')
|
makedepends=('git' 'scons' 'boost')
|
||||||
checkdepends=('nodejs')
|
|
||||||
backup=("etc/$pkgname/rippled.cfg")
|
backup=("etc/$pkgname/rippled.cfg")
|
||||||
source=("git://github.com/ripple/rippled.git#branch=master")
|
source=("git://github.com/ripple/rippled.git#branch=master")
|
||||||
sha512sums=('SKIP')
|
sha512sums=('SKIP')
|
||||||
@@ -26,8 +25,6 @@ build() {
|
|||||||
|
|
||||||
check() {
|
check() {
|
||||||
cd "$srcdir/$pkgname"
|
cd "$srcdir/$pkgname"
|
||||||
npm install
|
|
||||||
npm test
|
|
||||||
build/rippled --unittest
|
build/rippled --unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
658
Builds/CMake/CMakeFuncs.cmake
Normal file
@@ -0,0 +1,658 @@
|
|||||||
|
# This is a set of common functions and settings for rippled
|
||||||
|
# and derived products.
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.1.0)
|
||||||
|
|
||||||
|
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
|
||||||
|
message(WARNING "Builds are strongly discouraged in "
|
||||||
|
"${CMAKE_SOURCE_DIR}.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
macro(parse_target)
|
||||||
|
|
||||||
|
if (NOT target AND NOT CMAKE_BUILD_TYPE)
|
||||||
|
if (APPLE)
|
||||||
|
set(target clang.debug)
|
||||||
|
elseif(WIN32)
|
||||||
|
set(target msvc)
|
||||||
|
else()
|
||||||
|
set(target gcc.debug)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (target)
|
||||||
|
# Parse the target
|
||||||
|
set(remaining ${target})
|
||||||
|
while (remaining)
|
||||||
|
# get the component up to the next dot or end
|
||||||
|
string(REGEX REPLACE "^\\.?([^\\.]+).*$" "\\1" cur_component ${remaining})
|
||||||
|
string(REGEX REPLACE "^\\.?[^\\.]+(.*$)" "\\1" remaining ${remaining})
|
||||||
|
|
||||||
|
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})
|
||||||
|
else()
|
||||||
|
find_program(CMAKE_C_COMPILER gcc)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (DEFINED ENV{GNU_CXX})
|
||||||
|
set(CMAKE_C_COMPILER $ENV{GNU_CXX})
|
||||||
|
elseif ($ENV{CXX} MATCHES .*g\\+\\+.*)
|
||||||
|
set(CMAKE_C_COMPILER $ENV{CC})
|
||||||
|
else()
|
||||||
|
find_program(CMAKE_CXX_COMPILER g++)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
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})
|
||||||
|
else()
|
||||||
|
find_program(CMAKE_C_COMPILER clang)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (DEFINED ENV{CLANG_CXX})
|
||||||
|
set(CMAKE_C_COMPILER $ENV{CLANG_CXX})
|
||||||
|
elseif ($ENV{CXX} MATCHES .*clang.*)
|
||||||
|
set(CMAKE_C_COMPILER $ENV{CC})
|
||||||
|
else()
|
||||||
|
find_program(CMAKE_CXX_COMPILER clang++)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${cur_component} STREQUAL msvc)
|
||||||
|
# TBD
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${cur_component} STREQUAL unity)
|
||||||
|
set(unity true)
|
||||||
|
set(nonunity false)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${cur_component} STREQUAL nounity)
|
||||||
|
set(unity false)
|
||||||
|
set(nonunity true)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${cur_component} STREQUAL debug)
|
||||||
|
set(release false)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${cur_component} STREQUAL release)
|
||||||
|
set(release true)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${cur_component} STREQUAL coverage)
|
||||||
|
set(coverage true)
|
||||||
|
set(debug true)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${cur_component} STREQUAL profile)
|
||||||
|
set(profile true)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${cur_component} STREQUAL ci)
|
||||||
|
# Workarounds that make various CI builds work, but that
|
||||||
|
# we don't want in the general case.
|
||||||
|
set(ci true)
|
||||||
|
set(openssl_min 1.0.1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endwhile()
|
||||||
|
|
||||||
|
if (release)
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
else()
|
||||||
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT unity)
|
||||||
|
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}Classic)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
macro(setup_build_cache)
|
||||||
|
set(san "" CACHE STRING "On gcc & clang, add sanitizer
|
||||||
|
instrumentation")
|
||||||
|
set_property(CACHE san PROPERTY STRINGS ";address;thread")
|
||||||
|
set(assert false CACHE BOOL "Enables asserts, even in release builds")
|
||||||
|
set(static false CACHE BOOL
|
||||||
|
"On linux, link protobuf, openssl, libc++, and boost statically")
|
||||||
|
|
||||||
|
if (static AND (WIN32 OR APPLE))
|
||||||
|
message(FATAL_ERROR "Static linking is only supported on linux.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${CMAKE_GENERATOR} STREQUAL "Unix Makefiles" AND NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Can't exclude files from configurations, so can't support both
|
||||||
|
# unity and nonunity configurations at the same time
|
||||||
|
if (NOT DEFINED unity OR unity)
|
||||||
|
set(CMAKE_CONFIGURATION_TYPES
|
||||||
|
Debug
|
||||||
|
Release)
|
||||||
|
else()
|
||||||
|
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()
|
||||||
|
|
||||||
|
set(CMAKE_CONFIGURATION_TYPES
|
||||||
|
${CMAKE_CONFIGURATION_TYPES} CACHE STRING "" FORCE)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
function(prepend var prefix)
|
||||||
|
set(listVar "")
|
||||||
|
foreach(f ${ARGN})
|
||||||
|
list(APPEND listVar "${prefix}${f}")
|
||||||
|
endforeach(f)
|
||||||
|
set(${var} "${listVar}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
macro(append_flags name)
|
||||||
|
foreach (arg ${ARGN})
|
||||||
|
set(${name} "${${name}} ${arg}")
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(group_sources curdir)
|
||||||
|
file(GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${curdir}
|
||||||
|
${PROJECT_SOURCE_DIR}/${curdir}/*)
|
||||||
|
foreach (child ${children})
|
||||||
|
if (IS_DIRECTORY ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
||||||
|
group_sources(${curdir}/${child})
|
||||||
|
else()
|
||||||
|
string(REPLACE "/" "\\" groupname ${curdir})
|
||||||
|
source_group(${groupname} FILES
|
||||||
|
${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(add_with_props src_var files)
|
||||||
|
list(APPEND ${src_var} ${files})
|
||||||
|
foreach (arg ${ARGN})
|
||||||
|
set(props "${props} ${arg}")
|
||||||
|
endforeach()
|
||||||
|
set_source_files_properties(
|
||||||
|
${files}
|
||||||
|
PROPERTIES COMPILE_FLAGS
|
||||||
|
${props})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
macro(determine_build_type)
|
||||||
|
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES ".*Clang") # both Clang and AppleClang
|
||||||
|
set(is_clang true)
|
||||||
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
|
set(is_gcc true)
|
||||||
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
|
set(is_msvc true)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (${CMAKE_GENERATOR} STREQUAL "Xcode")
|
||||||
|
set(is_xcode true)
|
||||||
|
else()
|
||||||
|
set(is_xcode false)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT is_gcc AND NOT is_clang AND NOT is_msvc)
|
||||||
|
message("Current compiler is ${CMAKE_CXX_COMPILER_ID}")
|
||||||
|
message(FATAL_ERROR "Missing compiler. Must be GNU, Clang, or MSVC")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
macro(check_gcc4_abi)
|
||||||
|
# Check if should use gcc4's ABI
|
||||||
|
set(gcc4_abi false)
|
||||||
|
|
||||||
|
if ($ENV{RIPPLED_OLD_GCC_ABI})
|
||||||
|
set(gcc4_abi true)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (is_gcc AND NOT gcc4_abi)
|
||||||
|
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5)
|
||||||
|
execute_process(COMMAND lsb_release -si OUTPUT_VARIABLE lsb)
|
||||||
|
string(STRIP "${lsb}" lsb)
|
||||||
|
if ("${lsb}" STREQUAL "Ubuntu")
|
||||||
|
execute_process(COMMAND lsb_release -sr OUTPUT_VARIABLE lsb)
|
||||||
|
string(STRIP ${lsb} lsb)
|
||||||
|
if (${lsb} VERSION_LESS 15.1)
|
||||||
|
set(gcc4_abi true)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (gcc4_abi)
|
||||||
|
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
macro(special_build_flags)
|
||||||
|
if (coverage)
|
||||||
|
add_compile_options(-fprofile-arcs -ftest-coverage)
|
||||||
|
append_flags(CMAKE_EXE_LINKER_FLAGS -fprofile-arcs -ftest-coverage)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (profile)
|
||||||
|
add_compile_options(-p -pg)
|
||||||
|
append_flags(CMAKE_EXE_LINKER_FLAGS -p -pg)
|
||||||
|
endif()
|
||||||
|
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(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)
|
||||||
|
else()
|
||||||
|
set(Boost_LIBRARY_DIR ${BOOST_ROOT}/stage/lib)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (is_clang AND DEFINED ENV{CLANG_BOOST_ROOT})
|
||||||
|
set(BOOST_ROOT $ENV{CLANG_BOOST_ROOT})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(Boost_USE_STATIC_LIBS on)
|
||||||
|
set(Boost_USE_MULTITHREADED on)
|
||||||
|
set(Boost_USE_STATIC_RUNTIME off)
|
||||||
|
find_package(Boost COMPONENTS
|
||||||
|
${ARGN})
|
||||||
|
|
||||||
|
if (Boost_FOUND OR
|
||||||
|
((CYGWIN OR WIN32) AND Boost_INCLUDE_DIRS AND Boost_LIBRARY_DIRS))
|
||||||
|
if(NOT Boost_FOUND)
|
||||||
|
message(WARNING "Boost directory found, but not all components. May not be able to build.")
|
||||||
|
endif()
|
||||||
|
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||||
|
link_directories(${Boost_LIBRARY_DIRS})
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Boost not found")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(use_pthread)
|
||||||
|
if (NOT WIN32)
|
||||||
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
|
find_package(Threads)
|
||||||
|
add_compile_options(${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(use_openssl openssl_min)
|
||||||
|
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()
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
if (DEFINED ENV{OPENSSL_ROOT})
|
||||||
|
include_directories($ENV{OPENSSL_ROOT}/include)
|
||||||
|
link_directories($ENV{OPENSSL_ROOT}/lib)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
if (static)
|
||||||
|
set(tmp CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(OpenSSL)
|
||||||
|
|
||||||
|
if (static)
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES tmp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (OPENSSL_FOUND)
|
||||||
|
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "OpenSSL not found")
|
||||||
|
endif()
|
||||||
|
if (UNIX AND NOT APPLE AND ${OPENSSL_VERSION} VERSION_LESS ${openssl_min})
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Your openssl is Version: ${OPENSSL_VERSION}, ${openssl_min} or better is required.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(use_protobuf)
|
||||||
|
if (WIN32)
|
||||||
|
if (DEFINED ENV{PROTOBUF_ROOT})
|
||||||
|
include_directories($ENV{PROTOBUF_ROOT}/src)
|
||||||
|
link_directories($ENV{PROTOBUF_ROOT}/src/.libs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Modified from FindProtobuf.cmake
|
||||||
|
FUNCTION(PROTOBUF_GENERATE_CPP SRCS HDRS PROTOFILES)
|
||||||
|
# argument parsing
|
||||||
|
IF(NOT PROTOFILES)
|
||||||
|
MESSAGE(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files")
|
||||||
|
RETURN()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
SET(OUTPATH ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
SET(PROTOROOT ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
# the real logic
|
||||||
|
SET(${SRCS})
|
||||||
|
SET(${HDRS})
|
||||||
|
FOREACH(PROTOFILE ${PROTOFILES})
|
||||||
|
# ensure that the file ends with .proto
|
||||||
|
STRING(REGEX MATCH "\\.proto$$" PROTOEND ${PROTOFILE})
|
||||||
|
IF(NOT PROTOEND)
|
||||||
|
MESSAGE(SEND_ERROR "Proto file '${PROTOFILE}' does not end with .proto")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
GET_FILENAME_COMPONENT(PROTO_PATH ${PROTOFILE} PATH)
|
||||||
|
GET_FILENAME_COMPONENT(ABS_FILE ${PROTOFILE} ABSOLUTE)
|
||||||
|
GET_FILENAME_COMPONENT(FILE_WE ${PROTOFILE} NAME_WE)
|
||||||
|
|
||||||
|
STRING(REGEX MATCH "^${PROTOROOT}" IN_ROOT_PATH ${PROTOFILE})
|
||||||
|
STRING(REGEX MATCH "^${PROTOROOT}" IN_ROOT_ABS_FILE ${ABS_FILE})
|
||||||
|
|
||||||
|
IF(IN_ROOT_PATH)
|
||||||
|
SET(MATCH_PATH ${PROTOFILE})
|
||||||
|
ELSEIF(IN_ROOT_ABS_FILE)
|
||||||
|
SET(MATCH_PATH ${ABS_FILE})
|
||||||
|
ELSE()
|
||||||
|
MESSAGE(SEND_ERROR "Proto file '${PROTOFILE}' is not in protoroot '${PROTOROOT}'")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
# build the result file name
|
||||||
|
STRING(REGEX REPLACE "^${PROTOROOT}(/?)" "" ROOT_CLEANED_FILE ${MATCH_PATH})
|
||||||
|
STRING(REGEX REPLACE "\\.proto$$" "" EXT_CLEANED_FILE ${ROOT_CLEANED_FILE})
|
||||||
|
|
||||||
|
SET(CPP_FILE "${OUTPATH}/${EXT_CLEANED_FILE}.pb.cc")
|
||||||
|
SET(H_FILE "${OUTPATH}/${EXT_CLEANED_FILE}.pb.h")
|
||||||
|
|
||||||
|
LIST(APPEND ${SRCS} "${CPP_FILE}")
|
||||||
|
LIST(APPEND ${HDRS} "${H_FILE}")
|
||||||
|
|
||||||
|
ADD_CUSTOM_COMMAND(
|
||||||
|
OUTPUT "${CPP_FILE}" "${H_FILE}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPATH}
|
||||||
|
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
|
||||||
|
ARGS "--cpp_out=${OUTPATH}" --proto_path "${PROTOROOT}" "${MATCH_PATH}"
|
||||||
|
DEPENDS ${ABS_FILE}
|
||||||
|
COMMENT "Running C++ protocol buffer compiler on ${MATCH_PATH} with root ${PROTOROOT}, generating: ${CPP_FILE}"
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
ENDFOREACH()
|
||||||
|
|
||||||
|
SET_SOURCE_FILES_PROPERTIES(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
|
||||||
|
SET(${SRCS} ${${SRCS}} PARENT_SCOPE)
|
||||||
|
SET(${HDRS} ${${HDRS}} PARENT_SCOPE)
|
||||||
|
|
||||||
|
ENDFUNCTION()
|
||||||
|
|
||||||
|
set(PROTOBUF_PROTOC_EXECUTABLE Protoc) # must be on path
|
||||||
|
else()
|
||||||
|
if (static)
|
||||||
|
set(tmp CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(Protobuf REQUIRED)
|
||||||
|
|
||||||
|
if (static)
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES tmp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (is_clang AND DEFINED ENV{CLANG_PROTOBUF_ROOT})
|
||||||
|
link_directories($ENV{CLANG_PROTOBUF_ROOT}/src/.libs)
|
||||||
|
include_directories($ENV{CLANG_PROTOBUF_ROOT}/src)
|
||||||
|
else()
|
||||||
|
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
file(GLOB ripple_proto src/ripple/proto/*.proto)
|
||||||
|
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${ripple_proto})
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
include_directories(src/protobuf/src
|
||||||
|
src/protobuf/vsprojects
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/src/ripple/proto)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
macro(setup_build_boilerplate)
|
||||||
|
if (NOT WIN32 AND san)
|
||||||
|
add_compile_options(-fsanitize=${san} -fno-omit-frame-pointer)
|
||||||
|
|
||||||
|
append_flags(CMAKE_EXE_LINKER_FLAGS
|
||||||
|
-fsanitize=${san})
|
||||||
|
|
||||||
|
string(TOLOWER ${san} ci_san)
|
||||||
|
if (${ci_san} STREQUAL address)
|
||||||
|
set(SANITIZER_LIBRARIES asan)
|
||||||
|
add_definitions(-DSANITIZER=ASAN)
|
||||||
|
endif()
|
||||||
|
if (${ci_san} STREQUAL thread)
|
||||||
|
set(SANITIZER_LIBRARIES tsan)
|
||||||
|
add_definitions(-DSANITIZER=TSAN)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
add_definitions(
|
||||||
|
-DOPENSSL_NO_SSL2
|
||||||
|
-DDEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
|
||||||
|
-DHAVE_USLEEP=1
|
||||||
|
-DSOCI_CXX_C11=1
|
||||||
|
-D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
|
||||||
|
-DBOOST_NO_AUTO_PTR
|
||||||
|
)
|
||||||
|
|
||||||
|
if (is_gcc)
|
||||||
|
add_compile_options(-Wno-unused-but-set-variable -Wno-deprecated)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Generator expressions are not supported in add_definitions, use set_property instead
|
||||||
|
set_property(
|
||||||
|
DIRECTORY
|
||||||
|
APPEND
|
||||||
|
PROPERTY COMPILE_DEFINITIONS
|
||||||
|
$<$<OR:$<CONFIG:Debug>,$<CONFIG:DebugClassic>>:DEBUG _DEBUG>)
|
||||||
|
|
||||||
|
if (NOT assert)
|
||||||
|
set_property(
|
||||||
|
DIRECTORY
|
||||||
|
APPEND
|
||||||
|
PROPERTY COMPILE_DEFINITIONS
|
||||||
|
$<$<OR:$<BOOL:${profile}>,$<CONFIG:Release>,$<CONFIG:ReleaseClassic>>:NDEBUG>)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
add_definitions(-D_FILE_OFFSET_BITS=64)
|
||||||
|
append_flags(CMAKE_CXX_FLAGS -frtti -std=c++14 -Wno-invalid-offsetof
|
||||||
|
-DBOOST_COROUTINE_NO_DEPRECATION_WARNING -DBOOST_COROUTINES_NO_DEPRECATION_WARNING)
|
||||||
|
add_compile_options(-Wall -Wno-sign-compare -Wno-char-subscripts -Wno-format
|
||||||
|
-Wno-unused-local-typedefs -g)
|
||||||
|
# There seems to be an issue using generator experssions with multiple values,
|
||||||
|
# split the expression
|
||||||
|
add_compile_options($<$<OR:$<CONFIG:Release>,$<CONFIG:ReleaseClassic>>:-O3>)
|
||||||
|
add_compile_options($<$<OR:$<CONFIG:Release>,$<CONFIG:ReleaseClassic>>:-fno-strict-aliasing>)
|
||||||
|
append_flags(CMAKE_EXE_LINKER_FLAGS -rdynamic -g)
|
||||||
|
|
||||||
|
if (is_clang)
|
||||||
|
add_compile_options(
|
||||||
|
-Wno-redeclared-class-member -Wno-mismatched-tags -Wno-deprecated-register)
|
||||||
|
add_definitions(-DBOOST_ASIO_HAS_STD_ARRAY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
add_definitions(-DBEAST_COMPILE_OBJECTIVE_CPP=1
|
||||||
|
-DNO_LOG_UNHANDLED_EXCEPTIONS)
|
||||||
|
add_compile_options(
|
||||||
|
-Wno-deprecated -Wno-deprecated-declarations -Wno-unused-variable -Wno-unused-function)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (is_gcc)
|
||||||
|
add_compile_options(-Wno-unused-but-set-variable -Wno-unused-local-typedefs)
|
||||||
|
add_compile_options($<$<OR:$<CONFIG:Debug>,$<CONFIG:DebugClassic>>:-O0>)
|
||||||
|
endif (is_gcc)
|
||||||
|
else(NOT WIN32)
|
||||||
|
add_compile_options(
|
||||||
|
/bigobj # Increase object file max size
|
||||||
|
/EHa # ExceptionHandling all
|
||||||
|
/fp:precise # Floating point behavior
|
||||||
|
/Gd # __cdecl calling convention
|
||||||
|
/Gm- # Minimal rebuild: disabled
|
||||||
|
/GR # Enable RTTI
|
||||||
|
/Gy- # Function level linking: disabled
|
||||||
|
/FS
|
||||||
|
/MP # Multiprocessor compilation
|
||||||
|
/openmp- # pragma omp: disabled
|
||||||
|
/Zc:forScope # Language extension: for scope
|
||||||
|
/Zi # Generate complete debug info
|
||||||
|
/errorReport:none # No error reporting to Internet
|
||||||
|
/nologo # Suppress login banner
|
||||||
|
/W3 # Warning level 3
|
||||||
|
/WX- # Disable warnings as errors
|
||||||
|
/wd"4018"
|
||||||
|
/wd"4244"
|
||||||
|
/wd"4267"
|
||||||
|
/wd"4800" # Disable C4800(int to bool performance)
|
||||||
|
/wd"4503" # Decorated name length exceeded, name was truncated
|
||||||
|
)
|
||||||
|
add_definitions(
|
||||||
|
-D_WIN32_WINNT=0x6000
|
||||||
|
-D_SCL_SECURE_NO_WARNINGS
|
||||||
|
-D_CRT_SECURE_NO_WARNINGS
|
||||||
|
-DWIN32_CONSOLE
|
||||||
|
-DNOMINMAX
|
||||||
|
-DBOOST_COROUTINE_NO_DEPRECATION_WARNING
|
||||||
|
-DBOOST_COROUTINES_NO_DEPRECATION_WARNING)
|
||||||
|
append_flags(CMAKE_EXE_LINKER_FLAGS
|
||||||
|
/DEBUG
|
||||||
|
/DYNAMICBASE
|
||||||
|
/ERRORREPORT:NONE
|
||||||
|
/MACHINE:X64
|
||||||
|
/MANIFEST
|
||||||
|
/nologo
|
||||||
|
/NXCOMPAT
|
||||||
|
/SUBSYSTEM:CONSOLE
|
||||||
|
/TLBID:1)
|
||||||
|
|
||||||
|
|
||||||
|
# There seems to be an issue using generator experssions with multiple values,
|
||||||
|
# split the expression
|
||||||
|
# /GS Buffers security check: enable
|
||||||
|
add_compile_options($<$<OR:$<CONFIG:Debug>,$<CONFIG:DebugClassic>>:/GS>)
|
||||||
|
# /MTd Language: Multi-threaded Debug CRT
|
||||||
|
add_compile_options($<$<OR:$<CONFIG:Debug>,$<CONFIG:DebugClassic>>:/MTd>)
|
||||||
|
# /Od Optimization: Disabled
|
||||||
|
add_compile_options($<$<OR:$<CONFIG:Debug>,$<CONFIG:DebugClassic>>:/Od>)
|
||||||
|
# /RTC1 Run-time error checks:
|
||||||
|
add_compile_options($<$<OR:$<CONFIG:Debug>,$<CONFIG:DebugClassic>>:/RTC1>)
|
||||||
|
|
||||||
|
# Generator expressions are not supported in add_definitions, use set_property instead
|
||||||
|
set_property(
|
||||||
|
DIRECTORY
|
||||||
|
APPEND
|
||||||
|
PROPERTY COMPILE_DEFINITIONS
|
||||||
|
$<$<OR:$<CONFIG:Debug>,$<CONFIG:DebugClassic>>:_CRTDBG_MAP_ALLOC>)
|
||||||
|
|
||||||
|
# /MT Language: Multi-threaded CRT
|
||||||
|
add_compile_options($<$<OR:$<CONFIG:Release>,$<CONFIG:ReleaseClassic>>:/MT>)
|
||||||
|
add_compile_options($<$<OR:$<CONFIG:Release>,$<CONFIG:ReleaseClassic>>:/Ox>)
|
||||||
|
# /Ox Optimization: Full
|
||||||
|
|
||||||
|
endif (NOT WIN32)
|
||||||
|
|
||||||
|
if (static)
|
||||||
|
append_flags(CMAKE_EXE_LINKER_FLAGS -static-libstdc++)
|
||||||
|
# set_target_properties(ripple-libpp PROPERTIES LINK_SEARCH_START_STATIC 1)
|
||||||
|
# set_target_properties(ripple-libpp PROPERTIES LINK_SEARCH_END_STATIC 1)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
macro(create_build_folder cur_project)
|
||||||
|
if (NOT WIN32)
|
||||||
|
ADD_CUSTOM_TARGET(build_folder ALL
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMENT "Creating build output folder")
|
||||||
|
add_dependencies(${cur_project} build_folder)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(set_startup_project cur_project)
|
||||||
|
if (WIN32 AND NOT ci)
|
||||||
|
if (CMAKE_VERSION VERSION_LESS 3.6)
|
||||||
|
message(WARNING
|
||||||
|
"Setting the VS startup project requires cmake 3.6 or later. Please upgrade.")
|
||||||
|
endif()
|
||||||
|
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY
|
||||||
|
VS_STARTUP_PROJECT ${cur_project})
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(link_common_libraries cur_project)
|
||||||
|
if (NOT MSVC)
|
||||||
|
target_link_libraries(${cur_project} ${Boost_LIBRARIES})
|
||||||
|
target_link_libraries(${cur_project} dl)
|
||||||
|
target_link_libraries(${cur_project} Threads::Threads)
|
||||||
|
if (APPLE)
|
||||||
|
find_library(app_kit AppKit)
|
||||||
|
find_library(foundation Foundation)
|
||||||
|
target_link_libraries(${cur_project}
|
||||||
|
crypto ssl ${app_kit} ${foundation})
|
||||||
|
else()
|
||||||
|
target_link_libraries(${cur_project} rt)
|
||||||
|
endif()
|
||||||
|
else(NOT MSVC)
|
||||||
|
target_link_libraries(${cur_project}
|
||||||
|
$<$<OR:$<CONFIG:Debug>,$<CONFIG:DebugClassic>>:VC/static/ssleay32MTd>
|
||||||
|
$<$<OR:$<CONFIG:Debug>,$<CONFIG:DebugClassic>>:VC/static/libeay32MTd>)
|
||||||
|
target_link_libraries(${cur_project}
|
||||||
|
$<$<OR:$<CONFIG:Release>,$<CONFIG:ReleaseClassic>>:VC/static/ssleay32MT>
|
||||||
|
$<$<OR:$<CONFIG:Release>,$<CONFIG:ReleaseClassic>>:VC/static/libeay32MT>)
|
||||||
|
target_link_libraries(${cur_project}
|
||||||
|
legacy_stdio_definitions.lib Shlwapi kernel32 user32 gdi32 winspool comdlg32
|
||||||
|
advapi32 shell32 ole32 oleaut32 uuid odbc32 odbccp32)
|
||||||
|
endif (NOT MSVC)
|
||||||
|
endmacro()
|
||||||
@@ -117,12 +117,6 @@ parser.add_argument(
|
|||||||
help='Add a prefix for unit tests',
|
help='Add a prefix for unit tests',
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'--nonpm', '-n',
|
|
||||||
action='store_true',
|
|
||||||
help='Do not run npm tests',
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--clean', '-c',
|
'--clean', '-c',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@@ -203,15 +197,6 @@ def run_tests(args):
|
|||||||
if not ARGS.keep_going:
|
if not ARGS.keep_going:
|
||||||
break
|
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
|
return failed
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ if [ ${ubuntu_release} == "12.04" ]; then
|
|||||||
add-apt-repository ppa:ubuntu-toolchain-r/test
|
add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get -y upgrade
|
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-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
|
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
|
exit 0
|
||||||
@@ -33,12 +33,12 @@ fi
|
|||||||
|
|
||||||
if [ ${ubuntu_release} == "14.04" ] || [ ${ubuntu_release} == "15.04" ]; then
|
if [ ${ubuntu_release} == "14.04" ] || [ ${ubuntu_release} == "15.04" ]; then
|
||||||
apt-get install python-software-properties
|
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 -
|
wget -O- -q https://mirrors.ripple.com/mirrors.ripple.com.gpg.key | sudo apt-key add -
|
||||||
add-apt-repository ppa:ubuntu-toolchain-r/test
|
add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get -y upgrade
|
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-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
|
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
|
exit 0
|
||||||
@@ -47,7 +47,7 @@ fi
|
|||||||
if [ ${ubuntu_release} == "16.04" ] || [ ${ubuntu_release} == "15.10" ]; then
|
if [ ${ubuntu_release} == "16.04" ] || [ ${ubuntu_release} == "15.10" ]; then
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get -y upgrade
|
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
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ software components:
|
|||||||
* [Google Protocol Buffers Compiler](README.md#install-google-protocol-buffers-compiler)
|
* [Google Protocol Buffers Compiler](README.md#install-google-protocol-buffers-compiler)
|
||||||
* (Optional) [Python and Scons](README.md#optional-install-python-and-scons)
|
* (Optional) [Python and Scons](README.md#optional-install-python-and-scons)
|
||||||
* [OpenSSL Library](README.md#install-openssl)
|
* [OpenSSL Library](README.md#install-openssl)
|
||||||
* [Boost 1.59 library](README.md#build-boost)
|
* [Boost library](README.md#build-boost)
|
||||||
* [Node.js](README.md#install-nodejs)
|
|
||||||
|
|
||||||
## Install Software
|
## Install Software
|
||||||
|
|
||||||
@@ -84,8 +83,8 @@ for Visual Studio 2015 support.
|
|||||||
[Download OpenSSL.](http://slproweb.com/products/Win32OpenSSL.html)
|
[Download OpenSSL.](http://slproweb.com/products/Win32OpenSSL.html)
|
||||||
There will be four variants available:
|
There will be four variants available:
|
||||||
|
|
||||||
1. 64-bit. Use this if you are running 64-bit windows. As of this writing, the link is called: "Win64 OpenSSL v1.0.2d".
|
1. 64-bit. Use this if you are running 64-bit windows. As of this writing, the link is called: "Win64 OpenSSL v1.0.2j".
|
||||||
2. 64-bit light - Don't use this. It is missing files needed to build rippled. As of this writing, the link is called: "Win64 OpenSSL v1.0.2d Light"
|
2. 64-bit light - Don't use this. It is missing files needed to build rippled. As of this writing, the link is called: "Win64 OpenSSL v1.0.2j Light"
|
||||||
|
|
||||||
Run the installer, and choose an appropriate location for your OpenSSL
|
Run the installer, and choose an appropriate location for your OpenSSL
|
||||||
installation. In this guide we use **C:\lib\OpenSSL-Win64** as the
|
installation. In this guide we use **C:\lib\OpenSSL-Win64** as the
|
||||||
@@ -108,8 +107,13 @@ unpacking it, open a **Developer Command Prompt** for
|
|||||||
Visual Studio, change to the directory containing boost, then
|
Visual Studio, change to the directory containing boost, then
|
||||||
bootstrap the build tools:
|
bootstrap the build tools:
|
||||||
|
|
||||||
|
(As of this writing, the most recent version of boost is 1.62.0, which
|
||||||
|
will unpack into a directory named `boost_1_62_0`. For higher versions
|
||||||
|
of boost, adjust the directories provided in these examples as
|
||||||
|
appropriate.)
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
cd C:\lib\boost_1_59_0
|
cd C:\lib\boost_1_62_0
|
||||||
bootstrap
|
bootstrap
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -119,7 +123,7 @@ affected by changes in outside files. Therefore, it is necessary to build the
|
|||||||
required boost static libraries using this command:
|
required boost static libraries using this command:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
bjam --toolset=msvc-14.0 --build-type=complete variant=debug,release link=static runtime-link=static address-model=64
|
bjam --toolset=msvc-14.0 address-model=64 architecture=x86 link=static threading=multi runtime-link=shared,static stage --stagedir=stage64
|
||||||
```
|
```
|
||||||
|
|
||||||
Building the boost libraries may take considerable time. When the build process
|
Building the boost libraries may take considerable time. When the build process
|
||||||
@@ -161,7 +165,7 @@ git checkout master
|
|||||||
### Configure Library Paths
|
### Configure Library Paths
|
||||||
|
|
||||||
Open the solution file located at **Builds/Visual Studio 2015/ripple.sln**
|
Open the solution file located at **Builds/Visual Studio 2015/ripple.sln**
|
||||||
and select the "View->Other Windows->Property Manager" to bring up the Property Manager.
|
and select the "View->Property Manager" to bring up the Property Manager.
|
||||||
Expand the *debug | x64* section and
|
Expand the *debug | x64* section and
|
||||||
double click the *Microsoft.Cpp.x64.user* property sheet to bring up the
|
double click the *Microsoft.Cpp.x64.user* property sheet to bring up the
|
||||||
*Property Pages* dialog. These are global properties applied to all
|
*Property Pages* dialog. These are global properties applied to all
|
||||||
@@ -237,9 +241,7 @@ and then choose the **Build->Build Solution** menu item.
|
|||||||
|
|
||||||
# Unit Tests (Recommended)
|
# Unit Tests (Recommended)
|
||||||
|
|
||||||
## Internal
|
The rippled unit tests are written in C++ and are part
|
||||||
|
|
||||||
The internal rippled unit tests are written in C++ and are part
|
|
||||||
of the rippled executable.
|
of the rippled executable.
|
||||||
|
|
||||||
From a Windows console, run the unit tests:
|
From a Windows console, run the unit tests:
|
||||||
@@ -250,108 +252,4 @@ From a Windows console, run the unit tests:
|
|||||||
|
|
||||||
Substitute the correct path to the executable to test different builds.
|
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
|
|
||||||
```
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 66 KiB |
177
Builds/XCode/README.md
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
# macos Build Instructions
|
||||||
|
|
||||||
|
## Important
|
||||||
|
|
||||||
|
We don't recommend OS X for rippled production use at this time. Currently, the
|
||||||
|
Ubuntu platform has received the highest level of quality assurance and
|
||||||
|
testing.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
You'll need OSX 10.8 or later
|
||||||
|
|
||||||
|
To clone the source code repository, create branches for inspection or
|
||||||
|
modification, build rippled using clang, and run the system tests you will need
|
||||||
|
these software components:
|
||||||
|
|
||||||
|
* [XCode](https://developer.apple.com/xcode/)
|
||||||
|
* [Homebrew](http://brew.sh/)
|
||||||
|
* [Git](http://git-scm.com/)
|
||||||
|
* [Scons](http://www.scons.org/)
|
||||||
|
|
||||||
|
## Install Software
|
||||||
|
|
||||||
|
### Install XCode
|
||||||
|
|
||||||
|
If not already installed on your system, download and install XCode using the
|
||||||
|
appstore or by using [this link](https://developer.apple.com/xcode/).
|
||||||
|
|
||||||
|
For more info, see "Step 1: Download and Install the Command Line Tools"
|
||||||
|
[here](http://www.moncefbelyamani.com/how-to-install-xcode-homebrew-git-rvm-ruby-on-mac)
|
||||||
|
|
||||||
|
The command line tools can be installed through the terminal with the command:
|
||||||
|
|
||||||
|
```
|
||||||
|
xcode-select --install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install Homebrew
|
||||||
|
|
||||||
|
> "[Homebrew](http://brew.sh/) installs the stuff you need that Apple didn’t."
|
||||||
|
|
||||||
|
Open a terminal and type:
|
||||||
|
|
||||||
|
```
|
||||||
|
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||||
|
```
|
||||||
|
|
||||||
|
For more info, see "Step 3: Install Homebrew"
|
||||||
|
[here](http://www.moncefbelyamani.com/how-to-install-xcode-homebrew-git-rvm-ruby-on-mac)
|
||||||
|
|
||||||
|
### Install Git
|
||||||
|
|
||||||
|
```
|
||||||
|
brew update brew install git
|
||||||
|
```
|
||||||
|
|
||||||
|
For more info, see "Step 4: Install Git"
|
||||||
|
[here](http://www.moncefbelyamani.com/how-to-install-xcode-homebrew-git-rvm-ruby-on-mac)
|
||||||
|
|
||||||
|
**NOTE**: To gain full featured access to the
|
||||||
|
[git-subtree](http://blogs.atlassian.com/2013/05/alternatives-to-git-submodule-git-subtree/)
|
||||||
|
functionality used in the rippled repository, we suggest Git version 1.8.3.2 or
|
||||||
|
later.
|
||||||
|
|
||||||
|
### Install Scons
|
||||||
|
|
||||||
|
Requires version 2.3.0 or later
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install scons
|
||||||
|
```
|
||||||
|
|
||||||
|
`brew` will generally install the latest stable version of any package, which
|
||||||
|
will satisfy the scons minimum version requirement for rippled.
|
||||||
|
|
||||||
|
### Install Package Config
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install pkg-config
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install/Build/Configure Dependencies
|
||||||
|
|
||||||
|
### Build Google Protocol Buffers Compiler
|
||||||
|
|
||||||
|
Building rippled on osx requires `protoc` version 2.5.x or 2.6.x (later versions
|
||||||
|
do not work with rippled at this time).
|
||||||
|
|
||||||
|
Download [this](https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.bz2)
|
||||||
|
|
||||||
|
We want to compile protocol buffers with clang/libc++:
|
||||||
|
|
||||||
|
```
|
||||||
|
tar xfvj protobuf-2.6.1.tar.bz2
|
||||||
|
cd protobuf-2.6.1
|
||||||
|
./configure CC=clang CXX=clang++ CXXFLAGS='-std=c++11 -stdlib=libc++ -O3 -g' LDFLAGS='-stdlib=libc++' LIBS="-lc++ -lc++abi"
|
||||||
|
make -j 4
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
If you have installed `protobuf` via brew - either directly or indirectly as a
|
||||||
|
dependency of some other package - this is likely to conflict with our specific
|
||||||
|
version requirements. The simplest way to avoid conflicts is to uninstall it.
|
||||||
|
`brew ls --versions protobuf` will list any versions of protobuf
|
||||||
|
you currently have installed.
|
||||||
|
|
||||||
|
### Install OpenSSL
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install openssl
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Boost
|
||||||
|
|
||||||
|
We want to compile boost with clang/libc++
|
||||||
|
|
||||||
|
Download [a release](https://sourceforge.net/projects/boost/files/boost/1.61.0/boost_1_61_0.tar.bz2)
|
||||||
|
|
||||||
|
Extract it to a folder, making note of where, open a terminal, then:
|
||||||
|
|
||||||
|
```
|
||||||
|
./bootstrap.sh ./b2 toolset=clang threading=multi runtime-link=static link=static cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" address-model=64
|
||||||
|
```
|
||||||
|
|
||||||
|
Create an environment variable `BOOST_ROOT` in one of your `rc` files, pointing
|
||||||
|
to the root of the extracted directory.
|
||||||
|
|
||||||
|
### Clone the rippled repository
|
||||||
|
|
||||||
|
From the terminal
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone git@github.com:ripple/rippled.git
|
||||||
|
cd rippled
|
||||||
|
```
|
||||||
|
|
||||||
|
Choose the master branch or one of the tagged releases listed on
|
||||||
|
[GitHub](https://github.com/ripple/rippled/releases GitHub).
|
||||||
|
|
||||||
|
```
|
||||||
|
git checkout master
|
||||||
|
```
|
||||||
|
|
||||||
|
or to test the latest release candidate, choose the `release` branch.
|
||||||
|
|
||||||
|
```
|
||||||
|
git checkout release
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configure Library Paths
|
||||||
|
|
||||||
|
If you didn't persistently set the `BOOST_ROOT` environment variable to the
|
||||||
|
root of the extracted directory above, then you should set it temporarily.
|
||||||
|
|
||||||
|
For example, assuming your username were `Abigail` and you extracted Boost
|
||||||
|
1.61.0 in `/Users/Abigail/Downloads/boost_1_61_0`, you would do for any
|
||||||
|
shell in which you want to build:
|
||||||
|
|
||||||
|
```
|
||||||
|
export BOOST_ROOT=/Users/Abigail/Downloads/boost_1_61_0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```
|
||||||
|
scons
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [here](https://ripple.com/wiki/Rippled_build_instructions#Building)
|
||||||
|
|
||||||
|
## Unit Tests (Recommended)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Place XCode project file here!
|
|
||||||
966
CMakeLists.txt
11
Jamroot
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
#
|
||||||
|
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
#
|
||||||
|
|
||||||
|
import boost ;
|
||||||
|
|
||||||
|
boost.use-project ;
|
||||||
|
|
||||||
@@ -5,7 +5,7 @@ Ripple is a network of computers which use the [Ripple consensus algorithm]
|
|||||||
(https://www.youtube.com/watch?v=pj1QVb1vlC0) to atomically settle and record
|
(https://www.youtube.com/watch?v=pj1QVb1vlC0) to atomically settle and record
|
||||||
transactions on a secure distributed database, the Ripple Consensus Ledger
|
transactions on a secure distributed database, the Ripple Consensus Ledger
|
||||||
(RCL). Because of its distributed nature, the RCL offers transaction immutability
|
(RCL). Because of its distributed nature, the RCL offers transaction immutability
|
||||||
without a central operator. The RCL contains a built-incurrency exchange and its
|
without a central operator. The RCL contains a built-in currency exchange and its
|
||||||
path-finding algorithm finds competitive exchange rates across order books
|
path-finding algorithm finds competitive exchange rates across order books
|
||||||
and currency pairs.
|
and currency pairs.
|
||||||
|
|
||||||
@@ -67,8 +67,6 @@ ISC license. See the LICENSE file for more details.
|
|||||||
| ./Builds| Platform or IDE-specific project files. |
|
| ./Builds| Platform or IDE-specific project files. |
|
||||||
| ./doc | Documentation and example configuration files. |
|
| ./doc | Documentation and example configuration files. |
|
||||||
| ./src | Source code. |
|
| ./src | Source code. |
|
||||||
| ./test | Javascript / Mocha tests. |
|
|
||||||
|
|
||||||
|
|
||||||
Some of the directories under `src` are external repositories inlined via
|
Some of the directories under `src` are external repositories inlined via
|
||||||
git-subtree. See the corresponding README for more details.
|
git-subtree. See the corresponding README for more details.
|
||||||
|
|||||||
104
SConstruct
@@ -115,6 +115,7 @@ TODO
|
|||||||
|
|
||||||
import collections
|
import collections
|
||||||
import os
|
import os
|
||||||
|
import platform
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
@@ -122,6 +123,10 @@ import time
|
|||||||
import glob
|
import glob
|
||||||
import SCons.Action
|
import SCons.Action
|
||||||
|
|
||||||
|
if (not platform.machine().endswith('64')):
|
||||||
|
print('Warning: Detected {} architecture. Rippled requires a 64-bit OS.'.format(
|
||||||
|
platform.machine()));
|
||||||
|
|
||||||
sys.path.append(os.path.join('src', 'ripple', 'beast', 'site_scons'))
|
sys.path.append(os.path.join('src', 'ripple', 'beast', 'site_scons'))
|
||||||
sys.path.append(os.path.join('src', 'ripple', 'site_scons'))
|
sys.path.append(os.path.join('src', 'ripple', 'site_scons'))
|
||||||
|
|
||||||
@@ -380,11 +385,13 @@ def config_base(env):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
elif Beast.system.osx:
|
elif Beast.system.osx:
|
||||||
OSX_OPENSSL_ROOT = '/usr/local/Cellar/openssl/'
|
try:
|
||||||
most_recent = sorted(os.listdir(OSX_OPENSSL_ROOT))[-1]
|
openssl = subprocess.check_output(['brew', '--prefix','openssl'],
|
||||||
openssl = os.path.join(OSX_OPENSSL_ROOT, most_recent)
|
stderr=subprocess.STDOUT).strip()
|
||||||
env.Prepend(CPPPATH='%s/include' % openssl)
|
env.Prepend(CPPPATH='%s/include' % openssl)
|
||||||
env.Prepend(LIBPATH=['%s/lib' % openssl])
|
env.Prepend(LIBPATH=['%s/lib' % openssl])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
if not 'vcxproj' in COMMAND_LINE_TARGETS:
|
if not 'vcxproj' in COMMAND_LINE_TARGETS:
|
||||||
env.Append(CPPDEFINES=['NO_LOG_UNHANDLED_EXCEPTIONS'])
|
env.Append(CPPDEFINES=['NO_LOG_UNHANDLED_EXCEPTIONS'])
|
||||||
|
|
||||||
@@ -456,9 +463,15 @@ def add_boost_and_protobuf(toolchain, env):
|
|||||||
br_cands = ['CLANG_BOOST_ROOT'] if toolchain == 'clang' else []
|
br_cands = ['CLANG_BOOST_ROOT'] if toolchain == 'clang' else []
|
||||||
br_cands.append('BOOST_ROOT')
|
br_cands.append('BOOST_ROOT')
|
||||||
BOOST_ROOT = os.path.normpath(get_environ_value(br_cands))
|
BOOST_ROOT = os.path.normpath(get_environ_value(br_cands))
|
||||||
env.Append(LIBPATH=[
|
stage64_path = os.path.join(BOOST_ROOT, 'stage64', 'lib')
|
||||||
os.path.join(BOOST_ROOT, 'stage', 'lib'),
|
if os.path.exists(stage64_path):
|
||||||
])
|
env.Append(LIBPATH=[
|
||||||
|
stage64_path,
|
||||||
|
])
|
||||||
|
else:
|
||||||
|
env.Append(LIBPATH=[
|
||||||
|
os.path.join(BOOST_ROOT, 'stage', 'lib'),
|
||||||
|
])
|
||||||
env['BOOST_ROOT'] = BOOST_ROOT
|
env['BOOST_ROOT'] = BOOST_ROOT
|
||||||
if toolchain in ['gcc', 'clang']:
|
if toolchain in ['gcc', 'clang']:
|
||||||
env.Append(CCFLAGS=['-isystem' + env['BOOST_ROOT']])
|
env.Append(CCFLAGS=['-isystem' + env['BOOST_ROOT']])
|
||||||
@@ -487,6 +500,10 @@ def enable_asserts ():
|
|||||||
# Set toolchain and variant specific construction variables
|
# Set toolchain and variant specific construction variables
|
||||||
def config_env(toolchain, variant, env):
|
def config_env(toolchain, variant, env):
|
||||||
add_boost_and_protobuf(toolchain, env)
|
add_boost_and_protobuf(toolchain, env)
|
||||||
|
env.Append(CPPDEFINES=[
|
||||||
|
'BOOST_COROUTINE_NO_DEPRECATION_WARNING',
|
||||||
|
'BOOST_COROUTINES_NO_DEPRECATION_WARNING'
|
||||||
|
])
|
||||||
if is_debug_variant(variant):
|
if is_debug_variant(variant):
|
||||||
env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
|
env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
|
||||||
|
|
||||||
@@ -541,7 +558,8 @@ def config_env(toolchain, variant, env):
|
|||||||
env.Append(CXXFLAGS=[
|
env.Append(CXXFLAGS=[
|
||||||
'-frtti',
|
'-frtti',
|
||||||
'-std=c++14',
|
'-std=c++14',
|
||||||
'-Wno-invalid-offsetof'])
|
'-Wno-invalid-offsetof'
|
||||||
|
])
|
||||||
|
|
||||||
env.Append(CPPDEFINES=['_FILE_OFFSET_BITS=64'])
|
env.Append(CPPDEFINES=['_FILE_OFFSET_BITS=64'])
|
||||||
|
|
||||||
@@ -575,6 +593,9 @@ def config_env(toolchain, variant, env):
|
|||||||
])
|
])
|
||||||
|
|
||||||
boost_libs = [
|
boost_libs = [
|
||||||
|
# resist the temptation to alphabetize these. coroutine
|
||||||
|
# must come before context.
|
||||||
|
'boost_chrono',
|
||||||
'boost_coroutine',
|
'boost_coroutine',
|
||||||
'boost_context',
|
'boost_context',
|
||||||
'boost_date_time',
|
'boost_date_time',
|
||||||
@@ -591,9 +612,13 @@ def config_env(toolchain, variant, env):
|
|||||||
else:
|
else:
|
||||||
# We prefer static libraries for boost
|
# We prefer static libraries for boost
|
||||||
if env.get('BOOST_ROOT'):
|
if env.get('BOOST_ROOT'):
|
||||||
|
static_libs64 = ['%s/stage64/lib/lib%s.a' % (env['BOOST_ROOT'], l) for
|
||||||
|
l in boost_libs]
|
||||||
static_libs = ['%s/stage/lib/lib%s.a' % (env['BOOST_ROOT'], l) for
|
static_libs = ['%s/stage/lib/lib%s.a' % (env['BOOST_ROOT'], l) for
|
||||||
l in boost_libs]
|
l in boost_libs]
|
||||||
if all(os.path.exists(f) for f in static_libs):
|
if all(os.path.exists(f) for f in static_libs64):
|
||||||
|
boost_libs = [File(f) for f in static_libs64]
|
||||||
|
elif all(os.path.exists(f) for f in static_libs):
|
||||||
boost_libs = [File(f) for f in static_libs]
|
boost_libs = [File(f) for f in static_libs]
|
||||||
env.Append(LIBS=boost_libs)
|
env.Append(LIBS=boost_libs)
|
||||||
|
|
||||||
@@ -771,6 +796,7 @@ base.Append(CPPPATH=[
|
|||||||
os.path.join('src', 'beast'),
|
os.path.join('src', 'beast'),
|
||||||
os.path.join('src', 'beast', 'include'),
|
os.path.join('src', 'beast', 'include'),
|
||||||
os.path.join('src', 'beast', 'extras'),
|
os.path.join('src', 'beast', 'extras'),
|
||||||
|
os.path.join('src', 'nudb', 'include'),
|
||||||
os.path.join(build_dir, 'proto'),
|
os.path.join(build_dir, 'proto'),
|
||||||
os.path.join('src','soci','src'),
|
os.path.join('src','soci','src'),
|
||||||
os.path.join('src','soci','include'),
|
os.path.join('src','soci','include'),
|
||||||
@@ -908,10 +934,10 @@ def get_classic_sources(toolchain):
|
|||||||
append_sources(result, *list_sources('src/ripple/beast/container', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/beast/container', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/beast/insight', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/beast/insight', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/beast/net', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/beast/net', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/beast/nudb', '.cpp'))
|
|
||||||
append_sources(result, *list_sources('src/ripple/beast/utility', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/beast/utility', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/app', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/app', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/basics', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/basics', '.cpp'))
|
||||||
|
append_sources(result, *list_sources('src/ripple/conditions', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/crypto', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/crypto', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/json', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/json', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/ledger', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/ledger', '.cpp'))
|
||||||
@@ -923,14 +949,10 @@ def get_classic_sources(toolchain):
|
|||||||
append_sources(result, *list_sources('src/ripple/rpc', '.cpp'))
|
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/shamap', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/server', '.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/app', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/basics', '.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/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/core', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/json', '.cpp'))
|
append_sources(result, *list_sources('src/test/json', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/ledger', '.cpp'))
|
append_sources(result, *list_sources('src/test/ledger', '.cpp'))
|
||||||
@@ -941,6 +963,8 @@ def get_classic_sources(toolchain):
|
|||||||
append_sources(result, *list_sources('src/test/rpc', '.cpp'))
|
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/server', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/shamap', '.cpp'))
|
append_sources(result, *list_sources('src/test/shamap', '.cpp'))
|
||||||
|
append_sources(result, *list_sources('src/test/jtx', '.cpp'))
|
||||||
|
|
||||||
|
|
||||||
if use_shp(toolchain):
|
if use_shp(toolchain):
|
||||||
cc_flags = {'CCFLAGS': ['--system-header-prefix=rocksdb2']}
|
cc_flags = {'CCFLAGS': ['--system-header-prefix=rocksdb2']}
|
||||||
@@ -974,6 +998,7 @@ def get_unity_sources(toolchain):
|
|||||||
'src/ripple/unity/app_misc.cpp',
|
'src/ripple/unity/app_misc.cpp',
|
||||||
'src/ripple/unity/app_paths.cpp',
|
'src/ripple/unity/app_paths.cpp',
|
||||||
'src/ripple/unity/app_tx.cpp',
|
'src/ripple/unity/app_tx.cpp',
|
||||||
|
'src/ripple/unity/conditions.cpp',
|
||||||
'src/ripple/unity/core.cpp',
|
'src/ripple/unity/core.cpp',
|
||||||
'src/ripple/unity/basics.cpp',
|
'src/ripple/unity/basics.cpp',
|
||||||
'src/ripple/unity/crypto.cpp',
|
'src/ripple/unity/crypto.cpp',
|
||||||
@@ -986,21 +1011,21 @@ def get_unity_sources(toolchain):
|
|||||||
'src/ripple/unity/rpcx.cpp',
|
'src/ripple/unity/rpcx.cpp',
|
||||||
'src/ripple/unity/shamap.cpp',
|
'src/ripple/unity/shamap.cpp',
|
||||||
'src/ripple/unity/server.cpp',
|
'src/ripple/unity/server.cpp',
|
||||||
'src/ripple/unity/test.cpp',
|
'src/test/unity/app_test_unity.cpp',
|
||||||
'src/unity/app_test_unity.cpp',
|
'src/test/unity/basics_test_unity.cpp',
|
||||||
'src/unity/basics_test_unity.cpp',
|
'src/test/unity/beast_test_unity.cpp',
|
||||||
'src/unity/beast_test_unity.cpp',
|
'src/test/unity/core_test_unity.cpp',
|
||||||
'src/unity/core_test_unity.cpp',
|
'src/test/unity/conditions_test_unity.cpp',
|
||||||
'src/unity/json_test_unity.cpp',
|
'src/test/unity/json_test_unity.cpp',
|
||||||
'src/unity/ledger_test_unity.cpp',
|
'src/test/unity/ledger_test_unity.cpp',
|
||||||
'src/unity/overlay_test_unity.cpp',
|
'src/test/unity/overlay_test_unity.cpp',
|
||||||
'src/unity/peerfinder_test_unity.cpp',
|
'src/test/unity/peerfinder_test_unity.cpp',
|
||||||
'src/unity/protocol_test_unity.cpp',
|
'src/test/unity/protocol_test_unity.cpp',
|
||||||
'src/unity/resource_test_unity.cpp',
|
'src/test/unity/resource_test_unity.cpp',
|
||||||
'src/unity/rpc_test_unity.cpp',
|
'src/test/unity/rpc_test_unity.cpp',
|
||||||
'src/unity/server_test_unity.cpp',
|
'src/test/unity/server_test_unity.cpp',
|
||||||
'src/unity/shamap_test_unity.cpp',
|
'src/test/unity/shamap_test_unity.cpp',
|
||||||
'src/unity/test_unity.cpp'
|
'src/test/unity/support_unity.cpp'
|
||||||
)
|
)
|
||||||
|
|
||||||
if use_shp(toolchain):
|
if use_shp(toolchain):
|
||||||
@@ -1011,7 +1036,7 @@ def get_unity_sources(toolchain):
|
|||||||
append_sources(
|
append_sources(
|
||||||
result,
|
result,
|
||||||
'src/ripple/unity/nodestore.cpp',
|
'src/ripple/unity/nodestore.cpp',
|
||||||
'src/unity/nodestore_test_unity.cpp',
|
'src/test/unity/nodestore_test_unity.cpp',
|
||||||
CPPPATH=[
|
CPPPATH=[
|
||||||
'src/rocksdb2/include',
|
'src/rocksdb2/include',
|
||||||
'src/snappy/snappy',
|
'src/snappy/snappy',
|
||||||
@@ -1134,7 +1159,6 @@ for tu_style in ['classic', 'unity']:
|
|||||||
'src/ripple/unity/protobuf.cpp',
|
'src/ripple/unity/protobuf.cpp',
|
||||||
'src/ripple/unity/ripple.proto.cpp',
|
'src/ripple/unity/ripple.proto.cpp',
|
||||||
'src/ripple/unity/resource.cpp',
|
'src/ripple/unity/resource.cpp',
|
||||||
'src/ripple/unity/websocket02.cpp',
|
|
||||||
**cc_flags
|
**cc_flags
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1150,7 +1174,7 @@ for tu_style in ['classic', 'unity']:
|
|||||||
cc_flags = {}
|
cc_flags = {}
|
||||||
|
|
||||||
object_builder.add_source_files(
|
object_builder.add_source_files(
|
||||||
'src/ripple/unity/ed25519.c',
|
'src/ripple/unity/ed25519_donna.c',
|
||||||
CPPPATH=[
|
CPPPATH=[
|
||||||
'src/ed25519-donna',
|
'src/ed25519-donna',
|
||||||
]
|
]
|
||||||
@@ -1219,7 +1243,13 @@ for key, value in aliases.iteritems():
|
|||||||
vcxproj = base.VSProject(
|
vcxproj = base.VSProject(
|
||||||
os.path.join('Builds', 'VisualStudio2015', 'RippleD'),
|
os.path.join('Builds', 'VisualStudio2015', 'RippleD'),
|
||||||
source = [],
|
source = [],
|
||||||
VSPROJECT_ROOT_DIRS = ['src/beast', 'src/beast/include', 'src/beast/extras', 'src', '.'],
|
VSPROJECT_ROOT_DIRS = [
|
||||||
|
'build/',
|
||||||
|
'src/beast/extras',
|
||||||
|
'src/beast/include',
|
||||||
|
'src/nudb/include',
|
||||||
|
'src',
|
||||||
|
'.'],
|
||||||
VSPROJECT_CONFIGS = msvc_configs)
|
VSPROJECT_CONFIGS = msvc_configs)
|
||||||
base.Alias('vcxproj', vcxproj)
|
base.Alias('vcxproj', vcxproj)
|
||||||
|
|
||||||
@@ -1241,10 +1271,10 @@ def do_count(target, source, env):
|
|||||||
path = os.path.join(parent, path)
|
path = os.path.join(parent, path)
|
||||||
r = os.path.splitext(path)
|
r = os.path.splitext(path)
|
||||||
if r[1] in suffixes:
|
if r[1] in suffixes:
|
||||||
if r[0].endswith('.test'):
|
if r[0].endswith('_test'):
|
||||||
yield os.path.normpath(path)
|
yield os.path.normpath(path)
|
||||||
return list(_iter(base))
|
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
|
lines = 0
|
||||||
for f in testfiles:
|
for f in testfiles:
|
||||||
lines = lines + sum(1 for line in open(f))
|
lines = lines + sum(1 for line in open(f))
|
||||||
|
|||||||
115
appveyor.yml
@@ -6,22 +6,39 @@ environment:
|
|||||||
# that it's a small download. We also use appveyor's free cache, avoiding fees
|
# that it's a small download. We also use appveyor's free cache, avoiding fees
|
||||||
# downloading from S3 each time.
|
# downloading from S3 each time.
|
||||||
# TODO: script to create this package.
|
# TODO: script to create this package.
|
||||||
RIPPLED_DEPS_URL: https://ripple.github.io/Downloads/appveyor/rippled_deps15.01.zip
|
RIPPLED_DEPS_PATH: rippled_deps15.02
|
||||||
|
RIPPLED_DEPS_URL: https://ripple.github.io/Downloads/appveyor/%RIPPLED_DEPS_PATH%.zip
|
||||||
|
|
||||||
# Other dependencies we just download each time.
|
# Other dependencies we just download each time.
|
||||||
PIP_URL: https://bootstrap.pypa.io/get-pip.py
|
PIP_PATH: get-pip.py
|
||||||
|
PIP_URL: https://bootstrap.pypa.io/%PIP_PATH%
|
||||||
|
# The % in this URL messes up variable substition, so any updates will
|
||||||
|
# need to update both PYWIN32_PATH and PYWIN32_URL
|
||||||
|
PYWIN32_PATH: pywin32-220.win-amd64-py2.7.exe
|
||||||
PYWIN32_URL: https://downloads.sourceforge.net/project/pywin32/pywin32/Build%20220/pywin32-220.win-amd64-py2.7.exe
|
PYWIN32_URL: https://downloads.sourceforge.net/project/pywin32/pywin32/Build%20220/pywin32-220.win-amd64-py2.7.exe
|
||||||
|
|
||||||
# Scons honours these environment variables, setting the include/lib paths.
|
# Scons honours these environment variables, setting the include/lib paths.
|
||||||
BOOST_ROOT: C:/rippled_deps15.01/boost
|
BOOST_ROOT: C:/%RIPPLED_DEPS_PATH%/boost
|
||||||
OPENSSL_ROOT: C:/rippled_deps15.01/openssl
|
OPENSSL_ROOT: C:/%RIPPLED_DEPS_PATH%/openssl
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
# This build works, but our current Appveyor config runs matrix builds
|
||||||
|
# sequentially, and the one build is already slow enough.
|
||||||
|
# - build: scons
|
||||||
|
# target: msvc.debug
|
||||||
|
- build: cmake
|
||||||
|
target: msvc.debug
|
||||||
|
buildconfig: Debug
|
||||||
|
|
||||||
os: Visual Studio 2015
|
os: Visual Studio 2015
|
||||||
|
|
||||||
# At the end of each successful build we cache this directory. It must be less
|
# At the end of each successful build we cache this directory.
|
||||||
# than 100MB total compressed.
|
# https://www.appveyor.com/docs/build-cache/
|
||||||
|
# Resulting archive should not exceed 100 MB.
|
||||||
cache:
|
cache:
|
||||||
- "C:\\rippled_deps15.01"
|
- 'C:\%RIPPLED_DEPS_PATH%'
|
||||||
|
- '%PIP_PATH%'
|
||||||
|
- '%PYWIN32_PATH%'
|
||||||
|
|
||||||
# This means we'll download a zip of the branch we want, rather than the full
|
# This means we'll download a zip of the branch we want, rather than the full
|
||||||
# history.
|
# history.
|
||||||
@@ -29,38 +46,37 @@ shallow_clone: true
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
# We want easy_install, python and protoc.exe on PATH.
|
# We want easy_install, python and protoc.exe on PATH.
|
||||||
- SET PATH=%PYTHON%;%PYTHON%/Scripts;C:/rippled_deps15.01;%PATH%
|
- SET PATH=%PYTHON%;%PYTHON%/Scripts;C:/%RIPPLED_DEPS_PATH%;%PATH%
|
||||||
|
|
||||||
# `ps` prefix means the command is executed by powershell.
|
# `ps` prefix means the command is executed by powershell.
|
||||||
- ps: Start-FileDownload $env:PIP_URL
|
- ps: |
|
||||||
- ps: Start-FileDownload $env:PYWIN32_URL
|
if ($env:build -eq "scons") {
|
||||||
|
if(-not(Test-Path $env:PIP_PATH)) {
|
||||||
# Installing pip will install setuptools/easy_install.
|
echo "Download from $env:PIP_URL"
|
||||||
- python get-pip.py
|
Start-FileDownload $env:PIP_URL
|
||||||
|
}
|
||||||
# Pip has some problems installing scons on windows so we use easy install.
|
if(-not(Test-Path $env:PYWIN32_PATH)) {
|
||||||
# - easy_install scons
|
echo "Download from $env:PYWIN32_URL"
|
||||||
# Workaround
|
Start-FileDownload $env:PYWIN32_URL
|
||||||
- easy_install https://pypi.python.org/packages/source/S/SCons/scons-2.5.0.tar.gz#md5=bda5530a70a41a7831d83c8b191c021e
|
}
|
||||||
|
}
|
||||||
# Scons has problems with parallel builds on windows without pywin32.
|
- bin/ci/windows/install-dependencies.bat
|
||||||
- easy_install pywin32-220.win-amd64-py2.7.exe
|
|
||||||
# (easy_install can do headless installs of .exe wizards)
|
|
||||||
|
|
||||||
# Download dependencies if appveyor didn't restore them from the cache.
|
# Download dependencies if appveyor didn't restore them from the cache.
|
||||||
# Use 7zip to unzip.
|
# Use 7zip to unzip.
|
||||||
- ps: |
|
- ps: |
|
||||||
if (-not(Test-Path 'C:/rippled_deps15.01')) {
|
if (-not(Test-Path 'C:/$env:RIPPLED_DEPS_PATH')) {
|
||||||
echo "Download from $env:RIPPLED_DEPS_URL"
|
echo "Download from $env:RIPPLED_DEPS_URL"
|
||||||
Start-FileDownload "$env:RIPPLED_DEPS_URL"
|
Start-FileDownload "$env:RIPPLED_DEPS_URL"
|
||||||
7z x rippled_deps15.01.zip -oC:\ -y > $null
|
7z x "$($env:RIPPLED_DEPS_PATH).zip" -oC:\ -y > $null
|
||||||
|
if ($LastExitCode -ne 0) { throw "7z failed" }
|
||||||
}
|
}
|
||||||
|
|
||||||
# Newer DEPS include a versions file.
|
# Newer DEPS include a versions file.
|
||||||
# Dump it so we can verify correct behavior.
|
# Dump it so we can verify correct behavior.
|
||||||
- ps: |
|
- ps: |
|
||||||
if (Test-Path 'C:/rippled_deps15.01/versions.txt') {
|
if (Test-Path "C:/$env:RIPPLED_DEPS_PATH/versions.txt") {
|
||||||
cat 'C:/rippled_deps15.01/versions.txt'
|
cat "C:/$env:RIPPLED_DEPS_PATH/versions.txt"
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: This is giving me grief
|
# TODO: This is giving me grief
|
||||||
@@ -73,17 +89,46 @@ build_script:
|
|||||||
- '"%VS140COMNTOOLS%../../VC/vcvarsall.bat" x86_amd64'
|
- '"%VS140COMNTOOLS%../../VC/vcvarsall.bat" x86_amd64'
|
||||||
# Show which version of the compiler we are using.
|
# Show which version of the compiler we are using.
|
||||||
- cl
|
- cl
|
||||||
- scons msvc.debug -j%NUMBER_OF_PROCESSORS%
|
- ps: |
|
||||||
|
if ($env:build -eq "scons") {
|
||||||
|
# Build with scons
|
||||||
|
scons $env:target -j%NUMBER_OF_PROCESSORS%
|
||||||
|
if ($LastExitCode -ne 0) { throw "scons build failed" }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# Build with cmake
|
||||||
|
cmake --version
|
||||||
|
$cmake_target="$($env:target).ci"
|
||||||
|
"$cmake_target"
|
||||||
|
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:
|
after_build:
|
||||||
# Put our executable in a place where npm test can find it.
|
- ps: |
|
||||||
- ps: cp build/msvc.debug/rippled.exe build
|
if ($env:build -eq "scons") {
|
||||||
- ps: ls build
|
cp build/$($env:target)/rippled.exe build
|
||||||
|
ls build
|
||||||
|
$exe="build/rippled"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$exe="build/$cmake_target/$env:buildconfig/rippled"
|
||||||
|
}
|
||||||
|
"Exe is at $exe"
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
# Run the unit tests
|
- ps: |
|
||||||
- build\\rippled --unittest
|
& {
|
||||||
|
# Run the rippled unit tests
|
||||||
|
& $exe --unittest
|
||||||
|
# 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" }
|
||||||
|
}
|
||||||
|
|
||||||
# Run the integration tests
|
|
||||||
- npm install --progress=false
|
|
||||||
- npm test
|
|
||||||
|
|||||||
@@ -1,25 +1,59 @@
|
|||||||
#!/bin/bash -u
|
#!/bin/bash -u
|
||||||
# We use set -e and bash with -u to bail on first non zero exit code of any
|
# We use set -e and bash with -u to bail on first non zero exit code of any
|
||||||
# processes launched or upon any unbound variable
|
# processes launched or upon any unbound variable.
|
||||||
set -e
|
# We use set -x to print commands before running them to help with
|
||||||
|
# debugging.
|
||||||
|
set -ex
|
||||||
__dirname=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
__dirname=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||||
echo "using CC: $CC"
|
echo "using CC: $CC"
|
||||||
echo "using TARGET: $TARGET"
|
echo "using TARGET: $TARGET"
|
||||||
export RIPPLED_PATH="$PWD/build/$CC.$TARGET/rippled"
|
|
||||||
echo "using RIPPLED_PATH: $RIPPLED_PATH"
|
# Ensure APP defaults to rippled if it's not set.
|
||||||
# Make sure vcxproj is up to date
|
: ${APP:=rippled}
|
||||||
scons vcxproj
|
if [[ ${BUILD:-scons} == "cmake" ]]; then
|
||||||
git diff --exit-code
|
echo "cmake building ${APP}"
|
||||||
# $CC will be either `clang` or `gcc`
|
CMAKE_TARGET=$CC.$TARGET
|
||||||
# http://docs.travis-ci.com/user/migrating-from-legacy/?utm_source=legacy-notice&utm_medium=banner&utm_campaign=legacy-upgrade
|
if [[ ${CI:-} == true ]]; then
|
||||||
# indicates that 2 cores are available to containers.
|
CMAKE_TARGET=$CMAKE_TARGET.ci
|
||||||
scons -j${NUM_PROCESSORS:-2} $CC.$TARGET
|
fi
|
||||||
|
mkdir -p "build/${CMAKE_TARGET}"
|
||||||
|
pushd "build/${CMAKE_TARGET}"
|
||||||
|
cmake ../.. -Dtarget=$CMAKE_TARGET
|
||||||
|
cmake --build . -- -j${NUM_PROCESSORS:-2}
|
||||||
|
popd
|
||||||
|
export APP_PATH="$PWD/build/${CMAKE_TARGET}/${APP}"
|
||||||
|
echo "using APP_PATH: $APP_PATH"
|
||||||
|
|
||||||
|
else
|
||||||
|
export APP_PATH="$PWD/build/$CC.$TARGET/${APP}"
|
||||||
|
echo "using APP_PATH: $APP_PATH"
|
||||||
|
# Make sure vcxproj is up to date
|
||||||
|
scons vcxproj
|
||||||
|
git diff --exit-code
|
||||||
|
# $CC will be either `clang` or `gcc`
|
||||||
|
# http://docs.travis-ci.com/user/migrating-from-legacy/?utm_source=legacy-notice&utm_medium=banner&utm_campaign=legacy-upgrade
|
||||||
|
# indicates that 2 cores are available to containers.
|
||||||
|
scons -j${NUM_PROCESSORS:-2} $CC.$TARGET
|
||||||
|
fi
|
||||||
# We can be sure we're using the build/$CC.$TARGET variant
|
# We can be sure we're using the build/$CC.$TARGET variant
|
||||||
# (-f so never err)
|
# (-f so never err)
|
||||||
rm -f build/rippled
|
rm -f build/${APP}
|
||||||
|
|
||||||
# See what we've actually built
|
# See what we've actually built
|
||||||
ldd $RIPPLED_PATH
|
ldd $APP_PATH
|
||||||
|
|
||||||
|
if [[ ${APP} == "rippled" ]]; then
|
||||||
|
export APP_ARGS="--unittest"
|
||||||
|
# Only report on src/ripple files
|
||||||
|
export LCOV_FILES="*/src/ripple/*"
|
||||||
|
# Nothing to explicitly exclude
|
||||||
|
export LCOV_EXCLUDE_FILES="LCOV_NO_EXCLUDE"
|
||||||
|
else
|
||||||
|
: ${APP_ARGS:=}
|
||||||
|
: ${LCOV_FILES:="*/src/*"}
|
||||||
|
# Don't exclude anything
|
||||||
|
: ${LCOV_EXCLUDE_FILES:="LCOV_NO_EXCLUDE"}
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $TARGET == "coverage" ]]; then
|
if [[ $TARGET == "coverage" ]]; then
|
||||||
export PATH=$PATH:$LCOV_ROOT/usr/bin
|
export PATH=$PATH:$LCOV_ROOT/usr/bin
|
||||||
@@ -36,7 +70,7 @@ gdb -return-child-result -quiet -batch \
|
|||||||
-ex run \
|
-ex run \
|
||||||
-ex "thread apply all backtrace full" \
|
-ex "thread apply all backtrace full" \
|
||||||
-ex "quit" \
|
-ex "quit" \
|
||||||
--args $RIPPLED_PATH --unittest
|
--args $APP_PATH --unittest
|
||||||
|
|
||||||
if [[ $TARGET == "coverage" ]]; then
|
if [[ $TARGET == "coverage" ]]; then
|
||||||
# Create test coverage data file
|
# Create test coverage data file
|
||||||
@@ -45,16 +79,14 @@ if [[ $TARGET == "coverage" ]]; then
|
|||||||
# Combine baseline and test coverage data
|
# Combine baseline and test coverage data
|
||||||
lcov -a baseline.info -a tests.info -o lcov-all.info
|
lcov -a baseline.info -a tests.info -o lcov-all.info
|
||||||
|
|
||||||
# Only report on src/ripple files
|
# Included files
|
||||||
lcov -e "lcov-all.info" "*/src/ripple/*" -o lcov.pre.info
|
lcov -e "lcov-all.info" "${LCOV_FILES}" -o lcov.pre.info
|
||||||
|
|
||||||
# Exclude */src/test directory
|
# Excluded files
|
||||||
lcov --remove lcov.pre.info "*/src/ripple/test/*" -o lcov.info
|
lcov --remove lcov.pre.info "${LCOV_EXCLUDE_FILES}" -o lcov.info
|
||||||
|
|
||||||
# Push the results (lcov.info) to codecov
|
# Push the results (lcov.info) to codecov
|
||||||
codecov -X gcov # don't even try and look for .gcov files ;)
|
codecov -X gcov # don't even try and look for .gcov files ;)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run NPM tests
|
|
||||||
npm install --progress=false
|
|
||||||
npm test --rippled=$RIPPLED_PATH
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
#!/bin/bash -u
|
#!/bin/bash -u
|
||||||
# Exit if anything fails.
|
# Exit if anything fails. Echo commands to aid debugging.
|
||||||
set -e
|
set -ex
|
||||||
|
|
||||||
|
# Target working dir - defaults to current dir.
|
||||||
|
# Can be set from caller, or in the first parameter
|
||||||
|
TWD=$( cd ${TWD:-${1:-${PWD:-$( pwd )}}}; pwd )
|
||||||
|
echo "Target path is: $TWD"
|
||||||
# Override gcc version to $GCC_VER.
|
# Override gcc version to $GCC_VER.
|
||||||
# Put an appropriate symlink at the front of the path.
|
# Put an appropriate symlink at the front of the path.
|
||||||
mkdir -v $HOME/bin
|
mkdir -v $HOME/bin
|
||||||
@@ -13,16 +18,34 @@ done
|
|||||||
if [[ -n ${CLANG_VER:-} ]]; then
|
if [[ -n ${CLANG_VER:-} ]]; then
|
||||||
# There are cases where the directory exists, but the exe is not available.
|
# There are cases where the directory exists, but the exe is not available.
|
||||||
# Use this workaround for now.
|
# Use this workaround for now.
|
||||||
if [[ ! -x llvm-${LLVM_VERSION}/bin/llvm-config ]] && [[ -d llvm-${LLVM_VERSION} ]]; then
|
if [[ ! -x ${TWD}/llvm-${LLVM_VERSION}/bin/llvm-config && -d ${TWD}/llvm-${LLVM_VERSION} ]]; then
|
||||||
rm -fr llvm-${LLVM_VERSION}
|
rm -fr ${TWD}/llvm-${LLVM_VERSION}
|
||||||
fi
|
fi
|
||||||
if [[ ! -d llvm-${LLVM_VERSION} ]]; then
|
if [[ ! -d ${TWD}/llvm-${LLVM_VERSION} ]]; then
|
||||||
mkdir llvm-${LLVM_VERSION}
|
mkdir ${TWD}/llvm-${LLVM_VERSION}
|
||||||
LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-14.04.tar.xz"
|
LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-14.04.tar.xz"
|
||||||
wget -O - ${LLVM_URL} | tar -Jxvf - --strip 1 -C llvm-${LLVM_VERSION}
|
wget -O - ${LLVM_URL} | tar -Jxvf - --strip 1 -C ${TWD}/llvm-${LLVM_VERSION}
|
||||||
|
fi
|
||||||
|
${TWD}/llvm-${LLVM_VERSION}/bin/llvm-config --version;
|
||||||
|
export LLVM_CONFIG="${TWD}/llvm-${LLVM_VERSION}/bin/llvm-config";
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${BUILD:-} == cmake ]]; then
|
||||||
|
# There are cases where the directory exists, but the exe is not available.
|
||||||
|
# Use this workaround for now.
|
||||||
|
if [[ ! -x ${TWD}/cmake/bin/cmake && -d ${TWD}/cmake ]]; then
|
||||||
|
rm -fr ${TWD}/cmake
|
||||||
|
fi
|
||||||
|
if [[ ! -d ${TWD}/cmake ]]; then
|
||||||
|
CMAKE_URL="https://www.cmake.org/files/v3.6/cmake-3.6.1-Linux-x86_64.tar.gz"
|
||||||
|
wget --version
|
||||||
|
# wget version 1.13.4 thinks this certificate is invalid, even though it's fine.
|
||||||
|
# "ERROR: no certificate subject alternative name matches"
|
||||||
|
# See also: https://github.com/travis-ci/travis-ci/issues/5059
|
||||||
|
mkdir ${TWD}/cmake &&
|
||||||
|
wget -O - --no-check-certificate ${CMAKE_URL} | tar --strip-components=1 -xz -C ${TWD}/cmake
|
||||||
|
cmake --version
|
||||||
fi
|
fi
|
||||||
llvm-${LLVM_VERSION}/bin/llvm-config --version;
|
|
||||||
export LLVM_CONFIG="llvm-${LLVM_VERSION}/bin/llvm-config";
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# What versions are we ACTUALLY running?
|
# What versions are we ACTUALLY running?
|
||||||
@@ -30,11 +53,6 @@ if [ -x $HOME/bin/g++ ]; then
|
|||||||
$HOME/bin/g++ -v
|
$HOME/bin/g++ -v
|
||||||
fi
|
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
|
pip install --user https://github.com/codecov/codecov-python/archive/master.zip
|
||||||
|
|
||||||
bash bin/sh/install-boost.sh
|
bash bin/sh/install-boost.sh
|
||||||
|
|||||||
13
bin/ci/windows/install-dependencies.bat
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
if "%build%" == "scons" (
|
||||||
|
rem Installing pip will install setuptools/easy_install.
|
||||||
|
python "%PIP_PATH%"
|
||||||
|
|
||||||
|
rem Pip has some problems installing scons on windows so we use easy install.
|
||||||
|
rem - easy_install scons
|
||||||
|
rem Workaround
|
||||||
|
easy_install https://pypi.python.org/packages/source/S/SCons/scons-2.5.0.tar.gz#md5=bda5530a70a41a7831d83c8b191c021e
|
||||||
|
|
||||||
|
rem Scons has problems with parallel builds on windows without pywin32.
|
||||||
|
easy_install "%PYWIN32_PATH%"
|
||||||
|
rem (easy_install can do headless installs of .exe wizards)
|
||||||
|
)
|
||||||
@@ -5,4 +5,11 @@ To run the Python unit tests, execute:
|
|||||||
|
|
||||||
python -m unittest discover
|
python -m unittest discover
|
||||||
|
|
||||||
from this directory.
|
from this directory.
|
||||||
|
|
||||||
|
To run Python unit tests from a particular file (such as
|
||||||
|
`ripple/util/test_Sign.py`), execute:
|
||||||
|
|
||||||
|
python -m unittest ripple.util.test_Sign
|
||||||
|
|
||||||
|
Add `-v` to run tests in verbose mode.
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class DatumInContext(object):
|
|||||||
"""
|
"""
|
||||||
Represents a datum along a path from a context.
|
Represents a datum along a path from a context.
|
||||||
|
|
||||||
Essentially a zipper but with a structure represented by JsonPath,
|
Essentially a zipper but with a structure represented by JSONPath,
|
||||||
and where the context is more of a parent pointer than a proper
|
and where the context is more of a parent pointer than a proper
|
||||||
representation of the context.
|
representation of the context.
|
||||||
|
|
||||||
|
|||||||
@@ -49,3 +49,4 @@ sfSequence = field_code(STI_UINT32, 4)
|
|||||||
sfPublicKey = field_code(STI_VL, 1)
|
sfPublicKey = field_code(STI_VL, 1)
|
||||||
sfSigningPubKey = field_code(STI_VL, 3)
|
sfSigningPubKey = field_code(STI_VL, 3)
|
||||||
sfSignature = field_code(STI_VL, 6)
|
sfSignature = field_code(STI_VL, 6)
|
||||||
|
sfMasterSignature = field_code(STI_VL, 18)
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ from __future__ import print_function
|
|||||||
import base64, os, random, struct, sys
|
import base64, os, random, struct, sys
|
||||||
import ed25519
|
import ed25519
|
||||||
import ecdsa
|
import ecdsa
|
||||||
|
import hashlib
|
||||||
from ripple.util import Base58
|
from ripple.util import Base58
|
||||||
from ripple.ledger import SField
|
from ripple.ledger import SField
|
||||||
|
|
||||||
ED25519_BYTE = chr(0xed)
|
ED25519_BYTE = chr(0xed)
|
||||||
WRAP_COLUMNS = 60
|
WRAP_COLUMNS = 72
|
||||||
|
|
||||||
USAGE = """\
|
USAGE = """\
|
||||||
Usage:
|
Usage:
|
||||||
@@ -22,12 +23,9 @@ Usage:
|
|||||||
check <key>
|
check <key>
|
||||||
Check an existing key for validity.
|
Check an existing key for validity.
|
||||||
|
|
||||||
sign <sequence> <validator-public> <master-secret>
|
sign <sequence> <validation-public-key> <validation-private-key> <master-secret>
|
||||||
Create a new signed manifest with the given sequence
|
Create a new signed manifest with the given sequence
|
||||||
number, validator public key, and master secret key.
|
number and keys.
|
||||||
|
|
||||||
verify <sequence> <validator-public> <signature> <master-public>
|
|
||||||
Verify hex-encoded manifest signature with master public key.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def prepend_length_byte(b):
|
def prepend_length_byte(b):
|
||||||
@@ -44,17 +42,17 @@ def make_seed(urandom=os.urandom):
|
|||||||
return urandom(16)
|
return urandom(16)
|
||||||
|
|
||||||
def make_ed25519_keypair(urandom=os.urandom):
|
def make_ed25519_keypair(urandom=os.urandom):
|
||||||
private_key = urandom(32)
|
sk = urandom(32)
|
||||||
return private_key, ed25519.publickey(private_key)
|
return sk, ed25519.publickey(sk)
|
||||||
|
|
||||||
def make_ecdsa_keypair():
|
def make_ecdsa_keypair(urandom=None):
|
||||||
# This is not used.
|
# This is not used.
|
||||||
private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
|
sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1, entropy=urandom)
|
||||||
# Can't be unit tested easily - need a mock for ecdsa.
|
# Can't be unit tested easily - need a mock for ecdsa.
|
||||||
vk = private_key.get_verifying_key()
|
vk = sk.get_verifying_key()
|
||||||
sig = private_key.sign('message')
|
sig = sk.sign('message')
|
||||||
assert vk.verify(sig, 'message')
|
assert vk.verify(sig, 'message')
|
||||||
return private_key, vk
|
return sk, vk
|
||||||
|
|
||||||
def make_seed_from_passphrase(passphrase):
|
def make_seed_from_passphrase(passphrase):
|
||||||
# For convenience, like say testing against rippled we can hash a passphrase
|
# For convenience, like say testing against rippled we can hash a passphrase
|
||||||
@@ -62,18 +60,58 @@ def make_seed_from_passphrase(passphrase):
|
|||||||
# an optional arg, which can be a base58 encoded seed, or a passphrase.
|
# an optional arg, which can be a base58 encoded seed, or a passphrase.
|
||||||
return hashlib.sha512(passphrase).digest()[:16]
|
return hashlib.sha512(passphrase).digest()[:16]
|
||||||
|
|
||||||
def make_manifest(public_key, validator_public_key, seq):
|
def make_manifest(master_pk, validation_pk, seq):
|
||||||
|
"""create a manifest
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
master_pk : string
|
||||||
|
validator's master public key (binary, _not_ BASE58 encoded)
|
||||||
|
validation_pk : string
|
||||||
|
validator's validation public key (binary, _not_ BASE58 encoded)
|
||||||
|
seq : int
|
||||||
|
manifest sequence number
|
||||||
|
|
||||||
|
Returns
|
||||||
|
----------
|
||||||
|
string
|
||||||
|
String with fields for seq, master_pk, validation_pk
|
||||||
|
"""
|
||||||
return ''.join([
|
return ''.join([
|
||||||
SField.sfSequence,
|
SField.sfSequence,
|
||||||
to_int32(seq),
|
to_int32(seq),
|
||||||
SField.sfPublicKey, # Master public key.
|
SField.sfPublicKey,
|
||||||
prepend_length_byte(public_key),
|
prepend_length_byte(master_pk),
|
||||||
SField.sfSigningPubKey, # Ephemeral public key.
|
SField.sfSigningPubKey,
|
||||||
prepend_length_byte(validator_public_key)])
|
prepend_length_byte(validation_pk)])
|
||||||
|
|
||||||
def sign_manifest(manifest, private_key, public_key):
|
def sign_manifest(manifest, validation_sk, master_sk, master_pk):
|
||||||
sig = ed25519.signature('MAN\0' + manifest, private_key, public_key)
|
"""sign a validator manifest
|
||||||
return manifest + SField.sfSignature + prepend_length_byte(sig)
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
manifest : string
|
||||||
|
manifest to sign
|
||||||
|
validation_sk : string
|
||||||
|
validator's validation secret key (binary, _not_ BASE58 encoded)
|
||||||
|
This is one of the keys that will sign the manifest.
|
||||||
|
master_sk : string
|
||||||
|
validator's master secret key (binary, _not_ BASE58 encoded)
|
||||||
|
This is one of the keys that will sign the manifest.
|
||||||
|
master_pk : string
|
||||||
|
validator's master public key (binary, _not_ BASE58 encoded)
|
||||||
|
|
||||||
|
Returns
|
||||||
|
----------
|
||||||
|
string
|
||||||
|
manifest signed by both the validation and master keys
|
||||||
|
"""
|
||||||
|
man_hash = hashlib.sha512('MAN\0' + manifest).digest()[:32]
|
||||||
|
validation_sig = validation_sk.sign_digest_deterministic(
|
||||||
|
man_hash, hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_der_canonize)
|
||||||
|
master_sig = ed25519.signature('MAN\0' + manifest, master_sk, master_pk)
|
||||||
|
return manifest + SField.sfSignature + prepend_length_byte(validation_sig) + \
|
||||||
|
SField.sfMasterSignature + prepend_length_byte(master_sig)
|
||||||
|
|
||||||
def wrap(s, cols=WRAP_COLUMNS):
|
def wrap(s, cols=WRAP_COLUMNS):
|
||||||
if s:
|
if s:
|
||||||
@@ -83,72 +121,64 @@ def wrap(s, cols=WRAP_COLUMNS):
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
def create_ed_keys(urandom=os.urandom):
|
def create_ed_keys(urandom=os.urandom):
|
||||||
private_key, public_key = make_ed25519_keypair(urandom)
|
sk, pk = make_ed25519_keypair(urandom)
|
||||||
public_key_human = Base58.encode_version(
|
pk_human = Base58.encode_version(
|
||||||
Base58.VER_NODE_PUBLIC, ED25519_BYTE + public_key)
|
Base58.VER_NODE_PUBLIC, ED25519_BYTE + pk)
|
||||||
private_key_human = Base58.encode_version(
|
sk_human = Base58.encode_version(
|
||||||
Base58.VER_NODE_PRIVATE, private_key)
|
Base58.VER_NODE_PRIVATE, sk)
|
||||||
return public_key_human, private_key_human
|
return pk_human, sk_human
|
||||||
|
|
||||||
def create_ed_public_key(private_key_human):
|
def create_ed_public_key(sk_human):
|
||||||
v, private_key = Base58.decode_version(private_key_human)
|
v, sk = Base58.decode_version(sk_human)
|
||||||
check_master_secret(v, private_key)
|
check_secret_key(v, sk)
|
||||||
|
|
||||||
public_key = ed25519.publickey(private_key)
|
pk = ed25519.publickey(sk)
|
||||||
public_key_human = Base58.encode_version(
|
pk_human = Base58.encode_version(
|
||||||
Base58.VER_NODE_PUBLIC, ED25519_BYTE + public_key)
|
Base58.VER_NODE_PUBLIC, ED25519_BYTE + pk)
|
||||||
return public_key_human
|
return pk_human
|
||||||
|
|
||||||
def check_validator_public(v, validator_public_key):
|
def check_validation_public_key(v, pk):
|
||||||
Base58.check_version(v, Base58.VER_NODE_PUBLIC)
|
Base58.check_version(v, Base58.VER_NODE_PUBLIC)
|
||||||
if len(validator_public_key) != 33:
|
if len(pk) != 33:
|
||||||
raise ValueError('Validator key should be length 33, is %s' %
|
raise ValueError('Validation public key should be length 33, is %s' %
|
||||||
len(validator_public_key))
|
len(pk))
|
||||||
b = ord(validator_public_key[0])
|
b = ord(pk[0])
|
||||||
if b not in (2, 3):
|
if b not in (2, 3):
|
||||||
raise ValueError('First validator key byte must be 2 or 3, is %d' % b)
|
raise ValueError('First validation public key byte must be 2 or 3, is %d' % b)
|
||||||
|
|
||||||
def check_master_secret(v, private_key):
|
def check_secret_key(v, sk):
|
||||||
Base58.check_version(v, Base58.VER_NODE_PRIVATE)
|
Base58.check_version(v, Base58.VER_NODE_PRIVATE)
|
||||||
if len(private_key) != 32:
|
if len(sk) != 32:
|
||||||
raise ValueError('Length of master secret should be 32, is %s' %
|
raise ValueError('Length of master secret should be 32, is %s' %
|
||||||
len(private_key))
|
len(sk))
|
||||||
|
|
||||||
|
def get_signature(seq, validation_pk_human, validation_sk_human, master_sk_human):
|
||||||
|
v, validation_pk = Base58.decode_version(validation_pk_human)
|
||||||
|
check_validation_public_key(v, validation_pk)
|
||||||
|
|
||||||
def get_signature(seq, validator_public_key_human, private_key_human):
|
v, validation_sk_str = Base58.decode_version(validation_sk_human)
|
||||||
v, validator_public_key = Base58.decode_version(validator_public_key_human)
|
check_secret_key(v, validation_sk_str)
|
||||||
check_validator_public(v, validator_public_key)
|
validation_sk = ecdsa.SigningKey.from_string(validation_sk_str, curve=ecdsa.SECP256k1)
|
||||||
|
|
||||||
v, private_key = Base58.decode_version(private_key_human)
|
v, master_sk = Base58.decode_version(master_sk_human)
|
||||||
check_master_secret(v, private_key)
|
check_secret_key(v, master_sk)
|
||||||
|
|
||||||
pk = ed25519.publickey(private_key)
|
pk = ed25519.publickey(master_sk)
|
||||||
apk = ED25519_BYTE + pk
|
apk = ED25519_BYTE + pk
|
||||||
m = make_manifest(apk, validator_public_key, seq)
|
m = make_manifest(apk, validation_pk, seq)
|
||||||
m1 = sign_manifest(m, private_key, pk)
|
m1 = sign_manifest(m, validation_sk, master_sk, pk)
|
||||||
return base64.b64encode(m1)
|
return base64.b64encode(m1)
|
||||||
|
|
||||||
def verify_signature(seq, validator_public_key_human, public_key_human, signature):
|
|
||||||
v, validator_public_key = Base58.decode_version(validator_public_key_human)
|
|
||||||
check_validator_public(v, validator_public_key)
|
|
||||||
|
|
||||||
v, public_key = Base58.decode_version(public_key_human)
|
|
||||||
|
|
||||||
m = make_manifest(public_key, validator_public_key, seq)
|
|
||||||
public_key = public_key[1:] # Remove ED25519_BYTE
|
|
||||||
sig = signature.decode('hex')
|
|
||||||
ed25519.checkvalid(sig, 'MAN\0' + m, public_key)
|
|
||||||
|
|
||||||
# Testable versions of functions.
|
# Testable versions of functions.
|
||||||
def perform_create(urandom=os.urandom, print=print):
|
def perform_create(urandom=os.urandom, print=print):
|
||||||
public, private = create_ed_keys(urandom)
|
pk, sk = create_ed_keys(urandom)
|
||||||
print('[validator_keys]', public, '', '[master_secret]', private, sep='\n')
|
print('[validator_keys]', pk, '', '[master_secret]', sk, sep='\n')
|
||||||
|
|
||||||
def perform_create_public(private_key_human, print=print):
|
def perform_create_public(sk_human, print=print):
|
||||||
public_key_human = create_ed_public_key(private_key_human)
|
pk_human = create_ed_public_key(sk_human)
|
||||||
print(
|
print(
|
||||||
'[validator_keys]',public_key_human, '',
|
'[validator_keys]',pk_human, '',
|
||||||
'[master_secret]', private_key_human, sep='\n')
|
'[master_secret]', sk_human, sep='\n')
|
||||||
|
|
||||||
def perform_check(s, print=print):
|
def perform_check(s, print=print):
|
||||||
version, b = Base58.decode_version(s)
|
version, b = Base58.decode_version(s)
|
||||||
@@ -157,32 +187,29 @@ def perform_check(s, print=print):
|
|||||||
assert Base58.encode_version(version, b) == s
|
assert Base58.encode_version(version, b) == s
|
||||||
|
|
||||||
def perform_sign(
|
def perform_sign(
|
||||||
seq, validator_public_key_human, private_key_human, print=print):
|
seq, validation_pk_human, validation_sk_human, master_sk_human, print=print):
|
||||||
print('[validation_manifest]')
|
print('[validation_manifest]')
|
||||||
print(wrap(get_signature(
|
print(wrap(get_signature(
|
||||||
int(seq), validator_public_key_human, private_key_human)))
|
int(seq), validation_pk_human, validation_sk_human, master_sk_human)))
|
||||||
|
|
||||||
def perform_verify(
|
def perform_verify(
|
||||||
seq, validator_public_key_human, public_key_human, signature, print=print):
|
seq, validation_pk_human, master_pk_human, signature, print=print):
|
||||||
verify_signature(
|
verify_signature(
|
||||||
int(seq), validator_public_key_human, public_key_human, signature)
|
int(seq), validation_pk_human, master_pk_human, signature)
|
||||||
print('Signature valid for', public_key_human)
|
print('Signature valid for', master_pk_human)
|
||||||
|
|
||||||
# Externally visible versions of functions.
|
# Externally visible versions of functions.
|
||||||
def create(private_key_human=None):
|
def create(sk_human=None):
|
||||||
if private_key_human:
|
if sk_human:
|
||||||
perform_create_public(private_key_human)
|
perform_create_public(sk_human)
|
||||||
else:
|
else:
|
||||||
perform_create()
|
perform_create()
|
||||||
|
|
||||||
def check(s):
|
def check(s):
|
||||||
perform_check(s)
|
perform_check(s)
|
||||||
|
|
||||||
def sign(seq, validator_public_key_human, private_key_human):
|
def sign(seq, validation_pk_human, validation_sk_human, master_sk_human):
|
||||||
perform_sign(seq, validator_public_key_human, private_key_human)
|
perform_sign(seq, validation_pk_human, validation_sk_human, master_sk_human)
|
||||||
|
|
||||||
def verify(seq, validator_public_key_human, public_key_human, signature):
|
|
||||||
perform_verify(seq, validator_public_key_human, public_key_human, signature)
|
|
||||||
|
|
||||||
def usage(*errors):
|
def usage(*errors):
|
||||||
if errors:
|
if errors:
|
||||||
@@ -190,7 +217,7 @@ def usage(*errors):
|
|||||||
print(USAGE)
|
print(USAGE)
|
||||||
return not errors
|
return not errors
|
||||||
|
|
||||||
_COMMANDS = dict((f.__name__, f) for f in (create, check, sign, verify))
|
_COMMANDS = dict((f.__name__, f) for f in (create, check, sign))
|
||||||
|
|
||||||
def run_command(args):
|
def run_command(args):
|
||||||
if not args:
|
if not args:
|
||||||
|
|||||||
@@ -10,14 +10,7 @@ BINARY = 'nN9kfUnKTf7PpgLG'
|
|||||||
|
|
||||||
class test_Sign(TestCase):
|
class test_Sign(TestCase):
|
||||||
SEQUENCE = 23
|
SEQUENCE = 23
|
||||||
SIGNATURE = (
|
|
||||||
'JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2'
|
|
||||||
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJM'
|
|
||||||
'zqkBJwDz30b2SkxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA')
|
|
||||||
VALIDATOR_KEY_HUMAN = 'n9JijuoCv8ubEy5ag3LiX3hyq27GaLJsitZPbQ6APkwx2MkUXq8E'
|
VALIDATOR_KEY_HUMAN = 'n9JijuoCv8ubEy5ag3LiX3hyq27GaLJsitZPbQ6APkwx2MkUXq8E'
|
||||||
SIGNATURE_HEX = (
|
|
||||||
'0a1546caa29c887f9fcb5e6143ea101b31fb5895a5cdfa24939301c66ff51794'
|
|
||||||
'a0b729e0ebbf576f2cc7cdb9f68c2366324a53b8e1ecf16f3c17bebbdb8d7102')
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.results = []
|
self.results = []
|
||||||
@@ -59,13 +52,17 @@ class test_Sign(TestCase):
|
|||||||
'\xef*\x97\x16n<\xa6\xf2\xe4\xfb\xfc\xcd\x80P[\xf1s\x06verify')
|
'\xef*\x97\x16n<\xa6\xf2\xe4\xfb\xfc\xcd\x80P[\xf1s\x06verify')
|
||||||
|
|
||||||
def test_sign_manifest(self):
|
def test_sign_manifest(self):
|
||||||
|
ssk, spk = Sign.make_ecdsa_keypair(self.urandom)
|
||||||
sk, pk = Sign.make_ed25519_keypair(self.urandom)
|
sk, pk = Sign.make_ed25519_keypair(self.urandom)
|
||||||
s = Sign.sign_manifest('manifest', sk, pk)
|
s = Sign.sign_manifest('manifest', ssk, sk, pk)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
s, 'manifestv@\xe5\x84\xbe\xc4\x80N\xa0v"\xb2\x80A\x88\x06\xc0'
|
s, 'manifestvF0D\x02 \x04\x85\x95p\x0f\xb8\x17\x7f\xdf\xdd\x04'
|
||||||
'\xd2\xbae\x92\x89\xa8\'!\xdd\x00\x88\x06s\xe0\xf74\xe3Yg\xad{$'
|
'\xaa+\x16q1W\xf6\xfd\xe8X\xb12l\xd5\xc3\xf1\xd6\x05\x1b\x1c\x9a'
|
||||||
'\x17\xd3\x99\xaa\x16\xb0\xeaZ\xd7]\r\xb3\xdc\x1b\x8f\xc1Z\xdfHU'
|
'\x02 \x18\\.(o\xa8 \xeb\x87\xfa&~\xbd\xe6,\xfb\xa61\xd1\xcd\xcd'
|
||||||
'\xb5\x92\xac\x82jI\x02')
|
'\xc8\r\x16[\x81\x9a\x19\xda\x93i\xcdp\x12@\xe5\x84\xbe\xc4\x80N'
|
||||||
|
'\xa0v"\xb2\x80A\x88\x06\xc0\xd2\xbae\x92\x89\xa8\'!\xdd\x00\x88'
|
||||||
|
'\x06s\xe0\xf74\xe3Yg\xad{$\x17\xd3\x99\xaa\x16\xb0\xeaZ\xd7]\r'
|
||||||
|
'\xb3\xdc\x1b\x8f\xc1Z\xdfHU\xb5\x92\xac\x82jI\x02')
|
||||||
|
|
||||||
def test_wrap(self):
|
def test_wrap(self):
|
||||||
wrap = lambda s: Sign.wrap(s, 5)
|
wrap = lambda s: Sign.wrap(s, 5)
|
||||||
@@ -93,23 +90,21 @@ class test_Sign(TestCase):
|
|||||||
public = (Base58.VER_NODE_PUBLIC, '\x02' + (32 * 'v'))
|
public = (Base58.VER_NODE_PUBLIC, '\x02' + (32 * 'v'))
|
||||||
private = (Base58.VER_NODE_PRIVATE, 32 * 'k')
|
private = (Base58.VER_NODE_PRIVATE, 32 * 'k')
|
||||||
|
|
||||||
Sign.check_validator_public(*public)
|
Sign.check_validation_public_key(*public)
|
||||||
Sign.check_master_secret(*private)
|
Sign.check_secret_key(*private)
|
||||||
|
|
||||||
return (Base58.encode_version(*public), Base58.encode_version(*private))
|
return (Base58.encode_version(*public), Base58.encode_version(*private))
|
||||||
|
|
||||||
def test_get_signature(self):
|
def test_get_signature(self):
|
||||||
signature = Sign.get_signature(self.SEQUENCE, *self.get_test_keypair())
|
pk, sk = self.get_test_keypair()
|
||||||
|
signature = Sign.get_signature(self.SEQUENCE, pk, sk, sk)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
signature,
|
signature,
|
||||||
'JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2'
|
'JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2'
|
||||||
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJM'
|
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkYwRAIgXyobHA8sDQxmDJNLE6HI'
|
||||||
'zqkBJwDz30b2SkxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA')
|
'aARlzvcd79/wT068e113gUkCIHkI540JQT2LHwAD7/y3wFE5X3lEXMfgZRkpLZTx'
|
||||||
|
'kpticBJAzo5VrUEr0U47sHvuIjbrINLCTM6pAScA899G9kpMWexbXv1ceIbTP5JH'
|
||||||
def test_verify_signature(self):
|
'1HyQmsZsROTeHR0irojvYgx7JLaiAA==')
|
||||||
Sign.verify_signature(self.SEQUENCE, self.VALIDATOR_KEY_HUMAN,
|
|
||||||
'nHUUaKHpxyRP4TZZ79tTpXuTpoM8pRNs5crZpGVA5jdrjib5easY',
|
|
||||||
self.SIGNATURE_HEX)
|
|
||||||
|
|
||||||
def test_check(self):
|
def test_check(self):
|
||||||
public = Base58.encode_version(Base58.VER_NODE_PRIVATE, 32 * 'k')
|
public = Base58.encode_version(Base58.VER_NODE_PRIVATE, 32 * 'k')
|
||||||
@@ -143,17 +138,12 @@ class test_Sign(TestCase):
|
|||||||
|
|
||||||
def test_sign(self):
|
def test_sign(self):
|
||||||
public, private = self.get_test_keypair()
|
public, private = self.get_test_keypair()
|
||||||
Sign.perform_sign(self.SEQUENCE, public, private, print=self.print)
|
Sign.perform_sign(self.SEQUENCE, public, private, private, print=self.print)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.results,
|
self.results,
|
||||||
[[['[validation_manifest]'], {}],
|
[[['[validation_manifest]'], {}],
|
||||||
[['JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmo\n'
|
[['JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2dnZ2dnZ2\n'
|
||||||
'VCdIw6nMhAnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dn\n'
|
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkYwRAIgXyobHA8sDQxmDJNLE6HIaARlzvcd79/wT068\n'
|
||||||
'Z2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJMzqkBJwDz30b2S\n'
|
'e113gUkCIHkI540JQT2LHwAD7/y3wFE5X3lEXMfgZRkpLZTxkpticBJAzo5VrUEr0U47sHvu\n'
|
||||||
'kxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA'],
|
'IjbrINLCTM6pAScA899G9kpMWexbXv1ceIbTP5JH1HyQmsZsROTeHR0irojvYgx7JLaiAA=='],
|
||||||
{}]])
|
{}]])
|
||||||
|
|
||||||
def test_verify(self):
|
|
||||||
Sign.perform_verify(self.SEQUENCE, self.VALIDATOR_KEY_HUMAN,
|
|
||||||
'nHUUaKHpxyRP4TZZ79tTpXuTpoM8pRNs5crZpGVA5jdrjib5easY',
|
|
||||||
self.SIGNATURE_HEX, print=self.print)
|
|
||||||
|
|||||||
@@ -22,7 +22,3 @@ test:
|
|||||||
override:
|
override:
|
||||||
# Execute unit tests under gdb
|
# 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
|
- 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
|
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ master key pair:
|
|||||||
Sample output:
|
Sample output:
|
||||||
```
|
```
|
||||||
[validator_keys]
|
[validator_keys]
|
||||||
nHUSSzGw4A9zEmFtK2Q2NcWDH9xmGdXMHc1MsVej3QkLTgvDNeBr
|
nHDwNP6jbJgVKj5zSEjMn8SJhTnPV54Fx5sSiNpwqLbb42nmh3Ln
|
||||||
|
|
||||||
[master_secret]
|
[master_secret]
|
||||||
pnxayCakmZRQE2qhEVRbFjiWCunReSbN1z64vPL36qwyLgogyYc
|
paamfhAn5m1NM4UUu5mmvVaHQy8Fb65bkpbaNrvKwX3YMKdjzi2
|
||||||
```
|
```
|
||||||
|
|
||||||
The first value is the master public key. Add the public key to the config
|
The first value is the master public key. Add the public key to the config
|
||||||
@@ -54,10 +54,11 @@ Sample output:
|
|||||||
Securely connecting to 127.0.0.1:5005
|
Securely connecting to 127.0.0.1:5005
|
||||||
{
|
{
|
||||||
"result" : {
|
"result" : {
|
||||||
"status" : "success",
|
"status" : "success",
|
||||||
"validation_key" : "TOO EDNA SHUN FEUD STAB JOAN BIAS FLEA WISE BOHR LOSS WEEK",
|
"validation_key" : "MIN HEAT NUN FAWN HIP KAHN BORG PHI BALK ANN TWIG RACY",
|
||||||
"validation_public_key" : "n9JzKV3ZrcZ3DW5pwjakj4hpijJ9oMiyrPDGJc3mpsndL6Gf3zwd",
|
"validation_private_key" : "pn6kTqE4WyeRQzZrRp5FnJ5J2vLdSCB5KD3DEyfVw6C9woDBfED",
|
||||||
"validation_seed" : "sahzkAajS2dyhjXg2yovjdZhXmjsx"
|
"validation_public_key" : "n9LtZ9haqYMbzJ92cDd3pu3Lko6uEznrXuYea3ehuhVcwDHF5coX",
|
||||||
|
"validation_seed" : "sh8bLqqkGBknGcsgRTrFMxcciwytm"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -68,36 +69,37 @@ number as a comment as well (sequence numbers are be explained below):
|
|||||||
|
|
||||||
```
|
```
|
||||||
[validation_seed]
|
[validation_seed]
|
||||||
sahzkAajS2dyhjXg2yovjdZhXmjsx
|
sh8bLqqkGBknGcsgRTrFMxcciwytm
|
||||||
# validation_public_key: n9JzKV3ZrcZ3DW5pwjakj4hpijJ9oMiyrPDGJc3mpsndL6Gf3zwd
|
# validation_public_key: n9LtZ9haqYMbzJ92cDd3pu3Lko6uEznrXuYea3ehuhVcwDHF5coX
|
||||||
# sequence number: 1
|
# sequence number: 1
|
||||||
```
|
```
|
||||||
|
|
||||||
A manifest is a signed message used to inform other servers of this validator's
|
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
|
ephemeral public key. A manifest contains a sequence number, the new ephemeral
|
||||||
public key, and it is signed with the master secret key. The sequence number
|
public key, and it is signed with both the ephemeral and master secret keys.
|
||||||
should be higher than the previous sequence number (if it is not, the manifest
|
The sequence number should be higher than the previous sequence number (if it
|
||||||
will be ignored). Usually the previous sequence number will be incremented by
|
is not, the manifest will be ignored). Usually the previous sequence number
|
||||||
one. Use the `manifest` script to create a manifest. It has the form:
|
will be incremented by one. Use the `manifest` script to create a manifest.
|
||||||
|
It has the form:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ bin/manifest sign sequence_number validation_public_key master_secret
|
$ bin/manifest sign sequence validation_public_key validation_private_key master_secret
|
||||||
```
|
```
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ bin/manifest sign 1 n9JzKV3Z...L6Gf3zwd pnxayCak...yLgogyYc
|
$ bin/manifest sign 1 n9LtZ9ha...wDHF5coX pn6kTqE4...9woDBfED paamfhAn...YMKdjzi2
|
||||||
```
|
```
|
||||||
|
|
||||||
Sample output:
|
Sample output:
|
||||||
|
|
||||||
```
|
```
|
||||||
[validation_manifest]
|
[validation_manifest]
|
||||||
JAAAAAFxIe2PEzNhe996gykB1PJQNoDxvr/Y0XhDELw8d/i
|
JAAAAAFxIe3t8rIb4Ba8JHI97CbwpxmTq0LhN/7ZAbsNaSwrbHaypHMhAzTuu07YGOvVvB3+
|
||||||
Fcgz3A3MhAjqhKsgZTmK/3BPEI+kzjV1p9ip7pl/AtF7CKd
|
aS0jhP+q0TVgTjGJKhx+yTY1Da3ddkYwRAIgDkmIt3dPNsfeCH3ApMZgpwqG4JwtIlKEymqK
|
||||||
NSfAH9dkCxezV6apS4FLYzAcQilONx315HvebwAB/pLPaM4
|
S7v+VqkCIFQXg20ZMpXXT86vmLdlmPspgeUN1scWsuFoPYUUJywycBJAl93+/bZbfZ4quTeM
|
||||||
2sWCEppSuLNKN/JJjTABOo9tmAiNnnstF83yvecKMJzniwN
|
5y80/OSIcVoWPcHajwrAl68eiAW4MVFeJXvShXNfnT+XsxMjDh0VpOkhvyp971i1MgjBAA==
|
||||||
```
|
```
|
||||||
|
|
||||||
Copy this to the config for this validator. Don't forget to update the comment
|
Copy this to the config for this validator. Don't forget to update the comment
|
||||||
@@ -107,4 +109,4 @@ noting the sequence number.
|
|||||||
|
|
||||||
If a master key is compromised, the key may be revoked permanently. To revoke a
|
If a master key is compromised, the key may be revoked permanently. To revoke a
|
||||||
master key, sign a manifest with the highest possible sequence number:
|
master key, sign a manifest with the highest possible sequence number:
|
||||||
`4,294,967,295`
|
`4294967295`
|
||||||
|
|||||||
@@ -260,6 +260,19 @@
|
|||||||
# If you need a certificate chain, specify the path to the
|
# If you need a certificate chain, specify the path to the
|
||||||
# certificate chain here. The chain may include the end certificate.
|
# 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.
|
||||||
|
#
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# [rpc_startup]
|
# [rpc_startup]
|
||||||
|
|||||||
3
docs/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
html
|
||||||
|
temp
|
||||||
|
out.txt
|
||||||
22
docs/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/rippled/docs && \
|
||||||
|
chmod +x makeqbk.sh && \
|
||||||
|
./makeqbk.sh && \
|
||||||
|
$BOOST_ROOT/b2
|
||||||
71
docs/Jamfile.v2
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
#
|
||||||
|
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
#
|
||||||
|
|
||||||
|
import os ;
|
||||||
|
|
||||||
|
local broot = [ os.environ BOOST_ROOT ] ;
|
||||||
|
|
||||||
|
project rippled/doc ;
|
||||||
|
|
||||||
|
using boostbook ;
|
||||||
|
using quickbook ;
|
||||||
|
using doxygen ;
|
||||||
|
|
||||||
|
path-constant out : . ;
|
||||||
|
|
||||||
|
install stylesheets
|
||||||
|
:
|
||||||
|
$(broot)/doc/src/boostbook.css
|
||||||
|
:
|
||||||
|
<location>$(out)/html
|
||||||
|
;
|
||||||
|
|
||||||
|
explicit stylesheets ;
|
||||||
|
|
||||||
|
install images
|
||||||
|
:
|
||||||
|
[ glob $(broot)/doc/src/images/*.png ]
|
||||||
|
:
|
||||||
|
<location>$(out)/html/images
|
||||||
|
;
|
||||||
|
|
||||||
|
explicit images ;
|
||||||
|
|
||||||
|
install callouts
|
||||||
|
:
|
||||||
|
[ glob $(broot)/doc/src/images/callouts/*.png ]
|
||||||
|
:
|
||||||
|
<location>$(out)/html/images/callouts
|
||||||
|
;
|
||||||
|
|
||||||
|
explicit callout ;
|
||||||
|
|
||||||
|
xml doc
|
||||||
|
:
|
||||||
|
main.qbk
|
||||||
|
:
|
||||||
|
<location>temp
|
||||||
|
<include>$(broot)/tools/boostbook/dtd
|
||||||
|
;
|
||||||
|
|
||||||
|
boostbook boostdoc
|
||||||
|
:
|
||||||
|
doc
|
||||||
|
:
|
||||||
|
<xsl:param>chapter.autolabel=0
|
||||||
|
<xsl:param>boost.root=$(broot)
|
||||||
|
<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?
|
||||||
|
<xsl:param>generate.toc="chapter toc section toc"
|
||||||
|
:
|
||||||
|
<location>temp
|
||||||
|
<dependency>stylesheets
|
||||||
|
<dependency>images
|
||||||
|
;
|
||||||
84
docs/README.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Building documentation
|
||||||
|
|
||||||
|
## Specifying Files
|
||||||
|
|
||||||
|
To specify the source files for which to build documentation, modify `INPUT`
|
||||||
|
and its related fields in `docs/source.dox`. Note that the `INPUT` paths are
|
||||||
|
relative to the `docs/` 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. (Optional, if you also plan to build rippled) `./bjam.exe --toolset=msvc-14.0
|
||||||
|
--build-type=complete variant=debug,release link=static runtime-link=static
|
||||||
|
address-model=64 stage`
|
||||||
|
5. 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. (Optional, if you also plan to build rippled)
|
||||||
|
`$ ./b2 toolset=clang threading=multi runtime-link=static link=static
|
||||||
|
cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" adress-model=64`
|
||||||
|
5. 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 rippled root folder:
|
||||||
|
```
|
||||||
|
sudo docker build -t rippled-docs docs/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup project submodules
|
||||||
|
|
||||||
|
1. Open a shell in your rippled root folder.
|
||||||
|
2. `git submodule init`
|
||||||
|
3. `git submodule update docs/docca`
|
||||||
|
|
||||||
|
## Do it
|
||||||
|
|
||||||
|
### Windows & MacOS
|
||||||
|
|
||||||
|
From the rippled root folder:
|
||||||
|
```
|
||||||
|
cd docs
|
||||||
|
./makeqbk.sh && b2
|
||||||
|
```
|
||||||
|
The output will be in `docs/html`.
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
From the rippled root folder:
|
||||||
|
```
|
||||||
|
sudo docker run -v $PWD:/opt/rippled --rm rippled-docs
|
||||||
|
```
|
||||||
|
The output will be in `docs/html`.
|
||||||
439
docs/boostbook.dtd
Normal file
@@ -0,0 +1,439 @@
|
|||||||
|
<!--
|
||||||
|
BoostBook DTD - development version
|
||||||
|
|
||||||
|
For further information, see: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Boost_Documentation_Format
|
||||||
|
|
||||||
|
Copyright (c) 2002 by Peter Simons <simons@cryp.to>
|
||||||
|
Copyright (c) 2003-2004 by Douglas Gregor <doug.gregor -at- gmail.com>
|
||||||
|
Copyright (c) 2007 by Frank Mori Hess <fmhess@users.sourceforge.net>
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
The latest stable DTD module is identified by the PUBLIC and SYSTEM identifiers:
|
||||||
|
|
||||||
|
PUBLIC "-//Boost//DTD BoostBook XML V1.1//EN"
|
||||||
|
SYSTEM "http://www.boost.org/tools/boostbook/dtd/1.1/boostbook.dtd"
|
||||||
|
|
||||||
|
$Revision$
|
||||||
|
$Date$
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--========== Define XInclude features. ==========-->
|
||||||
|
<!-- This is not really integrated into the DTD yet. Needs more
|
||||||
|
research. -->
|
||||||
|
<!--
|
||||||
|
<!ELEMENT xi:include (xi:fallback)?>
|
||||||
|
<!ATTLIST xi:include
|
||||||
|
xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude"
|
||||||
|
href CDATA #REQUIRED
|
||||||
|
parse (xml|text) "xml"
|
||||||
|
encoding CDATA #IMPLIED>
|
||||||
|
|
||||||
|
<!ELEMENT xi:fallback ANY>
|
||||||
|
<!ATTLIST xi:fallback
|
||||||
|
xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!ENTITY % local.common.attrib "last-revision CDATA #IMPLIED">
|
||||||
|
|
||||||
|
<!--========== Define the BoostBook extensions ==========-->
|
||||||
|
<!ENTITY % boost.common.attrib "%local.common.attrib;
|
||||||
|
id CDATA #IMPLIED">
|
||||||
|
|
||||||
|
<!ENTITY % boost.namespace.mix
|
||||||
|
"class|class-specialization|struct|struct-specialization|
|
||||||
|
union|union-specialization|typedef|enum|
|
||||||
|
free-function-group|function|overloaded-function|
|
||||||
|
namespace">
|
||||||
|
|
||||||
|
<!ENTITY % boost.template.mix
|
||||||
|
"template-type-parameter|template-nontype-parameter|template-varargs">
|
||||||
|
|
||||||
|
<!ENTITY % boost.class.members
|
||||||
|
"static-constant|typedef|enum|
|
||||||
|
copy-assignment|constructor|destructor|method-group|
|
||||||
|
method|overloaded-method|data-member|class|class-specialization|struct|
|
||||||
|
struct-specialization|union|union-specialization">
|
||||||
|
|
||||||
|
<!ENTITY % boost.class.mix
|
||||||
|
"%boost.class.members;|free-function-group|function|overloaded-function">
|
||||||
|
|
||||||
|
<!ENTITY % boost.class.content
|
||||||
|
"template?, inherit*, purpose?, description?,
|
||||||
|
(%boost.class.mix;|access)*">
|
||||||
|
|
||||||
|
<!ENTITY % boost.class-specialization.content
|
||||||
|
"template?, specialization?, inherit?, purpose?, description?,
|
||||||
|
(%boost.class.mix;|access)*">
|
||||||
|
|
||||||
|
<!ENTITY % boost.function.semantics
|
||||||
|
"purpose?, description?, requires?, effects?, postconditions?,
|
||||||
|
returns?, throws?, complexity?, notes?, rationale?">
|
||||||
|
|
||||||
|
<!ENTITY % library.content
|
||||||
|
"libraryinfo, (title, ((section|library-reference|testsuite))+)?">
|
||||||
|
|
||||||
|
<!ELEMENT library (%library.content;)>
|
||||||
|
<!ATTLIST library
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
dirname CDATA #REQUIRED
|
||||||
|
html-only CDATA #IMPLIED
|
||||||
|
url CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT boostbook (title, (chapter|library)*)>
|
||||||
|
<!ATTLIST boostbook %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT libraryinfo (author+, copyright*, legalnotice*, librarypurpose, librarycategory*)>
|
||||||
|
<!ATTLIST libraryinfo %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT librarypurpose (#PCDATA|code|ulink|functionname|methodname|classname|macroname|headername|enumname|globalname)*>
|
||||||
|
<!ATTLIST librarypurpose %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT librarycategory (#PCDATA)>
|
||||||
|
<!ATTLIST librarycategory
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT libraryname (#PCDATA)>
|
||||||
|
<!ATTLIST libraryname %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT library-reference ANY>
|
||||||
|
<!ATTLIST library-reference
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT librarylist EMPTY>
|
||||||
|
<!ATTLIST librarylist %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT librarycategorylist (librarycategorydef)*>
|
||||||
|
<!ATTLIST librarycategorylist %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT librarycategorydef (#PCDATA)>
|
||||||
|
<!ATTLIST librarycategorydef
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT header ANY>
|
||||||
|
<!ATTLIST header
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT namespace (%boost.namespace.mix;)*>
|
||||||
|
<!ATTLIST namespace
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT class (%boost.class.content;)>
|
||||||
|
<!ATTLIST class
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT struct (%boost.class.content;)>
|
||||||
|
<!ATTLIST struct
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT union (%boost.class.content;)>
|
||||||
|
<!ATTLIST union
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT class-specialization (%boost.class-specialization.content;)>
|
||||||
|
<!ATTLIST class-specialization
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT struct-specialization (%boost.class-specialization.content;)>
|
||||||
|
<!ATTLIST struct-specialization
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT union-specialization (%boost.class-specialization.content;)>
|
||||||
|
<!ATTLIST union-specialization
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT access (%boost.class.members;)+>
|
||||||
|
<!ATTLIST access
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!--========= C++ Templates =========-->
|
||||||
|
<!ELEMENT template (%boost.template.mix;)*>
|
||||||
|
<!ATTLIST template %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT template-type-parameter (default?, purpose?)>
|
||||||
|
<!ATTLIST template-type-parameter
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
pack CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT template-nontype-parameter (type, default?, purpose?)>
|
||||||
|
<!ATTLIST template-nontype-parameter
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
pack CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT template-varargs EMPTY>
|
||||||
|
<!ATTLIST template-varargs %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT specialization (template-arg)*>
|
||||||
|
<!ATTLIST specialization %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT template-arg ANY>
|
||||||
|
<!ATTLIST template-arg
|
||||||
|
pack CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT default ANY>
|
||||||
|
<!ATTLIST default %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT inherit (type, purpose?)>
|
||||||
|
<!ATTLIST inherit
|
||||||
|
access CDATA #IMPLIED
|
||||||
|
pack CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT purpose ANY>
|
||||||
|
<!ATTLIST purpose %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT description ANY>
|
||||||
|
<!ATTLIST description %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT type ANY>
|
||||||
|
<!ATTLIST type %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT typedef (type, purpose?, description?)>
|
||||||
|
<!ATTLIST typedef
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT enum (enumvalue*, purpose?, description?)>
|
||||||
|
<!ATTLIST enum
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT enumvalue (default?, purpose?, description?)>
|
||||||
|
<!ATTLIST enumvalue
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT static-constant (type, default, purpose?, description?)>
|
||||||
|
<!ATTLIST static-constant
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT data-member (type, purpose?, description?)>
|
||||||
|
<!ATTLIST data-member
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
specifiers CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT paramtype ANY>
|
||||||
|
<!ATTLIST paramtype %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT effects ANY>
|
||||||
|
<!ATTLIST effects %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT postconditions ANY>
|
||||||
|
<!ATTLIST postconditions %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT method-group (method|overloaded-method)*>
|
||||||
|
<!ATTLIST method-group
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT constructor (template?, parameter*, %boost.function.semantics;)>
|
||||||
|
<!ATTLIST constructor
|
||||||
|
specifiers CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT destructor (%boost.function.semantics;)>
|
||||||
|
<!ATTLIST destructor
|
||||||
|
specifiers CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT method (template?, type, parameter*, %boost.function.semantics;)>
|
||||||
|
<!ATTLIST method
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
cv CDATA #IMPLIED
|
||||||
|
specifiers CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT function (template?, type, parameter*, %boost.function.semantics;)>
|
||||||
|
<!ATTLIST function
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
specifiers CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT overloaded-method (signature*, %boost.function.semantics;)>
|
||||||
|
<!ATTLIST overloaded-method
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT overloaded-function (signature*, %boost.function.semantics;)>
|
||||||
|
<!ATTLIST overloaded-function
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT signature (template?, type, parameter*)>
|
||||||
|
<!ATTLIST signature
|
||||||
|
cv CDATA #IMPLIED
|
||||||
|
specifiers CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT requires ANY>
|
||||||
|
<!ATTLIST requires %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT returns ANY>
|
||||||
|
<!ATTLIST returns %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT throws ANY>
|
||||||
|
<!ATTLIST throws %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT complexity ANY>
|
||||||
|
<!ATTLIST complexity %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT notes ANY>
|
||||||
|
<!ATTLIST notes %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT rationale ANY>
|
||||||
|
<!ATTLIST rationale %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT functionname (#PCDATA)>
|
||||||
|
<!ATTLIST functionname
|
||||||
|
alt CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT enumname (#PCDATA)>
|
||||||
|
<!ATTLIST enumname
|
||||||
|
alt CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT macroname (#PCDATA)>
|
||||||
|
<!ATTLIST macroname
|
||||||
|
alt CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT headername (#PCDATA)>
|
||||||
|
<!ATTLIST headername
|
||||||
|
alt CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT globalname (#PCDATA)>
|
||||||
|
<!ATTLIST globalname
|
||||||
|
alt CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT copy-assignment
|
||||||
|
(template?, type?, parameter*, %boost.function.semantics;)>
|
||||||
|
<!ATTLIST copy-assignment
|
||||||
|
cv CDATA #IMPLIED
|
||||||
|
specifiers CDATA #IMPLIED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT free-function-group (function|overloaded-function)*>
|
||||||
|
<!ATTLIST free-function-group
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT precondition ANY>
|
||||||
|
<!ATTLIST precondition %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT code ANY>
|
||||||
|
<!ATTLIST code %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT using-namespace EMPTY>
|
||||||
|
<!ATTLIST using-namespace
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT using-class EMPTY>
|
||||||
|
<!ATTLIST using-class
|
||||||
|
name CDATA #REQUIRED
|
||||||
|
%boost.common.attrib;>
|
||||||
|
|
||||||
|
<!--========== Boost Testsuite Extensions ==========-->
|
||||||
|
<!ENTITY % boost.testsuite.tests
|
||||||
|
"compile-test|link-test|run-test|
|
||||||
|
compile-fail-test|link-fail-test|run-fail-test">
|
||||||
|
<!ENTITY % boost.testsuite.test.content
|
||||||
|
"source*, lib*, requirement*, purpose, if-fails?">
|
||||||
|
|
||||||
|
<!ELEMENT testsuite ((%boost.testsuite.tests;)+)>
|
||||||
|
<!ATTLIST testsuite %boost.common.attrib;>
|
||||||
|
|
||||||
|
<!ELEMENT compile-test (%boost.testsuite.test.content;)>
|
||||||
|
<!ATTLIST compile-test
|
||||||
|
filename CDATA #REQUIRED
|
||||||
|
name CDATA #IMPLIED>
|
||||||
|
|
||||||
|
<!ELEMENT link-test (%boost.testsuite.test.content;)>
|
||||||
|
<!ATTLIST link-test
|
||||||
|
filename CDATA #REQUIRED
|
||||||
|
name CDATA #IMPLIED>
|
||||||
|
|
||||||
|
<!ELEMENT run-test (%boost.testsuite.test.content;)>
|
||||||
|
<!ATTLIST run-test
|
||||||
|
filename CDATA #REQUIRED
|
||||||
|
name CDATA #IMPLIED>
|
||||||
|
|
||||||
|
<!ELEMENT compile-fail-test (%boost.testsuite.test.content;)>
|
||||||
|
<!ATTLIST compile-fail-test
|
||||||
|
filename CDATA #REQUIRED
|
||||||
|
name CDATA #IMPLIED>
|
||||||
|
|
||||||
|
<!ELEMENT link-fail-test (%boost.testsuite.test.content;)>
|
||||||
|
<!ATTLIST link-fail-test
|
||||||
|
filename CDATA #REQUIRED
|
||||||
|
name CDATA #IMPLIED>
|
||||||
|
|
||||||
|
<!ELEMENT run-fail-test (%boost.testsuite.test.content;)>
|
||||||
|
<!ATTLIST run-fail-test
|
||||||
|
filename CDATA #REQUIRED
|
||||||
|
name CDATA #IMPLIED>
|
||||||
|
|
||||||
|
<!ELEMENT source (#PCDATA|snippet)*>
|
||||||
|
|
||||||
|
<!ELEMENT snippet EMPTY>
|
||||||
|
<!ATTLIST snippet
|
||||||
|
name CDATA #REQUIRED>
|
||||||
|
|
||||||
|
<!ELEMENT lib (#PCDATA)>
|
||||||
|
|
||||||
|
<!ELEMENT requirement (#PCDATA)>
|
||||||
|
<!ATTLIST requirement
|
||||||
|
name CDATA #REQUIRED>
|
||||||
|
|
||||||
|
<!ELEMENT if-fails ANY>
|
||||||
|
|
||||||
|
<!ELEMENT parameter (paramtype, default?, description?)>
|
||||||
|
<!ATTLIST parameter
|
||||||
|
name CDATA #IMPLIED
|
||||||
|
pack CDATA #IMPLIED>
|
||||||
|
|
||||||
|
<!ELEMENT programlisting ANY>
|
||||||
|
<!ATTLIST programlisting
|
||||||
|
name CDATA #IMPLIED>
|
||||||
|
|
||||||
|
<!--========== Customize the DocBook DTD ==========-->
|
||||||
|
<!ENTITY % local.tech.char.class "|functionname|libraryname|enumname|headername|macroname|code">
|
||||||
|
<!ENTITY % local.para.class
|
||||||
|
"|using-namespace|using-class|librarylist|librarycategorylist">
|
||||||
|
<!ENTITY % local.descobj.class "|libraryinfo">
|
||||||
|
<!ENTITY % local.classname.attrib "alt CDATA #IMPLIED">
|
||||||
|
<!ENTITY % local.methodname.attrib "alt CDATA #IMPLIED">
|
||||||
|
<!ENTITY % local.refentry.class "|library-reference|testsuite">
|
||||||
|
<!ENTITY % local.title.char.mix "">
|
||||||
|
<!ENTITY % programlisting.module "IGNORE">
|
||||||
|
<!ENTITY % parameter.module "IGNORE">
|
||||||
|
<!ENTITY % function.module "IGNORE">
|
||||||
|
<!ENTITY % type.module "IGNORE">
|
||||||
|
|
||||||
|
<!--========== Import DocBook DTD ==========-->
|
||||||
|
<!ENTITY % DocBook PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
%DocBook;
|
||||||
1
docs/docca
Submodule
14
docs/index.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!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)
|
||||||
|
|
||||||
|
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="rippled.index">
|
||||||
|
<title>Index</title>
|
||||||
|
<index/>
|
||||||
|
</section>
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
//------------------------------------------------------------------------------
|
[/
|
||||||
/*
|
Copyright (c) Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -14,14 +12,26 @@
|
|||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
]
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef RIPPLE_TEST_MAO_H_INCLUDED
|
[library rippled
|
||||||
#define RIPPLE_TEST_MAO_H_INCLUDED
|
[quickbook 1.6]
|
||||||
|
[copyright 2012 - 2016 Ripple Labs Inc.]
|
||||||
|
[purpose C++ Library]
|
||||||
|
[license
|
||||||
|
Distributed under the ISC License
|
||||||
|
]
|
||||||
|
[authors [Labs, Ripple]]
|
||||||
|
[category template]
|
||||||
|
[category generic]
|
||||||
|
]
|
||||||
|
|
||||||
// Convenience header that includes everything
|
[template mdash[] '''— ''']
|
||||||
|
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
|
||||||
|
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
|
||||||
|
|
||||||
#include <ripple/test/mao/Net.h>
|
[section:ref Reference]
|
||||||
|
[include temp/reference.qbk]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
#endif
|
[xinclude index.xml]
|
||||||
11
docs/makeqbk.sh
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
#
|
||||||
|
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
mkdir -p temp
|
||||||
|
doxygen source.dox
|
||||||
|
xsltproc temp/combine.xslt temp/index.xml > temp/all.xml
|
||||||
|
xsltproc reference.xsl temp/all.xml > temp/reference.qbk
|
||||||
61
docs/quickref.xml
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "boostbook.dtd">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Copyright (c) Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<informaltable frame="all">
|
||||||
|
<tgroup cols="3">
|
||||||
|
<colspec colname="a"/>
|
||||||
|
<colspec colname="b"/>
|
||||||
|
<colspec colname="c"/>
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry valign="center" namest="a" nameend="c">
|
||||||
|
<bridgehead renderas="sect2">Core</bridgehead>
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry valign="top">
|
||||||
|
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
</simplelist>
|
||||||
|
</entry>
|
||||||
|
<entry valign="top">
|
||||||
|
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
</simplelist>
|
||||||
|
</entry>
|
||||||
|
<entry valign="top">
|
||||||
|
<bridgehead renderas="sect3">Types</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
</simplelist>
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
14
docs/reference.xsl
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||||
|
|
||||||
|
<!-- Variables (Edit for your project) -->
|
||||||
|
<xsl:variable name="doc-ref" select="'rippled.ref.'"/>
|
||||||
|
<xsl:variable name="doc-ns" select="'ripple'"/>
|
||||||
|
<xsl:variable name="debug" select="0"/>
|
||||||
|
<xsl:variable name="private" select="0"/>
|
||||||
|
<!-- End Variables -->
|
||||||
|
|
||||||
|
<xsl:include href="docca/include/docca/doxygen.xsl"/>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
|
|
||||||
341
docs/source.dox
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Project related configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
DOXYFILE_ENCODING = UTF-8
|
||||||
|
PROJECT_NAME = "rippled"
|
||||||
|
PROJECT_NUMBER =
|
||||||
|
PROJECT_BRIEF = C++ Library
|
||||||
|
PROJECT_LOGO =
|
||||||
|
OUTPUT_DIRECTORY =
|
||||||
|
CREATE_SUBDIRS = NO
|
||||||
|
ALLOW_UNICODE_NAMES = NO
|
||||||
|
OUTPUT_LANGUAGE = English
|
||||||
|
BRIEF_MEMBER_DESC = YES
|
||||||
|
REPEAT_BRIEF = YES
|
||||||
|
ABBREVIATE_BRIEF =
|
||||||
|
ALWAYS_DETAILED_SEC = NO
|
||||||
|
INLINE_INHERITED_MEMB = YES
|
||||||
|
FULL_PATH_NAMES = NO
|
||||||
|
STRIP_FROM_PATH = ../src/
|
||||||
|
STRIP_FROM_INC_PATH =
|
||||||
|
SHORT_NAMES = NO
|
||||||
|
JAVADOC_AUTOBRIEF = YES
|
||||||
|
QT_AUTOBRIEF = NO
|
||||||
|
MULTILINE_CPP_IS_BRIEF = NO
|
||||||
|
INHERIT_DOCS = YES
|
||||||
|
SEPARATE_MEMBER_PAGES = NO
|
||||||
|
TAB_SIZE = 4
|
||||||
|
ALIASES =
|
||||||
|
TCL_SUBST =
|
||||||
|
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||||
|
OPTIMIZE_OUTPUT_JAVA = NO
|
||||||
|
OPTIMIZE_FOR_FORTRAN = NO
|
||||||
|
OPTIMIZE_OUTPUT_VHDL = NO
|
||||||
|
EXTENSION_MAPPING =
|
||||||
|
MARKDOWN_SUPPORT = YES
|
||||||
|
AUTOLINK_SUPPORT = YES
|
||||||
|
BUILTIN_STL_SUPPORT = NO
|
||||||
|
CPP_CLI_SUPPORT = NO
|
||||||
|
SIP_SUPPORT = NO
|
||||||
|
IDL_PROPERTY_SUPPORT = YES
|
||||||
|
DISTRIBUTE_GROUP_DOC = NO
|
||||||
|
GROUP_NESTED_COMPOUNDS = NO
|
||||||
|
SUBGROUPING = YES
|
||||||
|
INLINE_GROUPED_CLASSES = NO
|
||||||
|
INLINE_SIMPLE_STRUCTS = NO
|
||||||
|
TYPEDEF_HIDES_STRUCT = NO
|
||||||
|
LOOKUP_CACHE_SIZE = 0
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Build related configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
EXTRACT_ALL = YES
|
||||||
|
EXTRACT_PRIVATE = YES
|
||||||
|
EXTRACT_PACKAGE = NO
|
||||||
|
EXTRACT_STATIC = YES
|
||||||
|
EXTRACT_LOCAL_CLASSES = YES
|
||||||
|
EXTRACT_LOCAL_METHODS = YES
|
||||||
|
EXTRACT_ANON_NSPACES = NO
|
||||||
|
HIDE_UNDOC_MEMBERS = NO
|
||||||
|
HIDE_UNDOC_CLASSES = NO
|
||||||
|
HIDE_FRIEND_COMPOUNDS = NO
|
||||||
|
HIDE_IN_BODY_DOCS = NO
|
||||||
|
INTERNAL_DOCS = NO
|
||||||
|
CASE_SENSE_NAMES = YES
|
||||||
|
HIDE_SCOPE_NAMES = NO
|
||||||
|
HIDE_COMPOUND_REFERENCE= NO
|
||||||
|
SHOW_INCLUDE_FILES = NO
|
||||||
|
SHOW_GROUPED_MEMB_INC = NO
|
||||||
|
FORCE_LOCAL_INCLUDES = NO
|
||||||
|
INLINE_INFO = NO
|
||||||
|
SORT_MEMBER_DOCS = NO
|
||||||
|
SORT_BRIEF_DOCS = NO
|
||||||
|
SORT_MEMBERS_CTORS_1ST = YES
|
||||||
|
SORT_GROUP_NAMES = NO
|
||||||
|
SORT_BY_SCOPE_NAME = NO
|
||||||
|
STRICT_PROTO_MATCHING = NO
|
||||||
|
GENERATE_TODOLIST = NO
|
||||||
|
GENERATE_TESTLIST = NO
|
||||||
|
GENERATE_BUGLIST = NO
|
||||||
|
GENERATE_DEPRECATEDLIST= NO
|
||||||
|
ENABLED_SECTIONS =
|
||||||
|
MAX_INITIALIZER_LINES = 30
|
||||||
|
SHOW_USED_FILES = NO
|
||||||
|
SHOW_FILES = NO
|
||||||
|
SHOW_NAMESPACES = NO
|
||||||
|
FILE_VERSION_FILTER =
|
||||||
|
LAYOUT_FILE =
|
||||||
|
CITE_BIB_FILES =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to warning and progress messages
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
QUIET = NO
|
||||||
|
WARNINGS = YES
|
||||||
|
WARN_IF_UNDOCUMENTED = YES
|
||||||
|
WARN_IF_DOC_ERROR = YES
|
||||||
|
WARN_NO_PARAMDOC = NO
|
||||||
|
WARN_AS_ERROR = NO
|
||||||
|
WARN_FORMAT = "$file:$line: $text"
|
||||||
|
WARN_LOGFILE =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the input files
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
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
|
||||||
|
FILE_PATTERNS =
|
||||||
|
RECURSIVE = NO
|
||||||
|
EXCLUDE =
|
||||||
|
EXCLUDE_SYMLINKS = NO
|
||||||
|
EXCLUDE_PATTERNS =
|
||||||
|
EXCLUDE_SYMBOLS =
|
||||||
|
EXAMPLE_PATH =
|
||||||
|
EXAMPLE_PATTERNS =
|
||||||
|
EXAMPLE_RECURSIVE = NO
|
||||||
|
IMAGE_PATH =
|
||||||
|
INPUT_FILTER =
|
||||||
|
FILTER_PATTERNS =
|
||||||
|
FILTER_SOURCE_FILES = NO
|
||||||
|
FILTER_SOURCE_PATTERNS =
|
||||||
|
USE_MDFILE_AS_MAINPAGE =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to source browsing
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
SOURCE_BROWSER = NO
|
||||||
|
INLINE_SOURCES = NO
|
||||||
|
STRIP_CODE_COMMENTS = YES
|
||||||
|
REFERENCED_BY_RELATION = NO
|
||||||
|
REFERENCES_RELATION = NO
|
||||||
|
REFERENCES_LINK_SOURCE = YES
|
||||||
|
SOURCE_TOOLTIPS = YES
|
||||||
|
USE_HTAGS = NO
|
||||||
|
VERBATIM_HEADERS = YES
|
||||||
|
CLANG_ASSISTED_PARSING = NO
|
||||||
|
CLANG_OPTIONS =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the alphabetical class index
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
ALPHABETICAL_INDEX = YES
|
||||||
|
COLS_IN_ALPHA_INDEX = 5
|
||||||
|
IGNORE_PREFIX =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the HTML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_HTML = NO
|
||||||
|
HTML_OUTPUT = dhtm
|
||||||
|
HTML_FILE_EXTENSION = .html
|
||||||
|
HTML_HEADER =
|
||||||
|
HTML_FOOTER =
|
||||||
|
HTML_STYLESHEET =
|
||||||
|
HTML_EXTRA_STYLESHEET =
|
||||||
|
HTML_EXTRA_FILES =
|
||||||
|
HTML_COLORSTYLE_HUE = 220
|
||||||
|
HTML_COLORSTYLE_SAT = 100
|
||||||
|
HTML_COLORSTYLE_GAMMA = 80
|
||||||
|
HTML_TIMESTAMP = NO
|
||||||
|
HTML_DYNAMIC_SECTIONS = NO
|
||||||
|
HTML_INDEX_NUM_ENTRIES = 100
|
||||||
|
GENERATE_DOCSET = NO
|
||||||
|
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||||
|
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||||
|
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||||
|
DOCSET_PUBLISHER_NAME = Publisher
|
||||||
|
GENERATE_HTMLHELP = NO
|
||||||
|
CHM_FILE =
|
||||||
|
HHC_LOCATION =
|
||||||
|
GENERATE_CHI = NO
|
||||||
|
CHM_INDEX_ENCODING =
|
||||||
|
BINARY_TOC = NO
|
||||||
|
TOC_EXPAND = NO
|
||||||
|
GENERATE_QHP = NO
|
||||||
|
QCH_FILE =
|
||||||
|
QHP_NAMESPACE = org.doxygen.Project
|
||||||
|
QHP_VIRTUAL_FOLDER = doc
|
||||||
|
QHP_CUST_FILTER_NAME =
|
||||||
|
QHP_CUST_FILTER_ATTRS =
|
||||||
|
QHP_SECT_FILTER_ATTRS =
|
||||||
|
QHG_LOCATION =
|
||||||
|
GENERATE_ECLIPSEHELP = NO
|
||||||
|
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||||
|
DISABLE_INDEX = NO
|
||||||
|
GENERATE_TREEVIEW = NO
|
||||||
|
ENUM_VALUES_PER_LINE = 4
|
||||||
|
TREEVIEW_WIDTH = 250
|
||||||
|
EXT_LINKS_IN_WINDOW = NO
|
||||||
|
FORMULA_FONTSIZE = 10
|
||||||
|
FORMULA_TRANSPARENT = YES
|
||||||
|
USE_MATHJAX = NO
|
||||||
|
MATHJAX_FORMAT = HTML-CSS
|
||||||
|
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
||||||
|
MATHJAX_EXTENSIONS =
|
||||||
|
MATHJAX_CODEFILE =
|
||||||
|
SEARCHENGINE = YES
|
||||||
|
SERVER_BASED_SEARCH = NO
|
||||||
|
EXTERNAL_SEARCH = NO
|
||||||
|
SEARCHENGINE_URL =
|
||||||
|
SEARCHDATA_FILE = searchdata.xml
|
||||||
|
EXTERNAL_SEARCH_ID =
|
||||||
|
EXTRA_SEARCH_MAPPINGS =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the LaTeX output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
LATEX_OUTPUT = latex
|
||||||
|
LATEX_CMD_NAME = latex
|
||||||
|
MAKEINDEX_CMD_NAME = makeindex
|
||||||
|
COMPACT_LATEX = NO
|
||||||
|
PAPER_TYPE = a4
|
||||||
|
EXTRA_PACKAGES =
|
||||||
|
LATEX_HEADER =
|
||||||
|
LATEX_FOOTER =
|
||||||
|
LATEX_EXTRA_STYLESHEET =
|
||||||
|
LATEX_EXTRA_FILES =
|
||||||
|
PDF_HYPERLINKS = YES
|
||||||
|
USE_PDFLATEX = YES
|
||||||
|
LATEX_BATCHMODE = NO
|
||||||
|
LATEX_HIDE_INDICES = NO
|
||||||
|
LATEX_SOURCE_CODE = NO
|
||||||
|
LATEX_BIB_STYLE = plain
|
||||||
|
LATEX_TIMESTAMP = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the RTF output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_RTF = NO
|
||||||
|
RTF_OUTPUT = rtf
|
||||||
|
COMPACT_RTF = NO
|
||||||
|
RTF_HYPERLINKS = NO
|
||||||
|
RTF_STYLESHEET_FILE =
|
||||||
|
RTF_EXTENSIONS_FILE =
|
||||||
|
RTF_SOURCE_CODE = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the man page output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_MAN = NO
|
||||||
|
MAN_OUTPUT = man
|
||||||
|
MAN_EXTENSION = .3
|
||||||
|
MAN_SUBDIR =
|
||||||
|
MAN_LINKS = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the XML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_XML = YES
|
||||||
|
XML_OUTPUT = temp/
|
||||||
|
XML_PROGRAMLISTING = YES
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the DOCBOOK output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_DOCBOOK = NO
|
||||||
|
DOCBOOK_OUTPUT = docbook
|
||||||
|
DOCBOOK_PROGRAMLISTING = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options for the AutoGen Definitions output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_AUTOGEN_DEF = NO
|
||||||
|
GENERATE_PERLMOD = NO
|
||||||
|
PERLMOD_LATEX = NO
|
||||||
|
PERLMOD_PRETTY = YES
|
||||||
|
PERLMOD_MAKEVAR_PREFIX =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the preprocessor
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
ENABLE_PREPROCESSING = YES
|
||||||
|
MACRO_EXPANSION = YES
|
||||||
|
EXPAND_ONLY_PREDEF = YES
|
||||||
|
SEARCH_INCLUDES = YES
|
||||||
|
INCLUDE_PATH = ../
|
||||||
|
INCLUDE_FILE_PATTERNS =
|
||||||
|
PREDEFINED = DOXYGEN \
|
||||||
|
GENERATING_DOCS \
|
||||||
|
_MSC_VER \
|
||||||
|
NUDB_POSIX_FILE=1
|
||||||
|
|
||||||
|
EXPAND_AS_DEFINED =
|
||||||
|
SKIP_FUNCTION_MACROS = YES
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to external references
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
TAGFILES =
|
||||||
|
GENERATE_TAGFILE =
|
||||||
|
ALLEXTERNALS = NO
|
||||||
|
EXTERNAL_GROUPS = YES
|
||||||
|
EXTERNAL_PAGES = YES
|
||||||
|
PERL_PATH = /usr/bin/perl
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the dot tool
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
CLASS_DIAGRAMS = NO
|
||||||
|
MSCGEN_PATH =
|
||||||
|
DIA_PATH =
|
||||||
|
HIDE_UNDOC_RELATIONS = YES
|
||||||
|
HAVE_DOT = NO
|
||||||
|
DOT_NUM_THREADS = 0
|
||||||
|
DOT_FONTNAME = Helvetica
|
||||||
|
DOT_FONTSIZE = 10
|
||||||
|
DOT_FONTPATH =
|
||||||
|
CLASS_GRAPH = YES
|
||||||
|
COLLABORATION_GRAPH = YES
|
||||||
|
GROUP_GRAPHS = YES
|
||||||
|
UML_LOOK = NO
|
||||||
|
UML_LIMIT_NUM_FIELDS = 10
|
||||||
|
TEMPLATE_RELATIONS = NO
|
||||||
|
INCLUDE_GRAPH = YES
|
||||||
|
INCLUDED_BY_GRAPH = YES
|
||||||
|
CALL_GRAPH = NO
|
||||||
|
CALLER_GRAPH = NO
|
||||||
|
GRAPHICAL_HIERARCHY = YES
|
||||||
|
DIRECTORY_GRAPH = YES
|
||||||
|
DOT_IMAGE_FORMAT = png
|
||||||
|
INTERACTIVE_SVG = NO
|
||||||
|
DOT_PATH =
|
||||||
|
DOTFILE_DIRS =
|
||||||
|
MSCFILE_DIRS =
|
||||||
|
DIAFILE_DIRS =
|
||||||
|
PLANTUML_JAR_PATH =
|
||||||
|
PLANTUML_INCLUDE_PATH =
|
||||||
|
DOT_GRAPH_MAX_NODES = 50
|
||||||
|
MAX_DOT_GRAPH_DEPTH = 0
|
||||||
|
DOT_TRANSPARENT = NO
|
||||||
|
DOT_MULTI_TARGETS = NO
|
||||||
|
GENERATE_LEGEND = YES
|
||||||
|
DOT_CLEANUP = YES
|
||||||
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"
|
|
||||||
}
|
|
||||||
30
src/beast/.gitignore
vendored
@@ -1,30 +1,2 @@
|
|||||||
docs/
|
|
||||||
._*
|
|
||||||
*.mode1v3
|
|
||||||
*.pbxuser
|
|
||||||
*.perspectivev3
|
|
||||||
*.user
|
|
||||||
*.ncb
|
|
||||||
*.suo
|
|
||||||
*.obj
|
|
||||||
*.ilk
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.dep
|
|
||||||
*.idb
|
|
||||||
*.manifest
|
|
||||||
*.manifest.res
|
|
||||||
*.o
|
|
||||||
*.opensdf
|
|
||||||
*.d
|
|
||||||
*.sdf
|
|
||||||
xcuserdata
|
|
||||||
contents.xcworkspacedata
|
|
||||||
.DS_Store
|
|
||||||
.svn
|
|
||||||
profile
|
|
||||||
bin/
|
bin/
|
||||||
node_modules/
|
bin64/
|
||||||
cov-int/
|
|
||||||
nohup.out
|
|
||||||
venv/
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
sudo: false
|
||||||
language: cpp
|
language: cpp
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
|
- LLVM_VERSION=3.8.0
|
||||||
# Maintenance note: to move to a new version
|
# Maintenance note: to move to a new version
|
||||||
# of boost, update both BOOST_ROOT and BOOST_URL.
|
# of boost, update both BOOST_ROOT and BOOST_URL.
|
||||||
# Note that for simplicity, BOOST_ROOT's final
|
# Note that for simplicity, BOOST_ROOT's final
|
||||||
@@ -9,8 +11,8 @@ env:
|
|||||||
# to boost's .tar.gz.
|
# to boost's .tar.gz.
|
||||||
- LCOV_ROOT=$HOME/lcov
|
- LCOV_ROOT=$HOME/lcov
|
||||||
- VALGRIND_ROOT=$HOME/valgrind-install
|
- VALGRIND_ROOT=$HOME/valgrind-install
|
||||||
- BOOST_ROOT=$HOME/boost_1_60_0
|
- BOOST_ROOT=$HOME/boost_1_61_0
|
||||||
- BOOST_URL='http://downloads.sourceforge.net/project/boost/boost/1.60.0/boost_1_60_0.tar.gz?r=https%3A%2F%2Fsourceforge.net%2Fprojects%2Fboost%2Ffiles%2Fboost%2F1.60.0%2Fboost_1_60_0.tar.gz&ts=1460417589&use_mirror=netix'
|
- BOOST_URL='http://sourceforge.net/projects/boost/files/boost/1.61.0/boost_1_61_0.tar.gz'
|
||||||
packages: &gcc5_pkgs
|
packages: &gcc5_pkgs
|
||||||
- gcc-5
|
- gcc-5
|
||||||
- g++-5
|
- g++-5
|
||||||
@@ -27,63 +29,56 @@ packages: &gcc5_pkgs
|
|||||||
- autotools-dev
|
- autotools-dev
|
||||||
- libc6-dbg
|
- libc6-dbg
|
||||||
|
|
||||||
packages: &clang38_pkgs
|
|
||||||
- clang-3.8
|
|
||||||
- g++-5
|
|
||||||
- python-software-properties
|
|
||||||
- libssl-dev
|
|
||||||
- libffi-dev
|
|
||||||
- libstdc++6
|
|
||||||
- binutils-gold
|
|
||||||
# Provides a backtrace if the unittests crash
|
|
||||||
- gdb
|
|
||||||
# Needed for installing valgrind
|
|
||||||
- subversion
|
|
||||||
- automake
|
|
||||||
- autotools-dev
|
|
||||||
- libc6-dbg
|
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
# GCC/Coverage
|
# GCC/Coverage/Autobahn (if master or develop branch)
|
||||||
- compiler: gcc
|
- compiler: gcc
|
||||||
env: GCC_VER=5 VARIANT=coverage ADDRESS_MODEL=64
|
env:
|
||||||
|
- GCC_VER=5
|
||||||
|
- VARIANT=coverage
|
||||||
|
- ADDRESS_MODEL=64
|
||||||
|
- BUILD_SYSTEM=cmake
|
||||||
|
- PATH=$PWD/cmake/bin:$PATH
|
||||||
addons: &ao_gcc5
|
addons: &ao_gcc5
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
packages: *gcc5_pkgs
|
packages: *gcc5_pkgs
|
||||||
|
|
||||||
# # GCC/Debug
|
|
||||||
# - compiler: gcc
|
|
||||||
# env: GCC_VER=5 VARIANT=debug ADDRESS_MODEL=64
|
|
||||||
# addons: *ao_gcc5
|
|
||||||
# branches: # NOTE: this does NOT work, though it SHOULD
|
|
||||||
# - master
|
|
||||||
# - develop
|
|
||||||
|
|
||||||
# Clang/UndefinedBehaviourSanitizer
|
# Clang/UndefinedBehaviourSanitizer
|
||||||
- compiler: clang
|
- compiler: clang
|
||||||
env: GCC_VER=5 VARIANT=usan CLANG_VER=3.8 ADDRESS_MODEL=64 UBSAN_OPTIONS='print_stacktrace=1'
|
env:
|
||||||
addons: &ao_clang38
|
- GCC_VER=5
|
||||||
apt:
|
- VARIANT=usan
|
||||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8']
|
- CLANG_VER=3.8
|
||||||
packages: *clang38_pkgs
|
- ADDRESS_MODEL=64
|
||||||
|
- UBSAN_OPTIONS='print_stacktrace=1'
|
||||||
|
- BUILD_SYSTEM=cmake
|
||||||
|
- PATH=$PWD/cmake/bin:$PATH
|
||||||
|
- PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
||||||
|
addons: *ao_gcc5
|
||||||
|
|
||||||
# Clang/AddressSanitizer
|
# Clang/AddressSanitizer
|
||||||
- compiler: clang
|
- compiler: clang
|
||||||
env: GCC_VER=5 VARIANT=asan CLANG_VER=3.8 ADDRESS_MODEL=64
|
env:
|
||||||
addons: *ao_clang38
|
- GCC_VER=5
|
||||||
|
- VARIANT=asan
|
||||||
|
- CLANG_VER=3.8
|
||||||
|
- ADDRESS_MODEL=64
|
||||||
|
- PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
||||||
|
addons: *ao_gcc5
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $BOOST_ROOT
|
- $BOOST_ROOT
|
||||||
- $VALGRIND_ROOT
|
- $VALGRIND_ROOT
|
||||||
|
- llvm-$LLVM_VERSION
|
||||||
|
- cmake
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- scripts/install-dependencies.sh
|
- scripts/install-dependencies.sh
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- scripts/build-and-test.sh
|
- travis_retry scripts/build-and-test.sh
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
- cat nohup.out || echo "nohup.out already deleted"
|
- cat nohup.out || echo "nohup.out already deleted"
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
1.0.0-b6
|
|
||||||
|
|
||||||
* Use SFINAE on return values
|
|
||||||
* Use beast::error_code instead of nested types
|
|
||||||
* Tidy up use of GENERATING_DOCS
|
|
||||||
* Remove obsolete RFC2616 functions
|
|
||||||
* Add message swap members and free functions
|
|
||||||
* Add HTTP field value parser containers: ext_list, param_list, token_list
|
|
||||||
* Fixes for some corner cases in basic_parser_v1
|
|
||||||
* Configurable limits on headers and body sizes in basic_parser_v1
|
|
||||||
|
|
||||||
API Changes:
|
|
||||||
|
|
||||||
* ci_equal is moved to beast::http namespace, in rfc7230.hpp
|
|
||||||
|
|
||||||
* "DynamicBuffer","dynabuf" renamed from "Streambuf", "streambuf". See:
|
|
||||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4478.html#requirements.dynamic_buffers
|
|
||||||
|
|
||||||
* basic_parser_v1 adheres to rfc7230 as strictly as possible
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
277
src/beast/CHANGELOG.md
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
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
|
||||||
|
* Remove bin and bin64 directories
|
||||||
|
* Tidy up .vcxproj file groupings
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b12
|
||||||
|
|
||||||
|
* Use -p to print suites from unit test main.
|
||||||
|
* BEAST_EXPECTS to add a reason string to test failures
|
||||||
|
* Fix unit test runner to output all case names
|
||||||
|
* Update README for build requirements
|
||||||
|
* Rename to CHANGELOG.md
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b11
|
||||||
|
|
||||||
|
* Set URI in generated WebSocket Upgrade requests
|
||||||
|
* Rename echo server class and file names
|
||||||
|
* Rename to DynamicBuffer in some code and documentation
|
||||||
|
* Fix integer warnings in Windows builds
|
||||||
|
* Add 32 and 64 bit Windows build support
|
||||||
|
* Update README for build instructions and more
|
||||||
|
* Add repository and documention banners
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b10
|
||||||
|
|
||||||
|
* Fix compilation warnings
|
||||||
|
* Add websocketpp comparison to HTML documentation
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b9
|
||||||
|
|
||||||
|
* Fix CMakeLists.txt
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b8
|
||||||
|
|
||||||
|
* Fix include in example code
|
||||||
|
* Fix basic_headers rfc2616 Section 4.2 compliance
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b7
|
||||||
|
|
||||||
|
* Fix prepare by calling init. prepare() can throw depending on the
|
||||||
|
implementation of Writer. Publicly provided beast::http writers never throw.
|
||||||
|
* Fixes to example HTTP server
|
||||||
|
* Fully qualify ambiguous calls to read and parse
|
||||||
|
* Remove deprecated http::stream wrapper
|
||||||
|
* Example HTTP server now calculates the MIME-type
|
||||||
|
* Fixes and documentation for teardown and use with SSL:
|
||||||
|
* Add example code to rfc7230 javadocs
|
||||||
|
* Remove extraneous header file <beast/http/status.hpp>
|
||||||
|
* Add skip_body parser option
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
1.0.0-b6
|
||||||
|
|
||||||
|
* Use SFINAE on return values
|
||||||
|
* Use beast::error_code instead of nested types
|
||||||
|
* Tidy up use of GENERATING_DOCS
|
||||||
|
* Remove obsolete RFC2616 functions
|
||||||
|
* Add message swap members and free functions
|
||||||
|
* Add HTTP field value parser containers: ext_list, param_list, token_list
|
||||||
|
* Fixes for some corner cases in basic_parser_v1
|
||||||
|
* Configurable limits on headers and body sizes in basic_parser_v1
|
||||||
|
|
||||||
|
API Changes:
|
||||||
|
|
||||||
|
* ci_equal is moved to beast::http namespace, in rfc7230.hpp
|
||||||
|
|
||||||
|
* "DynamicBuffer","dynabuf" renamed from "Streambuf", "streambuf". See:
|
||||||
|
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4478.html#requirements.dynamic_buffers
|
||||||
|
|
||||||
|
* basic_parser_v1 adheres to rfc7230 as strictly as possible
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
@@ -6,24 +6,73 @@ project (Beast)
|
|||||||
|
|
||||||
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
|
||||||
if (WIN32)
|
if (MSVC)
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4 /wd4100 /D_SCL_SECURE_NO_WARNINGS=1 /D_CRT_SECURE_NO_WARNINGS=1")
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /MP /W4 /wd4100 /bigobj /D _WIN32_WINNT=0x0601 /D _SCL_SECURE_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
||||||
|
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||||
|
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /Oi /Ot /GL /MT")
|
||||||
|
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Oi /Ot /MT")
|
||||||
|
|
||||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
|
||||||
|
|
||||||
|
# for RelWithDebInfo builds, disable incremental linking
|
||||||
|
# since CMake sets it ON by default for that build type and it
|
||||||
|
# causes warnings
|
||||||
|
string (REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" replacement_flags
|
||||||
|
${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO})
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO ${replacement_flags})
|
||||||
|
|
||||||
else()
|
else()
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
set(Boost_USE_MULTITHREADED ON)
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
find_package(Boost REQUIRED COMPONENTS coroutine context thread filesystem program_options system)
|
find_package(Boost REQUIRED COMPONENTS coroutine context thread filesystem program_options system)
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||||
link_directories(${Boost_LIBRARY_DIR})
|
link_directories(${Boost_LIBRARY_DIR})
|
||||||
|
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS
|
set(CMAKE_CXX_FLAGS
|
||||||
"${CMAKE_CXX_FLAGS} -g -std=c++11 -Wall -Wpedantic")
|
"${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
message ("cxx Flags: " ${CMAKE_CXX_FLAGS})
|
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")
|
||||||
|
set(CMAKE_CXX_FLAGS
|
||||||
|
"${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||||
|
set(CMAKE_BUILD_TYPE RELWITHDEBINFO)
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov")
|
||||||
|
elseif ("${VARIANT}" STREQUAL "asan")
|
||||||
|
set(CMAKE_CXX_FLAGS
|
||||||
|
"${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||||
|
set(CMAKE_BUILD_TYPE RELWITHDEBINFO)
|
||||||
|
elseif ("${VARIANT}" STREQUAL "usan")
|
||||||
|
set(CMAKE_CXX_FLAGS
|
||||||
|
"${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-omit-frame-pointer")
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
|
||||||
|
set(CMAKE_BUILD_TYPE RELWITHDEBINFO)
|
||||||
|
elseif ("${VARIANT}" STREQUAL "debug")
|
||||||
|
set(CMAKE_BUILD_TYPE DEBUG)
|
||||||
|
elseif ("${VARIANT}" STREQUAL "release")
|
||||||
|
set(CMAKE_BUILD_TYPE RELEASE)
|
||||||
|
endif()
|
||||||
|
|
||||||
function(DoGroupSources curdir rootdir folder)
|
function(DoGroupSources curdir rootdir folder)
|
||||||
file(GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${curdir} ${PROJECT_SOURCE_DIR}/${curdir}/*)
|
file(GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${curdir} ${PROJECT_SOURCE_DIR}/${curdir}/*)
|
||||||
@@ -34,7 +83,6 @@ function(DoGroupSources curdir rootdir folder)
|
|||||||
source_group("" FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
source_group("" FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
||||||
else()
|
else()
|
||||||
string(REGEX REPLACE ^${rootdir} ${folder} groupname ${curdir})
|
string(REGEX REPLACE ^${rootdir} ${folder} groupname ${curdir})
|
||||||
#set(groupname ${curdir})
|
|
||||||
string(REPLACE "/" "\\" groupname ${groupname})
|
string(REPLACE "/" "\\" groupname ${groupname})
|
||||||
source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
||||||
endif()
|
endif()
|
||||||
@@ -51,14 +99,22 @@ include_directories (include)
|
|||||||
file(GLOB_RECURSE BEAST_INCLUDES
|
file(GLOB_RECURSE BEAST_INCLUDES
|
||||||
${PROJECT_SOURCE_DIR}/include/beast/*.hpp
|
${PROJECT_SOURCE_DIR}/include/beast/*.hpp
|
||||||
${PROJECT_SOURCE_DIR}/include/beast/*.ipp
|
${PROJECT_SOURCE_DIR}/include/beast/*.ipp
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE EXTRAS_INCLUDES
|
||||||
${PROJECT_SOURCE_DIR}/extras/beast/*.hpp
|
${PROJECT_SOURCE_DIR}/extras/beast/*.hpp
|
||||||
${PROJECT_SOURCE_DIR}/extras/beast/*.ipp
|
${PROJECT_SOURCE_DIR}/extras/beast/*.ipp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory (examples)
|
add_subdirectory (examples)
|
||||||
|
if (NOT OPENSSL_FOUND)
|
||||||
|
message("OpenSSL not found. Not building examples/ssl")
|
||||||
|
else()
|
||||||
|
add_subdirectory (examples/ssl)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory (test)
|
add_subdirectory (test)
|
||||||
add_subdirectory (test/core)
|
add_subdirectory (test/core)
|
||||||
add_subdirectory (test/http)
|
add_subdirectory (test/http)
|
||||||
add_subdirectory (test/websocket)
|
add_subdirectory (test/websocket)
|
||||||
|
add_subdirectory (test/zlib)
|
||||||
#enable_testing()
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ else if [ os.name ] = HAIKU
|
|||||||
if [ os.name ] = NT
|
if [ os.name ] = NT
|
||||||
{
|
{
|
||||||
lib ssl : : <name>ssleay32 ;
|
lib ssl : : <name>ssleay32 ;
|
||||||
lib crypto : : <name>libeay32 ;
|
lib crypto : : <name>libeay32 ;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -87,19 +87,20 @@ project beast
|
|||||||
<library>/boost/coroutine//boost_coroutine
|
<library>/boost/coroutine//boost_coroutine
|
||||||
<library>/boost/filesystem//boost_filesystem
|
<library>/boost/filesystem//boost_filesystem
|
||||||
<library>/boost/program_options//boost_program_options
|
<library>/boost/program_options//boost_program_options
|
||||||
# <library>ssl
|
|
||||||
# <library>crypto
|
|
||||||
<define>BOOST_ALL_NO_LIB=1
|
<define>BOOST_ALL_NO_LIB=1
|
||||||
<define>BOOST_SYSTEM_NO_DEPRECATED=1
|
|
||||||
<threading>multi
|
<threading>multi
|
||||||
<link>static
|
|
||||||
<runtime-link>shared
|
<runtime-link>shared
|
||||||
<debug-symbols>on
|
<debug-symbols>on
|
||||||
<toolset>gcc:<cxxflags>-std=c++11
|
<toolset>gcc:<cxxflags>-std=c++11
|
||||||
<toolset>gcc:<cxxflags>-Wno-unused-variable
|
<toolset>gcc:<cxxflags>-Wno-unused-parameter
|
||||||
<toolset>clang:<cxxflags>-std=c++11
|
<toolset>clang:<cxxflags>-std=c++11
|
||||||
|
<toolset>clang:<cxxflags>-Wno-unused-parameter
|
||||||
|
<toolset>gcc:<cxxflags>-Wno-unused-variable # Temporary until we can figure out -isystem
|
||||||
|
<toolset>clang:<cxxflags>-Wno-unused-variable # Temporary until we can figure out -isystem
|
||||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||||
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
||||||
|
<toolset>msvc:<cxxflags>"/wd4100 /bigobj"
|
||||||
|
<toolset>msvc,<variant>release:<cxxflags>"/Ob2 /Oi /Ot"
|
||||||
<os>LINUX:<define>_XOPEN_SOURCE=600
|
<os>LINUX:<define>_XOPEN_SOURCE=600
|
||||||
<os>LINUX:<define>_GNU_SOURCE=1
|
<os>LINUX:<define>_GNU_SOURCE=1
|
||||||
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
||||||
@@ -112,12 +113,7 @@ project beast
|
|||||||
<os>NT,<toolset>gcc:<library>ws2_32
|
<os>NT,<toolset>gcc:<library>ws2_32
|
||||||
<os>NT,<toolset>gcc:<library>mswsock
|
<os>NT,<toolset>gcc:<library>mswsock
|
||||||
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
|
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
|
||||||
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
|
|
||||||
<os>HPUX:<library>ipv6
|
|
||||||
<os>QNXNTO:<library>socket
|
|
||||||
<os>HAIKU:<library>network
|
|
||||||
: usage-requirements
|
: usage-requirements
|
||||||
<include>.
|
|
||||||
:
|
:
|
||||||
build-dir bin
|
build-dir bin
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Beast
|
<img width="880" height = "80" alt = "Beast"
|
||||||
|
src="https://raw.githubusercontent.com/vinniefalco/Beast/master/doc/images/readme.png">
|
||||||
|
|
||||||
[](https://gitter.im/vinniefalco/Beast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status]
|
[](https://gitter.im/vinniefalco/Beast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status]
|
||||||
(https://travis-ci.org/vinniefalco/Beast.svg?branch=master)](https://travis-ci.org/vinniefalco/Beast) [![codecov]
|
(https://travis-ci.org/vinniefalco/Beast.svg?branch=master)](https://travis-ci.org/vinniefalco/Beast) [![codecov]
|
||||||
@@ -7,23 +8,151 @@
|
|||||||
(https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/) [![License]
|
(https://img.shields.io/badge/documentation-master-brightgreen.svg)](http://vinniefalco.github.io/beast/) [![License]
|
||||||
(https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)
|
(https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt)
|
||||||
|
|
||||||
Beast provides implementations of the HTTP and WebSocket protocols
|
# HTTP and WebSocket implementations built on Boost.Asio
|
||||||
built on top of Boost.Asio and other parts of boost.
|
|
||||||
|
|
||||||
Requirements:
|
---
|
||||||
|
|
||||||
* Boost
|
## Beast at CppCon 2016
|
||||||
* C++11 or greater
|
|
||||||
* OpenSSL (optional)
|
|
||||||
|
|
||||||
This software is currently in beta: interfaces are subject to change. For
|
Presentation
|
||||||
recent changes see [CHANGELOG](CHANGELOG).
|
(slides: <a href="https://raw.githubusercontent.com/vinniefalco/Beast/master/doc/images/CppCon2016.pdf">CppCon2016.pdf</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>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- [Introduction](#introduction)
|
||||||
|
- [Description](#description)
|
||||||
|
- [Requirements](#requirements)
|
||||||
|
- [Building](#building)
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [Licence](#licence)
|
||||||
|
- [Contact](#contact)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Beast is a header-only, cross-platform C++ library built on Boost.Asio and
|
||||||
|
Boost, containing two modules implementing widely used network protocols.
|
||||||
|
Beast.HTTP offers a universal model for describing, sending, and receiving
|
||||||
|
HTTP messages while Beast.WebSocket provides a complete implementation of
|
||||||
|
the WebSocket protocol. Their design achieves these goals:
|
||||||
|
|
||||||
|
* **Symmetry.** Interfaces are role-agnostic; the same interfaces can be
|
||||||
|
used to build clients, servers, or both.
|
||||||
|
|
||||||
|
* **Ease of Use.** HTTP messages are modeled using simple, readily
|
||||||
|
accessible objects. Functions and classes used to send and receive HTTP
|
||||||
|
or WebSocket messages are designed to resemble Boost.Asio as closely as
|
||||||
|
possible. Users familiar with Boost.Asio will be immediately comfortable
|
||||||
|
using this library.
|
||||||
|
|
||||||
|
* **Flexibility.** Interfaces do not mandate specific implementation
|
||||||
|
strategies; important decisions such as buffer or thread management are
|
||||||
|
left to users of the library.
|
||||||
|
|
||||||
|
* **Performance.** The implementation performs competitively, making it a
|
||||||
|
realistic choice for building high performance network servers.
|
||||||
|
|
||||||
|
* **Scalability.** Development of network applications that scale to thousands
|
||||||
|
of concurrent connections is possible with the implementation.
|
||||||
|
|
||||||
|
* **Basis for further abstraction.** The interfaces facilitate the
|
||||||
|
development of other libraries that provide higher levels of abstraction.
|
||||||
|
|
||||||
|
Beast is used in [rippled](https://github.com/ripple/rippled), an
|
||||||
|
open source server application that implements a decentralized
|
||||||
|
cryptocurrency system.
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This software is currently in beta: interfaces may change.
|
||||||
|
For recent changes see the [CHANGELOG](CHANGELOG.md).
|
||||||
The library has been submitted to the
|
The library has been submitted to the
|
||||||
[Boost Library Incubator](http://rrsd.com/blincubator.com/bi_library/beast-2/?gform_post_id=1579)
|
[Boost Library Incubator](http://rrsd.com/blincubator.com/bi_library/beast-2/?gform_post_id=1579)
|
||||||
|
|
||||||
|
* [Project Site](http://vinniefalco.github.io/)
|
||||||
|
* [Repository](https://github.com/vinniefalco/Beast)
|
||||||
|
* [Project Documentation](http://vinniefalco.github.io/beast/)
|
||||||
|
* [Autobahn.testsuite results](http://vinniefalco.github.io/autobahn/index.html)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
* Boost 1.58 or higher
|
||||||
|
* C++11 or greater
|
||||||
|
* OpenSSL (optional)
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Beast is header-only so there are no libraries to build or link with.
|
||||||
|
To use Beast in your project, simply copy the Beast sources to your
|
||||||
|
project's source tree (alternatively, bring Beast into your Git repository
|
||||||
|
using the `git subtree` or `git submodule` commands). Then, edit your
|
||||||
|
build scripts to add the `include/` directory to the list of paths checked
|
||||||
|
by the C++ compiler when searching for includes. Beast `#include` lines
|
||||||
|
will look like this:
|
||||||
|
```C++
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
#include <beast/websocket.hpp>
|
||||||
|
```
|
||||||
|
|
||||||
|
To link your program successfully, you'll need to add the Boost.System
|
||||||
|
library to link with. If you use coroutines you'll also need the
|
||||||
|
Boost.Coroutine library. Please visit the Boost documentation for
|
||||||
|
instructions on how to do this for your particular build system.
|
||||||
|
|
||||||
|
For the examples and tests, Beast provides build scripts for Boost.Build (bjam)
|
||||||
|
and CMake. Developers using Microsoft Visual Studio can generate Visual Studio
|
||||||
|
project files by executing these commands from the root of the repository:
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
cd bin
|
||||||
|
cmake .. # for 32-bit Windows build
|
||||||
|
|
||||||
|
cd ../bin64
|
||||||
|
cmake .. # for Linux/Mac builds, OR
|
||||||
|
cmake -G"Visual Studio 14 2015 Win64" .. # for 64-bit Windows builds
|
||||||
|
```
|
||||||
|
|
||||||
|
To build with Boost.Build, it is necessary to have the bjam executable
|
||||||
|
in your path. And bjam needs to know how to find the Boost sources. The
|
||||||
|
easiest way to do this is make sure that the version of bjam in your path
|
||||||
|
is the one at the root of the Boost source tree, which is built when
|
||||||
|
running `bootstrap.sh` (or `bootstrap.bat` on Windows).
|
||||||
|
|
||||||
|
Once bjam is in your path, simply run bjam in the root of the Beast
|
||||||
|
repository to automatically build the required Boost libraries if they
|
||||||
|
are not already built, build the examples, then build and run the unit
|
||||||
|
tests.
|
||||||
|
|
||||||
|
The files in the repository are laid out thusly:
|
||||||
|
|
||||||
|
```
|
||||||
|
./
|
||||||
|
bin/ Holds executables and project files
|
||||||
|
bin64/ Holds 64-bit Windows executables and project files
|
||||||
|
doc/ Source code and scripts for the documentation
|
||||||
|
include/ Add this to your compiler includes
|
||||||
|
beast/
|
||||||
|
extras/ Additional APIs, may change
|
||||||
|
examples/ Self contained example programs
|
||||||
|
test/ Unit tests and benchmarks
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
These examples are complete, self-contained programs that you can build
|
||||||
|
and run yourself (they are in the `examples` directory).
|
||||||
|
|
||||||
Example WebSocket program:
|
Example WebSocket program:
|
||||||
```C++
|
```C++
|
||||||
#include <beast/to_string.hpp>
|
#include <beast/core/to_string.hpp>
|
||||||
#include <beast/websocket.hpp>
|
#include <beast/websocket.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -34,22 +163,22 @@ int main()
|
|||||||
// Normal boost::asio setup
|
// Normal boost::asio setup
|
||||||
std::string const host = "echo.websocket.org";
|
std::string const host = "echo.websocket.org";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
boost::asio::ip::tcp::socket sock(ios);
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||||
|
|
||||||
// WebSocket connect and send message using beast
|
// WebSocket connect and send message using beast
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
ws.handshake(host, "/");
|
ws.handshake(host, "/");
|
||||||
ws.write(boost::asio::buffer("Hello, world!"));
|
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||||
|
|
||||||
// Receive WebSocket message, print and close using beast
|
// Receive WebSocket message, print and close using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
beast::websocket::opcode op;
|
beast::websocket::opcode op;
|
||||||
ws.read(op, sb);
|
ws.read(op, sb);
|
||||||
ws.close(beast::websocket::close_code::normal);
|
ws.close(beast::websocket::close_code::normal);
|
||||||
std::cout << to_string(sb.data()) << "\n";
|
std::cout << beast::to_string(sb.data()) << "\n";
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -57,6 +186,7 @@ Example HTTP program:
|
|||||||
```C++
|
```C++
|
||||||
#include <beast/http.hpp>
|
#include <beast/http.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -65,35 +195,37 @@ int main()
|
|||||||
// Normal boost::asio setup
|
// Normal boost::asio setup
|
||||||
std::string const host = "boost.org";
|
std::string const host = "boost.org";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
boost::asio::ip::tcp::socket sock(ios);
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
// Send HTTP request using beast
|
// Send HTTP request using beast
|
||||||
beast::http::request_v1<beast::http::empty_body> req;
|
beast::http::request<beast::http::empty_body> req;
|
||||||
req.method = "GET";
|
req.method = "GET";
|
||||||
req.url = "/";
|
req.url = "/";
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
req.fields.replace("Host", host + ":" +
|
||||||
req.headers.replace("User-Agent", "Beast");
|
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||||
|
req.fields.replace("User-Agent", "Beast");
|
||||||
beast::http::prepare(req);
|
beast::http::prepare(req);
|
||||||
beast::http::write(sock, req);
|
beast::http::write(sock, req);
|
||||||
|
|
||||||
// Receive and print HTTP response using beast
|
// Receive and print HTTP response using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
beast::http::response<beast::http::streambuf_body> resp;
|
||||||
beast::http::read(sock, sb, resp);
|
beast::http::read(sock, sb, resp);
|
||||||
std::cout << resp;
|
std::cout << resp;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Links:
|
## License
|
||||||
|
|
||||||
* [Home](http://vinniefalco.github.io/)
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
* [Repository](https://github.com/vinniefalco/Beast)
|
(See accompanying file [LICENSE_1_0.txt](LICENSE_1_0.txt) or copy at
|
||||||
* [Documentation](http://vinniefalco.github.io/beast/)
|
http://www.boost.org/LICENSE_1_0.txt)
|
||||||
* [Autobahn.testsuite results](http://vinniefalco.github.io/autobahn/index.html)
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
Please report issues or questions here:
|
Please report issues or questions here:
|
||||||
https://github.com/vinniefalco/Beast/issues
|
https://github.com/vinniefalco/Beast/issues
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ Core:
|
|||||||
* Complete allocator testing in basic_streambuf
|
* Complete allocator testing in basic_streambuf
|
||||||
|
|
||||||
WebSocket:
|
WebSocket:
|
||||||
|
* Minimize sizeof(websocket::stream)
|
||||||
|
* Move check for message size limit to account for compression
|
||||||
* more invokable unit test coverage
|
* more invokable unit test coverage
|
||||||
* More control over the HTTP request and response during handshakes
|
* More control over the HTTP request and response during handshakes
|
||||||
* optimized versions of key/masking, choose prepared_key size
|
* optimized versions of key/masking, choose prepared_key size
|
||||||
|
|||||||
97
src/beast/doc/Jamfile.v2
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
#
|
||||||
|
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
#
|
||||||
|
|
||||||
|
import os ;
|
||||||
|
|
||||||
|
local broot = [ os.environ BOOST_ROOT ] ;
|
||||||
|
|
||||||
|
project beast/doc ;
|
||||||
|
|
||||||
|
using boostbook ;
|
||||||
|
using quickbook ;
|
||||||
|
using doxygen ;
|
||||||
|
|
||||||
|
import quickbook ;
|
||||||
|
|
||||||
|
path-constant here : . ;
|
||||||
|
|
||||||
|
install stylesheets
|
||||||
|
:
|
||||||
|
$(broot)/doc/src/boostbook.css
|
||||||
|
:
|
||||||
|
<location>$(here)/html
|
||||||
|
;
|
||||||
|
|
||||||
|
explicit stylesheets ;
|
||||||
|
|
||||||
|
install images
|
||||||
|
:
|
||||||
|
[ glob $(broot)/doc/src/images/*.png ]
|
||||||
|
images/beast.png
|
||||||
|
images/body.png
|
||||||
|
images/message.png
|
||||||
|
:
|
||||||
|
<location>$(here)/html/images
|
||||||
|
;
|
||||||
|
|
||||||
|
explicit images ;
|
||||||
|
|
||||||
|
install callouts
|
||||||
|
:
|
||||||
|
[ glob $(broot)/doc/src/images/callouts/*.png ]
|
||||||
|
:
|
||||||
|
<location>$(here)/html/images/callouts
|
||||||
|
;
|
||||||
|
|
||||||
|
explicit callout ;
|
||||||
|
|
||||||
|
install examples
|
||||||
|
:
|
||||||
|
[ glob
|
||||||
|
../examples/*.cpp
|
||||||
|
../examples/*.hpp
|
||||||
|
../examples/ssl/*.cpp
|
||||||
|
../examples/ssl/*.hpp
|
||||||
|
]
|
||||||
|
:
|
||||||
|
<location>$(here)/html/examples
|
||||||
|
;
|
||||||
|
|
||||||
|
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
|
||||||
|
;
|
||||||
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
[/
|
|
||||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
||||||
|
|
||||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
]
|
|
||||||
|
|
||||||
[library Beast
|
|
||||||
[quickbook 1.6]
|
|
||||||
[copyright 2013 - 2016 Vinnie Falco]
|
|
||||||
[purpose C++ Library]
|
|
||||||
[license
|
|
||||||
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])
|
|
||||||
]
|
|
||||||
[authors [Falco, Vinnie]]
|
|
||||||
[category template]
|
|
||||||
[category generic]
|
|
||||||
]
|
|
||||||
|
|
||||||
[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()`]]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:intro Introduction]
|
|
||||||
|
|
||||||
Beast is a cross-platform C++ library built on Boost.Asio and Boost, containing
|
|
||||||
two modules implementing widely used network protocols. Beast.HTTP offers a
|
|
||||||
universal model for describing, sending, and receiving HTTP messages while
|
|
||||||
Beast.WebSocket provides a complete implementation of the WebSocket protocol.
|
|
||||||
Their design achieves these goals:
|
|
||||||
|
|
||||||
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
|
|
||||||
used to build clients, servers, or both.
|
|
||||||
|
|
||||||
* [*Ease of Use.] HTTP messages are modeled using simple, readily
|
|
||||||
accessible objects. Functions and classes used to send and receive HTTP
|
|
||||||
or WebSocket messages are designed to resemble Boost.Asio as closely as
|
|
||||||
possible. Users familiar with Boost.Asio will be immediately comfortable
|
|
||||||
using this library.
|
|
||||||
|
|
||||||
* [*Flexibility.] Interfaces do not mandate specific implementation
|
|
||||||
strategies; important decisions such as buffer or thread management are
|
|
||||||
left to users of the library.
|
|
||||||
|
|
||||||
* [*Performance.] The implementation performs competitively, making it a
|
|
||||||
realistic choice for building high performance network servers.
|
|
||||||
|
|
||||||
* [*Scalability.] Development of network applications that scale to thousands
|
|
||||||
of concurrent connections is possible with the implementation.
|
|
||||||
|
|
||||||
* [*Basis for further abstraction.] The interfaces facilitate the
|
|
||||||
development of other libraries that provide higher levels of abstraction.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[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/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]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[include http.qbk]
|
|
||||||
[include websocket.qbk]
|
|
||||||
|
|
||||||
[section:types Type Requirements]
|
|
||||||
[include types/Body.qbk]
|
|
||||||
[include types/BufferSequence.qbk]
|
|
||||||
[include types/DynamicBuffer.qbk]
|
|
||||||
[include types/Field.qbk]
|
|
||||||
[include types/FieldSequence.qbk]
|
|
||||||
[include types/Parser.qbk]
|
|
||||||
[include types/Reader.qbk]
|
|
||||||
[include types/Streams.qbk]
|
|
||||||
[include types/Writer.qbk]
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
[include design.qbk]
|
|
||||||
[section:quickref Quick Reference]
|
|
||||||
[xinclude quickref.xml]
|
|
||||||
[endsect]
|
|
||||||
[include reference.qbk]
|
|
||||||
[section:idx Index]
|
|
||||||
[xinclude index.xml]
|
|
||||||
[endsect]
|
|
||||||
@@ -5,74 +5,85 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:design Design choices]
|
[section:design Design Choices]
|
||||||
|
|
||||||
|
[block '''
|
||||||
|
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||||
|
<member><link linkend="beast.design.http">HTTP FAQ</link></member>
|
||||||
|
<member><link linkend="beast.design.websocket">WebSocket FAQ</link></member>
|
||||||
|
<member><link linkend="beast.design.websocketpp">Comparison to Zaphoyd Studios WebSocket++</link></member>
|
||||||
|
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||||
|
''']
|
||||||
|
|
||||||
The implementations are driven by business needs of cryptocurrency server
|
The implementations are driven by business needs of cryptocurrency server
|
||||||
applications ([@https://ripple.com Ripple] written in C++. These
|
applications (e.g. [@https://ripple.com Ripple]) written in C++. These
|
||||||
needs were not met by existing solutions so new code was written. The new
|
needs were not met by existing solutions so Beast was written from scratch
|
||||||
code tries to avoid design flaws encountered in the already-existing software
|
as a solution. Beast's design philosophy avoids flaws exhibited by other
|
||||||
libraries:
|
libraries:
|
||||||
|
|
||||||
|
* Don't try to do too much.
|
||||||
|
|
||||||
* Don't sacrifice performance.
|
* Don't sacrifice performance.
|
||||||
|
|
||||||
* Don't do too much, otherwise interfaces become rigid.
|
* Mimic Boost.Asio; familiarity breeds confidence.
|
||||||
|
|
||||||
* Symmetric interfaces (client and server the same, or close to it).
|
* Role-symmetric interfaces; client and server the same (or close to it).
|
||||||
|
|
||||||
* Emulate Boost.Asio interfaces as much as possible, since Asio is
|
* Leave important decisions to the user, such as allocating memory or
|
||||||
proven and it is familiar to users.
|
managing flow control.
|
||||||
|
|
||||||
* Let library users make the important decisions such as how to
|
Beast uses the __DynamicBuffer__ concept presented in the Networking TS
|
||||||
allocate memory or how to leverage flow control.
|
(__N4588__), and relies heavily on the Boost.Asio __ConstBufferSequence__
|
||||||
|
and __MutableBufferSequence__ concepts for passing buffers to functions.
|
||||||
Beast uses the [link beast.types.DynamicBuffer [*`DynamicBuffer`]] concept
|
The authors have found the dynamic buffer and buffer sequence interfaces to
|
||||||
presented in the Netwoking TS, and relies heavily on the Boost.Asio
|
be optimal for interacting with Asio, and for other tasks such as incremental
|
||||||
[*`ConstBufferSequence`] and [*`MutableBufferSequence`] concepts for passing
|
parsing of data in buffers (for example, parsing websocket frames stored
|
||||||
buffers to functions. The authors have found the dynamic buffer and buffer
|
in a [link beast.ref.static_streambuf `static_streambuf`]).
|
||||||
sequence interfaces to be optimal for interacting with Asio, and for other
|
|
||||||
tasks such as incremental parsing of data in buffers (for example, parsing
|
|
||||||
websocket frames stored in a [link beast.ref.static_streambuf `static_streambuf`]).
|
|
||||||
|
|
||||||
During the development of Beast the authors have studied other software
|
During the development of Beast the authors have studied other software
|
||||||
packages and in particular the comments left during the Boost Review process
|
packages and in particular the comments left during the Boost Review process
|
||||||
of other packages offering similar functionality. In this section we attempt
|
of other packages offering similar functionality. In this section and the
|
||||||
to address those issues.
|
FAQs that follow we attempt to answer those questions that are also applicable
|
||||||
|
to Beast.
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
[[
|
[[
|
||||||
"I would also like to see instances of this library being used
|
"I would also like to see instances of this library being used
|
||||||
in production. That would give some evidence that the design
|
in production. That would give some evidence that the design
|
||||||
works in practice.""
|
works in practice."
|
||||||
][
|
][
|
||||||
Beast.HTTP and Beast.WebSocket will be used in [*rippled], an
|
Beast.HTTP and Beast.WebSocket are production ready and currently
|
||||||
asynchronous peer to peer server that implements the
|
running on public servers receiving traffic and handling millions of
|
||||||
[*Ripple Consensus Protocol]. These servers are deployed in multiple
|
dollars worth of financial transactions daily. The servers run [*rippled],
|
||||||
production environments, with banks in many countries running client
|
open source software ([@https://github.com/ripple/rippled repository])
|
||||||
applications that connect to [*rippled].
|
implementing the
|
||||||
|
[@https://ripple.com/files/ripple_consensus_whitepaper.pdf [*Ripple Consensus Protocol]],
|
||||||
|
technology provided by [@http://ripple.com Ripple].
|
||||||
]]
|
]]
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[section:http HTTP]
|
|
||||||
|
|
||||||
For HTTP we to model the message to maximize flexibility of implementation
|
[section:http HTTP FAQ]
|
||||||
|
|
||||||
|
For HTTP we model the message to maximize flexibility of implementation
|
||||||
strategies while allowing familiar verbs such as [*`read`] and [*`write`].
|
strategies while allowing familiar verbs such as [*`read`] and [*`write`].
|
||||||
The HTTP interface is further driven by the needs of the WebSocket module,
|
The HTTP interface is further driven by the needs of the WebSocket module,
|
||||||
as a WebSocket session requires a HTTP Upgrade handshake exchange at the
|
as a WebSocket session requires a HTTP Upgrade handshake exchange at the
|
||||||
start. Other design goals:
|
start. Other design goals:
|
||||||
|
|
||||||
* Don't try to invent a complete web server or client
|
* Keep it simple.
|
||||||
|
|
||||||
* Have simple free functions to send and receive messages.
|
* Stay low level; don't invent a whole web server or client.
|
||||||
|
|
||||||
* Allow the message object to be customized,
|
* Allow for customizations, if the user needs it.
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
[[
|
[[
|
||||||
"Some more advanced examples, e.g. including TLS with client/server
|
"Some more advanced examples, e.g. including TLS with client/server
|
||||||
certificates would help.""
|
certificates would help."
|
||||||
][
|
][
|
||||||
The HTTP interface doesn't try to reinvent the wheel, it just uses
|
The HTTP interface doesn't try to reinvent the wheel, it just uses
|
||||||
the `boost::asio::ip::tcp::socket` or `boost::asio::ssl::stream` that
|
the `boost::asio::ip::tcp::socket` or `boost::asio::ssl::stream` that
|
||||||
@@ -92,7 +103,7 @@ start. Other design goals:
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
[[
|
[[
|
||||||
"Cookies? Forms/File Uploads?""
|
"Cookies? Forms/File Uploads?"
|
||||||
][
|
][
|
||||||
Cookies, or managing these types of HTTP headers in general, is the
|
Cookies, or managing these types of HTTP headers in general, is the
|
||||||
responsibility of higher levels. Beast.HTTP just tries to get complete
|
responsibility of higher levels. Beast.HTTP just tries to get complete
|
||||||
@@ -105,7 +116,7 @@ start. Other design goals:
|
|||||||
|
|
||||||
[[
|
[[
|
||||||
"...supporting TLS (is this a feature? If not this would be a show-stopper),
|
"...supporting TLS (is this a feature? If not this would be a show-stopper),
|
||||||
etc.
|
etc."
|
||||||
][
|
][
|
||||||
Beast.HTTP does not provide direct facilities for implementing TLS
|
Beast.HTTP does not provide direct facilities for implementing TLS
|
||||||
connections; however, the interfaces already existing on the
|
connections; however, the interfaces already existing on the
|
||||||
@@ -124,17 +135,24 @@ start. Other design goals:
|
|||||||
over Asio. Such an implementation should serve as a building block upon
|
over Asio. Such an implementation should serve as a building block upon
|
||||||
which higher abstractions such as the aforementioned HTTP service or
|
which higher abstractions such as the aforementioned HTTP service or
|
||||||
cgi-gateway can be built.
|
cgi-gateway can be built.
|
||||||
|
|
||||||
|
One of the example programs implements a simple HTTP server that
|
||||||
|
delivers files from the filesystem.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
[[
|
[[
|
||||||
"You should send a 100-continue to ask for the rest of the body if required."
|
"You should send a 100-continue to ask for the rest of the body if required."
|
||||||
][
|
][
|
||||||
These behaviors are best left to the calling software. A future library
|
The Beast interface needs to support this functionality (by allowing this
|
||||||
can build on Beast.HTTP to provide these behaviors.
|
special case of partial message parsing and serialization). Specifically,
|
||||||
|
it should let callers read the request up to just before the body,
|
||||||
|
and let callers write the request up to just before the body. However,
|
||||||
|
making use of this behavior should be up to callers (since Beast is low
|
||||||
|
level).
|
||||||
]]
|
]]
|
||||||
|
|
||||||
[[
|
[[
|
||||||
"What about HTTP/2?""
|
"What about HTTP/2?"
|
||||||
][
|
][
|
||||||
Many reviewers feel that HTTP/2 support is an essential feature of
|
Many reviewers feel that HTTP/2 support is an essential feature of
|
||||||
a HTTP library. The authors agree that HTTP/2 is important but also
|
a HTTP library. The authors agree that HTTP/2 is important but also
|
||||||
@@ -143,13 +161,13 @@ start. Other design goals:
|
|||||||
and 1.1.
|
and 1.1.
|
||||||
|
|
||||||
The Beast.HTTP message model is suitable for HTTP/2 and can be re-used.
|
The Beast.HTTP message model is suitable for HTTP/2 and can be re-used.
|
||||||
The IEFT HTTP Working Group adopted message compatiblity with HTTP/1.x
|
The IETF HTTP Working Group adopted message compatiblity with HTTP/1.x
|
||||||
as an explicit goal. A parser can simply emit full headers after
|
as an explicit goal. A parser can simply emit full headers after
|
||||||
decoding the compressed HTTP/2 headers. The stream ID is not logicaly
|
decoding the compressed HTTP/2 headers. The stream ID is not logically
|
||||||
part of the message but rather message metadata and should be
|
part of the message but rather message metadata and should be
|
||||||
communicated out-of-band (see below). HTTP/2 sessions begin with a
|
communicated out-of-band (see below). HTTP/2 sessions begin with a
|
||||||
traditional HTTP/1.1 Upgrade similar in fashion to the WebSocket
|
traditional HTTP/1.1 Upgrade similar in fashion to the WebSocket
|
||||||
upgrade. A HTTP/2 implementation can use existing Beast.HTTP primitives
|
upgrade. An HTTP/2 implementation can use existing Beast.HTTP primitives
|
||||||
to perform this handshake.
|
to perform this handshake.
|
||||||
|
|
||||||
Free functions for HTTP/2 sessions are not possible because of the
|
Free functions for HTTP/2 sessions are not possible because of the
|
||||||
@@ -165,34 +183,40 @@ start. Other design goals:
|
|||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section:websocket WebSocket]
|
|
||||||
|
|
||||||
|
[section:websocket WebSocket FAQ]
|
||||||
|
|
||||||
[variablelist
|
[variablelist
|
||||||
|
|
||||||
[[
|
[[
|
||||||
What about message compression?
|
What about message compression?
|
||||||
][
|
][
|
||||||
The feature is not currently present in the library, but the choice
|
The author is currently porting ZLib 1.2.8 to modern, header-only C++11
|
||||||
of type requirements for buffers passed to the read functions have been
|
that does not use macros or try to support ancient architectures. This
|
||||||
made with compression in mind. There is the plan to add this feature;
|
deflate implementation will be available as its own individually
|
||||||
however, we feel that even without compression users can begin taking
|
usable interface, and also will be used to power Beast WebSocket's
|
||||||
advantage of the WebSocket protocol immediately with this library.
|
permessage-deflate implementation, due Q1 of 2017.
|
||||||
|
|
||||||
|
However, Beast currently has sufficient functionality that users can
|
||||||
|
begin taking advantage of the WebSocket protocol using this library
|
||||||
|
immediately.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
[[
|
[[
|
||||||
Where is the TLS/SSL interface?
|
Where is the TLS/SSL interface?
|
||||||
][
|
][
|
||||||
The `websocket::stream` just wraps the socket or stream that you
|
The `websocket::stream` wraps the socket or stream that you provide
|
||||||
provide (for example, a `boost::asio::ip::tcp::socket` or a
|
(for example, a `boost::asio::ip::tcp::socket` or a
|
||||||
`boost::asio::ssl::stream`). You establish your TLS connection
|
`boost::asio::ssl::stream`). You establish your TLS connection using the
|
||||||
using the interface on `ssl::stream` like shown in all of the Asio
|
interface on `ssl::stream` like shown in all of the Asio examples, then
|
||||||
examples, they construct your `websocket::stream` around it.
|
construct your `websocket::stream` around it. It works perfectly fine;
|
||||||
It works perfectly fine - Beast.WebSocket doesn't try to reinvent the
|
Beast.WebSocket doesn't try to reinvent the wheel or put a fresh coat of
|
||||||
wheel or put a fresh coat of interface paint on the `ssl::stream`.
|
interface paint on the `ssl::stream`.
|
||||||
|
|
||||||
The WebSocket implementation [*does] provides support for shutting down
|
The WebSocket implementation [*does] provide support for shutting down
|
||||||
the TLS connection through the use of the ADL compile-time virtual functions
|
the TLS connection through the use of the ADL compile-time virtual functions
|
||||||
[link beast.ref.websocket__teardown `teardown`] and
|
[link beast.ref.websocket__teardown `teardown`] and
|
||||||
[link beast.ref.websocket__async_teardown `async_teardown`]. These will
|
[link beast.ref.websocket__async_teardown `async_teardown`]. These will
|
||||||
@@ -200,14 +224,436 @@ start. Other design goals:
|
|||||||
for TLS streams. Callers may provide their own overloads of these functions
|
for TLS streams. Callers may provide their own overloads of these functions
|
||||||
for user-defined next layer types.
|
for user-defined next layer types.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[section:websocketpp Comparison to Zaphoyd Studios WebSocket++]
|
||||||
|
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[
|
||||||
|
How does this compare to [@https://www.zaphoyd.com/websocketpp websocketpp],
|
||||||
|
an alternate header-only WebSocket implementation?
|
||||||
|
][
|
||||||
|
[variablelist
|
||||||
|
|
||||||
|
[[1. Synchronous Interface][
|
||||||
|
|
||||||
|
Beast offers full support for WebSockets using a synchronous interface. It
|
||||||
|
uses the same style of interfaces found in Boost.Asio: versions that throw
|
||||||
|
exceptions, or versions that return the error code in a reference parameter:
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]]
|
||||||
|
[websocketpp]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class DynamicBuffer>
|
||||||
|
void
|
||||||
|
read(opcode& op, DynamicBuffer& dynabuf)
|
||||||
|
```]
|
||||||
|
[
|
||||||
|
/<not available>/
|
||||||
|
]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[2. Connection Model][
|
||||||
|
|
||||||
|
websocketpp supports multiple transports by utilizing a trait, the `config::transport_type`
|
||||||
|
([@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/connection.hpp#L60 asio transport example])
|
||||||
|
To get an idea of the complexity involved with implementing a transport,
|
||||||
|
compare the asio transport to the
|
||||||
|
[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport]
|
||||||
|
(a layer that allows websocket communication over a `std::iostream`).
|
||||||
|
|
||||||
|
In contrast, Beast abstracts the transport by defining just one [*`NextLayer`]
|
||||||
|
template argument The type requirements for [*`NextLayer`] are
|
||||||
|
already familiar to users as they are documented in Asio:
|
||||||
|
__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
|
||||||
|
`shared_ptr` if they want to, but there is no requirement to do so.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp Beast]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L234 websocketpp]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class NextLayer>
|
||||||
|
class stream
|
||||||
|
{
|
||||||
|
NextLayer next_layer_;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
template <typename config>
|
||||||
|
class connection
|
||||||
|
: public config::transport_type::transport_con_type
|
||||||
|
, public config::connection_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef lib::shared_ptr<type> ptr;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[3. Client and Server Role][
|
||||||
|
|
||||||
|
websocketpp provides multi-role support through a hierarchy of
|
||||||
|
different classes. A `beast::websocket::stream` is role-agnostic, it
|
||||||
|
offers member functions to perform both client and server handshakes
|
||||||
|
in the same class. The same types are used for client and server
|
||||||
|
streams.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[Beast]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/server_endpoint.hpp#L39 websocketpp],
|
||||||
|
[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/client_endpoint.hpp#L42 also]]
|
||||||
|
][
|
||||||
|
[
|
||||||
|
/<not needed>/
|
||||||
|
]
|
||||||
|
[```
|
||||||
|
template <typename config>
|
||||||
|
class client : public endpoint<connection<config>,config>;
|
||||||
|
template <typename config>
|
||||||
|
class server : public endpoint<connection<config>,config>;
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[4. Thread Safety][
|
||||||
|
|
||||||
|
websocketpp uses mutexes to protect shared data from concurrent
|
||||||
|
access. In contrast, Beast does not use mutexes anywhere in its
|
||||||
|
implementation. Instead, it follows the Asio pattern. Calls to
|
||||||
|
asynchronous initiation functions use the same method to invoke
|
||||||
|
intermediate handlers as the method used to invoke the final handler,
|
||||||
|
through the __asio_handler_invoke__ mechanism.
|
||||||
|
|
||||||
|
The only requirement in Beast is that calls to asynchronous initiation
|
||||||
|
functions are made from the same implicit or explicit strand. For
|
||||||
|
example, if the `io_service` associated with a `beast::websocket::stream`
|
||||||
|
is single threaded, this counts as an implicit strand and no performance
|
||||||
|
costs associated with mutexes are incurred.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/read_frame_op.ipp#L118 Beast]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L706 websocketpp]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template <class Function>
|
||||||
|
friend
|
||||||
|
void asio_handler_invoke(Function&& f, read_frame_op* op)
|
||||||
|
{
|
||||||
|
return boost_asio_handler_invoke_helpers::invoke(f, op->d_->h);
|
||||||
|
}
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
mutex_type m_read_mutex;
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[5. Callback Model][
|
||||||
|
|
||||||
|
websocketpp requires a one-time call to set the handler for each event
|
||||||
|
in its interface (for example, upon message receipt). The handler is
|
||||||
|
represented by a `std::function` equivalent. Its important to recognize
|
||||||
|
that the websocketpp interface performs type-erasure on this handler.
|
||||||
|
|
||||||
|
In comparison, Beast handlers are specified in a manner identical to
|
||||||
|
Boost.Asio. They are function objects which can be copied or moved but
|
||||||
|
most importantly they are not type erased. The compiler can see
|
||||||
|
through the type directly to the implementation, permitting
|
||||||
|
optimization. Furthermore, Beast follows the Asio rules for treatment
|
||||||
|
of handlers. It respects any allocation, continuation, or invocation
|
||||||
|
customizations associated with the handler through the use of argument
|
||||||
|
dependent lookup overloads of functions such as `asio_handler_allocate`.
|
||||||
|
|
||||||
|
The Beast completion handler is provided at the call site. For each
|
||||||
|
call to an asynchronous initiation function, it is guaranteed that
|
||||||
|
there will be exactly one final call to the handler. This functions
|
||||||
|
exactly the same way as the asynchronous initiation functions found in
|
||||||
|
Boost.Asio, allowing the composition of higher level abstractions.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L834 Beast]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L281 websocketpp],
|
||||||
|
[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L473 also]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class DynamicBuffer, class ReadHandler>
|
||||||
|
typename async_completion<ReadHandler, void(error_code)>::result_type
|
||||||
|
async_read(opcode& op, DynamicBuffer& dynabuf, ReadHandler&& handler);
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
typedef lib::function<void(connection_hdl,message_ptr)> message_handler;
|
||||||
|
void set_message_handler(message_handler h);
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[6. Extensible Asynchronous Model][
|
||||||
|
|
||||||
|
Beast fully supports the
|
||||||
|
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf Extensible Asynchronous Model]
|
||||||
|
developed by Christopher Kohlhoff, author of Boost.Asio (see Section 8).
|
||||||
|
|
||||||
|
Beast websocket asynchronous interfaces may be used seamlessly with
|
||||||
|
`std::future` stackful/stackless coroutines, or user defined customizations.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/stream.ipp#L378 Beast]]
|
||||||
|
[websocketpp]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
beast::async_completion<ReadHandler, void(error_code)> completion(handler);
|
||||||
|
read_op<DynamicBuffer, decltype(completion.handler)>{
|
||||||
|
completion.handler, *this, op, streambuf};
|
||||||
|
return completion.result.get();
|
||||||
|
```]
|
||||||
|
[
|
||||||
|
/<not available>/
|
||||||
|
]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[7. Message Buffering][
|
||||||
|
|
||||||
|
websocketpp defines a message buffer, passed in arguments by
|
||||||
|
`shared_ptr`, and an associated message manager which permits
|
||||||
|
aggregation and reuse of memory. The implementation of
|
||||||
|
`websocketpp::message` uses a `std::string` to hold the payload. If an
|
||||||
|
incoming message is broken up into multiple frames, the string may be
|
||||||
|
reallocated for each continuation frame. The `std::string` always uses
|
||||||
|
the standard allocator, it is not possible to customize the choice of
|
||||||
|
allocator.
|
||||||
|
|
||||||
|
Beast allows callers to specify the object for receiving the message
|
||||||
|
or frame data, which is of any type meeting the requirements of
|
||||||
|
__DynamicBuffer__ (modeled after `boost::asio::streambuf`).
|
||||||
|
|
||||||
|
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,
|
||||||
|
customize the allocator if you desire, or provide your own type that
|
||||||
|
meets the requirements.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/message_buffer/message.hpp#L78 websocketpp]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class DynamicBuffer>
|
||||||
|
read(opcode& op, DynamicBuffer& dynabuf);
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
template <template<class> class con_msg_manager>
|
||||||
|
class message {
|
||||||
|
public:
|
||||||
|
typedef lib::shared_ptr<message> ptr;
|
||||||
|
...
|
||||||
|
std::string m_payload;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[8. Sending Messages][
|
||||||
|
|
||||||
|
When sending a message, websocketpp requires that the payload is
|
||||||
|
packaged in a `websocketpp::message` object using `std::string` as the
|
||||||
|
storage, or it requires a copy of the caller provided buffer by
|
||||||
|
constructing a new message object. Messages are placed onto an
|
||||||
|
outgoing queue. An asynchronous write operation runs in the background
|
||||||
|
to clear the queue. No user facing handler can be registered to be
|
||||||
|
notified when messages or frames have completed sending.
|
||||||
|
|
||||||
|
Beast doesn't allocate or make copies of buffers when sending data. The
|
||||||
|
caller's buffers are sent in-place. You can use any object meeting the
|
||||||
|
requirements of
|
||||||
|
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html ConstBufferSequence],
|
||||||
|
permitting efficient scatter-gather I/O.
|
||||||
|
|
||||||
|
The [*ConstBufferSequence] interface allows callers to send data from
|
||||||
|
memory-mapped regions (not possible in websocketpp). Callers can also
|
||||||
|
use the same buffers to send data to multiple streams, for example
|
||||||
|
broadcasting common subscription data to many clients at once. For
|
||||||
|
each call to `async_write` the completion handler is called once when
|
||||||
|
the data finishes sending, in a manner identical to `boost::asio::async_write`.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1048 Beast]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L672 websocketpp]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
void
|
||||||
|
write(ConstBufferSequence const& buffers);
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
lib::error_code send(std::string const & payload,
|
||||||
|
frame::opcode::value op = frame::opcode::text);
|
||||||
|
...
|
||||||
|
lib::error_code send(message_ptr msg);
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[9. Streaming Messages][
|
||||||
|
|
||||||
|
websocketpp requires that the entire message fit into memory, and that
|
||||||
|
the size is known ahead of time.
|
||||||
|
|
||||||
|
Beast allows callers to compose messages in individual frames. This is
|
||||||
|
useful when the size of the data is not known ahead of time or if it
|
||||||
|
is not desired to buffer the entire message in memory at once before
|
||||||
|
sending it. For example, sending periodic output of a database query
|
||||||
|
running on a coroutine. Or sending the contents of a file in pieces,
|
||||||
|
without bringing it all into memory.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1151 Beast]]
|
||||||
|
[websocketpp]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
void
|
||||||
|
write_frame(bool fin,
|
||||||
|
ConstBufferSequence const& buffers);
|
||||||
|
```]
|
||||||
|
[
|
||||||
|
/<not available>/
|
||||||
|
]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[10. Flow Control][
|
||||||
|
|
||||||
|
The websocketpp read implementation continuously reads asynchronously
|
||||||
|
from the network and buffers message data. To prevent unbounded growth
|
||||||
|
and leverage TCP/IP's flow control mechanism, callers can periodically
|
||||||
|
turn this 'read pump' off and back on.
|
||||||
|
|
||||||
|
In contrast a `beast::websocket::stream` does not independently begin
|
||||||
|
background activity, nor does it buffer messages. It receives data only
|
||||||
|
when there is a call to an asynchronous initiation function (for
|
||||||
|
example `beast::websocket::stream::async_read`) with an associated handler.
|
||||||
|
Applications do not need to implement explicit logic to regulate the
|
||||||
|
flow of data. Instead, they follow the traditional model of issuing a
|
||||||
|
read, receiving a read completion, processing the message, then
|
||||||
|
issuing a new read and repeating the process.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[Beast]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L728 websocketpp]]
|
||||||
|
][
|
||||||
|
[
|
||||||
|
/<implicit>/
|
||||||
|
]
|
||||||
|
[```
|
||||||
|
lib::error_code pause_reading();
|
||||||
|
lib::error_code resume_reading();
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[11. Connection Establishment][
|
||||||
|
|
||||||
|
websocketpp offers the `endpoint` class which can handle binding and
|
||||||
|
listening to a port, and spawning connection objects.
|
||||||
|
|
||||||
|
Beast does not reinvent the wheel here, callers use the interfaces
|
||||||
|
already in `boost::asio` for receiving incoming connections resolving
|
||||||
|
host names, or establishing outgoing connections. After the socket (or
|
||||||
|
`boost::asio::ssl::stream`) is connected, the `beast::websocket::stream`
|
||||||
|
is constructed around it and the WebSocket handshake can be performed.
|
||||||
|
|
||||||
|
Beast users are free to implement their own "connection manager", but
|
||||||
|
there is no requirement to do so.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/async_connect.html Beast],
|
||||||
|
[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html also]]
|
||||||
|
[[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/endpoint.hpp#L52 websocketpp]]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
```]
|
||||||
|
[```
|
||||||
|
template <typename config>
|
||||||
|
class endpoint : public config::socket_type;
|
||||||
|
```]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
[[12. WebSocket Handshaking][
|
||||||
|
|
||||||
|
Callers invoke `beast::websocket::accept` to perform the WebSocket
|
||||||
|
handshake, but there is no requirement to use this function. Advanced
|
||||||
|
users can perform the WebSocket handshake themselves. Beast WebSocket
|
||||||
|
provides the tools for composing the request or response, and the
|
||||||
|
Beast HTTP interface provides the container and algorithms for sending
|
||||||
|
and receiving HTTP/1 messages including the necessary HTTP Upgrade
|
||||||
|
request for establishing the WebSocket session.
|
||||||
|
|
||||||
|
Beast allows the caller to pass the incoming HTTP Upgrade request for
|
||||||
|
the cases where the caller has already received an HTTP message.
|
||||||
|
This flexibility permits novel and robust implementations. For example,
|
||||||
|
a listening socket that can handshake in multiple protocols on the
|
||||||
|
same port.
|
||||||
|
|
||||||
|
Sometimes callers want to read some bytes on the socket before reading
|
||||||
|
the WebSocket HTTP Upgrade request. Beast allows these already-received
|
||||||
|
bytes to be supplied to an overload of the accepting function to permit
|
||||||
|
sophisticated features. For example, a listening socket that can
|
||||||
|
accept both regular WebSocket and Secure WebSocket (SSL) connections.
|
||||||
|
|
||||||
|
[table
|
||||||
|
[
|
||||||
|
[[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L501 Beast],
|
||||||
|
[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L401 also]]
|
||||||
|
[websocketpp]
|
||||||
|
][
|
||||||
|
[```
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
void
|
||||||
|
accept(ConstBufferSequence const& buffers);
|
||||||
|
|
||||||
|
template<class Body, class Headers>
|
||||||
|
void
|
||||||
|
accept(http::request_v1<Body, Headers> const& request);
|
||||||
|
```]
|
||||||
|
[
|
||||||
|
/<not available>/
|
||||||
|
]
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
]
|
||||||
|
]]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|||||||
127
src/beast/doc/examples.qbk
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
[/
|
||||||
|
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
]
|
||||||
|
|
||||||
|
[section:example Examples]
|
||||||
|
|
||||||
|
These usage examples are intended to quickly impress upon readers the
|
||||||
|
flavor of the library. They are complete programs which may be built
|
||||||
|
and run. Source code and build scripts for these programs may be found
|
||||||
|
in the examples directory.
|
||||||
|
|
||||||
|
[heading HTTP GET]
|
||||||
|
|
||||||
|
Use HTTP to request the root page from a website and print the response:
|
||||||
|
|
||||||
|
```
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Normal boost::asio setup
|
||||||
|
std::string const host = "boost.org";
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
|
boost::asio::connect(sock,
|
||||||
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
|
// Send HTTP request using beast
|
||||||
|
beast::http::request<beast::http::empty_body> req;
|
||||||
|
req.method = "GET";
|
||||||
|
req.url = "/";
|
||||||
|
req.version = 11;
|
||||||
|
req.fields.replace("Host", host + ":" +
|
||||||
|
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||||
|
req.fields.replace("User-Agent", "Beast");
|
||||||
|
beast::http::prepare(req);
|
||||||
|
beast::http::write(sock, req);
|
||||||
|
|
||||||
|
// Receive and print HTTP response using beast
|
||||||
|
beast::streambuf sb;
|
||||||
|
beast::http::response<beast::http::streambuf_body> resp;
|
||||||
|
beast::http::read(sock, sb, resp);
|
||||||
|
std::cout << resp;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
[heading WebSocket]
|
||||||
|
|
||||||
|
Establish a WebSocket connection, send a message and receive the reply:
|
||||||
|
```
|
||||||
|
#include <beast/core/to_string.hpp>
|
||||||
|
#include <beast/websocket.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Normal boost::asio setup
|
||||||
|
std::string const host = "echo.websocket.org";
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
|
boost::asio::connect(sock,
|
||||||
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||||
|
|
||||||
|
// WebSocket connect and send message using beast
|
||||||
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
|
ws.handshake(host, "/");
|
||||||
|
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||||
|
|
||||||
|
// Receive WebSocket message, print and close using beast
|
||||||
|
beast::streambuf sb;
|
||||||
|
beast::websocket::opcode op;
|
||||||
|
ws.read(op, sb);
|
||||||
|
ws.close(beast::websocket::close_code::normal);
|
||||||
|
std::cout << beast::to_string(sb.data()) << "\n";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[heading Secure WebSocket]
|
||||||
|
|
||||||
|
Establish a WebSocket connection over an encrypted TLS connection,
|
||||||
|
send a message and receive the reply. Requires OpenSSL to build.
|
||||||
|
|
||||||
|
* [@examples/websocket_ssl_example.cpp]
|
||||||
|
|
||||||
|
[heading HTTPS GET]
|
||||||
|
|
||||||
|
This example demonstrates sending and receiving HTTP messages
|
||||||
|
over a TLS connection. Requires OpenSSL to build.
|
||||||
|
|
||||||
|
* [@examples/http_ssl_example.cpp]
|
||||||
|
|
||||||
|
[heading HTTP Crawl]
|
||||||
|
|
||||||
|
This example retrieves the page at each of the most popular domains
|
||||||
|
as measured by Alexa.
|
||||||
|
|
||||||
|
* [@examples/http_crawl.cpp]
|
||||||
|
|
||||||
|
[heading HTTP Server]
|
||||||
|
|
||||||
|
This example demonstrates both synchronous and asynchronous server
|
||||||
|
implementations. It also provides an example of implementing a [*Body]
|
||||||
|
type, in `file_body`.
|
||||||
|
|
||||||
|
* [@examples/file_body.hpp]
|
||||||
|
* [@examples/http_async_server.hpp]
|
||||||
|
* [@examples/http_sync_server.hpp]
|
||||||
|
* [@examples/http_server.cpp]
|
||||||
|
|
||||||
|
[heading Listings]
|
||||||
|
|
||||||
|
These are stand-alone listings of the HTTP and WebSocket examples.
|
||||||
|
|
||||||
|
* [@examples/http_example.cpp]
|
||||||
|
* [@examples/websocket_example.cpp]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
@@ -5,148 +5,203 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:http HTTP]
|
[/
|
||||||
|
ideas:
|
||||||
|
- complete send request walkthrough (client)
|
||||||
|
- complete receive response walkthrough (client)
|
||||||
|
- complete receive request walkthrough (server)
|
||||||
|
- complete send response walkthrough (server)
|
||||||
|
|
||||||
Beast.HTTP offers programmers simple and performant models of HTTP messages and
|
- Introduce concepts from simple to complex
|
||||||
|
- Smooth progression of new ideas building on the previous ideas
|
||||||
|
|
||||||
|
- do we show a simplified message with collapsed fields?
|
||||||
|
- do we introduce `header` or `message` first?
|
||||||
|
|
||||||
|
|
||||||
|
contents:
|
||||||
|
Message (and header, fields)
|
||||||
|
Create request
|
||||||
|
Create response
|
||||||
|
Algorithms
|
||||||
|
Write
|
||||||
|
Read
|
||||||
|
Parse
|
||||||
|
Examples
|
||||||
|
Send Request
|
||||||
|
Receive Response
|
||||||
|
Receive Request
|
||||||
|
Send Response
|
||||||
|
Advanced
|
||||||
|
Responding to HEAD
|
||||||
|
Expect: 100-continue
|
||||||
|
Body (user defined)
|
||||||
|
|
||||||
|
|
||||||
|
section beast.http.examples Examples
|
||||||
|
|
||||||
|
note
|
||||||
|
In the example code which follows, `socket` refers to an object of type
|
||||||
|
`boost::asio::ip::tcp::socket` which is currently connected to a remote peer.
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[section:http Using HTTP]
|
||||||
|
|
||||||
|
[block '''
|
||||||
|
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||||
|
<member><link linkend="beast.http.message">Message</link></member>
|
||||||
|
<member><link linkend="beast.http.fields">Fields</link></member>
|
||||||
|
<member><link linkend="beast.http.body">Body</link></member>
|
||||||
|
<member><link linkend="beast.http.algorithms">Algorithms</link></member>
|
||||||
|
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||||
|
''']
|
||||||
|
|
||||||
|
Beast offers programmers simple and performant models of HTTP messages and
|
||||||
their associated operations including synchronous and asynchronous reading and
|
their associated operations including synchronous and asynchronous reading and
|
||||||
writing of messages in the HTTP/1 wire format using Boost.Asio.
|
writing of messages and headers in the HTTP/1 wire format using Boost.Asio.
|
||||||
|
|
||||||
The HTTP protocol is described fully in
|
|
||||||
[@https://tools.ietf.org/html/rfc7230 rfc7230]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:motivation Motivation]
|
|
||||||
|
|
||||||
The HTTP protocol is pervasive in network applications. As C++ is a logical
|
|
||||||
choice for high performance network servers, there is great utility in solid
|
|
||||||
building blocks for manipulating, sending, and receiving HTTP messages
|
|
||||||
compliant with the Hypertext Transfer Protocol and the supplements that
|
|
||||||
follow. Unfortunately reliable implementations or industry standards do not
|
|
||||||
exist in C++.
|
|
||||||
|
|
||||||
Beast.HTTP is built on Boost.Asio and uses its own robust header-only HTTP/1
|
|
||||||
message parser modeled after the nodejs http-parser (written in C). A proposal
|
|
||||||
to add networking functionality to the C++ standard library, based on
|
|
||||||
Boost.Asio, is under consideration by the standards committee. Since the final
|
|
||||||
approved networking interface for the C++ standard library will likely closely
|
|
||||||
resemble the current interface of Boost.Asio, it is logical for Beast.HTTP to
|
|
||||||
use Boost.Asio as its network transport.
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:scope Scope]
|
|
||||||
|
|
||||||
This library is designed to be a building block for creating higher level
|
|
||||||
libraries. It is not designed to be end-user facing. There is no convenient
|
|
||||||
class that implements the core of a web server, nor is there a convenient
|
|
||||||
class to quickly perform common operations such as fetching a file or
|
|
||||||
connecting and retrieving a document from a secure connection. These
|
|
||||||
use-cases are important, but this library does not try to do that. Instead,
|
|
||||||
it offers primitives that can be used to build those user-facing algorithms.
|
|
||||||
|
|
||||||
A HTTP message (referred to hereafter as "message") contains request or
|
|
||||||
response specific attributes, a series of zero or more name/value pairs
|
|
||||||
(collectively termed "headers"), and a series of octets called the message
|
|
||||||
body which may be zero in length. The HTTP protocol defines the client and
|
|
||||||
server roles: clients send messages called requests and servers send back
|
|
||||||
messages called responses. `http::message` models both requests and responses.
|
|
||||||
Beast aims to offer this functionality:
|
|
||||||
|
|
||||||
* [*Model]: Provide a universal HTTP message class model.
|
|
||||||
|
|
||||||
* [*Build]: Construct a new message and manipulate its contents.
|
|
||||||
|
|
||||||
* [*Parse]: Deserialize a message from a network or memory stream in HTTP/1 wire format.
|
|
||||||
|
|
||||||
* [*Serialize]: Serialize a message into a network or memory stream in HTTP/1 wire format.
|
|
||||||
|
|
||||||
[note The documentation which follows assumes familiarity with
|
|
||||||
both Boost.Asio and the HTTP protocol specification described in
|
|
||||||
[@https://tools.ietf.org/html/rfc7230 rfc7230] ]
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:usage Usage]
|
|
||||||
|
|
||||||
[note
|
[note
|
||||||
Sample code and identifiers mentioned in this section are written
|
The following documentation assumes familiarity with both Boost.Asio
|
||||||
as if the following declarations are in effect:
|
and the HTTP protocol specification described in __rfc7230__. Sample code
|
||||||
|
and identifiers mentioned in this section are written as if the following
|
||||||
|
declarations are in effect:
|
||||||
```
|
```
|
||||||
|
#include <beast/core.hpp>
|
||||||
#include <beast/http.hpp>
|
#include <beast/http.hpp>
|
||||||
using namespace beast;
|
using namespace beast;
|
||||||
|
using namespace beast::http;
|
||||||
```
|
```
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In the paragraphs that follow we describe the available interfaces for
|
|
||||||
performing typical operations such as interacting with a HTTP server
|
|
||||||
or handling simple requests. Subsequent sections cover the message model
|
|
||||||
and its customization points in more depth, for advanced applications.
|
|
||||||
|
|
||||||
[heading Declarations]
|
|
||||||
|
|
||||||
To do anything, a message must be declared. The message class template
|
[section:message Message]
|
||||||
requires at mininum, a value indicating whether the message is a request
|
|
||||||
(versus a response), and a `Body` type. The choice of `Body` determines the
|
The HTTP protocol defines the client and server roles: clients send messages
|
||||||
kind of container used to represent the message body. Here we will
|
called requests and servers send back messages called responses. A HTTP message
|
||||||
declare a request that has a `std::string` for the body container:
|
(referred to hereafter as "message") contains request or response specific
|
||||||
|
attributes (contained in the "Start Line"), a series of zero or more name/value
|
||||||
|
pairs (collectively termed "Fields"), and an optional series of octets called
|
||||||
|
the message body which may be zero in length. The start line for a HTTP request
|
||||||
|
includes a string called the method, a string called the URL, and a version
|
||||||
|
number indicating HTTP/1.0 or HTTP/1.1. For a response, the start line contains
|
||||||
|
an integer status code and a string called the reason phrase. Alternatively, a
|
||||||
|
HTTP message can be viewed as two parts: a header, followed by a body.
|
||||||
|
|
||||||
|
[note
|
||||||
|
The Reason-Phrase is obsolete as of rfc7230.
|
||||||
|
]
|
||||||
|
|
||||||
|
The __header__ class template models the header for HTTP/1 and HTTP/2 messages.
|
||||||
|
This class template is a family of specializations, one for requests and one
|
||||||
|
for responses, depending on the [*`isRequest`] template value.
|
||||||
|
The [*`Fields`] template type determines the type of associative container
|
||||||
|
used to store the field values. The provided __basic_fields__ class template
|
||||||
|
and __fields__ type alias are typical choices for the [*`Fields`] type, but
|
||||||
|
advanced applications may supply user defined types which meet the requirements.
|
||||||
|
The __message__ class template models the header and optional body for HTTP/1
|
||||||
|
and HTTP/2 requests and responses. It is derived from the __header__ class
|
||||||
|
template with the same shared template parameters, and adds the `body` data
|
||||||
|
member. The message class template requires an additional template argument
|
||||||
|
type [*`Body`]. This type controls the container used to represent the body,
|
||||||
|
if any, as well as the algorithms needed to serialize and parse bodies of
|
||||||
|
that type.
|
||||||
|
|
||||||
|
This illustration shows the declarations and members of the __header__ and
|
||||||
|
__message__ class templates, as well as the inheritance relationship:
|
||||||
|
|
||||||
|
[$images/message.png [width 650px] [height 390px]]
|
||||||
|
|
||||||
|
For notational convenience, these template type aliases are provided which
|
||||||
|
supply typical choices for the [*`Fields`] type:
|
||||||
```
|
```
|
||||||
http::message<true, http::string_body> req;
|
using request_header = header<true, fields>;
|
||||||
|
using response_header = header<false, fields>;
|
||||||
|
|
||||||
|
template<class Body, class Fields = fields>
|
||||||
|
using request = message<true, Body, Fields>;
|
||||||
|
|
||||||
|
template<class Body, class Fields = fields>
|
||||||
|
using response = message<false, Body, Fields>;
|
||||||
```
|
```
|
||||||
|
|
||||||
Two type aliases are provided for notational convenience when declaring
|
The code examples below show how to create and fill in a request and response
|
||||||
messages. These two statements declare a request and a response respectively:
|
object:
|
||||||
```
|
|
||||||
http::request<http::string_body> req;
|
|
||||||
http::response<http::string_body> resp;
|
|
||||||
```
|
|
||||||
|
|
||||||
[heading Members]
|
[table Create Message
|
||||||
|
[[HTTP Request] [HTTP Response]]
|
||||||
|
[[
|
||||||
|
```
|
||||||
|
request<empty_body> req;
|
||||||
|
req.version = 11; // HTTP/1.1
|
||||||
|
req.method = "GET";
|
||||||
|
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 = "****";
|
||||||
|
```
|
||||||
|
]]]
|
||||||
|
|
||||||
Message objects are default constructible, with public access to data members.
|
In the serialized format of a HTTP message, the header is represented as a
|
||||||
Request and response objects have some common members, and some members unique
|
series of text lines ending in CRLF (`"\r\n"`). The end of the header is
|
||||||
to the message type. These statements set all the members in each message:
|
indicated by a line containing only CRLF. Here are examples of serialized HTTP
|
||||||
```
|
request and response objects. The objects created above will produce these
|
||||||
http::request<http::string_body> req;
|
results when serialized. Note that only the response has a body:
|
||||||
req.method = http::method_t::http_get;
|
|
||||||
req.url = "/index.html";
|
|
||||||
req.version = 11; // HTTP/1.1
|
|
||||||
req.headers.insert("User-Agent", "hello_world");
|
|
||||||
req.body = "";
|
|
||||||
|
|
||||||
http::response<http::string_body> resp;
|
[table Serialized HTTP Request and Response
|
||||||
resp.status = 404;
|
[[HTTP Request] [HTTP Response]]
|
||||||
resp.reason = "Not Found";
|
[[
|
||||||
resp.version = 10; // HTTP/1.0
|
```
|
||||||
resp.headers.insert("Server", "Beast.HTTP");
|
GET /index.htm HTTP/1.1\r\n
|
||||||
resp.body = "The requested resource was not found.";
|
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 following statements achieve the same effects as the statements above:
|
|
||||||
```
|
|
||||||
http::request<http::string_body> req({http::method_t::http_get, "/index.html", 11});
|
|
||||||
req.headers.insert("User-Agent", "hello_world");
|
|
||||||
req.body = "";
|
|
||||||
|
|
||||||
http::response<http::string_body> resp({404, "Not Found", 10});
|
|
||||||
resp.headers.insert("Server", "Beast.HTTP");
|
|
||||||
resp.body = "The requested resource was not found.";
|
|
||||||
```
|
|
||||||
|
|
||||||
[heading Headers]
|
|
||||||
|
|
||||||
The `message::headers` member is a container for setting the field/value
|
[endsect]
|
||||||
pairs in the message. These statements change the values of the headers
|
|
||||||
in the message passed:
|
|
||||||
|
|
||||||
|
|
||||||
|
[section:fields Fields]
|
||||||
|
|
||||||
|
The [*`Fields`] type represents a container that can set or retrieve the
|
||||||
|
fields in a message. Beast provides the
|
||||||
|
[link beast.ref.http__basic_fields `basic_fields`] class which serves
|
||||||
|
the needs for most users. It supports modification and inspection of values.
|
||||||
|
The field names are not case-sensitive.
|
||||||
|
|
||||||
|
These statements change the values of the headers in the message passed:
|
||||||
```
|
```
|
||||||
template<class Body>
|
template<class Body>
|
||||||
void set_fields(http::request<Body>& req)
|
void set_fields(request<Body>& req)
|
||||||
{
|
{
|
||||||
if(! req.exists("User-Agent"))
|
if(! req.exists("User-Agent"))
|
||||||
req.insert("User-Agent", "myWebClient");
|
req.insert("User-Agent", "myWebClient");
|
||||||
@@ -158,17 +213,27 @@ in the message passed:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[heading Body]
|
User defined [*`Fields`] types are possible. To support serialization, the
|
||||||
|
type must meet the requirements of __FieldSequence__. To support parsing using
|
||||||
|
the provided parser, the type must provide the `insert` member function.
|
||||||
|
|
||||||
The `message::body` member represents the message body. Depending on the
|
[endsect]
|
||||||
`Body` template argument type, this could be a writable container. The
|
|
||||||
following types, provided by the library, are suitable choices for the
|
|
||||||
`Body` type:
|
|
||||||
|
[section:body Body]
|
||||||
|
|
||||||
|
The message [*`Body`] template parameter controls both the type of the data
|
||||||
|
member of the resulting message object, and the algorithms used during parsing
|
||||||
|
and serialization. Beast provides three very common [*`Body`] types:
|
||||||
|
|
||||||
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
|
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
|
||||||
Used in GET requests where there is no message body. Example:
|
Used in GET requests where there is no message body. Example:
|
||||||
```
|
```
|
||||||
http::request<http::empty_body> req({http::method_t::http_get, "/index.html", 11});
|
request<empty_body> req;
|
||||||
|
req.version = 11;
|
||||||
|
req.method = "GET";
|
||||||
|
req.url = "/index.html";
|
||||||
```
|
```
|
||||||
|
|
||||||
* [link beast.ref.http__string_body [*`string_body`:]] A body with a
|
* [link beast.ref.http__string_body [*`string_body`:]] A body with a
|
||||||
@@ -177,33 +242,77 @@ or response with simple text in the message body (such as an error message).
|
|||||||
Has the same insertion complexity of `std::string`. This is the type of body
|
Has the same insertion complexity of `std::string`. This is the type of body
|
||||||
used in the examples:
|
used in the examples:
|
||||||
```
|
```
|
||||||
http::response<http::string_body> resp;
|
response<string_body> res;
|
||||||
static_assert(std::is_same<decltype(resp.body), std::string>::value);
|
static_assert(std::is_same<decltype(res.body), std::string>::value);
|
||||||
resp.body = "Here is the data you requested";
|
res.body = "Here is the data you requested";
|
||||||
```
|
```
|
||||||
|
|
||||||
* [link beast.ref.http__streambuf_body [*`streambuf_body`:]] A body with a
|
* [link beast.ref.http__streambuf_body [*`streambuf_body`:]] A body with a
|
||||||
`value_type` of [link beast.ref.streambuf `streambuf`]: an efficient storage
|
`value_type` of [link beast.ref.streambuf `streambuf`]: an efficient storage
|
||||||
object which uses multiple octet arrays of varying lengths to represent data.
|
object which uses multiple octet arrays of varying lengths to represent data.
|
||||||
|
|
||||||
[heading Sockets]
|
[heading Advanced]
|
||||||
|
|
||||||
The library provides simple free functions modeled after Boost.Asio to
|
User-defined types are possible for the message body, where the type meets the
|
||||||
send and receive messages on TCP/IP sockets, SSL streams, or any object
|
[link beast.ref.Body [*`Body`]] requirements. This simplified class declaration
|
||||||
which meets the Boost.Asio type requirements (SyncReadStream, SyncWriteStream,
|
shows the customization points available to user-defined body types:
|
||||||
AsyncReadStream, and AsyncWriteStream depending on the types of operations
|
|
||||||
performed). To send messages synchronously, use one of the `http:write`
|
[$images/body.png [width 510px] [height 210px]]
|
||||||
functions:
|
|
||||||
|
* [*`value_type`]: Determines the type of the
|
||||||
|
[link beast.ref.http__message.body `message::body`] member. If this
|
||||||
|
type defines default construction, move, copy, or swap, then message objects
|
||||||
|
declared with this [*`Body`] will have those operations defined.
|
||||||
|
|
||||||
|
* [*`reader`]: An optional nested type meeting the requirements of
|
||||||
|
[link beast.ref.Reader [*`Reader`]]. If present, this defines the algorithm
|
||||||
|
used for parsing bodies of this type.
|
||||||
|
|
||||||
|
* [*`writer`]: An optional nested type meeting the requirements of
|
||||||
|
[link beast.ref.Writer [*`Writer`]]. If present, this defines the algorithm
|
||||||
|
used for serializing bodies of this type.
|
||||||
|
|
||||||
|
The examples included with this library provide a Body implementation that
|
||||||
|
serializing message bodies that come from a file.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[section:algorithms Algorithms]
|
||||||
|
|
||||||
|
Algorithms are provided to serialize and deserialize HTTP/1 messages on
|
||||||
|
streams.
|
||||||
|
|
||||||
|
* [link beast.ref.http__read [*read]]: Deserialize a HTTP/1 __header__ or __message__ from a stream.
|
||||||
|
* [link beast.ref.http__write [*write]]: Serialize a HTTP/1 __header__ or __message__ to a stream.
|
||||||
|
|
||||||
|
Asynchronous versions of these algorithms are also available:
|
||||||
|
|
||||||
|
* [link beast.ref.http__async_read [*async_read]]: Deserialize a HTTP/1 __header__ or __message__ asynchronously from a stream.
|
||||||
|
* [link beast.ref.http__async_write [*async_write]]: Serialize a HTTP/1 __header__ or __message__ asynchronously to a stream.
|
||||||
|
|
||||||
|
[heading Using Sockets]
|
||||||
|
|
||||||
|
The free function algorithms are modeled after Boost.Asio to send and receive
|
||||||
|
messages on TCP/IP sockets, SSL streams, or any object which meets the
|
||||||
|
Boost.Asio type requirements (__SyncReadStream__, __SyncWriteStream__,
|
||||||
|
__AsyncReadStream__, and __AsyncWriteStream__ depending on the types of
|
||||||
|
operations performed). To send messages synchronously, use one of the
|
||||||
|
[link beast.ref.http__write `write`] functions:
|
||||||
```
|
```
|
||||||
void send_request(boost::asio::ip::tcp::socket& sock)
|
void send_request(boost::asio::ip::tcp::socket& sock)
|
||||||
{
|
{
|
||||||
http::request<http::empty_body> req({http::method_t::http_get, "/index.html", 11});
|
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
|
// Alternatively
|
||||||
boost::system::error:code ec;
|
boost::system::error:code ec;
|
||||||
http::write(sock, req, ec);
|
write(sock, req, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
std::cerr << "error writing http message: " << ec.message();
|
std::cerr << "error writing http message: " << ec.message();
|
||||||
}
|
}
|
||||||
@@ -213,27 +322,27 @@ An asynchronous interface is available:
|
|||||||
```
|
```
|
||||||
void handle_write(boost::system::error_code);
|
void handle_write(boost::system::error_code);
|
||||||
...
|
...
|
||||||
http::request<http::empty_body> req;
|
request<empty_body> req;
|
||||||
...
|
...
|
||||||
http::async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
|
async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
|
||||||
```
|
```
|
||||||
|
|
||||||
When the implementation reads messages from a socket, it can read bytes lying
|
When the implementation reads messages from a socket, it can read bytes lying
|
||||||
after the end of the message if they are present (the alternative is to read
|
after the end of the message if they are present (the alternative is to read
|
||||||
a single byte at a time which is unsuitable for performance reasons). To
|
a single byte at a time which is unsuitable for performance reasons). To
|
||||||
store and re-use these extra bytes on subsequent messages, the read interface
|
store and re-use these extra bytes on subsequent messages, the read interface
|
||||||
requires an additional paramter: a [link beast.types.DynamicBuffer [*`DynamicBuffer`]]
|
requires an additional parameter: a [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]
|
||||||
object. This example reads a message from the socket, with the extra bytes
|
object. This example reads a message from the socket, with the extra bytes
|
||||||
stored in the streambuf parameter for use in a subsequent call to read:
|
stored in the streambuf parameter for use in a subsequent call to read:
|
||||||
```
|
```
|
||||||
boost::asio::streambuf sb;
|
boost::asio::streambuf sb;
|
||||||
...
|
...
|
||||||
http::response<http::string_body> resp;
|
response<string_body> res;
|
||||||
http::read(sock, sb, resp); // Throws exception on error
|
read(sock, sb, res); // Throws exception on error
|
||||||
...
|
...
|
||||||
// Alternatively
|
// Alternatively
|
||||||
boost::system::error:code ec;
|
boost::system::error:code ec;
|
||||||
http::read(sock, sb, resp, ec);
|
read(sock, sb, res, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
std::cerr << "error reading http message: " << ec.message();
|
std::cerr << "error reading http message: " << ec.message();
|
||||||
```
|
```
|
||||||
@@ -245,116 +354,28 @@ called:
|
|||||||
void handle_read(boost::system::error_code);
|
void handle_read(boost::system::error_code);
|
||||||
...
|
...
|
||||||
boost::asio::streambuf sb;
|
boost::asio::streambuf sb;
|
||||||
http::response<http::string_body> resp;
|
response<string_body> res;
|
||||||
...
|
...
|
||||||
http::async_read(sock, resp, std::bind(&handle_read, std::placeholders::_1));
|
async_read(sock, res, std::bind(&handle_read, std::placeholders::_1));
|
||||||
```
|
```
|
||||||
|
|
||||||
An alternative to using a `boost::asio::streambuf` is to use a
|
An alternative to using a `boost::asio::streambuf` is to use a
|
||||||
[link beast.ref.streambuf `beast::streambuf`], which meets the requirements of
|
__streambuf__, which meets the requirements of __DynamicBuffer__ and
|
||||||
[*`DynamicBuffer`] and is optimized for performance:
|
is optimized for performance:
|
||||||
```
|
```
|
||||||
void handle_read(boost::system::error_code);
|
void handle_read(boost::system::error_code);
|
||||||
...
|
...
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
http::response<http::string_body> resp;
|
response<string_body> res;
|
||||||
http::read(sock, sb, resp);
|
read(sock, sb, res);
|
||||||
```
|
```
|
||||||
|
|
||||||
The `read` implementation can use any object meeting the requirements of
|
The `read` implementation can use any object meeting the requirements of
|
||||||
[link beast.types.DynamicBuffer [*`DynamicBuffer`]], allowing callers to define custom
|
__DynamicBuffer__, allowing callers to define custom
|
||||||
memory management strategies used by the implementation.
|
memory management strategies used by the implementation.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:advanced Advanced]
|
|
||||||
|
|
||||||
The spectrum of hardware and software platforms which perform these typical
|
|
||||||
HTTP operations is vast, ranging from powerful servers in large datacenters
|
|
||||||
to tiny resource-limited embedded devices. No single concrete implementation
|
|
||||||
of a class intended to model messages can efficiently serve all needs.
|
|
||||||
For example, an object that minimizes resources during parsing may not be
|
|
||||||
able to edit and change headers dynamically. A message that represents the
|
|
||||||
message body as a disk file may support sending but not parsing. Many efficient
|
|
||||||
and correct models of messages exist, supporting some or all of the
|
|
||||||
operations listed above.
|
|
||||||
|
|
||||||
[heading Message model]
|
|
||||||
|
|
||||||
The message class template and provided Body types are suitable for casual
|
|
||||||
library users. This section explains the message model for advanced users
|
|
||||||
who wish to take control over aspects of the implementation. We introduce
|
|
||||||
customization points for the header and body via class template arguments.
|
|
||||||
This illustration shows more detail about the
|
|
||||||
[link beast.ref.http__message [*`message`]] class template (boilerplate
|
|
||||||
present in the actual declaration has been removed for clarity):
|
|
||||||
|
|
||||||
[$images/message.png [width 580px] [height 225px]]
|
|
||||||
|
|
||||||
The default constructor, move special members, and copy special members are
|
|
||||||
all defaulted. A message is movable, copyable, or default constructible based
|
|
||||||
on the capabilities of its template arguments.
|
|
||||||
|
|
||||||
Messages modeled in this fashion are ['complete], containing all of the
|
|
||||||
information required to perform the supported set of operations. They are
|
|
||||||
['first-class types], returnable from functions and composable. HTTP
|
|
||||||
requests and responses are distinct types, allowing functions to be
|
|
||||||
overloaded on the type of message.
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:headers Headers Type]
|
|
||||||
|
|
||||||
The `Headers` type represents the field/value pairs present in every HTTP
|
|
||||||
message. These types implement the
|
|
||||||
[link beast.types.FieldSequence [*`FieldSequence`]]
|
|
||||||
concept. The value type of a field sequence is an object meeting the
|
|
||||||
requirements of [link beast.types.Field [*`Field`]]. The implementation can
|
|
||||||
serialize any instance of `Headers` that meets the field sequence requirements.
|
|
||||||
This example shows a function which returns `true` if the specified field
|
|
||||||
sequence has a connect field:
|
|
||||||
```
|
|
||||||
template<class FieldSequence>
|
|
||||||
bool
|
|
||||||
has_connect(FieldSequence const& fs)
|
|
||||||
{
|
|
||||||
return std::find_if(fs.begin(), fs.end(),
|
|
||||||
[&](auto const& field)
|
|
||||||
{
|
|
||||||
return ci_equal(field.name(), "Connect");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:body Body Type]
|
|
||||||
|
|
||||||
The `Body` template argument in the `message` class must meet the
|
|
||||||
[link beast.types.Body [*`Body`] requirements]. It provides customization
|
|
||||||
of the data member in the message, the algorithm for parsing, and the
|
|
||||||
algorithm for serialization:
|
|
||||||
|
|
||||||
[$images/body.png [width 510px] [height 210px]]
|
|
||||||
|
|
||||||
Instances of the optional nested types `writer` and `reader` perform
|
|
||||||
serialization and deserialization of the message body. If either or
|
|
||||||
both of these types are present, the message becomes serializable, parsable,
|
|
||||||
or both. They model [link beast.types.Reader [*`Reader`]] and
|
|
||||||
[link beast.types.Writer [*`Writer`]] respectively.
|
|
||||||
|
|
||||||
For specialized applications, users may implement their own types which
|
|
||||||
meet the requirements. The examples included with this library provide a
|
|
||||||
Body implementation used to serve files in a HTTP server.
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
|
|||||||
BIN
src/beast/doc/images/CppCon2016.pdf
Normal file
BIN
src/beast/doc/images/CppCon2016.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 30 KiB |
BIN
src/beast/doc/images/readme.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
@@ -8,6 +8,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<section id="index">
|
<section id="beast.index">
|
||||||
|
<title>Index</title>
|
||||||
<index/>
|
<index/>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
4
src/beast/doc/makeqbk.sh
Normal file → Executable file
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
#
|
#
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
mkdir -p ../bin/doc/xml
|
mkdir -p ../bin/doc/xml
|
||||||
doxygen beast.dox
|
doxygen source.dox
|
||||||
cd ../bin/doc/xml
|
cd ../bin/doc/xml
|
||||||
xsltproc combine.xslt index.xml > all.xml
|
xsltproc combine.xslt index.xml > all.xml
|
||||||
cd ../../../doc
|
cd ../../../doc
|
||||||
|
|||||||
116
src/beast/doc/master.qbk
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
[/
|
||||||
|
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
]
|
||||||
|
|
||||||
|
[library Beast
|
||||||
|
[quickbook 1.6]
|
||||||
|
[copyright 2013 - 2016 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
|
||||||
|
[@http://www.boost.org/LICENSE_1_0.txt])
|
||||||
|
]
|
||||||
|
[authors [Falco, Vinnie]]
|
||||||
|
[category template]
|
||||||
|
[category generic]
|
||||||
|
]
|
||||||
|
|
||||||
|
[template mdash[] '''— ''']
|
||||||
|
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
|
||||||
|
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
|
||||||
|
|
||||||
|
[def __N4588__ [@http://cplusplus.github.io/networking-ts/draft.pdf [*N4588]]]
|
||||||
|
[def __rfc6455__ [@https://tools.ietf.org/html/rfc6455 rfc6455]]
|
||||||
|
[def __rfc7230__ [@https://tools.ietf.org/html/rfc7230 rfc7230]]
|
||||||
|
|
||||||
|
[def __asio_handler_invoke__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]]
|
||||||
|
[def __asio_handler_allocate__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]]
|
||||||
|
[def __void_or_deduced__ [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]]
|
||||||
|
|
||||||
|
[def __AsyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]]
|
||||||
|
[def __AsyncWriteStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]]
|
||||||
|
[def __CompletionHandler__ [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]]
|
||||||
|
[def __ConstBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]]
|
||||||
|
[def __MutableBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]]
|
||||||
|
[def __SyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]]
|
||||||
|
[def __SyncWriteStream__ [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]]
|
||||||
|
|
||||||
|
[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`]]]
|
||||||
|
|
||||||
|
[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:ref Reference]
|
||||||
|
[xinclude quickref.xml]
|
||||||
|
[include types/Body.qbk]
|
||||||
|
[include types/BufferSequence.qbk]
|
||||||
|
[include types/DynamicBuffer.qbk]
|
||||||
|
[include types/Field.qbk]
|
||||||
|
[include types/FieldSequence.qbk]
|
||||||
|
[include types/Parser.qbk]
|
||||||
|
[include types/Reader.qbk]
|
||||||
|
[include types/Streams.qbk]
|
||||||
|
[include types/Writer.qbk]
|
||||||
|
[include reference.qbk]
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[xinclude index.xml]
|
||||||
114
src/beast/doc/overview.qbk
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
[/
|
||||||
|
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
]
|
||||||
|
|
||||||
|
[section:overview Introduction]
|
||||||
|
|
||||||
|
Beast is a header-only, cross-platform C++ library built on Boost.Asio and
|
||||||
|
parts of Boost, containing two modules implementing widely used network
|
||||||
|
protocols. Beast offers a universal HTTP message model, plus algorithms for
|
||||||
|
parsing and serializing HTTP/1 messages. Beast.WebSocket provides a complete
|
||||||
|
implementation of the WebSocket protocol. Their design achieves these goals:
|
||||||
|
|
||||||
|
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
|
||||||
|
used to build clients, servers, or both.
|
||||||
|
|
||||||
|
* [*Ease of Use.] HTTP messages are modeled using simple, readily
|
||||||
|
accessible objects. Functions and classes used to send and receive HTTP
|
||||||
|
or WebSocket messages are designed to resemble Boost.Asio as closely as
|
||||||
|
possible. Users familiar with Boost.Asio will be immediately comfortable
|
||||||
|
using this library.
|
||||||
|
|
||||||
|
* [*Flexibility.] Interfaces do not mandate specific implementation
|
||||||
|
strategies; important decisions such as buffer or thread management are
|
||||||
|
left to users of the library.
|
||||||
|
|
||||||
|
* [*Performance.] The implementation performs competitively, making it a
|
||||||
|
realistic choice for building high performance network servers.
|
||||||
|
|
||||||
|
* [*Scalability.] Development of network applications that scale to thousands
|
||||||
|
of concurrent connections is possible with the implementation.
|
||||||
|
|
||||||
|
* [*Basis for further abstraction.] The interfaces facilitate the
|
||||||
|
development of other libraries that provide higher levels of abstraction.
|
||||||
|
|
||||||
|
The HTTP portion of Beast is designed to be a low-level building block for
|
||||||
|
creating higher level libraries. It implements only the HTTP protocol, and
|
||||||
|
does not handle domain specific features (for example: cookies, redirects, or
|
||||||
|
deflate content encodings).
|
||||||
|
|
||||||
|
[heading Requirements]
|
||||||
|
|
||||||
|
Beast requires:
|
||||||
|
|
||||||
|
* [*C++11.] A minimum of C++11 is needed.
|
||||||
|
* [*Boost.] Beast is built on Boost, especially Boost.Asio.
|
||||||
|
* [*OpenSSL.] If using TLS/Secure sockets (optional).
|
||||||
|
|
||||||
|
[note Tested compilers: msvc-14+, gcc 5+, clang 3.6+]
|
||||||
|
|
||||||
|
The library is [*header-only]. It is not necessary to add any .cpp files,
|
||||||
|
or to add commands to your build script for building Beast. To link your
|
||||||
|
program successfully, you'll need to add the Boost.System library to link
|
||||||
|
with. If you use coroutines you'll also need the Boost.Coroutine library.
|
||||||
|
Please visit the Boost documentation for instructions on how to do this for
|
||||||
|
your particular build system.
|
||||||
|
|
||||||
|
[heading Motivation]
|
||||||
|
|
||||||
|
Beast is built on Boost.Asio A proposal to add networking functionality to the
|
||||||
|
C++ standard library, based on Boost.Asio, is under consideration by the
|
||||||
|
committee and on track for standardization. Since the final approved networking
|
||||||
|
interface for the C++ standard library will likely closely resemble the current
|
||||||
|
interface of Boost.Asio, the choice of Boost.Asio as the network transport
|
||||||
|
layer is prudent.
|
||||||
|
|
||||||
|
The HTTP protocol is pervasive in network applications. As C++ is a logical
|
||||||
|
choice for high performance network servers, there is great utility in solid
|
||||||
|
building blocks for manipulating, sending, and receiving HTTP messages
|
||||||
|
compliant with the Hypertext Transfer Protocol and the supplements that
|
||||||
|
follow. Unfortunately reliable implementations or industry standards do not
|
||||||
|
exist in C++. The development of higher level libraries is stymied by the
|
||||||
|
lack of a common set of low-level algorithms and types for interacting with
|
||||||
|
the HTTP protocol.
|
||||||
|
|
||||||
|
Today's web applications increasingly rely on alternatives to standard HTTP
|
||||||
|
to achieve performance and/or responsiveness. While WebSocket implementations
|
||||||
|
are widely available in common web development languages such as Javascript,
|
||||||
|
good implementations in C++ are scarce. A survey of existing C++ WebSocket
|
||||||
|
solutions reveals interfaces which lack symmetry, impose performance penalties,
|
||||||
|
and needlessly restrict implementation strategies.
|
||||||
|
|
||||||
|
Beast.WebSocket takes advantage of Boost.Asio's extensible asynchronous
|
||||||
|
model, handler allocation, and handler invocation hooks. Calls to
|
||||||
|
Beast.WebSocket asynchronous initiation functions allow callers the choice
|
||||||
|
of using a completion handler, stackful or stackless coroutines, futures,
|
||||||
|
or user defined customizations (for example, Boost.Fiber). The
|
||||||
|
implementation uses handler invocation hooks (__asio_handler_invoke__),
|
||||||
|
providing execution guarantees on composed operations in a manner identical
|
||||||
|
to Boost.Asio. The implementation also uses handler allocation hooks
|
||||||
|
(__asio_handler_allocate__) when allocating memory internally for composed
|
||||||
|
operations.
|
||||||
|
|
||||||
|
There is no need for inheritance or virtual members in a
|
||||||
|
[link beast.ref.websocket__stream `websocket::stream`].
|
||||||
|
All operations are templated and transparent to the compiler, allowing for
|
||||||
|
maximum inlining and optimization.
|
||||||
|
|
||||||
|
[heading Credits]
|
||||||
|
|
||||||
|
Boost.Asio is the inspiration behind which all of the interfaces and
|
||||||
|
implementation strategies are built. Some parts of the documentation are
|
||||||
|
written to closely resemble the wording and presentation of Boost.Asio
|
||||||
|
documentation. Credit goes to Christopher Kohlhoff for the wonderful
|
||||||
|
Asio library and the ideas upon which Beast is built.
|
||||||
|
|
||||||
|
Beast would not be possible without the considerable time and patience
|
||||||
|
contributed by David Schwartz, Edward Hennis, Howard Hinnant, Miguel Portilla,
|
||||||
|
Nikolaos Bougalis, Scott Determan, Scott Schurr, and Ripple Labs for
|
||||||
|
supporting its development.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
<colspec colname="d"/>
|
<colspec colname="d"/>
|
||||||
<thead>
|
<thead>
|
||||||
<row>
|
<row>
|
||||||
<entry valign="center" namest="a" nameend="b">
|
<entry valign="center" namest="a" nameend="c">
|
||||||
<bridgehead renderas="sect2">HTTP</bridgehead>
|
<bridgehead renderas="sect2">HTTP</bridgehead>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="center" namest="c" nameend="d">
|
<entry valign="center" namest="d" nameend="d">
|
||||||
<bridgehead renderas="sect2">WebSocket</bridgehead>
|
<bridgehead renderas="sect2">WebSocket</bridgehead>
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
@@ -30,52 +30,82 @@
|
|||||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.http__basic_dynabuf_body">basic_dynabuf_body</link></member>
|
<member><link linkend="beast.ref.http__basic_dynabuf_body">basic_dynabuf_body</link></member>
|
||||||
<member><link linkend="beast.ref.http__basic_headers">basic_headers</link></member>
|
<member><link linkend="beast.ref.http__basic_fields">basic_fields</link></member>
|
||||||
<member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member>
|
<member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member>
|
||||||
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
|
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
|
||||||
<member><link linkend="beast.ref.http__headers">headers</link></member>
|
<member><link linkend="beast.ref.http__fields">fields</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__header">header</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__header_parser_v1">header_parser_v1</link></member>
|
||||||
<member><link linkend="beast.ref.http__message">message</link></member>
|
<member><link linkend="beast.ref.http__message">message</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__parser_v1">parser_v1</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__request">request</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__request_header">request_header</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__response">response</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__response_header">response_header</link></member>
|
||||||
<member><link linkend="beast.ref.http__resume_context">resume_context</link></member>
|
<member><link linkend="beast.ref.http__resume_context">resume_context</link></member>
|
||||||
<member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member>
|
<member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member>
|
||||||
<member><link linkend="beast.ref.http__string_body">string_body</link></member>
|
<member><link linkend="beast.ref.http__string_body">string_body</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Options</bridgehead>
|
<bridgehead renderas="sect3">rfc7230</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
|
||||||
<member><link linkend="beast.ref.http__headers_max_size">headers_max_size</link></member>
|
<member><link linkend="beast.ref.http__ext_list">ext_list</link></member>
|
||||||
</simplelist>
|
<member><link linkend="beast.ref.http__param_list">param_list</link></member>
|
||||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
<member><link linkend="beast.ref.http__token_list">token_list</link></member>
|
||||||
<simplelist type="vert" columns="1">
|
|
||||||
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
|
|
||||||
<member><link linkend="beast.ref.http__is_Parser">is_Parser</link></member>
|
|
||||||
<member><link linkend="beast.ref.http__is_ReadableBody">is_ReadableBody</link></member>
|
|
||||||
<member><link linkend="beast.ref.http__is_WritableBody">is_WritableBody</link></member>
|
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
|
|
||||||
<member><link linkend="beast.ref.http__async_read">async_read</link></member>
|
<member><link linkend="beast.ref.http__async_read">async_read</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
|
||||||
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
|
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__chunk_encode">chunk_encode</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__chunk_encode_final">chunk_encode_final</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__swap">swap</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__is_keep_alive">is_keep_alive</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__is_upgrade">is_upgrade</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__operator_ls_">operator<<</link></member>
|
||||||
<member><link linkend="beast.ref.http__parse">parse</link></member>
|
<member><link linkend="beast.ref.http__parse">parse</link></member>
|
||||||
<member><link linkend="beast.ref.http__prepare">prepare</link></member>
|
<member><link linkend="beast.ref.http__prepare">prepare</link></member>
|
||||||
<member><link linkend="beast.ref.http__read">read</link></member>
|
<member><link linkend="beast.ref.http__read">read</link></member>
|
||||||
<member><link linkend="beast.ref.http__swap">swap</link></member>
|
<member><link linkend="beast.ref.http__reason_string">reason_string</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__with_body">with_body</link></member>
|
||||||
<member><link linkend="beast.ref.http__write">write</link></member>
|
<member><link linkend="beast.ref.http__write">write</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__is_Parser">is_Parser</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__is_Reader">is_Reader</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__is_Writer">is_Writer</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__has_reader">has_reader</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__has_writer">has_writer</link></member>
|
||||||
|
</simplelist>
|
||||||
|
</entry>
|
||||||
|
<entry valign="top">
|
||||||
|
<bridgehead renderas="sect3">Options</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.http__header_max_size">header_max_size</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__skip_body">skip_body</link></member>
|
||||||
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.http__body_what">body_what</link></member>
|
||||||
<member><link linkend="beast.ref.http__connection">connection</link></member>
|
<member><link linkend="beast.ref.http__connection">connection</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__no_content_length">no_content_length</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__parse_error">parse_error</link></member>
|
||||||
|
<member><link linkend="beast.ref.http__parse_flag">parse_flag</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.types.Body">Body</link></member>
|
<member><link linkend="beast.ref.Body">Body</link></member>
|
||||||
<member><link linkend="beast.types.Field">Field</link></member>
|
<member><link linkend="beast.ref.Field">Field</link></member>
|
||||||
<member><link linkend="beast.types.FieldSequence">FieldSequence</link></member>
|
<member><link linkend="beast.ref.FieldSequence">FieldSequence</link></member>
|
||||||
<member><link linkend="beast.types.Parser">Parser</link></member>
|
<member><link linkend="beast.ref.Parser">Parser</link></member>
|
||||||
<member><link linkend="beast.types.Reader">Reader</link></member>
|
<member><link linkend="beast.ref.Reader">Reader</link></member>
|
||||||
<member><link linkend="beast.types.Writer">Writer</link></member>
|
<member><link linkend="beast.ref.Writer">Writer</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
@@ -85,25 +115,24 @@
|
|||||||
<member><link linkend="beast.ref.websocket__ping_data">ping_data</link></member>
|
<member><link linkend="beast.ref.websocket__ping_data">ping_data</link></member>
|
||||||
<member><link linkend="beast.ref.websocket__stream">stream</link></member>
|
<member><link linkend="beast.ref.websocket__stream">stream</link></member>
|
||||||
<member><link linkend="beast.ref.websocket__reason_string">reason_string</link></member>
|
<member><link linkend="beast.ref.websocket__reason_string">reason_string</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__teardown_tag">teardown_tag</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Options</bridgehead>
|
|
||||||
<simplelist type="vert" columns="1">
|
|
||||||
<member><link linkend="beast.ref.websocket__auto_fragment_size">auto_fragment_size</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__decorate">decorate</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__mask_buffer_size">mask_buffer_size</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__message_type">message_type</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__pong_callback">pong_callback</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__read_buffer_size">read_buffer_size</link></member>
|
|
||||||
<member><link linkend="beast.ref.websocket__read_message_max">read_message_max</link></member>
|
|
||||||
</simplelist>
|
|
||||||
</entry>
|
|
||||||
<entry valign="top">
|
|
||||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.websocket__async_teardown">async_teardown</link></member>
|
<member><link linkend="beast.ref.websocket__async_teardown">async_teardown</link></member>
|
||||||
<member><link linkend="beast.ref.websocket__teardown">teardown</link></member>
|
<member><link linkend="beast.ref.websocket__teardown">teardown</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Options</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.websocket__auto_fragment">auto_fragment</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__decorate">decorate</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__message_type">message_type</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__pong_callback">pong_callback</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__read_buffer_size">read_buffer_size</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__read_message_max">read_message_max</link></member>
|
||||||
|
<member><link linkend="beast.ref.websocket__write_buffer_size">write_buffer_size</link></member>
|
||||||
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.websocket__close_code">close_code</link></member>
|
<member><link linkend="beast.ref.websocket__close_code">close_code</link></member>
|
||||||
@@ -119,11 +148,15 @@
|
|||||||
<colspec colname="b"/>
|
<colspec colname="b"/>
|
||||||
<colspec colname="c"/>
|
<colspec colname="c"/>
|
||||||
<colspec colname="d"/>
|
<colspec colname="d"/>
|
||||||
|
<colspec colname="e"/>
|
||||||
<thead>
|
<thead>
|
||||||
<row>
|
<row>
|
||||||
<entry valign="center" namest="a" nameend="d">
|
<entry valign="center" namest="a" nameend="d">
|
||||||
<bridgehead renderas="sect2">Core</bridgehead>
|
<bridgehead renderas="sect2">Core</bridgehead>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry valign="center" namest="e" nameend="e">
|
||||||
|
<bridgehead renderas="sect2">ZLib</bridgehead>
|
||||||
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -136,9 +169,12 @@
|
|||||||
<member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member>
|
<member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member>
|
||||||
<member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member>
|
<member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member>
|
||||||
<member><link linkend="beast.ref.dynabuf_readstream">dynabuf_readstream</link></member>
|
<member><link linkend="beast.ref.dynabuf_readstream">dynabuf_readstream</link></member>
|
||||||
|
<member><link linkend="beast.ref.errc">errc</link></member>
|
||||||
|
<member><link linkend="beast.ref.error_category">error_category</link></member>
|
||||||
<member><link linkend="beast.ref.error_code">error_code</link></member>
|
<member><link linkend="beast.ref.error_code">error_code</link></member>
|
||||||
|
<member><link linkend="beast.ref.error_condition">error_condition</link></member>
|
||||||
<member><link linkend="beast.ref.handler_alloc">handler_alloc</link></member>
|
<member><link linkend="beast.ref.handler_alloc">handler_alloc</link></member>
|
||||||
<member><link linkend="beast.ref.prepared_buffers">prepared_buffers</link></member>
|
<member><link linkend="beast.ref.handler_ptr">handler_ptr</link></member>
|
||||||
<member><link linkend="beast.ref.static_streambuf">static_streambuf</link></member>
|
<member><link linkend="beast.ref.static_streambuf">static_streambuf</link></member>
|
||||||
<member><link linkend="beast.ref.static_streambuf_n">static_streambuf_n</link></member>
|
<member><link linkend="beast.ref.static_streambuf_n">static_streambuf_n</link></member>
|
||||||
<member><link linkend="beast.ref.static_string">static_string</link></member>
|
<member><link linkend="beast.ref.static_string">static_string</link></member>
|
||||||
@@ -151,18 +187,15 @@
|
|||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.bind_handler">bind_handler</link></member>
|
<member><link linkend="beast.ref.bind_handler">bind_handler</link></member>
|
||||||
<member><link linkend="beast.ref.buffer_cat">buffer_cat</link></member>
|
<member><link linkend="beast.ref.buffer_cat">buffer_cat</link></member>
|
||||||
<member><link linkend="beast.ref.consumed_buffers">consumed_buffers</link></member>
|
|
||||||
<member><link linkend="beast.ref.prepare_buffer">prepare_buffer</link></member>
|
<member><link linkend="beast.ref.prepare_buffer">prepare_buffer</link></member>
|
||||||
<member><link linkend="beast.ref.prepare_buffers">prepare_buffers</link></member>
|
<member><link linkend="beast.ref.prepare_buffers">prepare_buffers</link></member>
|
||||||
<member><link linkend="beast.ref.to_string">to_string</link></member>
|
<member><link linkend="beast.ref.to_string">to_string</link></member>
|
||||||
|
|
||||||
<member><link linkend="beast.ref.write">write</link></member>
|
<member><link linkend="beast.ref.write">write</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
|
|
||||||
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
|
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
|
||||||
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
|
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
|
||||||
<member><link linkend="beast.ref.is_AsyncStream">is_AsyncStream</link></member>
|
<member><link linkend="beast.ref.is_AsyncStream">is_AsyncStream</link></member>
|
||||||
@@ -179,11 +212,29 @@
|
|||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.types.streams.AsyncStream">AsyncStream</link></member>
|
<member><link linkend="beast.ref.streams.AsyncStream">AsyncStream</link></member>
|
||||||
<member><link linkend="beast.types.BufferSequence">BufferSequence</link></member>
|
<member><link linkend="beast.ref.BufferSequence">BufferSequence</link></member>
|
||||||
<member><link linkend="beast.types.DynamicBuffer">DynamicBuffer</link></member>
|
<member><link linkend="beast.ref.DynamicBuffer">DynamicBuffer</link></member>
|
||||||
<member><link linkend="beast.types.streams.Stream">Stream</link></member>
|
<member><link linkend="beast.ref.streams.Stream">Stream</link></member>
|
||||||
<member><link linkend="beast.types.streams.SyncStream">SyncStream</link></member>
|
<member><link linkend="beast.ref.streams.SyncStream">SyncStream</link></member>
|
||||||
|
</simplelist>
|
||||||
|
</entry>
|
||||||
|
<entry valign="top">
|
||||||
|
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.zlib__deflate_stream">deflate_stream</link></member>
|
||||||
|
<member><link linkend="beast.ref.zlib__inflate_stream">inflate_stream</link></member>
|
||||||
|
<member><link linkend="beast.ref.zlib__z_params">z_params</link></member>
|
||||||
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.zlib__deflate_upper_bound">deflate_upper_bound</link></member>
|
||||||
|
</simplelist>
|
||||||
|
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||||
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.zlib__error">error</link></member>
|
||||||
|
<member><link linkend="beast.ref.zlib__Flush">Flush</link></member>
|
||||||
|
<member><link linkend="beast.ref.zlib__Strategy">Strategy</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||||
|
|
||||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
file LICENSE_1_0.txt or copy at http://www.beast.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<xsl:output method="text"/>
|
<xsl:output method="text"/>
|
||||||
@@ -31,8 +31,6 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:ref Reference]
|
|
||||||
|
|
||||||
</xsl:text>
|
</xsl:text>
|
||||||
<xsl:for-each select="
|
<xsl:for-each select="
|
||||||
compounddef[@kind = 'class' or @kind = 'struct'] |
|
compounddef[@kind = 'class' or @kind = 'struct'] |
|
||||||
@@ -59,7 +57,6 @@
|
|||||||
</xsl:otherwise>
|
</xsl:otherwise>
|
||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
</xsl:for-each>
|
</xsl:for-each>
|
||||||
<xsl:text>
[endsect]</xsl:text>
|
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<!--========== Utilities ==========-->
|
<!--========== Utilities ==========-->
|
||||||
@@ -165,7 +162,7 @@
|
|||||||
<xsl:text>``['implementation-defined]``</xsl:text>
|
<xsl:text>``['implementation-defined]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="$type='void_or_deduced'">
|
<xsl:when test="$type='void_or_deduced'">
|
||||||
<xsl:text>``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]``</xsl:text>
|
<xsl:text>__void_or_deduced__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:otherwise>
|
<xsl:otherwise>
|
||||||
<xsl:value-of select="$type"/>
|
<xsl:value-of select="$type"/>
|
||||||
@@ -198,6 +195,18 @@
|
|||||||
select="concat(substring-before($name, '::'), '__', substring-after($name, '::'))"/>
|
select="concat(substring-before($name, '::'), '__', substring-after($name, '::'))"/>
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
<xsl:when test="substring($name, string-length($name) - 1) = '<<'">
|
||||||
|
<xsl:call-template name="make-id">
|
||||||
|
<xsl:with-param name="name"
|
||||||
|
select="concat(substring-before($name, '<<'), '_ls_')"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:when test="substring($name, string-length($name) - 1) = '>>'">
|
||||||
|
<xsl:call-template name="make-id">
|
||||||
|
<xsl:with-param name="name"
|
||||||
|
select="concat(substring-before($name, '>>'), '_rs_')"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
<xsl:when test="contains($name, '=')">
|
<xsl:when test="contains($name, '=')">
|
||||||
<xsl:call-template name="make-id">
|
<xsl:call-template name="make-id">
|
||||||
<xsl:with-param name="name"
|
<xsl:with-param name="name"
|
||||||
@@ -270,10 +279,10 @@
|
|||||||
select="concat(substring-before($name, '*'), '_star_', substring-after($name, '*'))"/>
|
select="concat(substring-before($name, '*'), '_star_', substring-after($name, '*'))"/>
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="contains($name, '~')">
|
<xsl:when test="starts-with($name, '~')">
|
||||||
<xsl:call-template name="make-id">
|
<xsl:call-template name="make-id">
|
||||||
<xsl:with-param name="name"
|
<xsl:with-param name="name"
|
||||||
select="concat(substring-before($name, '~'), '_', substring-after($name, '~'))"/>
|
select="concat(substring-after($name, '~'), '_dtor_')"/>
|
||||||
</xsl:call-template>
|
</xsl:call-template>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="contains($name, ' ')">
|
<xsl:when test="contains($name, ' ')">
|
||||||
@@ -1055,10 +1064,26 @@
|
|||||||
</xsl:for-each>
|
</xsl:for-each>
|
||||||
<xsl:text>]
</xsl:text>
|
<xsl:text>]
</xsl:text>
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
<xsl:if test="count(sectiondef[@kind='public-attrib' or @kind='public-static-attrib']) > 0">
|
<xsl:if test="count(sectiondef[@kind='public-static-attrib']) > 0">
|
||||||
|
<xsl:text>[heading Static Data Members]
</xsl:text>
|
||||||
|
<xsl:text>[table
 [[Name][Description]]
</xsl:text>
|
||||||
|
<xsl:for-each select="sectiondef[@kind='public-static-attrib']/memberdef" mode="class-table">
|
||||||
|
<xsl:sort select="name"/>
|
||||||
|
<xsl:text> [
</xsl:text>
|
||||||
|
<xsl:text> [[link beast.ref.</xsl:text>
|
||||||
|
<xsl:value-of select="$class-id"/>.<xsl:value-of select="name"/>
|
||||||
|
<xsl:text> [*</xsl:text>
|
||||||
|
<xsl:value-of select="name"/>
|
||||||
|
<xsl:text>]]]
 [
 </xsl:text>
|
||||||
|
<xsl:value-of select="briefdescription"/>
|
||||||
|
<xsl:text>
 ]
 ]
</xsl:text>
|
||||||
|
</xsl:for-each>
|
||||||
|
<xsl:text>]
</xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test="count(sectiondef[@kind='public-attrib']) > 0">
|
||||||
<xsl:text>[heading Data Members]
</xsl:text>
|
<xsl:text>[heading Data Members]
</xsl:text>
|
||||||
<xsl:text>[table
 [[Name][Description]]
</xsl:text>
|
<xsl:text>[table
 [[Name][Description]]
</xsl:text>
|
||||||
<xsl:for-each select="sectiondef[@kind='public-attrib' or @kind='public-static-attrib']/memberdef" mode="class-table">
|
<xsl:for-each select="sectiondef[@kind='public-attrib']/memberdef" mode="class-table">
|
||||||
<xsl:sort select="name"/>
|
<xsl:sort select="name"/>
|
||||||
<xsl:text> [
</xsl:text>
|
<xsl:text> [
</xsl:text>
|
||||||
<xsl:text> [[link beast.ref.</xsl:text>
|
<xsl:text> [[link beast.ref.</xsl:text>
|
||||||
@@ -1528,47 +1553,50 @@
|
|||||||
<xsl:text> </xsl:text>
|
<xsl:text> </xsl:text>
|
||||||
<xsl:choose>
|
<xsl:choose>
|
||||||
<xsl:when test="type = 'class AsyncStream'">
|
<xsl:when test="type = 'class AsyncStream'">
|
||||||
<xsl:text>class ``[link beast.types.streams.AsyncStream [*AsyncStream]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.streams.AsyncStream [*AsyncStream]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="type = 'class AsyncReadStream'">
|
<xsl:when test="type = 'class AsyncReadStream'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]``</xsl:text>
|
<xsl:text>class __AsyncReadStream__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="type = 'class AsyncWriteStream'">
|
<xsl:when test="type = 'class AsyncWriteStream'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]``</xsl:text>
|
<xsl:text>class __AsyncWriteStream__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="type = 'class Body'">
|
<xsl:when test="type = 'class Body'">
|
||||||
<xsl:text>class ``[link beast.types.Body [*Body]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.Body [*Body]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="type = 'class BufferSequence'">
|
<xsl:when test="type = 'class BufferSequence'">
|
||||||
<xsl:text>class ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="(type = 'class' or type = 'class...') and declname = 'BufferSequence'">
|
<xsl:when test="(type = 'class' or type = 'class...') and declname = 'BufferSequence'">
|
||||||
<xsl:value-of select="type"/>
|
<xsl:value-of select="type"/>
|
||||||
<xsl:text> ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
|
<xsl:text> ``[link beast.ref.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'CompletionHandler' or type = 'class CompletionHandler'">
|
<xsl:when test="declname = 'CompletionHandler' or type = 'class CompletionHandler'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]``</xsl:text>
|
<xsl:text>class __CompletionHandler__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'ConstBufferSequence' or type = 'class ConstBufferSequence'">
|
<xsl:when test="declname = 'ConstBufferSequence' or type = 'class ConstBufferSequence'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]``</xsl:text>
|
<xsl:text>class __ConstBufferSequence__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'DynamicBuffer' or type = 'class DynamicBuffer'">
|
<xsl:when test="declname = 'DynamicBuffer' or type = 'class DynamicBuffer'">
|
||||||
<xsl:text>class ``[link beast.types.DynamicBuffer [*DynamicBuffer]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.DynamicBuffer [*DynamicBuffer]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'MutableBufferSequence' or type = 'class MutableBufferSequence'">
|
<xsl:when test="declname = 'MutableBufferSequence' or type = 'class MutableBufferSequence'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]``</xsl:text>
|
<xsl:text>class __MutableBufferSequence__</xsl:text>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:when test="declname = 'Parser' or type = 'class Parser'">
|
||||||
|
<xsl:text>class ``[link beast.ref.Parser [*Parser]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'Stream' or type = 'class Stream'">
|
<xsl:when test="declname = 'Stream' or type = 'class Stream'">
|
||||||
<xsl:text>class ``[link beast.types.streams.Stream [*Stream]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.streams.Stream [*Stream]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="type = 'class SyncStream'">
|
<xsl:when test="type = 'class SyncStream'">
|
||||||
<xsl:text>class ``[link beast.types.streams.SyncStream [*SyncStream]]``</xsl:text>
|
<xsl:text>class ``[link beast.ref.streams.SyncStream [*SyncStream]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'SyncReadStream' or type = 'class SyncReadStream'">
|
<xsl:when test="declname = 'SyncReadStream' or type = 'class SyncReadStream'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]``</xsl:text>
|
<xsl:text>class __SyncReadStream__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'SyncWriteStream' or type = 'class SyncWriteStream'">
|
<xsl:when test="declname = 'SyncWriteStream' or type = 'class SyncWriteStream'">
|
||||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]``</xsl:text>
|
<xsl:text>class __SyncWriteStream__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
|
||||||
<xsl:when test="declname = 'T'">
|
<xsl:when test="declname = 'T'">
|
||||||
@@ -1682,6 +1710,14 @@
|
|||||||
</xsl:choose>
|
</xsl:choose>
|
||||||
<xsl:text>```
</xsl:text>
|
<xsl:text>```
</xsl:text>
|
||||||
<xsl:for-each select="../memberdef[name = $unqualified-name]">
|
<xsl:for-each select="../memberdef[name = $unqualified-name]">
|
||||||
|
<xsl:if test="position() > 1">
|
||||||
|
<xsl:text>
</xsl:text>
|
||||||
|
<xsl:if test=" not(briefdescription = preceding-sibling::*/briefdescription)">
|
||||||
|
<xsl:text>```
</xsl:text>
|
||||||
|
<xsl:apply-templates select="briefdescription" mode="markup"/>
|
||||||
|
<xsl:text>```
</xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:if>
|
||||||
<xsl:variable name="stripped-type">
|
<xsl:variable name="stripped-type">
|
||||||
<xsl:call-template name="cleanup-type">
|
<xsl:call-template name="cleanup-type">
|
||||||
<xsl:with-param name="name" select="type"/>
|
<xsl:with-param name="name" select="type"/>
|
||||||
|
|||||||
@@ -107,52 +107,8 @@ INPUT = \
|
|||||||
../include/beast/core \
|
../include/beast/core \
|
||||||
../include/beast/http \
|
../include/beast/http \
|
||||||
../include/beast/websocket \
|
../include/beast/websocket \
|
||||||
../include/beast/doc_debug.hpp \
|
../include/beast/zlib \
|
||||||
|
../extras/beast/doc_debug.hpp
|
||||||
../include/beast/async_completion.hpp \
|
|
||||||
../include/beast/basic_streambuf.hpp \
|
|
||||||
../include/beast/bind_handler.hpp \
|
|
||||||
../include/beast/buffer_cat.hpp \
|
|
||||||
../include/beast/buffers_adapter.hpp \
|
|
||||||
../include/beast/consuming_buffers.hpp \
|
|
||||||
../include/beast/handler_alloc.hpp \
|
|
||||||
../include/beast/http.hpp \
|
|
||||||
../include/beast/placeholders.hpp \
|
|
||||||
../include/beast/prepare_buffers.hpp \
|
|
||||||
../include/beast/static_streambuf.hpp \
|
|
||||||
../include/beast/streambuf.hpp \
|
|
||||||
../include/beast/streambuf_readstream.hpp \
|
|
||||||
../include/beast/to_string.hpp \
|
|
||||||
../include/beast/type_check.hpp \
|
|
||||||
../include/beast/websocket.hpp \
|
|
||||||
../include/beast/write_streambuf.hpp \
|
|
||||||
../include/beast/http/basic_headers.hpp \
|
|
||||||
../include/beast/http/basic_parser_v1.hpp \
|
|
||||||
../include/beast/http/body_writer.hpp \
|
|
||||||
../include/beast/http/chunk_encode.hpp \
|
|
||||||
../include/beast/http/empty_body.hpp \
|
|
||||||
../include/beast/http/error.hpp \
|
|
||||||
../include/beast/http/fields.hpp \
|
|
||||||
../include/beast/http/headers.hpp \
|
|
||||||
../include/beast/http/message.hpp \
|
|
||||||
../include/beast/http/message_v1.hpp \
|
|
||||||
../include/beast/http/method.hpp \
|
|
||||||
../include/beast/http/parse_error.hpp \
|
|
||||||
../include/beast/http/parser.hpp \
|
|
||||||
../include/beast/http/read.hpp \
|
|
||||||
../include/beast/http/resume_context.hpp \
|
|
||||||
../include/beast/http/rfc2616.hpp \
|
|
||||||
../include/beast/http/streambuf_body.hpp \
|
|
||||||
../include/beast/http/string_body.hpp \
|
|
||||||
../include/beast/http/type_check.hpp \
|
|
||||||
../include/beast/http/write.hpp \
|
|
||||||
../include/beast/websocket/error.hpp \
|
|
||||||
../include/beast/websocket/option.hpp \
|
|
||||||
../include/beast/websocket/rfc6455.hpp \
|
|
||||||
../include/beast/websocket/ssl.hpp \
|
|
||||||
../include/beast/websocket/static_string.hpp \
|
|
||||||
../include/beast/websocket/stream.hpp \
|
|
||||||
../include/beast/websocket/teardown.hpp \
|
|
||||||
|
|
||||||
INPUT_ENCODING = UTF-8
|
INPUT_ENCODING = UTF-8
|
||||||
FILE_PATTERNS =
|
FILE_PATTERNS =
|
||||||
@@ -5,7 +5,11 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:Body Body]
|
[section:Body Body requirements]
|
||||||
|
|
||||||
|
A [*Body] type is supplied as a template argument to the __message__ class. It
|
||||||
|
controls both the type of the data member of the resulting message object, and
|
||||||
|
the algorithms used during parsing and serialization.
|
||||||
|
|
||||||
In this table:
|
In this table:
|
||||||
|
|
||||||
@@ -22,17 +26,12 @@ In this table:
|
|||||||
will be not movable or not copyable.
|
will be not movable or not copyable.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
|
||||||
[`X:value_type{}`]
|
|
||||||
[]
|
|
||||||
[`DefaultConstructible`]
|
|
||||||
]
|
|
||||||
[
|
[
|
||||||
[`Body::reader`]
|
[`Body::reader`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
If present, a type meeting the requirements of
|
If present, a type meeting the requirements of
|
||||||
[link beast.types.Reader [*`Reader`]].
|
[link beast.ref.Reader [*`Reader`]].
|
||||||
Provides an implementation to parse the body.
|
Provides an implementation to parse the body.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@@ -41,7 +40,7 @@ In this table:
|
|||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
If present, a type meeting the requirements of
|
If present, a type meeting the requirements of
|
||||||
[link beast.types.Writer [*`Writer`]].
|
[link beast.ref.Writer [*`Writer`]].
|
||||||
Provides an implementation to serialize the body.
|
Provides an implementation to serialize the body.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:BufferSequence BufferSequence]
|
[section:BufferSequence BufferSequence requirements]
|
||||||
|
|
||||||
A `BufferSequence` is a type meeting either of the following requirements:
|
A `BufferSequence` is a type meeting either of the following requirements:
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:DynamicBuffer DynamicBuffer]
|
[section:DynamicBuffer DynamicBuffer requirements]
|
||||||
|
|
||||||
A dynamic buffer encapsulates memory storage that may be automatically resized
|
A dynamic buffer encapsulates memory storage that may be automatically resized
|
||||||
as required, where the memory is divided into an input sequence followed by an
|
as required, where the memory is divided into an input sequence followed by an
|
||||||
@@ -27,7 +27,7 @@ implementation strategies:
|
|||||||
|
|
||||||
* A sequence of one or more octet arrays of varying sizes. Additional octet
|
* A sequence of one or more octet arrays of varying sizes. Additional octet
|
||||||
array objects are appended to the sequence to accommodate changes in the
|
array objects are appended to the sequence to accommodate changes in the
|
||||||
size of the character sequence. This is the implementation approached
|
size of the character sequence. This is the implementation approach
|
||||||
currently offered by [link beast.ref.basic_streambuf `basic_streambuf`].
|
currently offered by [link beast.ref.basic_streambuf `basic_streambuf`].
|
||||||
|
|
||||||
In the table below:
|
In the table below:
|
||||||
@@ -88,7 +88,7 @@ In the table below:
|
|||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.prepare(n)`]
|
[`a.prepare(n)`]
|
||||||
[`X:mutable_buffers_type`]
|
[`X::mutable_buffers_type`]
|
||||||
[
|
[
|
||||||
Returns a mutable buffer sequence u representing the output sequence,
|
Returns a mutable buffer sequence u representing the output sequence,
|
||||||
and where `buffer_size(u) == n`. The dynamic buffer reallocates memory
|
and where `buffer_size(u) == n`. The dynamic buffer reallocates memory
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:Field Field]
|
[section:Field Field requirements]
|
||||||
|
|
||||||
A [*`Field`] represents a single HTTP header field/value pair.
|
A [*`Field`] represents a single HTTP header field/value pair.
|
||||||
|
|
||||||
|
|||||||
@@ -5,16 +5,17 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:FieldSequence FieldSequence]
|
[section:FieldSequence FieldSequence requirements]
|
||||||
|
|
||||||
A [*`FieldSequence`] is an iterable container whose value type meets
|
A [*FieldSequence] is an iterable container whose value type meets
|
||||||
the requirements of [link beast.types.Field [*`Field`]].
|
the requirements of [link beast.ref.Field [*Field]]. Objects that meet
|
||||||
|
these requirements become serializable by the implementation.
|
||||||
|
|
||||||
In this table:
|
In this table:
|
||||||
|
|
||||||
* `X` denotes a type that meets the requirements of [*`FieldSequence`].
|
* `X` denotes a type that meets the requirements of [*FieldSequence].
|
||||||
|
|
||||||
* `a` is a value of type `X`.
|
* `c` is a value of type `X const`.
|
||||||
|
|
||||||
[table FieldSequence requirements
|
[table FieldSequence requirements
|
||||||
[[operation][type][semantics, pre/post-conditions]]
|
[[operation][type][semantics, pre/post-conditions]]
|
||||||
@@ -22,25 +23,33 @@ In this table:
|
|||||||
[`X::value_type`]
|
[`X::value_type`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
A type that meets the requirements of `Field`.
|
A type that meets the requirements of [link beast.ref.Field [*Field]].
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`X::const_iterator`]
|
[`X::const_iterator`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
A type that meets the requirements of `ForwardIterator`.
|
An iterator type whose `reference` type meets the
|
||||||
|
requirements of [link beast.ref.Field [*Field]], and which
|
||||||
|
satisfies all the requirements of [*ForwardIterator],
|
||||||
|
except that:
|
||||||
|
|
||||||
|
[ordered_list
|
||||||
|
[there is no requirement that `operator->` is provided, and]
|
||||||
|
[there is no requirement that `reference` be a reference type.]
|
||||||
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.begin()`]
|
[`c.begin()`]
|
||||||
[`X::const_iterator`]
|
[`X::const_iterator`]
|
||||||
[
|
[
|
||||||
Returns an iterator to the beginning of the field sequence.
|
Returns an iterator to the beginning of the field sequence.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.end()`]
|
[`c.end()`]
|
||||||
[`X::const_iterator`]
|
[`X::const_iterator`]
|
||||||
[
|
[
|
||||||
Returns an iterator to the end of the field sequence.
|
Returns an iterator to the end of the field sequence.
|
||||||
|
|||||||
@@ -5,19 +5,22 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:Parser Parser]
|
[section:Parser Parser requirements]
|
||||||
|
|
||||||
A [*`Parser`] is used to deserialize HTTP/1 messages from [link beast.types.streams streams].
|
A [*Parser] is used to deserialize objects from
|
||||||
Objects of this type are used with [link beast.ref.http__parse http::parse] and
|
[link beast.ref.streams streams]. Objects of this type are used with
|
||||||
[link beast.ref.http__async_parse http::async_parse].
|
[link beast.ref.http__parse http::parse] and
|
||||||
|
[link beast.ref.http__async_parse http::async_parse]. The definition of
|
||||||
|
an object, and the predicate defining when the parse is complete, are
|
||||||
|
determined by the implementation.
|
||||||
|
|
||||||
In this table:
|
In this table:
|
||||||
|
|
||||||
* `X` denotes a type meeting the requirements of [*`Parser`].
|
* `X` denotes a type meeting the requirements of [*Parser].
|
||||||
|
|
||||||
* `a` denotes a value of type `X`.
|
* `a` denotes a value of type `X`.
|
||||||
|
|
||||||
* `b` is a value meeting the requirements of [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConvertibleToConstBuffer.html [*`ConvertibleToConstBuffer`]].
|
* `b` is a value meeting the requirements of __ConstBufferSequence__.
|
||||||
|
|
||||||
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
||||||
|
|
||||||
@@ -27,18 +30,18 @@ In this table:
|
|||||||
[`a.complete()`]
|
[`a.complete()`]
|
||||||
[`bool`]
|
[`bool`]
|
||||||
[
|
[
|
||||||
Returns `true` when a complete HTTP/1 message has been parsed.
|
Returns `true` when parsing is complete.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.write(b, ec)`]
|
[`a.write(b, ec)`]
|
||||||
[`std::size_t`]
|
[`std::size_t`]
|
||||||
[
|
[
|
||||||
Parses the octets in the specified input buffer sequentially until
|
Sequentially parses the octets in the specified input buffer sequence
|
||||||
an error occurs, the end of the buffer is reached, or a complete
|
until an error occurs, the end of the buffer is reached, or parsing is
|
||||||
HTTP/1 message has been parsed. If an error occurs, `ec` is set
|
complete. Upon success, this function returns the number of bytes used
|
||||||
to the error code and parsing stops. This function returns the
|
from the input. If an error occurs, `ec` is set to the error code and
|
||||||
number of bytes consumed from the input buffer.
|
parsing stops.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
@@ -48,9 +51,9 @@ In this table:
|
|||||||
Indicates to the parser that no more octets will be available.
|
Indicates to the parser that no more octets will be available.
|
||||||
Typically this function is called when the end of stream is reached.
|
Typically this function is called when the end of stream is reached.
|
||||||
For example, if a call to `boost::asio::ip::tcp::socket::read_some`
|
For example, if a call to `boost::asio::ip::tcp::socket::read_some`
|
||||||
generates a `boost::asio::error::eof` error. Some HTTP/1 messages
|
generates a `boost::asio::error::eof` error. Some objects, such as
|
||||||
determine the end of the message body by an end of file marker or
|
certain HTTP/1 messages, determine the end of the message body by
|
||||||
closing of the connection.
|
an end of file marker or closing of the connection.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:Reader Reader]
|
[section:Reader Reader requirements]
|
||||||
|
|
||||||
Parser implementations will construct the corresponding `reader` object
|
Parsers provided by the implementation will construct the corresponding
|
||||||
during the parse. This customization point allows the Body to determine
|
`reader` object during parsing. This customization point allows the
|
||||||
the strategy for storing incoming message body data.
|
Body to determine the strategy for storing incoming message body data.
|
||||||
|
|
||||||
In this table:
|
In this table:
|
||||||
|
|
||||||
@@ -17,15 +17,14 @@ In this table:
|
|||||||
|
|
||||||
* `a` denotes a value of type `X`.
|
* `a` denotes a value of type `X`.
|
||||||
|
|
||||||
* `p` is any pointer.
|
|
||||||
|
|
||||||
* `n` is a value convertible to `std::size_t`.
|
* `n` is a value convertible to `std::size_t`.
|
||||||
|
|
||||||
* `ec` is a value of type `error_code&`.
|
* `p` is a `void const*` to valid memory of at least `n` bytes.
|
||||||
|
|
||||||
* `m` denotes a value of type `message const&` where
|
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
||||||
`std::is_same<decltype(m.body), Body::value_type>:value == true`
|
|
||||||
|
|
||||||
|
* `m` denotes a value of type `message&` where
|
||||||
|
`std::is_same<decltype(m.body), Body::value_type>::value == true`.
|
||||||
|
|
||||||
[table Reader requirements
|
[table Reader requirements
|
||||||
[[operation] [type] [semantics, pre/post-conditions]]
|
[[operation] [type] [semantics, pre/post-conditions]]
|
||||||
@@ -33,22 +32,38 @@ In this table:
|
|||||||
[`X a(m);`]
|
[`X a(m);`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
`a` is constructible from `m`. The lifetime of `m` is
|
`a` is constructible from `m`. The lifetime of `m` is guaranteed
|
||||||
guaranteed to end no earlier than after `a` is destroyed.
|
to end no earlier than after `a` is destroyed. The constructor
|
||||||
|
will be called after all headers have been stored in `m`, and
|
||||||
|
before any body data is deserialized. This function must be
|
||||||
|
`noexcept`.
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[
|
||||||
|
[`a.init(ec)`]
|
||||||
|
[`void`]
|
||||||
|
[
|
||||||
|
Called immediately after construction. If the function sets
|
||||||
|
an error code in `ec`, the parse is aborted and the error is
|
||||||
|
propagated to the caller. This function must be `noexcept`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.write(p, n, ec)`]
|
[`a.write(p, n, ec)`]
|
||||||
[`void`]
|
[`void`]
|
||||||
[
|
[
|
||||||
Deserializes the input sequence into the body.
|
Deserializes the input sequence into the body. If `ec` is set,
|
||||||
If `ec` is set, the deserialization is aborted and the error
|
the deserialization is aborted and the error is propagated to
|
||||||
is returned to the caller.
|
the caller. If the message headers specify a chunked transfer
|
||||||
|
encoding, the reader will receive the decoded version of the
|
||||||
|
body. This function must be `noexcept`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
[note Definitions for required `Reader` member functions should be declared
|
[note
|
||||||
inline so the generated code becomes part of the implementation. ]
|
Definitions for required `Reader` member functions should be declared
|
||||||
|
inline so the generated code can become part of the implementation.
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:streams Streams]
|
[section:streams Streams requirements]
|
||||||
|
|
||||||
Stream types represent objects capable of performing synchronous or
|
Stream types represent objects capable of performing synchronous or
|
||||||
asynchronous I/O. They are based on concepts from `boost::asio`.
|
asynchronous I/O. They are based on concepts from `boost::asio`.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[section:Writer Writer]
|
[section:Writer Writer requirements]
|
||||||
|
|
||||||
A `Writer` serializes the message body. The implementation creates an instance
|
A `Writer` serializes the message body. The implementation creates an instance
|
||||||
of this type when serializing a message, and calls into it zero or more times
|
of this type when serializing a message, and calls into it zero or more times
|
||||||
@@ -28,13 +28,13 @@ In this table:
|
|||||||
* `m` denotes a value of type `message const&` where
|
* `m` denotes a value of type `message const&` where
|
||||||
`std::is_same<decltype(m.body), Body::value_type>:value == true`.
|
`std::is_same<decltype(m.body), Body::value_type>:value == true`.
|
||||||
|
|
||||||
* `rc` is an object of type [link beast.ref.http__resume_context resume_context].
|
* `rc` is an object of type [link beast.ref.http__resume_context `resume_context`].
|
||||||
|
|
||||||
* `ec` is a value of type `error_code&`.
|
* `ec` is a value of type [link beast.ref.error_code `error_code&`]
|
||||||
|
|
||||||
* `wf` is a [*write function]: a function object of unspecified type provided
|
* `wf` is a [*write function]: a function object of unspecified type provided
|
||||||
by the implementation which accepts any value meeting the requirements
|
by the implementation which accepts any value meeting the requirements
|
||||||
of `ConstBufferSequence` as its single parameter.
|
of __ConstBufferSequence__ as its single parameter.
|
||||||
|
|
||||||
[table Writer requirements
|
[table Writer requirements
|
||||||
[[operation] [type] [semantics, pre/post-conditions]]
|
[[operation] [type] [semantics, pre/post-conditions]]
|
||||||
@@ -42,17 +42,18 @@ In this table:
|
|||||||
[`X a(m);`]
|
[`X a(m);`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
`a` is constructible from `m`. The lifetime of `m` is
|
`a` is constructible from `m`. The lifetime of `m` is guaranteed
|
||||||
guaranteed to end no earlier than after `a` is destroyed.
|
to end no earlier than after `a` is destroyed. This function must
|
||||||
|
be `noexcept`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.init(ec)`]
|
[`a.init(ec)`]
|
||||||
[`void`]
|
[`void`]
|
||||||
[
|
[
|
||||||
Called immediately after construction.
|
Called immediately after construction. If the function sets an
|
||||||
If `ec` is set, the serialization is aborted and the error
|
error code in `ec`, the serialization is aborted and the error
|
||||||
is propagated to the caller.
|
is propagated to the caller. This function must be `noexcept`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
@@ -67,31 +68,33 @@ In this table:
|
|||||||
the serialized message body will be sent unmodified, with the
|
the serialized message body will be sent unmodified, with the
|
||||||
error `boost::asio::error::eof` returned to the caller, to notify
|
error `boost::asio::error::eof` returned to the caller, to notify
|
||||||
they should close the connection to indicate the end of the message.
|
they should close the connection to indicate the end of the message.
|
||||||
|
This function must be `noexcept`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a(rc, ec, wf)`]
|
[`a.write(rc, ec, wf)`]
|
||||||
[`boost::tribool`]
|
[`boost::tribool`]
|
||||||
[
|
[
|
||||||
Called repeatedly after `init` succeeds.
|
Called repeatedly after `init` succeeds. `wf` is a function object
|
||||||
`wf` is a function object which takes as its single parameter,
|
which takes as its single parameter any value meeting the requirements
|
||||||
any value meeting the requirements of `ConstBufferSequence`.
|
of __ConstBufferSequence__. Buffers provided to this write function
|
||||||
Buffers provided by the `writer` to this [*write function] must
|
must remain valid until the next member function of `writer` is
|
||||||
remain valid until the next member function of `writer` is
|
|
||||||
invoked (which may be the destructor). This function returns `true`
|
invoked (which may be the destructor). This function returns `true`
|
||||||
to indicate all message body data has been written, or `false`
|
to indicate all message body data has been written, or `false` if
|
||||||
if there is more body data. If the return value is
|
there is more body data. If the return value is `boost::indeterminate`,
|
||||||
`boost::indeterminate`, the implementation will suspend the operation
|
the implementation will suspend the operation until the writer invokes
|
||||||
until the writer invokes `rc`. It is the writers responsibility when
|
`rc`. It is the writers responsibility when returning
|
||||||
returning `boost::indeterminate`, to acquire ownership of the
|
`boost::indeterminate`, to acquire ownership of `rc` via move
|
||||||
`resume_context` via move construction and eventually call it or else
|
construction and eventually call it or else undefined behavior
|
||||||
undefined behavior results.
|
results. This function must be `noexcept`.
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
[note Definitions for required `Writer` member functions should be declared
|
[note
|
||||||
inline so the generated code becomes part of the implementation. ]
|
Definitions for required `Writer` member functions should be declared
|
||||||
|
inline so the generated code can become part of the implementation.
|
||||||
|
]
|
||||||
|
|
||||||
Exemplar:
|
Exemplar:
|
||||||
```
|
```
|
||||||
@@ -109,7 +112,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<bool isRequest, class Body, class Headers>
|
template<bool isRequest, class Body, class Headers>
|
||||||
explicit
|
explicit
|
||||||
writer(message<isRequest, Body, Headers> const& msg);
|
writer(message<isRequest, Body, Headers> const& msg) noexcept;
|
||||||
|
|
||||||
/** Initialize the writer.
|
/** Initialize the writer.
|
||||||
|
|
||||||
@@ -119,7 +122,7 @@ public:
|
|||||||
@param ec Contains the error code if any errors occur.
|
@param ec Contains the error code if any errors occur.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
init(error_code& ec);
|
init(error_code& ec) noexcept;
|
||||||
|
|
||||||
/** Returns the content length.
|
/** Returns the content length.
|
||||||
|
|
||||||
@@ -128,8 +131,8 @@ public:
|
|||||||
use chunk-encoding or terminate the connection to indicate the end
|
use chunk-encoding or terminate the connection to indicate the end
|
||||||
of the message.
|
of the message.
|
||||||
*/
|
*/
|
||||||
std::size_t
|
std::uint64_t
|
||||||
content_length() const;
|
content_length() noexcept;
|
||||||
|
|
||||||
/** Write zero or one buffer representing the message body.
|
/** Write zero or one buffer representing the message body.
|
||||||
|
|
||||||
@@ -172,7 +175,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<class WriteFunction>
|
template<class WriteFunction>
|
||||||
boost::tribool
|
boost::tribool
|
||||||
operator()(resume_context&&, error_code&, WriteFunction&& write);
|
write(
|
||||||
|
resume_context&&,
|
||||||
|
error_code&,
|
||||||
|
WriteFunction&& wf) noexcept;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,21 @@
|
|||||||
|
|
||||||
[section:websocket WebSocket]
|
[section:websocket WebSocket]
|
||||||
|
|
||||||
|
[block '''
|
||||||
|
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||||
|
<member><link linkend="beast.websocket.creation">Creation</link></member>
|
||||||
|
<member><link linkend="beast.websocket.connections">Making connections</link></member>
|
||||||
|
<member><link linkend="beast.websocket.handshaking">Handshaking</link></member>
|
||||||
|
<member><link linkend="beast.websocket.messages">Messages</link></member>
|
||||||
|
<member><link linkend="beast.websocket.frames">Frames</link></member>
|
||||||
|
<member><link linkend="beast.websocket.control">Control Frames</link></member>
|
||||||
|
<member><link linkend="beast.websocket.buffers">Buffers</link></member>
|
||||||
|
<member><link linkend="beast.websocket.async">Asynchronous interface</link></member>
|
||||||
|
<member><link linkend="beast.websocket.io_service">The io_service</link></member>
|
||||||
|
<member><link linkend="beast.websocket.threads">Thread Safety</link></member>
|
||||||
|
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||||
|
''']
|
||||||
|
|
||||||
The WebSocket Protocol enables two-way communication between a client
|
The WebSocket Protocol enables two-way communication between a client
|
||||||
running untrusted code in a controlled environment to a remote host that has
|
running untrusted code in a controlled environment to a remote host that has
|
||||||
opted-in to communications from that code. The protocol consists of an opening
|
opted-in to communications from that code. The protocol consists of an opening
|
||||||
@@ -22,77 +37,57 @@ C++ approach.
|
|||||||
The WebSocket protocol is described fully in
|
The WebSocket protocol is described fully in
|
||||||
[@https://tools.ietf.org/html/rfc6455 rfc6455]
|
[@https://tools.ietf.org/html/rfc6455 rfc6455]
|
||||||
|
|
||||||
|
[note
|
||||||
|
The following documentation assumes familiarity with both
|
||||||
[section:motivation Motivation]
|
Boost.Asio and the WebSocket protocol specification described in __rfc6455__.
|
||||||
|
]
|
||||||
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:creating Creating the socket]
|
|
||||||
|
[section:creation Creation]
|
||||||
|
|
||||||
The interface to Beast's WebSocket implementation is a single template
|
The interface to Beast's WebSocket implementation is a single template
|
||||||
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
|
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
|
||||||
wraps a "next layer" object. The next layer object must meet the requirements
|
wraps a "next layer" object. The next layer object must meet the requirements
|
||||||
of [link beast.types.streams.SyncStream [*`SyncReadStream`]] if synchronous
|
of [link beast.ref.streams.SyncStream [*`SyncReadStream`]] if synchronous
|
||||||
operations are performed, or
|
operations are performed, or
|
||||||
[link beast.types.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
[link beast.ref.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
||||||
operations are performed, or both. Arguments supplied during construction are
|
operations are performed, or both. Arguments supplied during construction are
|
||||||
passed to next layer's constructor. Here we declare two websockets which have
|
passed to next layer's constructor. Here we declare a websocket stream over
|
||||||
ownership of the next layer:
|
a TCP/IP socket with ownership of the socket:
|
||||||
```
|
```
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||||
|
|
||||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
|
||||||
beast::websocket::stream<
|
|
||||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> wss(ios, ctx);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[heading Using SSL]
|
||||||
|
|
||||||
|
To use WebSockets over SSL, choose an SSL stream for the next layer template
|
||||||
|
argument when constructing the stream.
|
||||||
|
```
|
||||||
|
#include <beast/websocket/ssl.hpp>
|
||||||
|
#include <beast/websocket.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
|
||||||
|
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ws{ios, ctx};
|
||||||
|
```
|
||||||
|
|
||||||
|
[note
|
||||||
|
When creating websocket stream objects using SSL, it is necessary
|
||||||
|
to include the file `<beast/websocket/ssl.hpp>`.
|
||||||
|
]
|
||||||
|
|
||||||
|
[heading Non-owning references]
|
||||||
|
|
||||||
For servers that can handshake in multiple protocols, it may be desired
|
For servers that can handshake in multiple protocols, it may be desired
|
||||||
to wrap an object that already exists. This socket can be moved in:
|
to wrap an object that already exists. This socket can be moved in:
|
||||||
```
|
```
|
||||||
boost::asio::ip::tcp::socket&& sock;
|
boost::asio::ip::tcp::socket&& sock;
|
||||||
...
|
...
|
||||||
beast::websocket::stream<
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{std::move(sock)};
|
||||||
boost::asio::ip::tcp::socket> ws(std::move(sock));
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, the wrapper can be constructed with a non-owning reference. In
|
Or, the wrapper can be constructed with a non-owning reference. In
|
||||||
@@ -101,36 +96,37 @@ underlying socket being wrapped:
|
|||||||
```
|
```
|
||||||
boost::asio::ip::tcp::socket sock;
|
boost::asio::ip::tcp::socket sock;
|
||||||
...
|
...
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
```
|
```
|
||||||
|
|
||||||
The layer being wrapped can be accessed through the websocket's "next layer",
|
The layer being wrapped can be accessed through the websocket's "next layer",
|
||||||
permitting callers to interact directly with its interface.
|
permitting callers to interact directly with its interface.
|
||||||
```
|
```
|
||||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
|
||||||
beast::websocket::stream<
|
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws{ios, ctx};
|
||||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws(ios, ctx);
|
|
||||||
...
|
...
|
||||||
ws.next_layer().shutdown(); // ssl::stream shutdown
|
ws.next_layer().shutdown(); // ssl::stream shutdown
|
||||||
```
|
```
|
||||||
|
|
||||||
[important Initiating read and write operations on the next layer while
|
[warning
|
||||||
websocket operations are being performed can break invariants, and
|
Initiating read and write operations on the next layer while
|
||||||
result in undefined behavior. ]
|
stream operations are being performed can break invariants, and
|
||||||
|
result in undefined behavior.
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:connecting Making connections]
|
[section:connections Making connections]
|
||||||
|
|
||||||
Connections are established by using the interfaces which already exist
|
Connections are established by using the interfaces which already exist
|
||||||
for the next layer. For example, making an outgoing connection:
|
for the next layer. For example, making an outgoing connection:
|
||||||
```
|
```
|
||||||
std::string const host = "mywebapp.com";
|
std::string const host = "mywebapp.com";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||||
boost::asio::connect(ws.next_layer(),
|
boost::asio::connect(ws.next_layer(),
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"}));
|
||||||
```
|
```
|
||||||
@@ -139,12 +135,14 @@ Accepting an incoming connection:
|
|||||||
```
|
```
|
||||||
void do_accept(boost::asio::ip::tcp::acceptor& acceptor)
|
void do_accept(boost::asio::ip::tcp::acceptor& acceptor)
|
||||||
{
|
{
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(acceptor.get_io_service());
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{acceptor.get_io_service()};
|
||||||
acceptor.accept(ws.next_layer());
|
acceptor.accept(ws.next_layer());
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[note Examples use synchronous interfaces for clarity of exposition. ]
|
[note
|
||||||
|
Examples use synchronous interfaces for clarity of exposition.
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -156,16 +154,17 @@ A WebSocket session begins when one side sends the HTTP Upgrade request
|
|||||||
for websocket, and the other side sends an appropriate HTTP response
|
for websocket, and the other side sends an appropriate HTTP response
|
||||||
indicating that the request was accepted and that the connection has
|
indicating that the request was accepted and that the connection has
|
||||||
been upgraded. The HTTP Upgrade request must include the Host HTTP field,
|
been upgraded. The HTTP Upgrade request must include the Host HTTP field,
|
||||||
and the URI of the resource to request. `handshake` is used to send the
|
and the URI of the resource to request.
|
||||||
|
[link beast.ref.websocket__stream.handshake `handshake`] is used to send the
|
||||||
request with the required host and resource strings.
|
request with the required host and resource strings.
|
||||||
```
|
```
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||||
...
|
...
|
||||||
ws.set_option(beast::websocket::keep_alive(true));
|
ws.set_option(beast::websocket::keep_alive(true));
|
||||||
ws.handshake("ws.example.com:80", "/cgi-bin/bitcoin-prices");
|
ws.handshake("ws.example.com:80", "/cgi-bin/bitcoin-prices");
|
||||||
```
|
```
|
||||||
|
|
||||||
The [link beast.ref.websocket__stream `beast::websocket::stream`] automatically
|
The [link beast.ref.websocket__stream `stream`] automatically
|
||||||
handles receiving and processing the HTTP response to the handshake request.
|
handles receiving and processing the HTTP response to the handshake request.
|
||||||
The call to handshake is successful if a HTTP response is received with the
|
The call to handshake is successful if a HTTP response is received with the
|
||||||
101 "Switching Protocols" status code. On failure, an error is returned or an
|
101 "Switching Protocols" status code. On failure, an error is returned or an
|
||||||
@@ -175,7 +174,7 @@ open for a subsequent handshake attempt
|
|||||||
Performing a handshake for an incoming websocket upgrade request operates
|
Performing a handshake for an incoming websocket upgrade request operates
|
||||||
similarly. If the handshake fails, an error is returned or exception thrown:
|
similarly. If the handshake fails, an error is returned or exception thrown:
|
||||||
```
|
```
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||||
...
|
...
|
||||||
ws.accept();
|
ws.accept();
|
||||||
```
|
```
|
||||||
@@ -190,7 +189,7 @@ void do_accept(boost::asio::ip::tcp::socket& sock)
|
|||||||
boost::asio::streambuf sb;
|
boost::asio::streambuf sb;
|
||||||
boost::asio::read_until(sock, sb, "\r\n\r\n");
|
boost::asio::read_until(sock, sb, "\r\n\r\n");
|
||||||
...
|
...
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
ws.accept(sb.data());
|
ws.accept(sb.data());
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
@@ -203,10 +202,10 @@ void do_accept(boost::asio::ip::tcp::socket& sock)
|
|||||||
{
|
{
|
||||||
boost::asio::streambuf sb;
|
boost::asio::streambuf sb;
|
||||||
beast::http::request<http::empty_body> request;
|
beast::http::request<http::empty_body> request;
|
||||||
beast::http::read(sock, request);
|
beast::http::read(sock, sb, request);
|
||||||
if(beast::http::is_upgrade(request))
|
if(beast::http::is_upgrade(request))
|
||||||
{
|
{
|
||||||
websocket::stream<ip::tcp::socket&> ws(sock);
|
websocket::stream<ip::tcp::socket&> ws{sock};
|
||||||
ws.accept(request);
|
ws.accept(request);
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
@@ -227,17 +226,19 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
|||||||
{
|
{
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
beast::websocket::opcode::value op;
|
beast::websocket::opcode::value op;
|
||||||
ws.read(sb);
|
ws.read(op, sb);
|
||||||
|
|
||||||
ws.set_option(beast::websocket::message_type(op));
|
ws.set_option(beast::websocket::message_type{op});
|
||||||
ws.write(sb.data());
|
ws.write(sb.data());
|
||||||
sb.consume(sb.size());
|
sb.consume(sb.size());
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[important Calls to [link beast.ref.websocket__stream.set_option `set_option`]
|
[important
|
||||||
must be made from the same implicit or explicit strand as that used to perform
|
Calls to [link beast.ref.websocket__stream.set_option `set_option`]
|
||||||
other operations. ]
|
must be made from the same implicit or explicit strand as that used
|
||||||
|
to perform other operations.
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -265,9 +266,9 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
|||||||
if(fi.fin)
|
if(fi.fin)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ws.set_option(beast::websocket::message_type(fi.op));
|
ws.set_option(beast::websocket::message_type{fi.op});
|
||||||
beast::consuming_buffers<
|
beast::consuming_buffers<
|
||||||
beast::streambuf::const_buffers_type> cb(sb.data());
|
beast::streambuf::const_buffers_type> cb{sb.data()};
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
@@ -290,46 +291,49 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:controlframes Control frames]
|
[section:control Control Frames]
|
||||||
|
|
||||||
During read operations, the implementation automatically reads and processes
|
Control frames are small (less than 128 bytes) messages entirely contained
|
||||||
WebSocket control frames such as ping, pong, and close. Pings are replied
|
in an individual WebSocket frame. They may be sent at any time by either
|
||||||
to as soon as possible, pongs are delivered to the pong callback. The receipt
|
peer on an established connection, and can appear in between continuation
|
||||||
of a close frame initiates the WebSocket close procedure, eventually resulting
|
frames for a message. There are three types of control frames: ping, pong,
|
||||||
in the error code [link beast.ref.websocket__error `error::closed`] being
|
and close.
|
||||||
delivered to the caller in a subsequent read operation, assuming no other error
|
|
||||||
|
A sent ping indicates a request that the sender wants to receive a pong. A
|
||||||
|
pong is a response to a ping. Pongs may be sent unsolicited, at any time.
|
||||||
|
One use for an unsolicited pong is to inform the remote peer that the
|
||||||
|
session is still active after a long period of inactivity. A close frame
|
||||||
|
indicates that the remote peer wishes to close the WebSocket connection.
|
||||||
|
The connection is considered gracefully closed when each side has sent
|
||||||
|
and received a close frame.
|
||||||
|
|
||||||
|
During read operations, Beast automatically reads and processes control
|
||||||
|
frames. Pings are replied to as soon as possible with a pong, received
|
||||||
|
pongs are delivered to the pong callback. The receipt of a close frame
|
||||||
|
initiates the WebSocket close procedure, eventually resulting in the error
|
||||||
|
code [link beast.ref.websocket__error `error::closed`] being delivered
|
||||||
|
to the caller in a subsequent read operation, assuming no other error
|
||||||
takes place.
|
takes place.
|
||||||
|
|
||||||
To ensure timely delivery of control frames, large messages are broken up
|
A consequence of this automatic behavior is that caller-initiated read
|
||||||
into smaller sized frames. The implementation chooses the size and number
|
operations can cause socket writes. However, these writes will not
|
||||||
of the frames making up the message. The automatic fragment size option
|
compete with caller-initiated write operations. For the purposes of
|
||||||
gives callers control over the size of these frames:
|
correctness with respect to the stream invariants, caller-initiated
|
||||||
```
|
read operations still only count as a read. This means that callers can
|
||||||
...
|
have a simultaneous active read and write operation in progress, while
|
||||||
ws.set_option(beast::websocket::auto_fragment_size(8192));
|
the implementation also automatically handles control frames.
|
||||||
```
|
|
||||||
|
|
||||||
The WebSocket protocol defines a procedure and control message for initiating
|
[heading Ping and Pong Frames]
|
||||||
a close of the session. Handling of close initiated by the remote end of the
|
|
||||||
connection is performed automatically. To manually initiate a close, use
|
|
||||||
[link beast.ref.websocket__stream.close `close`]:
|
|
||||||
```
|
|
||||||
ws.close();
|
|
||||||
```
|
|
||||||
|
|
||||||
[note To receive the [link beast.ref.websocket__error `error::closed`]
|
Ping and pong messages are control frames which may be sent at any time
|
||||||
error, a read operation is required. ]
|
by either peer on an established WebSocket connection. They are sent
|
||||||
|
using the functions
|
||||||
[endsect]
|
[link beast.ref.websocket__stream.ping `ping`] and
|
||||||
|
[link beast.ref.websocket__stream.pong `pong`].
|
||||||
|
|
||||||
|
|
||||||
[section:pongs Pong messages]
|
|
||||||
|
|
||||||
To receive pong control frames, callers may register a "pong callback" using
|
To receive pong control frames, callers may register a "pong callback" using
|
||||||
[link beast.ref.websocket__stream.set_option `set_option`]:
|
[link beast.ref.websocket__stream.set_option `set_option`]. The object provided
|
||||||
|
with this option should be callable with the following signature:
|
||||||
the following signature:
|
|
||||||
```
|
```
|
||||||
void on_pong(ping_data const& payload);
|
void on_pong(ping_data const& payload);
|
||||||
...
|
...
|
||||||
@@ -346,9 +350,47 @@ reset when a pong is received. The same callback is used for both synchronous
|
|||||||
and asynchronous reads. The pong callback is passive; in order to receive
|
and asynchronous reads. The pong callback is passive; in order to receive
|
||||||
pongs, a synchronous or asynchronous stream read function must be active.
|
pongs, a synchronous or asynchronous stream read function must be active.
|
||||||
|
|
||||||
[note When an asynchronous read function receives a pong, the the pong callback
|
[note
|
||||||
is invoked in the same manner as that used to invoke the final completion
|
When an asynchronous read function receives a pong, the the pong
|
||||||
handler of the corresponding read function.]
|
callback is invoked in the same manner as that used to invoke the
|
||||||
|
final completion handler of the corresponding read function.
|
||||||
|
]
|
||||||
|
|
||||||
|
[heading Close Frames]
|
||||||
|
|
||||||
|
The WebSocket protocol defines a procedure and control message for initiating
|
||||||
|
a close of the session. Handling of close initiated by the remote end of the
|
||||||
|
connection is performed automatically. To manually initiate a close, use
|
||||||
|
the [link beast.ref.websocket__stream.close `close`] function:
|
||||||
|
```
|
||||||
|
ws.close();
|
||||||
|
```
|
||||||
|
|
||||||
|
When the remote peer initiates a close by sending a close frame, Beast
|
||||||
|
will handle it for you by causing the next read to return `error::closed`.
|
||||||
|
When this error code is delivered, it indicates to the application that
|
||||||
|
the WebSocket connection has been closed cleanly, and that the TCP/IP
|
||||||
|
connection has been closed. After initiating a close, it is necessary to
|
||||||
|
continue reading messages until receiving the error `error::closed`. This
|
||||||
|
is because the remote peer may still be sending message and control frames
|
||||||
|
before it receives and responds to the close frame.
|
||||||
|
|
||||||
|
[important
|
||||||
|
To receive the [link beast.ref.websocket__error `error::closed`]
|
||||||
|
error, a read operation is required.
|
||||||
|
]
|
||||||
|
|
||||||
|
[heading Auto-fragment]
|
||||||
|
|
||||||
|
To ensure timely delivery of control frames, large messages can be broken up
|
||||||
|
into smaller sized frames. The automatic fragment option turns on this
|
||||||
|
feature, and the write buffer size option determines the maximum size of
|
||||||
|
the fragments:
|
||||||
|
```
|
||||||
|
...
|
||||||
|
ws.set_option(beast::websocket::auto_fragment{true});
|
||||||
|
ws.set_option(beast::websocket::write_buffer_size{16384});
|
||||||
|
```
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -358,7 +400,7 @@ handler of the corresponding read function.]
|
|||||||
|
|
||||||
Because calls to read data may return a variable amount of bytes, the
|
Because calls to read data may return a variable amount of bytes, the
|
||||||
interface to calls that read data require an object that meets the requirements
|
interface to calls that read data require an object that meets the requirements
|
||||||
of [link beast.types.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on
|
of [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on
|
||||||
[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
|
[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
|
||||||
|
|
||||||
The implementation does not perform queueing or buffering of messages. If
|
The implementation does not perform queueing or buffering of messages. If
|
||||||
@@ -414,7 +456,7 @@ use or require threads.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[section:safety Thread Safety]
|
[section:threads Thread Safety]
|
||||||
|
|
||||||
Like a regular asio socket, a [link beast.ref.websocket__stream `stream`] is
|
Like a regular asio socket, a [link beast.ref.websocket__stream `stream`] is
|
||||||
not thread safe. Callers are responsible for synchronizing operations on the
|
not thread safe. Callers are responsible for synchronizing operations on the
|
||||||
|
|||||||
@@ -1,49 +1,52 @@
|
|||||||
# Part of Beast
|
# Part of Beast
|
||||||
|
|
||||||
GroupSources(extras/beast beast)
|
GroupSources(extras/beast extras)
|
||||||
GroupSources(include/beast beast)
|
GroupSources(include/beast beast)
|
||||||
|
|
||||||
GroupSources(examples "/")
|
GroupSources(examples "/")
|
||||||
|
|
||||||
add_executable (http-crawl
|
add_executable (http-crawl
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
urls_large_data.hpp
|
urls_large_data.hpp
|
||||||
urls_large_data.cpp
|
urls_large_data.cpp
|
||||||
http_crawl.cpp
|
http_crawl.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(http-crawl ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(http-crawl ${Boost_LIBRARIES} Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable (http-server
|
add_executable (http-server
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
file_body.hpp
|
file_body.hpp
|
||||||
|
mime_type.hpp
|
||||||
http_async_server.hpp
|
http_async_server.hpp
|
||||||
http_stream.hpp
|
|
||||||
http_stream.ipp
|
|
||||||
http_sync_server.hpp
|
http_sync_server.hpp
|
||||||
http_server.cpp
|
http_server.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(http-server ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(http-server ${Boost_LIBRARIES} Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable (http-example
|
add_executable (http-example
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
http_example.cpp
|
http_example.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(http-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(http-example ${Boost_LIBRARIES} Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable (websocket-example
|
add_executable (websocket-example
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
|
${EXTRAS_INCLUDES}
|
||||||
websocket_example.cpp
|
websocket_example.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
target_link_libraries(websocket-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(websocket-example ${Boost_LIBRARIES} Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
#
|
#
|
||||||
|
|
||||||
import os ;
|
|
||||||
|
|
||||||
exe http-crawl :
|
exe http-crawl :
|
||||||
http_crawl.cpp
|
http_crawl.cpp
|
||||||
urls_large_data.cpp
|
urls_large_data.cpp
|
||||||
@@ -23,4 +21,3 @@ exe http-example :
|
|||||||
exe websocket-example :
|
exe websocket-example :
|
||||||
websocket_example.cpp
|
websocket_example.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -8,9 +8,12 @@
|
|||||||
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||||
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/http/body_type.hpp>
|
#include <beast/core/error.hpp>
|
||||||
|
#include <beast/http/message.hpp>
|
||||||
|
#include <beast/http/resume_context.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/logic/tribool.hpp>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@@ -23,7 +26,7 @@ struct file_body
|
|||||||
|
|
||||||
class writer
|
class writer
|
||||||
{
|
{
|
||||||
std::uint64_t size_;
|
std::uint64_t size_ = 0;
|
||||||
std::uint64_t offset_ = 0;
|
std::uint64_t offset_ = 0;
|
||||||
std::string const& path_;
|
std::string const& path_;
|
||||||
FILE* file_ = nullptr;
|
FILE* file_ = nullptr;
|
||||||
@@ -34,8 +37,8 @@ struct file_body
|
|||||||
writer(writer const&) = delete;
|
writer(writer const&) = delete;
|
||||||
writer& operator=(writer const&) = delete;
|
writer& operator=(writer const&) = delete;
|
||||||
|
|
||||||
template<bool isRequest, class Headers>
|
template<bool isRequest, class Fields>
|
||||||
writer(message<isRequest, file_body, Headers> const& m) noexcept
|
writer(message<isRequest, file_body, Fields> const& m) noexcept
|
||||||
: path_(m.body)
|
: path_(m.body)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -58,14 +61,15 @@ struct file_body
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t
|
std::uint64_t
|
||||||
content_length() const
|
content_length() const noexcept
|
||||||
{
|
{
|
||||||
return size_;
|
return size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Write>
|
template<class WriteFunction>
|
||||||
boost::tribool
|
boost::tribool
|
||||||
operator()(resume_context&&, error_code&, Write&& write)
|
write(resume_context&&, error_code&,
|
||||||
|
WriteFunction&& wf) noexcept
|
||||||
{
|
{
|
||||||
if(size_ - offset_ < sizeof(buf_))
|
if(size_ - offset_ < sizeof(buf_))
|
||||||
buf_len_ = static_cast<std::size_t>(
|
buf_len_ = static_cast<std::size_t>(
|
||||||
@@ -75,7 +79,7 @@ struct file_body
|
|||||||
auto const nread = fread(buf_, 1, sizeof(buf_), file_);
|
auto const nread = fread(buf_, 1, sizeof(buf_), file_);
|
||||||
(void)nread;
|
(void)nread;
|
||||||
offset_ += buf_len_;
|
offset_ += buf_len_;
|
||||||
write(boost::asio::buffer(buf_, buf_len_));
|
wf(boost::asio::buffer(buf_, buf_len_));
|
||||||
return offset_ >= size_;
|
return offset_ >= size_;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,10 +9,15 @@
|
|||||||
#define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
#define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
||||||
|
|
||||||
#include "file_body.hpp"
|
#include "file_body.hpp"
|
||||||
#include "http_stream.hpp"
|
#include "mime_type.hpp"
|
||||||
|
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
#include <beast/core/handler_helpers.hpp>
|
||||||
|
#include <beast/core/handler_ptr.hpp>
|
||||||
#include <beast/core/placeholders.hpp>
|
#include <beast/core/placeholders.hpp>
|
||||||
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -29,20 +34,22 @@ class http_async_server
|
|||||||
using address_type = boost::asio::ip::address;
|
using address_type = boost::asio::ip::address;
|
||||||
using socket_type = boost::asio::ip::tcp::socket;
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
using req_type = request_v1<string_body>;
|
using req_type = request<string_body>;
|
||||||
using resp_type = response_v1<file_body>;
|
using resp_type = response<file_body>;
|
||||||
|
|
||||||
|
std::mutex m_;
|
||||||
|
bool log_ = true;
|
||||||
boost::asio::io_service ios_;
|
boost::asio::io_service ios_;
|
||||||
socket_type sock_;
|
|
||||||
boost::asio::ip::tcp::acceptor acceptor_;
|
boost::asio::ip::tcp::acceptor acceptor_;
|
||||||
|
socket_type sock_;
|
||||||
std::string root_;
|
std::string root_;
|
||||||
std::vector<std::thread> thread_;
|
std::vector<std::thread> thread_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
http_async_server(endpoint_type const& ep,
|
http_async_server(endpoint_type const& ep,
|
||||||
int threads, std::string const& root)
|
std::size_t threads, std::string const& root)
|
||||||
: sock_(ios_)
|
: acceptor_(ios_)
|
||||||
, acceptor_(ios_)
|
, sock_(ios_)
|
||||||
, root_(root)
|
, root_(root)
|
||||||
{
|
{
|
||||||
acceptor_.open(ep.protocol());
|
acceptor_.open(ep.protocol());
|
||||||
@@ -53,7 +60,7 @@ public:
|
|||||||
std::bind(&http_async_server::on_accept, this,
|
std::bind(&http_async_server::on_accept, this,
|
||||||
beast::asio::placeholders::error));
|
beast::asio::placeholders::error));
|
||||||
thread_.reserve(threads);
|
thread_.reserve(threads);
|
||||||
for(int i = 0; i < threads; ++i)
|
for(std::size_t i = 0; i < threads; ++i)
|
||||||
thread_.emplace_back(
|
thread_.emplace_back(
|
||||||
[&] { ios_.run(); });
|
[&] { ios_.run(); });
|
||||||
}
|
}
|
||||||
@@ -67,13 +74,118 @@ public:
|
|||||||
t.join();
|
t.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
void
|
||||||
|
log(Args const&... args)
|
||||||
|
{
|
||||||
|
if(log_)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_);
|
||||||
|
log_args(args...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template<class Stream, class Handler,
|
||||||
|
bool isRequest, class Body, class Fields>
|
||||||
|
class write_op
|
||||||
|
{
|
||||||
|
struct data
|
||||||
|
{
|
||||||
|
bool cont;
|
||||||
|
Stream& s;
|
||||||
|
message<isRequest, Body, Fields> m;
|
||||||
|
|
||||||
|
data(Handler& handler, Stream& s_,
|
||||||
|
message<isRequest, Body, Fields>&& m_)
|
||||||
|
: cont(beast_asio_helpers::
|
||||||
|
is_continuation(handler))
|
||||||
|
, s(s_)
|
||||||
|
, m(std::move(m_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handler_ptr<data, Handler> d_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
write_op(write_op&&) = default;
|
||||||
|
write_op(write_op const&) = default;
|
||||||
|
|
||||||
|
template<class DeducedHandler, class... Args>
|
||||||
|
write_op(DeducedHandler&& h, Stream& s, Args&&... args)
|
||||||
|
: d_(make_handler_ptr<data, Handler>(
|
||||||
|
std::forward<DeducedHandler>(h), s,
|
||||||
|
std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
(*this)(error_code{}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(error_code ec, bool again = true)
|
||||||
|
{
|
||||||
|
auto& d = *d_;
|
||||||
|
d.cont = d.cont || again;
|
||||||
|
if(! again)
|
||||||
|
{
|
||||||
|
beast::http::async_write(d.s, d.m, std::move(*this));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d_.invoke(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void* asio_handler_allocate(
|
||||||
|
std::size_t size, write_op* op)
|
||||||
|
{
|
||||||
|
return beast_asio_helpers::
|
||||||
|
allocate(size, op->d_.handler());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, write_op* op)
|
||||||
|
{
|
||||||
|
return beast_asio_helpers::
|
||||||
|
deallocate(p, size, op->d_.handler());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
bool asio_handler_is_continuation(write_op* op)
|
||||||
|
{
|
||||||
|
return op->d_->cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Function>
|
||||||
|
friend
|
||||||
|
void asio_handler_invoke(Function&& f, write_op* op)
|
||||||
|
{
|
||||||
|
return beast_asio_helpers::
|
||||||
|
invoke(f, op->d_.handler());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Stream,
|
||||||
|
bool isRequest, class Body, class Fields,
|
||||||
|
class DeducedHandler>
|
||||||
|
static
|
||||||
|
void
|
||||||
|
async_write(Stream& stream, message<
|
||||||
|
isRequest, Body, Fields>&& msg,
|
||||||
|
DeducedHandler&& handler)
|
||||||
|
{
|
||||||
|
write_op<Stream, typename std::decay<DeducedHandler>::type,
|
||||||
|
isRequest, Body, Fields>{std::forward<DeducedHandler>(
|
||||||
|
handler), stream, std::move(msg)};
|
||||||
|
}
|
||||||
|
|
||||||
class peer : public std::enable_shared_from_this<peer>
|
class peer : public std::enable_shared_from_this<peer>
|
||||||
{
|
{
|
||||||
int id_;
|
int id_;
|
||||||
stream<socket_type> stream_;
|
streambuf sb_;
|
||||||
|
socket_type sock_;
|
||||||
|
http_async_server& server_;
|
||||||
boost::asio::io_service::strand strand_;
|
boost::asio::io_service::strand strand_;
|
||||||
std::string root_;
|
|
||||||
req_type req_;
|
req_type req_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -82,16 +194,22 @@ private:
|
|||||||
peer& operator=(peer&&) = delete;
|
peer& operator=(peer&&) = delete;
|
||||||
peer& operator=(peer const&) = delete;
|
peer& operator=(peer const&) = delete;
|
||||||
|
|
||||||
explicit
|
peer(socket_type&& sock, http_async_server& server)
|
||||||
peer(socket_type&& sock, std::string const& root)
|
: sock_(std::move(sock))
|
||||||
: stream_(std::move(sock))
|
, server_(server)
|
||||||
, strand_(stream_.get_io_service())
|
, strand_(sock_.get_io_service())
|
||||||
, root_(root)
|
|
||||||
{
|
{
|
||||||
static int n = 0;
|
static int n = 0;
|
||||||
id_ = ++n;
|
id_ = ++n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fail(error_code ec, std::string what)
|
||||||
|
{
|
||||||
|
if(ec != boost::asio::error::operation_aborted)
|
||||||
|
server_.log("#", id_, " ", what, ": ", ec.message(), "\n");
|
||||||
|
}
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
do_read();
|
do_read();
|
||||||
@@ -99,81 +217,90 @@ private:
|
|||||||
|
|
||||||
void do_read()
|
void do_read()
|
||||||
{
|
{
|
||||||
stream_.async_read(req_, strand_.wrap(
|
async_read(sock_, sb_, req_, strand_.wrap(
|
||||||
std::bind(&peer::on_read, shared_from_this(),
|
std::bind(&peer::on_read, shared_from_this(),
|
||||||
asio::placeholders::error)));
|
asio::placeholders::error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_read(error_code ec)
|
void on_read(error_code const& ec)
|
||||||
{
|
{
|
||||||
if(ec)
|
if(ec)
|
||||||
return fail(ec, "read");
|
return fail(ec, "read");
|
||||||
do_read();
|
|
||||||
auto path = req_.url;
|
auto path = req_.url;
|
||||||
if(path == "/")
|
if(path == "/")
|
||||||
path = "/index.html";
|
path = "/index.html";
|
||||||
path = root_ + path;
|
path = server_.root_ + path;
|
||||||
if(! boost::filesystem::exists(path))
|
if(! boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
response_v1<string_body> resp;
|
response<string_body> res;
|
||||||
resp.status = 404;
|
res.status = 404;
|
||||||
resp.reason = "Not Found";
|
res.reason = "Not Found";
|
||||||
resp.version = req_.version;
|
res.version = req_.version;
|
||||||
resp.headers.replace("Server", "http_async_server");
|
res.fields.insert("Server", "http_async_server");
|
||||||
resp.body = "The file '" + path + "' was not found";
|
res.fields.insert("Content-Type", "text/html");
|
||||||
prepare(resp);
|
res.body = "The file '" + path + "' was not found";
|
||||||
stream_.async_write(std::move(resp),
|
prepare(res);
|
||||||
|
async_write(sock_, std::move(res),
|
||||||
std::bind(&peer::on_write, shared_from_this(),
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
asio::placeholders::error));
|
asio::placeholders::error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resp_type resp;
|
try
|
||||||
resp.status = 200;
|
{
|
||||||
resp.reason = "OK";
|
resp_type res;
|
||||||
resp.version = req_.version;
|
res.status = 200;
|
||||||
resp.headers.replace("Server", "http_async_server");
|
res.reason = "OK";
|
||||||
resp.headers.replace("Content-Type", "text/html");
|
res.version = req_.version;
|
||||||
resp.body = path;
|
res.fields.insert("Server", "http_async_server");
|
||||||
prepare(resp);
|
res.fields.insert("Content-Type", mime_type(path));
|
||||||
stream_.async_write(std::move(resp),
|
res.body = path;
|
||||||
std::bind(&peer::on_write, shared_from_this(),
|
prepare(res);
|
||||||
asio::placeholders::error));
|
async_write(sock_, std::move(res),
|
||||||
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
|
asio::placeholders::error));
|
||||||
|
}
|
||||||
|
catch(std::exception const& e)
|
||||||
|
{
|
||||||
|
response<string_body> res;
|
||||||
|
res.status = 500;
|
||||||
|
res.reason = "Internal Error";
|
||||||
|
res.version = req_.version;
|
||||||
|
res.fields.insert("Server", "http_async_server");
|
||||||
|
res.fields.insert("Content-Type", "text/html");
|
||||||
|
res.body =
|
||||||
|
std::string{"An internal error occurred"} + e.what();
|
||||||
|
prepare(res);
|
||||||
|
async_write(sock_, std::move(res),
|
||||||
|
std::bind(&peer::on_write, shared_from_this(),
|
||||||
|
asio::placeholders::error));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_write(error_code ec)
|
void on_write(error_code ec)
|
||||||
{
|
{
|
||||||
if(ec)
|
if(ec)
|
||||||
fail(ec, "write");
|
fail(ec, "write");
|
||||||
}
|
do_read();
|
||||||
|
|
||||||
private:
|
|
||||||
void
|
|
||||||
fail(error_code ec, std::string what)
|
|
||||||
{
|
|
||||||
if(ec != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
std::cerr <<
|
|
||||||
"#" << std::to_string(id_) << " " <<
|
|
||||||
what << ": " << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
fail(error_code ec, std::string what)
|
log_args()
|
||||||
{
|
{
|
||||||
std::cerr <<
|
}
|
||||||
what << ": " << ec.message() << std::endl;
|
|
||||||
|
template<class Arg, class... Args>
|
||||||
|
void
|
||||||
|
log_args(Arg const& arg, Args const&... args)
|
||||||
|
{
|
||||||
|
std::cerr << arg;
|
||||||
|
log_args(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
maybe_throw(error_code ec, std::string what)
|
fail(error_code ec, std::string what)
|
||||||
{
|
{
|
||||||
if(ec)
|
log(what, ": ", ec.message(), "\n");
|
||||||
{
|
|
||||||
fail(ec, what);
|
|
||||||
throw ec;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -181,12 +308,13 @@ private:
|
|||||||
{
|
{
|
||||||
if(! acceptor_.is_open())
|
if(! acceptor_.is_open())
|
||||||
return;
|
return;
|
||||||
maybe_throw(ec, "accept");
|
if(ec)
|
||||||
|
return fail(ec, "accept");
|
||||||
socket_type sock(std::move(sock_));
|
socket_type sock(std::move(sock_));
|
||||||
acceptor_.async_accept(sock_,
|
acceptor_.async_accept(sock_,
|
||||||
std::bind(&http_async_server::on_accept, this,
|
std::bind(&http_async_server::on_accept, this,
|
||||||
asio::placeholders::error));
|
asio::placeholders::error));
|
||||||
std::make_shared<peer>(std::move(sock), root_)->run();
|
std::make_shared<peer>(std::move(sock), *this)->run();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "http_stream.hpp"
|
|
||||||
#include "urls_large_data.hpp"
|
#include "urls_large_data.hpp"
|
||||||
|
|
||||||
|
#include <beast/core/streambuf.hpp>
|
||||||
|
#include <beast/http.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace beast::http;
|
using namespace beast::http;
|
||||||
@@ -31,23 +33,24 @@ int main(int, char const*[])
|
|||||||
ip::tcp::resolver r(ios);
|
ip::tcp::resolver r(ios);
|
||||||
auto it = r.resolve(
|
auto it = r.resolve(
|
||||||
ip::tcp::resolver::query{host, "http"});
|
ip::tcp::resolver::query{host, "http"});
|
||||||
stream<ip::tcp::socket> hs(ios);
|
ip::tcp::socket sock(ios);
|
||||||
connect(hs.lowest_layer(), it);
|
connect(sock, it);
|
||||||
auto ep = hs.lowest_layer().remote_endpoint();
|
auto ep = sock.remote_endpoint();
|
||||||
request_v1<empty_body> req;
|
request<empty_body> req;
|
||||||
req.method = "GET";
|
req.method = "GET";
|
||||||
req.url = "/";
|
req.url = "/";
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.headers.insert("Host", host +
|
req.fields.insert("Host", host + std::string(":") +
|
||||||
std::string(":") + std::to_string(ep.port()));
|
boost::lexical_cast<std::string>(ep.port()));
|
||||||
req.headers.insert("User-Agent", "beast/http");
|
req.fields.insert("User-Agent", "beast/http");
|
||||||
prepare(req);
|
prepare(req);
|
||||||
hs.write(req);
|
write(sock, req);
|
||||||
response_v1<string_body> resp;
|
response<string_body> res;
|
||||||
hs.read(resp);
|
streambuf sb;
|
||||||
std::cout << resp;
|
beast::http::read(sock, sb, res);
|
||||||
|
std::cout << res;
|
||||||
}
|
}
|
||||||
catch(boost::system::system_error const& ec)
|
catch(beast::system_error const& ec)
|
||||||
{
|
{
|
||||||
std::cerr << host << ": " << ec.what();
|
std::cerr << host << ": " << ec.what();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <beast/http.hpp>
|
#include <beast/http.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -15,24 +16,25 @@ int main()
|
|||||||
// Normal boost::asio setup
|
// Normal boost::asio setup
|
||||||
std::string const host = "boost.org";
|
std::string const host = "boost.org";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
boost::asio::ip::tcp::socket sock(ios);
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
// Send HTTP request using beast
|
// Send HTTP request using beast
|
||||||
beast::http::request_v1<beast::http::empty_body> req;
|
beast::http::request<beast::http::empty_body> req;
|
||||||
req.method = "GET";
|
req.method = "GET";
|
||||||
req.url = "/";
|
req.url = "/";
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
req.fields.replace("Host", host + ":" +
|
||||||
req.headers.replace("User-Agent", "Beast");
|
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||||
|
req.fields.replace("User-Agent", "Beast");
|
||||||
beast::http::prepare(req);
|
beast::http::prepare(req);
|
||||||
beast::http::write(sock, req);
|
beast::http::write(sock, req);
|
||||||
|
|
||||||
// Receive and print HTTP response using beast
|
// Receive and print HTTP response using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
beast::http::response<beast::http::streambuf_body> resp;
|
||||||
beast::http::read(sock, sb, resp);
|
beast::http::read(sock, sb, resp);
|
||||||
std::cout << resp;
|
std::cout << resp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,34 +20,26 @@ int main(int ac, char const* av[])
|
|||||||
po::options_description desc("Options");
|
po::options_description desc("Options");
|
||||||
|
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
("root,r", po::value<std::string>()->implicit_value("."),
|
("root,r", po::value<std::string>()->default_value("."),
|
||||||
"Set the root directory for serving files")
|
"Set the root directory for serving files")
|
||||||
("port,p", po::value<std::uint16_t>()->implicit_value(8080),
|
("port,p", po::value<std::uint16_t>()->default_value(8080),
|
||||||
"Set the port number for the server")
|
"Set the port number for the server")
|
||||||
("ip", po::value<std::string>()->implicit_value("0.0.0.0"),
|
("ip", po::value<std::string>()->default_value("0.0.0.0"),
|
||||||
"Set the IP address to bind to, \"0.0.0.0\" for all")
|
"Set the IP address to bind to, \"0.0.0.0\" for all")
|
||||||
("threads,n", po::value<std::size_t>()->implicit_value(4),
|
("threads,n", po::value<std::size_t>()->default_value(4),
|
||||||
"Set the number of threads to use")
|
"Set the number of threads to use")
|
||||||
("sync,s", "Launch a synchronous server")
|
("sync,s", "Launch a synchronous server")
|
||||||
;
|
;
|
||||||
po::variables_map vm;
|
po::variables_map vm;
|
||||||
po::store(po::parse_command_line(ac, av, desc), vm);
|
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||||
|
|
||||||
std::string root = ".";
|
std::string root = vm["root"].as<std::string>();
|
||||||
if(vm.count("root"))
|
|
||||||
root = vm["root"].as<std::string>();
|
|
||||||
|
|
||||||
std::uint16_t port = 8080;
|
std::uint16_t port = vm["port"].as<std::uint16_t>();
|
||||||
if(vm.count("port"))
|
|
||||||
port = vm["port"].as<std::uint16_t>();
|
|
||||||
|
|
||||||
std::string ip = "0.0.0.0";
|
std::string ip = vm["ip"].as<std::string>();
|
||||||
if(vm.count("ip"))
|
|
||||||
ip = vm["ip"].as<std::string>();
|
|
||||||
|
|
||||||
std::size_t threads = 4;
|
std::size_t threads = vm["threads"].as<std::size_t>();
|
||||||
if(vm.count("threads"))
|
|
||||||
threads = vm["threads"].as<std::size_t>();
|
|
||||||
|
|
||||||
bool sync = vm.count("sync") > 0;
|
bool sync = vm.count("sync") > 0;
|
||||||
|
|
||||||
@@ -57,8 +49,13 @@ int main(int ac, char const* av[])
|
|||||||
endpoint_type ep{address_type::from_string(ip), port};
|
endpoint_type ep{address_type::from_string(ip), port};
|
||||||
|
|
||||||
if(sync)
|
if(sync)
|
||||||
|
{
|
||||||
http_sync_server server(ep, root);
|
http_sync_server server(ep, root);
|
||||||
|
beast::test::sig_wait();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
http_async_server server(ep, threads, root);
|
http_async_server server(ep, threads, root);
|
||||||
beast::test::sig_wait();
|
beast::test::sig_wait();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,480 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
||||||
//
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BEAST_HTTP_STREAM_H_INCLUDED
|
|
||||||
#define BEAST_HTTP_STREAM_H_INCLUDED
|
|
||||||
|
|
||||||
#include <beast/core/async_completion.hpp>
|
|
||||||
#include <beast/core/basic_streambuf.hpp>
|
|
||||||
#include <beast/http.hpp>
|
|
||||||
#include <boost/asio/io_service.hpp>
|
|
||||||
#include <boost/intrusive/list.hpp>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace http {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
class stream_base
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
struct op
|
|
||||||
: boost::intrusive::list_base_hook<
|
|
||||||
boost::intrusive::link_mode<
|
|
||||||
boost::intrusive::normal_link>>
|
|
||||||
{
|
|
||||||
virtual ~op() = default;
|
|
||||||
virtual void operator()() = 0;
|
|
||||||
virtual void cancel() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
using op_list = typename boost::intrusive::make_list<
|
|
||||||
op, boost::intrusive::constant_time_size<false>>::type;
|
|
||||||
|
|
||||||
op_list wr_q_;
|
|
||||||
bool wr_active_ = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // detail
|
|
||||||
|
|
||||||
/** Provides message-oriented functionality using HTTP.
|
|
||||||
|
|
||||||
The stream class template provides asynchronous and blocking
|
|
||||||
message-oriented functionality necessary for clients and servers
|
|
||||||
to utilize the HTTP protocol.
|
|
||||||
|
|
||||||
@par Thread Safety
|
|
||||||
@e Distinct @e objects: Safe.@n
|
|
||||||
@e Shared @e objects: Unsafe. The application must ensure that
|
|
||||||
all asynchronous operations are performed within the same
|
|
||||||
implicit or explicit strand.
|
|
||||||
|
|
||||||
@par Example
|
|
||||||
|
|
||||||
To use the class template with an `ip::tcp::socket`, you would write:
|
|
||||||
|
|
||||||
@code
|
|
||||||
http::stream<ip::tcp::socket> hs(io_service);
|
|
||||||
@endcode
|
|
||||||
Alternatively, you can write:
|
|
||||||
@code
|
|
||||||
ip::tcp::socket sock(io_service);
|
|
||||||
http::stream<ip::tcp::socket&> hs(sock);
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
@note A stream object must not be destroyed while there are
|
|
||||||
pending asynchronous operations associated with it.
|
|
||||||
|
|
||||||
@par Concepts
|
|
||||||
AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
|
|
||||||
*/
|
|
||||||
template<class NextLayer,
|
|
||||||
class Allocator = std::allocator<char>>
|
|
||||||
class stream : public detail::stream_base
|
|
||||||
{
|
|
||||||
NextLayer next_layer_;
|
|
||||||
basic_streambuf<Allocator> rd_buf_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// The type of the next layer.
|
|
||||||
using next_layer_type =
|
|
||||||
typename std::remove_reference<NextLayer>::type;
|
|
||||||
|
|
||||||
/// The type of the lowest layer.
|
|
||||||
using lowest_layer_type =
|
|
||||||
typename next_layer_type::lowest_layer_type;
|
|
||||||
|
|
||||||
/// The type of endpoint of the lowest layer.
|
|
||||||
using endpoint_type =
|
|
||||||
typename lowest_layer_type::endpoint_type;
|
|
||||||
|
|
||||||
/// The protocol of the next layer.
|
|
||||||
using protocol_type =
|
|
||||||
typename lowest_layer_type::protocol_type;
|
|
||||||
|
|
||||||
/// The type of resolver of the next layer.
|
|
||||||
using resolver_type =
|
|
||||||
typename protocol_type::resolver;
|
|
||||||
|
|
||||||
/** Destructor.
|
|
||||||
|
|
||||||
@note A stream object must not be destroyed while there
|
|
||||||
are pending asynchronous operations associated with it.
|
|
||||||
*/
|
|
||||||
~stream();
|
|
||||||
|
|
||||||
/** Move constructor.
|
|
||||||
|
|
||||||
Undefined behavior if operations are active or pending.
|
|
||||||
*/
|
|
||||||
stream(stream&&) = default;
|
|
||||||
|
|
||||||
/** Move assignment.
|
|
||||||
|
|
||||||
Undefined behavior if operations are active or pending.
|
|
||||||
*/
|
|
||||||
stream& operator=(stream&&) = default;
|
|
||||||
|
|
||||||
/** Construct a HTTP stream.
|
|
||||||
|
|
||||||
This constructor creates a HTTP stream and initialises
|
|
||||||
the next layer.
|
|
||||||
|
|
||||||
@throws Any exceptions thrown by the Stream constructor.
|
|
||||||
|
|
||||||
@param args The arguments to be passed to initialise the
|
|
||||||
next layer. The arguments are forwarded to the next layer's
|
|
||||||
constructor.
|
|
||||||
*/
|
|
||||||
template<class... Args>
|
|
||||||
explicit
|
|
||||||
stream(Args&&... args);
|
|
||||||
|
|
||||||
/** Get the io_service associated with the stream.
|
|
||||||
|
|
||||||
This function may be used to obtain the io_service object
|
|
||||||
that the stream uses to dispatch handlers for asynchronous
|
|
||||||
operations.
|
|
||||||
|
|
||||||
@return A reference to the io_service object that the stream
|
|
||||||
will use to dispatch handlers. Ownership is not transferred
|
|
||||||
to the caller.
|
|
||||||
*/
|
|
||||||
boost::asio::io_service&
|
|
||||||
get_io_service()
|
|
||||||
{
|
|
||||||
return next_layer_.lowest_layer().get_io_service();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a reference to the next layer.
|
|
||||||
|
|
||||||
This function returns a reference to the next layer
|
|
||||||
in a stack of stream layers.
|
|
||||||
|
|
||||||
@return A reference to the next layer in the stack of
|
|
||||||
stream layers. Ownership is not transferred to the caller.
|
|
||||||
*/
|
|
||||||
next_layer_type&
|
|
||||||
next_layer()
|
|
||||||
{
|
|
||||||
return next_layer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a reference to the next layer.
|
|
||||||
|
|
||||||
This function returns a reference to the next layer in a
|
|
||||||
stack of stream layers.
|
|
||||||
|
|
||||||
@return A reference to the next layer in the stack of
|
|
||||||
stream layers. Ownership is not transferred to the caller.
|
|
||||||
*/
|
|
||||||
next_layer_type const&
|
|
||||||
next_layer() const
|
|
||||||
{
|
|
||||||
return next_layer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a reference to the lowest layer.
|
|
||||||
|
|
||||||
This function returns a reference to the lowest layer
|
|
||||||
in a stack of stream layers.
|
|
||||||
|
|
||||||
@return A reference to the lowest layer in the stack of
|
|
||||||
stream layers. Ownership is not transferred to the caller.
|
|
||||||
*/
|
|
||||||
lowest_layer_type&
|
|
||||||
lowest_layer()
|
|
||||||
{
|
|
||||||
return next_layer_.lowest_layer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a reference to the lowest layer.
|
|
||||||
|
|
||||||
This function returns a reference to the lowest layer
|
|
||||||
in a stack of stream layers.
|
|
||||||
|
|
||||||
@return A reference to the lowest layer in the stack of
|
|
||||||
stream layers. Ownership is not transferred to the caller.
|
|
||||||
*/
|
|
||||||
lowest_layer_type const&
|
|
||||||
lowest_layer() const
|
|
||||||
{
|
|
||||||
return next_layer_.lowest_layer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Cancel pending operations.
|
|
||||||
|
|
||||||
This will cancel all of the asynchronous operations pending,
|
|
||||||
including pipelined writes that have not been started. Handlers for
|
|
||||||
canceled writes will be called with
|
|
||||||
`boost::asio::error::operation_aborted`.
|
|
||||||
|
|
||||||
@throws boost::system::system_error Thrown on failure.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
cancel()
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
cancel(ec);
|
|
||||||
if(ec)
|
|
||||||
throw system_error{ec};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Cancel pending operations.
|
|
||||||
|
|
||||||
This will cancel all of the asynchronous operations pending,
|
|
||||||
including pipelined writes that have not been started. Handlers for
|
|
||||||
canceled writes will be called with
|
|
||||||
`boost::asio::error::operation_aborted`.
|
|
||||||
|
|
||||||
@param ec Set to indicate what error occurred, if any.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
cancel(error_code& ec);
|
|
||||||
|
|
||||||
/** Read a HTTP message from the stream.
|
|
||||||
|
|
||||||
This function is used to read a single HTTP message from the stream.
|
|
||||||
The call will block until one of the followign conditions is true:
|
|
||||||
|
|
||||||
@li A message has been read.
|
|
||||||
|
|
||||||
@li An error occurred.
|
|
||||||
|
|
||||||
The operation is implemented in terms of zero or more calls to the
|
|
||||||
next layer's `read_some` function.
|
|
||||||
|
|
||||||
@param msg An object used to store the message. The previous
|
|
||||||
contents of the object will be overwritten.
|
|
||||||
|
|
||||||
@throws boost::system::system_error Thrown on failure.
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
read(message_v1<isRequest, Body, Headers>& msg)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
read(msg, ec);
|
|
||||||
if(ec)
|
|
||||||
throw system_error{ec};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read a HTTP message from the stream.
|
|
||||||
|
|
||||||
This function is used to read a single HTTP message from the stream.
|
|
||||||
The call will block until one of the followign conditions is true:
|
|
||||||
|
|
||||||
@li A message has been read.
|
|
||||||
|
|
||||||
@li An error occurred.
|
|
||||||
|
|
||||||
The operation is implemented in terms of zero or more calls to the
|
|
||||||
next layer's `read_some` function.
|
|
||||||
|
|
||||||
@param msg An object used to store the message. The previous
|
|
||||||
contents of the object will be overwritten.
|
|
||||||
|
|
||||||
@param ec Set to indicate what error occurred, if any.
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
read(message_v1<isRequest, Body, Headers>& msg,
|
|
||||||
error_code& ec);
|
|
||||||
|
|
||||||
/** Start reading a HTTP message from the stream asynchronously.
|
|
||||||
|
|
||||||
This function is used to asynchronously read a single HTTP message
|
|
||||||
from the stream. The function call always returns immediately. The
|
|
||||||
asynchronous operation will continue until one of the following
|
|
||||||
conditions is true:
|
|
||||||
|
|
||||||
@li The message has been written.
|
|
||||||
|
|
||||||
@li An error occurred.
|
|
||||||
|
|
||||||
This operation is implemented in terms of zero or more calls to the
|
|
||||||
next layer's async_read_some function, and is known as a composed
|
|
||||||
operation. The program must ensure that the stream performs no other
|
|
||||||
read operations or any other composed operations that perform reads
|
|
||||||
until this operation completes.
|
|
||||||
|
|
||||||
@param msg An object used to store the message. The previous
|
|
||||||
contents of the object will be overwritten. Ownership of the message
|
|
||||||
is not transferred; the caller must guarantee that the object remains
|
|
||||||
valid until the handler is called.
|
|
||||||
|
|
||||||
@param handler The handler to be called when the request completes.
|
|
||||||
Copies will be made of the handler as required. The equivalent
|
|
||||||
function signature of the handler must be:
|
|
||||||
@code void handler(
|
|
||||||
error_code const& error // result of operation
|
|
||||||
); @endcode
|
|
||||||
Regardless of whether the asynchronous operation completes
|
|
||||||
immediately or not, the handler will not be invoked from within
|
|
||||||
this function. Invocation of the handler will be performed in a
|
|
||||||
manner equivalent to using boost::asio::io_service::post().
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class ReadHandler>
|
|
||||||
#if GENERATING_DOCS
|
|
||||||
void_or_deduced
|
|
||||||
#else
|
|
||||||
typename async_completion<
|
|
||||||
ReadHandler, void(error_code)>::result_type
|
|
||||||
#endif
|
|
||||||
async_read(message_v1<isRequest, Body, Headers>& msg,
|
|
||||||
ReadHandler&& handler);
|
|
||||||
|
|
||||||
/** Write a HTTP message to the stream.
|
|
||||||
|
|
||||||
This function is used to write a single HTTP message to the
|
|
||||||
stream. The call will block until one of the following conditions
|
|
||||||
is true:
|
|
||||||
|
|
||||||
@li The entire message is sent.
|
|
||||||
|
|
||||||
@li An error occurred.
|
|
||||||
|
|
||||||
If the semantics of the message require that the connection is
|
|
||||||
closed to indicate the end of the content body,
|
|
||||||
`boost::asio::error::eof` is thrown after the message is sent.
|
|
||||||
successfuly. The caller is responsible for actually closing the
|
|
||||||
connection. For regular TCP/IP streams this means shutting down the
|
|
||||||
send side, while SSL streams may call the SSL shutdown function.
|
|
||||||
|
|
||||||
@param msg The message to send.
|
|
||||||
|
|
||||||
@throws boost::system::system_error Thrown on failure.
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
write(message_v1<isRequest, Body, Headers> const& msg)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
write(msg, ec);
|
|
||||||
if(ec)
|
|
||||||
throw system_error{ec};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write a HTTP message to the stream.
|
|
||||||
|
|
||||||
This function is used to write a single HTTP message to the
|
|
||||||
stream. The call will block until one of the following conditions
|
|
||||||
is true:
|
|
||||||
|
|
||||||
@li The entire message is sent.
|
|
||||||
|
|
||||||
@li An error occurred.
|
|
||||||
|
|
||||||
If the semantics of the message require that the connection is
|
|
||||||
closed to indicate the end of the content body,
|
|
||||||
`boost::asio::error::eof` is returned after the message is sent.
|
|
||||||
successfuly. The caller is responsible for actually closing the
|
|
||||||
connection. For regular TCP/IP streams this means shutting down the
|
|
||||||
send side, while SSL streams may call the SSL shutdown function.
|
|
||||||
|
|
||||||
@param msg The message to send.
|
|
||||||
|
|
||||||
@param ec Set to the error, if any occurred.
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
write(message_v1<isRequest, Body, Headers> const& msg,
|
|
||||||
error_code& ec);
|
|
||||||
|
|
||||||
/** Start pipelining a HTTP message to the stream asynchronously.
|
|
||||||
|
|
||||||
This function is used to queue a message to be sent on the stream.
|
|
||||||
Unlike the free function, this version will place the message on an
|
|
||||||
outgoing message queue if there is already a write pending.
|
|
||||||
|
|
||||||
If the semantics of the message require that the connection is
|
|
||||||
closed to indicate the end of the content body, the handler
|
|
||||||
is called with the error `boost::asio::error::eof` after the message
|
|
||||||
has been sent successfully. The caller is responsible for actually
|
|
||||||
closing the connection. For regular TCP/IP streams this means
|
|
||||||
shutting down the send side, while SSL streams may call the SSL
|
|
||||||
`async_shutdown` function.
|
|
||||||
|
|
||||||
@param msg The message to send. A copy of the message will be made.
|
|
||||||
|
|
||||||
@param handler The handler to be called when the request completes.
|
|
||||||
Copies will be made of the handler as required. The equivalent
|
|
||||||
function signature of the handler must be:
|
|
||||||
@code void handler(
|
|
||||||
error_code const& error // result of operation
|
|
||||||
); @endcode
|
|
||||||
Regardless of whether the asynchronous operation completes
|
|
||||||
immediately or not, the handler will not be invoked from within
|
|
||||||
this function. Invocation of the handler will be performed in a
|
|
||||||
manner equivalent to using boost::asio::io_service::post().
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class WriteHandler>
|
|
||||||
#if GENERATING_DOCS
|
|
||||||
void_or_deduced
|
|
||||||
#else
|
|
||||||
typename async_completion<
|
|
||||||
WriteHandler, void(error_code)>::result_type
|
|
||||||
#endif
|
|
||||||
async_write(message_v1<isRequest, Body, Headers> const& msg,
|
|
||||||
WriteHandler&& handler);
|
|
||||||
|
|
||||||
/** Start pipelining a HTTP message to the stream asynchronously.
|
|
||||||
|
|
||||||
This function is used to queue a message to be sent on the stream.
|
|
||||||
Unlike the free function, this version will place the message on an
|
|
||||||
outgoing message queue if there is already a write pending.
|
|
||||||
|
|
||||||
If the semantics of the message require that the connection is
|
|
||||||
closed to indicate the end of the content body, the handler
|
|
||||||
is called with the error boost::asio::error::eof. The caller is
|
|
||||||
responsible for actually closing the connection. For regular
|
|
||||||
TCP/IP streams this means shutting down the send side, while SSL
|
|
||||||
streams may call the SSL async_shutdown function.
|
|
||||||
|
|
||||||
@param msg The message to send. Ownership of the message, which
|
|
||||||
must be movable, is transferred to the implementation. The message
|
|
||||||
will not be destroyed until the asynchronous operation completes.
|
|
||||||
|
|
||||||
@param handler The handler to be called when the request completes.
|
|
||||||
Copies will be made of the handler as required. The equivalent
|
|
||||||
function signature of the handler must be:
|
|
||||||
@code void handler(
|
|
||||||
error_code const& error // result of operation
|
|
||||||
); @endcode
|
|
||||||
Regardless of whether the asynchronous operation completes
|
|
||||||
immediately or not, the handler will not be invoked from within
|
|
||||||
this function. Invocation of the handler will be performed in a
|
|
||||||
manner equivalent to using boost::asio::io_service::post().
|
|
||||||
*/
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class WriteHandler>
|
|
||||||
#if GENERATING_DOCS
|
|
||||||
void_or_deduced
|
|
||||||
#else
|
|
||||||
typename async_completion<
|
|
||||||
WriteHandler, void(error_code)>::result_type
|
|
||||||
#endif
|
|
||||||
async_write(message_v1<isRequest, Body, Headers>&& msg,
|
|
||||||
WriteHandler&& handler);
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<bool, class, class, class> class read_op;
|
|
||||||
template<bool, class, class, class> class write_op;
|
|
||||||
|
|
||||||
void
|
|
||||||
cancel_all();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // http
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#include "http_stream.ipp"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,412 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
||||||
//
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BEAST_HTTP_STREAM_IPP_INCLUDED
|
|
||||||
#define BEAST_HTTP_STREAM_IPP_INCLUDED
|
|
||||||
|
|
||||||
#include <beast/core/bind_handler.hpp>
|
|
||||||
#include <beast/core/handler_alloc.hpp>
|
|
||||||
#include <beast/http/message_v1.hpp>
|
|
||||||
#include <beast/http/read.hpp>
|
|
||||||
#include <beast/http/write.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace http {
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class Handler>
|
|
||||||
class stream<NextLayer, Allocator>::read_op
|
|
||||||
{
|
|
||||||
using alloc_type =
|
|
||||||
handler_alloc<char, Handler>;
|
|
||||||
|
|
||||||
struct data
|
|
||||||
{
|
|
||||||
stream<NextLayer>& s;
|
|
||||||
message_v1<isRequest, Body, Headers>& m;
|
|
||||||
Handler h;
|
|
||||||
bool cont;
|
|
||||||
int state = 0;
|
|
||||||
|
|
||||||
template<class DeducedHandler>
|
|
||||||
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
|
||||||
message_v1<isRequest, Body, Headers>& m_)
|
|
||||||
: s(s_)
|
|
||||||
, m(m_)
|
|
||||||
, h(std::forward<DeducedHandler>(h_))
|
|
||||||
, cont(boost_asio_handler_cont_helpers::
|
|
||||||
is_continuation(h))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<data> d_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
read_op(read_op&&) = default;
|
|
||||||
read_op(read_op const&) = default;
|
|
||||||
|
|
||||||
template<class DeducedHandler, class... Args>
|
|
||||||
read_op(DeducedHandler&& h,
|
|
||||||
stream<NextLayer>& s, Args&&... args)
|
|
||||||
: d_(std::allocate_shared<data>(alloc_type{h},
|
|
||||||
std::forward<DeducedHandler>(h), s,
|
|
||||||
std::forward<Args>(args)...))
|
|
||||||
{
|
|
||||||
(*this)(error_code{}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(error_code const& ec, bool again = true);
|
|
||||||
|
|
||||||
friend
|
|
||||||
void* asio_handler_allocate(
|
|
||||||
std::size_t size, read_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_alloc_helpers::
|
|
||||||
allocate(size, op->d_->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
void asio_handler_deallocate(
|
|
||||||
void* p, std::size_t size, read_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_alloc_helpers::
|
|
||||||
deallocate(p, size, op->d_->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
bool asio_handler_is_continuation(read_op* op)
|
|
||||||
{
|
|
||||||
return op->d_->cont;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Function>
|
|
||||||
friend
|
|
||||||
void asio_handler_invoke(Function&& f, read_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_invoke_helpers::
|
|
||||||
invoke(f, op->d_->h);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers, class Handler>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
read_op<isRequest, Body, Headers, Handler>::
|
|
||||||
operator()(error_code const& ec, bool again)
|
|
||||||
{
|
|
||||||
auto& d = *d_;
|
|
||||||
d.cont = d.cont || again;
|
|
||||||
while(! ec && d.state != 99)
|
|
||||||
{
|
|
||||||
switch(d.state)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
d.state = 99;
|
|
||||||
beast::http::async_read(d.s.next_layer_,
|
|
||||||
d.s.rd_buf_, d.m, std::move(*this));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.h(ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class Handler>
|
|
||||||
class stream<NextLayer, Allocator>::write_op : public op
|
|
||||||
{
|
|
||||||
using alloc_type =
|
|
||||||
handler_alloc<char, Handler>;
|
|
||||||
|
|
||||||
struct data
|
|
||||||
{
|
|
||||||
stream<NextLayer>& s;
|
|
||||||
message_v1<isRequest, Body, Headers> m;
|
|
||||||
Handler h;
|
|
||||||
bool cont;
|
|
||||||
int state = 0;
|
|
||||||
|
|
||||||
template<class DeducedHandler>
|
|
||||||
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
|
||||||
message_v1<isRequest, Body, Headers> const& m_,
|
|
||||||
bool cont_)
|
|
||||||
: s(s_)
|
|
||||||
, m(m_)
|
|
||||||
, h(std::forward<DeducedHandler>(h_))
|
|
||||||
, cont(cont_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class DeducedHandler>
|
|
||||||
data(DeducedHandler&& h_, stream<NextLayer>& s_,
|
|
||||||
message_v1<isRequest, Body, Headers>&& m_,
|
|
||||||
bool cont_)
|
|
||||||
: s(s_)
|
|
||||||
, m(std::move(m_))
|
|
||||||
, h(std::forward<DeducedHandler>(h_))
|
|
||||||
, cont(cont_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<data> d_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
write_op(write_op&&) = default;
|
|
||||||
write_op(write_op const&) = default;
|
|
||||||
|
|
||||||
template<class DeducedHandler, class... Args>
|
|
||||||
write_op(DeducedHandler&& h,
|
|
||||||
stream<NextLayer>& s, Args&&... args)
|
|
||||||
: d_(std::allocate_shared<data>(alloc_type{h},
|
|
||||||
std::forward<DeducedHandler>(h), s,
|
|
||||||
std::forward<Args>(args)...))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
operator()() override
|
|
||||||
{
|
|
||||||
(*this)(error_code{}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cancel() override;
|
|
||||||
|
|
||||||
void operator()(error_code const& ec, bool again = true);
|
|
||||||
|
|
||||||
friend
|
|
||||||
void* asio_handler_allocate(
|
|
||||||
std::size_t size, write_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_alloc_helpers::
|
|
||||||
allocate(size, op->d_->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
void asio_handler_deallocate(
|
|
||||||
void* p, std::size_t size, write_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_alloc_helpers::
|
|
||||||
deallocate(p, size, op->d_->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend
|
|
||||||
bool asio_handler_is_continuation(write_op* op)
|
|
||||||
{
|
|
||||||
return op->d_->cont;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Function>
|
|
||||||
friend
|
|
||||||
void asio_handler_invoke(Function&& f, write_op* op)
|
|
||||||
{
|
|
||||||
return boost_asio_handler_invoke_helpers::
|
|
||||||
invoke(f, op->d_->h);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers, class Handler>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
write_op<isRequest, Body, Headers, Handler>::
|
|
||||||
cancel()
|
|
||||||
{
|
|
||||||
auto& d = *d_;
|
|
||||||
d.s.get_io_service().post(
|
|
||||||
bind_handler(std::move(*this),
|
|
||||||
boost::asio::error::operation_aborted));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers, class Handler>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
write_op<isRequest, Body, Headers, Handler>::
|
|
||||||
operator()(error_code const& ec, bool again)
|
|
||||||
{
|
|
||||||
auto& d = *d_;
|
|
||||||
d.cont = d.cont || again;
|
|
||||||
while(! ec && d.state != 99)
|
|
||||||
{
|
|
||||||
switch(d.state)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
d.state = 99;
|
|
||||||
beast::http::async_write(d.s.next_layer_,
|
|
||||||
d.m, std::move(*this));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.h(ec);
|
|
||||||
if(! d.s.wr_q_.empty())
|
|
||||||
{
|
|
||||||
auto& op = d.s.wr_q_.front();
|
|
||||||
op();
|
|
||||||
// VFALCO Use allocator
|
|
||||||
delete &op;
|
|
||||||
d.s.wr_q_.pop_front();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d.s.wr_active_ = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
~stream()
|
|
||||||
{
|
|
||||||
// Can't destroy with pending operations!
|
|
||||||
assert(wr_q_.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<class... Args>
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
stream(Args&&... args)
|
|
||||||
: next_layer_(std::forward<Args>(args)...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
cancel(error_code& ec)
|
|
||||||
{
|
|
||||||
cancel_all();
|
|
||||||
lowest_layer().cancel(ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
read(message_v1<isRequest, Body, Headers>& msg,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
beast::http::read(next_layer_, rd_buf_, msg, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class ReadHandler>
|
|
||||||
auto
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
async_read(message_v1<isRequest, Body, Headers>& msg,
|
|
||||||
ReadHandler&& handler) ->
|
|
||||||
typename async_completion<
|
|
||||||
ReadHandler, void(error_code)>::result_type
|
|
||||||
{
|
|
||||||
async_completion<
|
|
||||||
ReadHandler, void(error_code)
|
|
||||||
> completion(handler);
|
|
||||||
read_op<isRequest, Body, Headers,
|
|
||||||
decltype(completion.handler)>{
|
|
||||||
completion.handler, *this, msg};
|
|
||||||
return completion.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
write(message_v1<isRequest, Body, Headers> const& msg,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
beast::http::write(next_layer_, msg, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class WriteHandler>
|
|
||||||
auto
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
async_write(message_v1<isRequest, Body, Headers> const& msg,
|
|
||||||
WriteHandler&& handler) ->
|
|
||||||
typename async_completion<
|
|
||||||
WriteHandler, void(error_code)>::result_type
|
|
||||||
{
|
|
||||||
async_completion<
|
|
||||||
WriteHandler, void(error_code)> completion(handler);
|
|
||||||
auto const cont = wr_active_ ||
|
|
||||||
boost_asio_handler_cont_helpers::is_continuation(handler);
|
|
||||||
if(! wr_active_)
|
|
||||||
{
|
|
||||||
wr_active_ = true;
|
|
||||||
write_op<isRequest, Body, Headers,
|
|
||||||
decltype(completion.handler)>{
|
|
||||||
completion.handler, *this, msg, cont }();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// VFALCO Use allocator
|
|
||||||
wr_q_.push_back(*new write_op<isRequest, Body, Headers,
|
|
||||||
decltype(completion.handler)>(
|
|
||||||
completion.handler, *this, msg, cont));
|
|
||||||
}
|
|
||||||
return completion.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
template<bool isRequest, class Body, class Headers,
|
|
||||||
class WriteHandler>
|
|
||||||
auto
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
async_write(message_v1<isRequest, Body, Headers>&& msg,
|
|
||||||
WriteHandler&& handler) ->
|
|
||||||
typename async_completion<
|
|
||||||
WriteHandler, void(error_code)>::result_type
|
|
||||||
{
|
|
||||||
async_completion<
|
|
||||||
WriteHandler, void(error_code)> completion(handler);
|
|
||||||
auto const cont = wr_active_ ||
|
|
||||||
boost_asio_handler_cont_helpers::is_continuation(handler);
|
|
||||||
if(! wr_active_)
|
|
||||||
{
|
|
||||||
wr_active_ = true;
|
|
||||||
write_op<isRequest, Body, Headers,
|
|
||||||
decltype(completion.handler)>{completion.handler,
|
|
||||||
*this, std::move(msg), cont}();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// VFALCO Use allocator
|
|
||||||
wr_q_.push_back(*new write_op<isRequest, Body, Headers,
|
|
||||||
decltype(completion.handler)>(completion.handler,
|
|
||||||
*this, std::move(msg), cont));
|
|
||||||
}
|
|
||||||
return completion.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class NextLayer, class Allocator>
|
|
||||||
void
|
|
||||||
stream<NextLayer, Allocator>::
|
|
||||||
cancel_all()
|
|
||||||
{
|
|
||||||
for(auto it = wr_q_.begin(); it != wr_q_.end();)
|
|
||||||
{
|
|
||||||
auto& op = *it++;
|
|
||||||
op.cancel();
|
|
||||||
// VFALCO Use allocator
|
|
||||||
delete &op;
|
|
||||||
}
|
|
||||||
wr_q_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // http
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -9,8 +9,11 @@
|
|||||||
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
|
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
|
||||||
|
|
||||||
#include "file_body.hpp"
|
#include "file_body.hpp"
|
||||||
#include "http_stream.hpp"
|
#include "mime_type.hpp"
|
||||||
|
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
#include <beast/core/placeholders.hpp>
|
||||||
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -18,6 +21,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -31,9 +35,11 @@ class http_sync_server
|
|||||||
using address_type = boost::asio::ip::address;
|
using address_type = boost::asio::ip::address;
|
||||||
using socket_type = boost::asio::ip::tcp::socket;
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
using req_type = request_v1<string_body>;
|
using req_type = request<string_body>;
|
||||||
using resp_type = response_v1<file_body>;
|
using resp_type = response<file_body>;
|
||||||
|
|
||||||
|
bool log_ = true;
|
||||||
|
std::mutex m_;
|
||||||
boost::asio::io_service ios_;
|
boost::asio::io_service ios_;
|
||||||
socket_type sock_;
|
socket_type sock_;
|
||||||
boost::asio::ip::tcp::acceptor acceptor_;
|
boost::asio::ip::tcp::acceptor acceptor_;
|
||||||
@@ -65,21 +71,43 @@ public:
|
|||||||
thread_.join();
|
thread_.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
void
|
void
|
||||||
fail(error_code ec, std::string what)
|
log(Args const&... args)
|
||||||
{
|
{
|
||||||
std::cerr <<
|
if(log_)
|
||||||
what << ": " << ec.message() << std::endl;
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_);
|
||||||
|
log_args(args...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void
|
||||||
|
log_args()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Arg, class... Args>
|
||||||
|
void
|
||||||
|
log_args(Arg const& arg, Args const&... args)
|
||||||
|
{
|
||||||
|
std::cerr << arg;
|
||||||
|
log_args(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
maybe_throw(error_code ec, std::string what)
|
fail(error_code ec, std::string what)
|
||||||
{
|
{
|
||||||
if(ec)
|
log(what, ": ", ec.message(), "\n");
|
||||||
{
|
}
|
||||||
fail(ec, what);
|
|
||||||
throw ec;
|
void
|
||||||
}
|
fail(int id, error_code const& ec)
|
||||||
|
{
|
||||||
|
if(ec != boost::asio::error::operation_aborted &&
|
||||||
|
ec != boost::asio::error::eof)
|
||||||
|
log("#", id, " ", ec.message(), "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lambda
|
struct lambda
|
||||||
@@ -109,7 +137,8 @@ public:
|
|||||||
{
|
{
|
||||||
if(! acceptor_.is_open())
|
if(! acceptor_.is_open())
|
||||||
return;
|
return;
|
||||||
maybe_throw(ec, "accept");
|
if(ec)
|
||||||
|
return fail(ec, "accept");
|
||||||
static int id_ = 0;
|
static int id_ = 0;
|
||||||
std::thread{lambda{++id_, *this, std::move(sock_)}}.detach();
|
std::thread{lambda{++id_, *this, std::move(sock_)}}.detach();
|
||||||
acceptor_.async_accept(sock_,
|
acceptor_.async_accept(sock_,
|
||||||
@@ -118,23 +147,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fail(int id, error_code const& ec)
|
do_peer(int id, socket_type&& sock0)
|
||||||
{
|
{
|
||||||
if(ec != boost::asio::error::operation_aborted &&
|
socket_type sock(std::move(sock0));
|
||||||
ec != boost::asio::error::eof)
|
streambuf sb;
|
||||||
std::cerr <<
|
|
||||||
"#" << std::to_string(id) << " " << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_peer(int id, socket_type&& sock)
|
|
||||||
{
|
|
||||||
http::stream<socket_type> hs(std::move(sock));
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
req_type req;
|
req_type req;
|
||||||
hs.read(req, ec);
|
http::read(sock, sb, req, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
auto path = req.url;
|
auto path = req.url;
|
||||||
@@ -143,28 +164,48 @@ public:
|
|||||||
path = root_ + path;
|
path = root_ + path;
|
||||||
if(! boost::filesystem::exists(path))
|
if(! boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
response_v1<string_body> resp;
|
response<string_body> res;
|
||||||
resp.status = 404;
|
res.status = 404;
|
||||||
resp.reason = "Not Found";
|
res.reason = "Not Found";
|
||||||
resp.version = req.version;
|
res.version = req.version;
|
||||||
resp.headers.replace("Server", "http_sync_server");
|
res.fields.insert("Server", "http_sync_server");
|
||||||
resp.body = "The file '" + path + "' was not found";
|
res.fields.insert("Content-Type", "text/html");
|
||||||
prepare(resp);
|
res.body = "The file '" + path + "' was not found";
|
||||||
hs.write(resp, ec);
|
prepare(res);
|
||||||
|
write(sock, res, ec);
|
||||||
|
if(ec)
|
||||||
|
break;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
response<string_body> res;
|
||||||
|
res.status = 500;
|
||||||
|
res.reason = "Internal Error";
|
||||||
|
res.version = req.version;
|
||||||
|
res.fields.insert("Server", "http_sync_server");
|
||||||
|
res.fields.insert("Content-Type", "text/html");
|
||||||
|
res.body =
|
||||||
|
std::string{"An internal error occurred: "} + e.what();
|
||||||
|
prepare(res);
|
||||||
|
write(sock, res, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
resp_type resp;
|
|
||||||
resp.status = 200;
|
|
||||||
resp.reason = "OK";
|
|
||||||
resp.version = req.version;
|
|
||||||
resp.headers.replace("Server", "http_sync_server");
|
|
||||||
resp.headers.replace("Content-Type", "text/html");
|
|
||||||
resp.body = path;
|
|
||||||
prepare(resp);
|
|
||||||
hs.write(resp, ec);
|
|
||||||
if(ec)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
fail(id, ec);
|
fail(id, ec);
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/beast/examples/mime_type.hpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BEAST_EXAMPLE_HTTP_MIME_TYPE_H_INCLUDED
|
||||||
|
#define BEAST_EXAMPLE_HTTP_MIME_TYPE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
// Return the Mime-Type for a given file extension
|
||||||
|
template<class = void>
|
||||||
|
std::string
|
||||||
|
mime_type(std::string const& path)
|
||||||
|
{
|
||||||
|
auto const ext =
|
||||||
|
boost::filesystem::path{path}.extension().string();
|
||||||
|
if(ext == ".txt") return "text/plain";
|
||||||
|
if(ext == ".htm") return "text/html";
|
||||||
|
if(ext == ".html") return "text/html";
|
||||||
|
if(ext == ".php") return "text/html";
|
||||||
|
if(ext == ".css") return "text/css";
|
||||||
|
if(ext == ".js") return "application/javascript";
|
||||||
|
if(ext == ".json") return "application/json";
|
||||||
|
if(ext == ".xml") return "application/xml";
|
||||||
|
if(ext == ".swf") return "application/x-shockwave-flash";
|
||||||
|
if(ext == ".flv") return "video/x-flv";
|
||||||
|
if(ext == ".png") return "image/png";
|
||||||
|
if(ext == ".jpe") return "image/jpeg";
|
||||||
|
if(ext == ".jpeg") return "image/jpeg";
|
||||||
|
if(ext == ".jpg") return "image/jpeg";
|
||||||
|
if(ext == ".gif") return "image/gif";
|
||||||
|
if(ext == ".bmp") return "image/bmp";
|
||||||
|
if(ext == ".ico") return "image/vnd.microsoft.icon";
|
||||||
|
if(ext == ".tiff") return "image/tiff";
|
||||||
|
if(ext == ".tif") return "image/tiff";
|
||||||
|
if(ext == ".svg") return "image/svg+xml";
|
||||||
|
if(ext == ".svgz") return "image/svg+xml";
|
||||||
|
return "application/text";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
||||||
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
@@ -0,0 +1,54 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
#
|
||||||
|
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
#
|
||||||
|
|
||||||
|
import os ;
|
||||||
|
|
||||||
|
if [ os.name ] = SOLARIS
|
||||||
|
{
|
||||||
|
lib socket ;
|
||||||
|
lib nsl ;
|
||||||
|
}
|
||||||
|
else if [ os.name ] = NT
|
||||||
|
{
|
||||||
|
lib ws2_32 ;
|
||||||
|
lib mswsock ;
|
||||||
|
}
|
||||||
|
else if [ os.name ] = HPUX
|
||||||
|
{
|
||||||
|
lib ipv6 ;
|
||||||
|
}
|
||||||
|
else if [ os.name ] = HAIKU
|
||||||
|
{
|
||||||
|
lib network ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ os.name ] = NT
|
||||||
|
{
|
||||||
|
lib ssl : : <name>ssleay32 ;
|
||||||
|
lib crypto : : <name>libeay32 ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lib ssl ;
|
||||||
|
lib crypto ;
|
||||||
|
}
|
||||||
|
|
||||||
|
project
|
||||||
|
: requirements
|
||||||
|
<library>ssl
|
||||||
|
<library>crypto
|
||||||
|
;
|
||||||
|
|
||||||
|
exe http-ssl-example
|
||||||
|
:
|
||||||
|
http_ssl_example.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
exe websocket-ssl-example
|
||||||
|
:
|
||||||
|
websocket_ssl_example.cpp
|
||||||
|
;
|
||||||
58
src/beast/examples/ssl/http_ssl_example.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::asio::connect;
|
||||||
|
using socket = boost::asio::ip::tcp::socket;
|
||||||
|
using resolver = boost::asio::ip::tcp::resolver;
|
||||||
|
using io_service = boost::asio::io_service;
|
||||||
|
namespace ssl = boost::asio::ssl;
|
||||||
|
|
||||||
|
// Normal boost::asio setup
|
||||||
|
std::string const host = "github.com";
|
||||||
|
io_service ios;
|
||||||
|
resolver r{ios};
|
||||||
|
socket sock{ios};
|
||||||
|
connect(sock, r.resolve(resolver::query{host, "https"}));
|
||||||
|
|
||||||
|
// Perform SSL handshaking
|
||||||
|
ssl::context ctx{ssl::context::sslv23};
|
||||||
|
ssl::stream<socket&> stream{sock, ctx};
|
||||||
|
stream.set_verify_mode(ssl::verify_none);
|
||||||
|
stream.handshake(ssl::stream_base::client);
|
||||||
|
|
||||||
|
// Send HTTP request over SSL using Beast
|
||||||
|
beast::http::request<beast::http::empty_body> req;
|
||||||
|
req.method = "GET";
|
||||||
|
req.url = "/";
|
||||||
|
req.version = 11;
|
||||||
|
req.fields.insert("Host", host + ":" +
|
||||||
|
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||||
|
req.fields.insert("User-Agent", "Beast");
|
||||||
|
beast::http::prepare(req);
|
||||||
|
beast::http::write(stream, req);
|
||||||
|
|
||||||
|
// Receive and print HTTP response using Beast
|
||||||
|
beast::streambuf sb;
|
||||||
|
beast::http::response<beast::http::streambuf_body> resp;
|
||||||
|
beast::http::read(stream, sb, resp);
|
||||||
|
std::cout << resp;
|
||||||
|
|
||||||
|
// Shut down SSL on the stream
|
||||||
|
boost::system::error_code ec;
|
||||||
|
stream.shutdown(ec);
|
||||||
|
if(ec && ec != boost::asio::error::eof)
|
||||||
|
std::cout << "error: " << ec.message();
|
||||||
|
}
|
||||||
49
src/beast/examples/ssl/websocket_ssl_example.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <beast/core/to_string.hpp>
|
||||||
|
#include <beast/websocket.hpp>
|
||||||
|
#include <beast/websocket/ssl.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using boost::asio::connect;
|
||||||
|
using socket = boost::asio::ip::tcp::socket;
|
||||||
|
using resolver = boost::asio::ip::tcp::resolver;
|
||||||
|
using io_service = boost::asio::io_service;
|
||||||
|
namespace ssl = boost::asio::ssl;
|
||||||
|
|
||||||
|
// Normal boost::asio setup
|
||||||
|
std::string const host = "echo.websocket.org";
|
||||||
|
io_service ios;
|
||||||
|
resolver r{ios};
|
||||||
|
socket sock{ios};
|
||||||
|
connect(sock, r.resolve(resolver::query{host, "https"}));
|
||||||
|
|
||||||
|
// Perform SSL handshaking
|
||||||
|
using stream_type = ssl::stream<socket&>;
|
||||||
|
ssl::context ctx{ssl::context::sslv23};
|
||||||
|
stream_type stream{sock, ctx};
|
||||||
|
stream.set_verify_mode(ssl::verify_none);
|
||||||
|
stream.handshake(ssl::stream_base::client);
|
||||||
|
|
||||||
|
// Secure WebSocket connect and send message using Beast
|
||||||
|
beast::websocket::stream<stream_type&> ws{stream};
|
||||||
|
ws.handshake(host, "/");
|
||||||
|
ws.write(boost::asio::buffer("Hello, world!"));
|
||||||
|
|
||||||
|
// Receive Secure WebSocket message, print and close using Beast
|
||||||
|
beast::streambuf sb;
|
||||||
|
beast::websocket::opcode op;
|
||||||
|
ws.read(op, sb);
|
||||||
|
ws.close(beast::websocket::close_code::normal);
|
||||||
|
std::cout << to_string(sb.data()) << "\n";
|
||||||
|
}
|
||||||
@@ -16,20 +16,20 @@ int main()
|
|||||||
// Normal boost::asio setup
|
// Normal boost::asio setup
|
||||||
std::string const host = "echo.websocket.org";
|
std::string const host = "echo.websocket.org";
|
||||||
boost::asio::io_service ios;
|
boost::asio::io_service ios;
|
||||||
boost::asio::ip::tcp::resolver r(ios);
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
boost::asio::ip::tcp::socket sock(ios);
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
boost::asio::connect(sock,
|
boost::asio::connect(sock,
|
||||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"}));
|
||||||
|
|
||||||
// WebSocket connect and send message using beast
|
// WebSocket connect and send message using beast
|
||||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||||
ws.handshake(host, "/");
|
ws.handshake(host, "/");
|
||||||
ws.write(boost::asio::buffer("Hello, world!"));
|
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||||
|
|
||||||
// Receive WebSocket message, print and close using beast
|
// Receive WebSocket message, print and close using beast
|
||||||
beast::streambuf sb;
|
beast::streambuf sb;
|
||||||
beast::websocket::opcode op;
|
beast::websocket::opcode op;
|
||||||
ws.read(op, sb);
|
ws.read(op, sb);
|
||||||
ws.close(beast::websocket::close_code::normal);
|
ws.close(beast::websocket::close_code::normal);
|
||||||
std::cout << to_string(sb.data()) << "\n";
|
std::cout << beast::to_string(sb.data()) << "\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
enum error
|
enum class error
|
||||||
{
|
{
|
||||||
fail_error = 1
|
fail_error = 1
|
||||||
};
|
};
|
||||||
@@ -77,14 +77,15 @@ inline
|
|||||||
error_code
|
error_code
|
||||||
make_error_code(error ev)
|
make_error_code(error ev)
|
||||||
{
|
{
|
||||||
return error_code{static_cast<int>(ev),
|
return error_code{
|
||||||
detail::get_error_category()};
|
static_cast<std::underlying_type<error>::type>(ev),
|
||||||
|
detail::get_error_category()};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A countdown to simulated failure.
|
/** A countdown to simulated failure.
|
||||||
|
|
||||||
On the Nth operation, the class will fail with the specified
|
On the Nth operation, the class will fail with the specified
|
||||||
error code, or the default error code of @ref fail_error.
|
error code, or the default error code of @ref error::fail_error.
|
||||||
*/
|
*/
|
||||||
class fail_counter
|
class fail_counter
|
||||||
{
|
{
|
||||||
@@ -100,7 +101,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
explicit
|
explicit
|
||||||
fail_counter(std::size_t n,
|
fail_counter(std::size_t n,
|
||||||
error_code ev = make_error_code(fail_error))
|
error_code ev = make_error_code(error::fail_error))
|
||||||
: n_(n)
|
: n_(n)
|
||||||
, ec_(ev)
|
, ec_(ev)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -161,19 +161,21 @@ public:
|
|||||||
|
|
||||||
friend
|
friend
|
||||||
void
|
void
|
||||||
teardown(fail_stream<NextLayer>& stream,
|
teardown(websocket::teardown_tag,
|
||||||
boost::system::error_code& ec)
|
fail_stream<NextLayer>& stream,
|
||||||
|
boost::system::error_code& ec)
|
||||||
{
|
{
|
||||||
if(stream.pfc_->fail(ec))
|
if(stream.pfc_->fail(ec))
|
||||||
return;
|
return;
|
||||||
websocket_helpers::call_teardown(stream.next_layer(), ec);
|
beast::websocket_helpers::call_teardown(stream.next_layer(), ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class TeardownHandler>
|
template<class TeardownHandler>
|
||||||
friend
|
friend
|
||||||
void
|
void
|
||||||
async_teardown(fail_stream<NextLayer>& stream,
|
async_teardown(websocket::teardown_tag,
|
||||||
TeardownHandler&& handler)
|
fail_stream<NextLayer>& stream,
|
||||||
|
TeardownHandler&& handler)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
if(stream.pfc_->fail(ec))
|
if(stream.pfc_->fail(ec))
|
||||||
@@ -182,7 +184,7 @@ public:
|
|||||||
bind_handler(std::move(handler), ec));
|
bind_handler(std::move(handler), ec));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
websocket_helpers::call_async_teardown(
|
beast::websocket_helpers::call_async_teardown(
|
||||||
stream.next_layer(), std::forward<TeardownHandler>(handler));
|
stream.next_layer(), std::forward<TeardownHandler>(handler));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#ifndef BEAST_TEST_STRING_STREAM_HPP
|
#ifndef BEAST_TEST_STRING_STREAM_HPP
|
||||||
#define BEAST_TEST_STRING_STREAM_HPP
|
#define BEAST_TEST_STRING_STREAM_HPP
|
||||||
|
|
||||||
|
#include <beast/core/async_completion.hpp>
|
||||||
#include <beast/core/bind_handler.hpp>
|
#include <beast/core/bind_handler.hpp>
|
||||||
#include <beast/core/error.hpp>
|
#include <beast/core/error.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
|
|||||||