Compare commits
185 Commits
0.33.0
...
0.50.0-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d24bb65639 | ||
|
|
d810f29e99 | ||
|
|
6e3e717876 | ||
|
|
2c87739d6c | ||
|
|
b00b81a861 | ||
|
|
a0a4eedc27 | ||
|
|
c0e9e3df49 | ||
|
|
7028579170 | ||
|
|
84ada74d53 | ||
|
|
be0fb67d8d | ||
|
|
fb60cc9b5b | ||
|
|
3c4d3b10c1 | ||
|
|
d9ef5ef98f | ||
|
|
be9c955506 | ||
|
|
1989b1028f | ||
|
|
0d577d9349 | ||
|
|
7536c53a48 | ||
|
|
e3ff30657c | ||
|
|
698ea58b39 | ||
|
|
a5500721db | ||
|
|
fd4ad29418 | ||
|
|
905c627043 | ||
|
|
8d8907e340 | ||
|
|
6724a63230 | ||
|
|
af4fe24939 | ||
|
|
c1c80dfc52 | ||
|
|
87273e21d8 | ||
|
|
610e51a162 | ||
|
|
e91aacc9a3 | ||
|
|
6e54461f4b | ||
|
|
ef23d72562 | ||
|
|
a1c0d15a1f | ||
|
|
b6a01ea41c | ||
|
|
8425e4558a | ||
|
|
5a688f9236 | ||
|
|
effd8c9737 | ||
|
|
a7c4d682d2 | ||
|
|
e00a6b0e5a | ||
|
|
dc3571184a | ||
|
|
22a375a5f4 | ||
|
|
3337d17fdd | ||
|
|
8ab2236cdd | ||
|
|
0cb6a0f961 | ||
|
|
28ae522ea2 | ||
|
|
c0cf7bd3c1 | ||
|
|
fd7a2835e4 | ||
|
|
3d0314c621 | ||
|
|
8d83aa5c07 | ||
|
|
7ff243ade9 | ||
|
|
2fd0540ed4 | ||
|
|
cdf470e68d | ||
|
|
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 | ||
|
|
98f878cf10 | ||
|
|
69b47890e6 | ||
|
|
41851022d3 | ||
|
|
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
|
||||
|
||||
bin/boostbook_catalog.xml
|
||||
bin/config.log
|
||||
bin/project-cache.jam
|
||||
|
||||
# Ignore vim swap files.
|
||||
*.swp
|
||||
|
||||
@@ -89,3 +93,4 @@ Builds/VisualStudio2015/*.sdf
|
||||
|
||||
# MSVC
|
||||
*.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.
|
||||
- LCOV_ROOT=$HOME/lcov
|
||||
- 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
|
||||
- gcc-5
|
||||
- g++-5
|
||||
- python-software-properties
|
||||
- protobuf-compiler
|
||||
- libprotobuf-dev
|
||||
- libssl-dev
|
||||
- libstdc++6
|
||||
- binutils-gold
|
||||
# Provides a backtrace if the unittests crash
|
||||
- gdb
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages:
|
||||
- gcc-5
|
||||
- g++-5
|
||||
- python-software-properties
|
||||
- protobuf-compiler
|
||||
- libprotobuf-dev
|
||||
- libssl-dev
|
||||
- libstdc++6
|
||||
- binutils-gold
|
||||
# Provides a backtrace if the unittests crash
|
||||
- gdb
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# Default BUILD is "scons".
|
||||
|
||||
- compiler: gcc
|
||||
env: GCC_VER=5 TARGET=debug.nounity
|
||||
addons: &ao_gcc5
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: *gcc5_pkgs
|
||||
env: GCC_VER=5 BUILD=cmake TARGET=debug.nounity PATH=$PWD/cmake/bin:$PATH
|
||||
|
||||
- compiler: gcc
|
||||
env: GCC_VER=5 TARGET=coverage
|
||||
addons: *ao_gcc5
|
||||
|
||||
- compiler: clang
|
||||
env: GCC_VER=5 TARGET=debug CLANG_VER=3.8 PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
||||
addons: *ao_gcc5
|
||||
|
||||
- compiler: clang
|
||||
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:
|
||||
directories:
|
||||
- $BOOST_ROOT
|
||||
- llvm-$LLVM_VERSION
|
||||
- cmake
|
||||
|
||||
before_install:
|
||||
- bin/ci/ubuntu/install-dependencies.sh
|
||||
|
||||
script:
|
||||
- bin/ci/ubuntu/build-and-test.sh
|
||||
- travis_retry bin/ci/ubuntu/build-and-test.sh
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
||||
@@ -9,7 +9,6 @@ url="https://github.com/ripple/rippled"
|
||||
license=('custom:ISC')
|
||||
depends=('protobuf' 'openssl' 'boost-libs')
|
||||
makedepends=('git' 'scons' 'boost')
|
||||
checkdepends=('nodejs')
|
||||
backup=("etc/$pkgname/rippled.cfg")
|
||||
source=("git://github.com/ripple/rippled.git#branch=master")
|
||||
sha512sums=('SKIP')
|
||||
@@ -26,8 +25,6 @@ build() {
|
||||
|
||||
check() {
|
||||
cd "$srcdir/$pkgname"
|
||||
npm install
|
||||
npm test
|
||||
build/rippled --unittest
|
||||
}
|
||||
|
||||
|
||||
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',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--nonpm', '-n',
|
||||
action='store_true',
|
||||
help='Do not run npm tests',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--clean', '-c',
|
||||
action='store_true',
|
||||
@@ -203,15 +197,6 @@ def run_tests(args):
|
||||
if not ARGS.keep_going:
|
||||
break
|
||||
|
||||
if not ARGS.nonpm:
|
||||
print('npm tests for', target)
|
||||
resultcode, lines = shell('npm', ('test', '--rippled=' + executable,))
|
||||
if resultcode:
|
||||
if not ARGS.verbose:
|
||||
print('ERROR:\n', *lines, sep='')
|
||||
failed.append([target, 'npm'])
|
||||
if not ARGS.keep_going:
|
||||
break
|
||||
return failed
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ if [ ${ubuntu_release} == "12.04" ]; then
|
||||
add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||
apt-get update
|
||||
apt-get -y upgrade
|
||||
apt-get -y install curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties boost1.57-all-dev nodejs g++-5 g++-4.9
|
||||
apt-get -y install curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties boost1.57-all-dev g++-5 g++-4.9
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 99 --slave /usr/bin/g++ g++ /usr/bin/g++-5
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 99 --slave /usr/bin/g++ g++ /usr/bin/g++-4.9
|
||||
exit 0
|
||||
@@ -33,12 +33,12 @@ fi
|
||||
|
||||
if [ ${ubuntu_release} == "14.04" ] || [ ${ubuntu_release} == "15.04" ]; then
|
||||
apt-get install python-software-properties
|
||||
echo "deb [arch=amd64] https://mirrors.ripple.com/ubuntu/ trusty stable contrib" | sudo tee /etc/apt/sources.list.d/ripple.list
|
||||
echo "deb [arch=amd64] https://mirrors.ripple.com/ubuntu/ trusty stable contrib" | sudo tee /etc/apt/sources.list.d/ripple.list
|
||||
wget -O- -q https://mirrors.ripple.com/mirrors.ripple.com.gpg.key | sudo apt-key add -
|
||||
add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||
apt-get update
|
||||
apt-get -y upgrade
|
||||
apt-get -y install curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties boost-all-dev nodejs g++-5 g++-4.9
|
||||
apt-get -y install curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties boost-all-dev g++-5 g++-4.9
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 99 --slave /usr/bin/g++ g++ /usr/bin/g++-5
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 99 --slave /usr/bin/g++ g++ /usr/bin/g++-4.9
|
||||
exit 0
|
||||
@@ -47,7 +47,7 @@ fi
|
||||
if [ ${ubuntu_release} == "16.04" ] || [ ${ubuntu_release} == "15.10" ]; then
|
||||
apt-get update
|
||||
apt-get -y upgrade
|
||||
apt-get -y install python-software-properties curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties libboost-all-dev nodejs
|
||||
apt-get -y install python-software-properties curl git scons ctags pkg-config protobuf-compiler libprotobuf-dev libssl-dev python-software-properties libboost-all-dev
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
@@ -17,8 +17,7 @@ software components:
|
||||
* [Google Protocol Buffers Compiler](README.md#install-google-protocol-buffers-compiler)
|
||||
* (Optional) [Python and Scons](README.md#optional-install-python-and-scons)
|
||||
* [OpenSSL Library](README.md#install-openssl)
|
||||
* [Boost 1.59 library](README.md#build-boost)
|
||||
* [Node.js](README.md#install-nodejs)
|
||||
* [Boost library](README.md#build-boost)
|
||||
|
||||
## Install Software
|
||||
|
||||
@@ -84,8 +83,8 @@ for Visual Studio 2015 support.
|
||||
[Download OpenSSL.](http://slproweb.com/products/Win32OpenSSL.html)
|
||||
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".
|
||||
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"
|
||||
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.2j Light"
|
||||
|
||||
Run the installer, and choose an appropriate location for your OpenSSL
|
||||
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
|
||||
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
|
||||
cd C:\lib\boost_1_59_0
|
||||
cd C:\lib\boost_1_62_0
|
||||
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:
|
||||
|
||||
```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
|
||||
@@ -161,7 +165,7 @@ git checkout master
|
||||
### Configure Library Paths
|
||||
|
||||
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
|
||||
double click the *Microsoft.Cpp.x64.user* property sheet to bring up the
|
||||
*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)
|
||||
|
||||
## Internal
|
||||
|
||||
The internal rippled unit tests are written in C++ and are part
|
||||
The rippled unit tests are written in C++ and are part
|
||||
of the rippled executable.
|
||||
|
||||
From a Windows console, run the unit tests:
|
||||
@@ -250,108 +252,4 @@ From a Windows console, run the unit tests:
|
||||
|
||||
Substitute the correct path to the executable to test different builds.
|
||||
|
||||
## External
|
||||
|
||||
The external rippled unit tests are written in Javascript using Node.js,
|
||||
and utilize the mocha unit test framework. To run the unit tests, it
|
||||
will be necessary to perform the following steps:
|
||||
|
||||
### Install Node.js
|
||||
|
||||
[Install Node.js](http://nodejs.org/download/). We recommend the Windows
|
||||
installer (**.msi** file) as it takes care of updating the *PATH* environment
|
||||
variable so that scripts can find the command. On Windows systems,
|
||||
**Node.js** comes with **npm**. A separate installation of **npm**
|
||||
is not necessary.
|
||||
|
||||
### Create node_modules
|
||||
|
||||
Open a windows console. From the root of your local rippled repository
|
||||
directory, invoke **npm** to bring in the necessary components:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
If you get an error that looks like
|
||||
|
||||
```
|
||||
Error: ENOENT, stat 'C:\Users\username\AppData\Roaming\npm'
|
||||
```
|
||||
|
||||
simply create the indicated folder and try again.
|
||||
|
||||
### Create a test config.js
|
||||
|
||||
From a *bash* shell (installed with Git for Windows), copy the
|
||||
example configuration file into the appropriate location:
|
||||
|
||||
```
|
||||
cp test/config-example.js test/config.js
|
||||
```
|
||||
|
||||
Edit your version of test/config.js to reflect the correct path to the rippled executable:
|
||||
|
||||
```
|
||||
exports.default_server_config = {
|
||||
// Where to find the binary.
|
||||
rippled_path: path.resolve(__dirname, "../build/msvc.debug/rippled.exe")
|
||||
};
|
||||
```
|
||||
|
||||
Also in **test/config.js**, change any occurrences of the
|
||||
IP address *0.0.0.0* to *127.0.0.1*.
|
||||
|
||||
### Run Tests
|
||||
|
||||
From a windows console, run the unit tests:
|
||||
|
||||
```
|
||||
npm test
|
||||
```
|
||||
|
||||
Alternatively, run an individual test using mocha:
|
||||
|
||||
```
|
||||
sh
|
||||
node_modules/mocha/bin/mocha test/account_tx-test.js
|
||||
```
|
||||
|
||||
* NOTE: The version of ripple-lib provided by the npm install
|
||||
facility is usually slightly behind the develop branch of the
|
||||
authoritative ripple-lib repository. Therefore, some tests might fail.
|
||||
|
||||
### Development ripple-lib
|
||||
|
||||
To use the latest branch of **ripple-lib** during the unit tests,
|
||||
first clone the repository in a new location outside of your rippled
|
||||
repository. Then update the submodules. After, run **npm install**
|
||||
to set up the **node_modules** directory. Finally, install the
|
||||
**grunt** command line tools required to run **grunt** and
|
||||
build **ripple-lib**.
|
||||
|
||||
```
|
||||
git clone git@github.com:ripple/ripple-lib.git
|
||||
cd ripple-lib
|
||||
git submodule update --init
|
||||
npm install
|
||||
npm install -g grunt-cli
|
||||
grunt
|
||||
```
|
||||
|
||||
Now link this version of **ripple-lib** into the global packages:
|
||||
|
||||
```
|
||||
sudo npm link
|
||||
```
|
||||
|
||||
To make rippled use the newly linked global **ripple-lib** package
|
||||
instead of the one installed under **node_modules**, change
|
||||
directories to the local rippled repository and delete the old
|
||||
**ripple-lib** then link to the new one:
|
||||
|
||||
```
|
||||
sh
|
||||
rm -rf node_modules/ripple-lib
|
||||
npm link ripple-lib
|
||||
```
|
||||
|
||||
|
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
|
||||
transactions on a secure distributed database, the Ripple Consensus Ledger
|
||||
(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
|
||||
and currency pairs.
|
||||
|
||||
@@ -67,8 +67,6 @@ ISC license. See the LICENSE file for more details.
|
||||
| ./Builds| Platform or IDE-specific project files. |
|
||||
| ./doc | Documentation and example configuration files. |
|
||||
| ./src | Source code. |
|
||||
| ./test | Javascript / Mocha tests. |
|
||||
|
||||
|
||||
Some of the directories under `src` are external repositories inlined via
|
||||
git-subtree. See the corresponding README for more details.
|
||||
|
||||
104
SConstruct
@@ -115,6 +115,7 @@ TODO
|
||||
|
||||
import collections
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
@@ -122,6 +123,10 @@ import time
|
||||
import glob
|
||||
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', 'site_scons'))
|
||||
|
||||
@@ -380,11 +385,13 @@ def config_base(env):
|
||||
except KeyError:
|
||||
pass
|
||||
elif Beast.system.osx:
|
||||
OSX_OPENSSL_ROOT = '/usr/local/Cellar/openssl/'
|
||||
most_recent = sorted(os.listdir(OSX_OPENSSL_ROOT))[-1]
|
||||
openssl = os.path.join(OSX_OPENSSL_ROOT, most_recent)
|
||||
env.Prepend(CPPPATH='%s/include' % openssl)
|
||||
env.Prepend(LIBPATH=['%s/lib' % openssl])
|
||||
try:
|
||||
openssl = subprocess.check_output(['brew', '--prefix','openssl'],
|
||||
stderr=subprocess.STDOUT).strip()
|
||||
env.Prepend(CPPPATH='%s/include' % openssl)
|
||||
env.Prepend(LIBPATH=['%s/lib' % openssl])
|
||||
except:
|
||||
pass
|
||||
if not 'vcxproj' in COMMAND_LINE_TARGETS:
|
||||
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.append('BOOST_ROOT')
|
||||
BOOST_ROOT = os.path.normpath(get_environ_value(br_cands))
|
||||
env.Append(LIBPATH=[
|
||||
os.path.join(BOOST_ROOT, 'stage', 'lib'),
|
||||
])
|
||||
stage64_path = os.path.join(BOOST_ROOT, 'stage64', '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
|
||||
if toolchain in ['gcc', 'clang']:
|
||||
env.Append(CCFLAGS=['-isystem' + env['BOOST_ROOT']])
|
||||
@@ -487,6 +500,10 @@ def enable_asserts ():
|
||||
# Set toolchain and variant specific construction variables
|
||||
def config_env(toolchain, variant, 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):
|
||||
env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
|
||||
|
||||
@@ -541,7 +558,8 @@ def config_env(toolchain, variant, env):
|
||||
env.Append(CXXFLAGS=[
|
||||
'-frtti',
|
||||
'-std=c++14',
|
||||
'-Wno-invalid-offsetof'])
|
||||
'-Wno-invalid-offsetof'
|
||||
])
|
||||
|
||||
env.Append(CPPDEFINES=['_FILE_OFFSET_BITS=64'])
|
||||
|
||||
@@ -575,6 +593,9 @@ def config_env(toolchain, variant, env):
|
||||
])
|
||||
|
||||
boost_libs = [
|
||||
# resist the temptation to alphabetize these. coroutine
|
||||
# must come before context.
|
||||
'boost_chrono',
|
||||
'boost_coroutine',
|
||||
'boost_context',
|
||||
'boost_date_time',
|
||||
@@ -591,9 +612,13 @@ def config_env(toolchain, variant, env):
|
||||
else:
|
||||
# We prefer static libraries for boost
|
||||
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
|
||||
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]
|
||||
env.Append(LIBS=boost_libs)
|
||||
|
||||
@@ -771,6 +796,7 @@ base.Append(CPPPATH=[
|
||||
os.path.join('src', 'beast'),
|
||||
os.path.join('src', 'beast', 'include'),
|
||||
os.path.join('src', 'beast', 'extras'),
|
||||
os.path.join('src', 'nudb', 'include'),
|
||||
os.path.join(build_dir, 'proto'),
|
||||
os.path.join('src','soci','src'),
|
||||
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/insight', '.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/app', '.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/json', '.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/shamap', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/server', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/test', '.cpp'))
|
||||
append_sources(result,
|
||||
'src/test/BasicNetwork_test.cpp',
|
||||
'src/test/Env_test.cpp',
|
||||
'src/test/WSClient_test.cpp')
|
||||
append_sources(result, *list_sources('src/test/app', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/basics', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/beast', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/conditions', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/core', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/json', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/ledger', '.cpp'))
|
||||
@@ -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/server', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/shamap', '.cpp'))
|
||||
append_sources(result, *list_sources('src/test/jtx', '.cpp'))
|
||||
|
||||
|
||||
if use_shp(toolchain):
|
||||
cc_flags = {'CCFLAGS': ['--system-header-prefix=rocksdb2']}
|
||||
@@ -974,6 +998,7 @@ def get_unity_sources(toolchain):
|
||||
'src/ripple/unity/app_misc.cpp',
|
||||
'src/ripple/unity/app_paths.cpp',
|
||||
'src/ripple/unity/app_tx.cpp',
|
||||
'src/ripple/unity/conditions.cpp',
|
||||
'src/ripple/unity/core.cpp',
|
||||
'src/ripple/unity/basics.cpp',
|
||||
'src/ripple/unity/crypto.cpp',
|
||||
@@ -986,21 +1011,21 @@ def get_unity_sources(toolchain):
|
||||
'src/ripple/unity/rpcx.cpp',
|
||||
'src/ripple/unity/shamap.cpp',
|
||||
'src/ripple/unity/server.cpp',
|
||||
'src/ripple/unity/test.cpp',
|
||||
'src/unity/app_test_unity.cpp',
|
||||
'src/unity/basics_test_unity.cpp',
|
||||
'src/unity/beast_test_unity.cpp',
|
||||
'src/unity/core_test_unity.cpp',
|
||||
'src/unity/json_test_unity.cpp',
|
||||
'src/unity/ledger_test_unity.cpp',
|
||||
'src/unity/overlay_test_unity.cpp',
|
||||
'src/unity/peerfinder_test_unity.cpp',
|
||||
'src/unity/protocol_test_unity.cpp',
|
||||
'src/unity/resource_test_unity.cpp',
|
||||
'src/unity/rpc_test_unity.cpp',
|
||||
'src/unity/server_test_unity.cpp',
|
||||
'src/unity/shamap_test_unity.cpp',
|
||||
'src/unity/test_unity.cpp'
|
||||
'src/test/unity/app_test_unity.cpp',
|
||||
'src/test/unity/basics_test_unity.cpp',
|
||||
'src/test/unity/beast_test_unity.cpp',
|
||||
'src/test/unity/core_test_unity.cpp',
|
||||
'src/test/unity/conditions_test_unity.cpp',
|
||||
'src/test/unity/json_test_unity.cpp',
|
||||
'src/test/unity/ledger_test_unity.cpp',
|
||||
'src/test/unity/overlay_test_unity.cpp',
|
||||
'src/test/unity/peerfinder_test_unity.cpp',
|
||||
'src/test/unity/protocol_test_unity.cpp',
|
||||
'src/test/unity/resource_test_unity.cpp',
|
||||
'src/test/unity/rpc_test_unity.cpp',
|
||||
'src/test/unity/server_test_unity.cpp',
|
||||
'src/test/unity/shamap_test_unity.cpp',
|
||||
'src/test/unity/support_unity.cpp'
|
||||
)
|
||||
|
||||
if use_shp(toolchain):
|
||||
@@ -1011,7 +1036,7 @@ def get_unity_sources(toolchain):
|
||||
append_sources(
|
||||
result,
|
||||
'src/ripple/unity/nodestore.cpp',
|
||||
'src/unity/nodestore_test_unity.cpp',
|
||||
'src/test/unity/nodestore_test_unity.cpp',
|
||||
CPPPATH=[
|
||||
'src/rocksdb2/include',
|
||||
'src/snappy/snappy',
|
||||
@@ -1134,7 +1159,6 @@ for tu_style in ['classic', 'unity']:
|
||||
'src/ripple/unity/protobuf.cpp',
|
||||
'src/ripple/unity/ripple.proto.cpp',
|
||||
'src/ripple/unity/resource.cpp',
|
||||
'src/ripple/unity/websocket02.cpp',
|
||||
**cc_flags
|
||||
)
|
||||
|
||||
@@ -1150,7 +1174,7 @@ for tu_style in ['classic', 'unity']:
|
||||
cc_flags = {}
|
||||
|
||||
object_builder.add_source_files(
|
||||
'src/ripple/unity/ed25519.c',
|
||||
'src/ripple/unity/ed25519_donna.c',
|
||||
CPPPATH=[
|
||||
'src/ed25519-donna',
|
||||
]
|
||||
@@ -1219,7 +1243,13 @@ for key, value in aliases.iteritems():
|
||||
vcxproj = base.VSProject(
|
||||
os.path.join('Builds', 'VisualStudio2015', 'RippleD'),
|
||||
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)
|
||||
base.Alias('vcxproj', vcxproj)
|
||||
|
||||
@@ -1241,10 +1271,10 @@ def do_count(target, source, env):
|
||||
path = os.path.join(parent, path)
|
||||
r = os.path.splitext(path)
|
||||
if r[1] in suffixes:
|
||||
if r[0].endswith('.test'):
|
||||
if r[0].endswith('_test'):
|
||||
yield os.path.normpath(path)
|
||||
return list(_iter(base))
|
||||
testfiles = list_testfiles(os.path.join('src', 'ripple'), env.get('CPPSUFFIXES'))
|
||||
testfiles = list_testfiles(os.path.join('src', 'test'), env.get('CPPSUFFIXES'))
|
||||
lines = 0
|
||||
for f in testfiles:
|
||||
lines = lines + sum(1 for line in open(f))
|
||||
|
||||
115
appveyor.yml
@@ -6,22 +6,39 @@ environment:
|
||||
# that it's a small download. We also use appveyor's free cache, avoiding fees
|
||||
# downloading from S3 each time.
|
||||
# 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.
|
||||
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
|
||||
|
||||
# Scons honours these environment variables, setting the include/lib paths.
|
||||
BOOST_ROOT: C:/rippled_deps15.01/boost
|
||||
OPENSSL_ROOT: C:/rippled_deps15.01/openssl
|
||||
BOOST_ROOT: C:/%RIPPLED_DEPS_PATH%/boost
|
||||
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
|
||||
|
||||
# At the end of each successful build we cache this directory. It must be less
|
||||
# than 100MB total compressed.
|
||||
# At the end of each successful build we cache this directory.
|
||||
# https://www.appveyor.com/docs/build-cache/
|
||||
# Resulting archive should not exceed 100 MB.
|
||||
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
|
||||
# history.
|
||||
@@ -29,38 +46,37 @@ shallow_clone: true
|
||||
|
||||
install:
|
||||
# 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: Start-FileDownload $env:PIP_URL
|
||||
- ps: Start-FileDownload $env:PYWIN32_URL
|
||||
|
||||
# Installing pip will install setuptools/easy_install.
|
||||
- python get-pip.py
|
||||
|
||||
# Pip has some problems installing scons on windows so we use easy install.
|
||||
# - easy_install scons
|
||||
# Workaround
|
||||
- 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.
|
||||
- easy_install pywin32-220.win-amd64-py2.7.exe
|
||||
# (easy_install can do headless installs of .exe wizards)
|
||||
- ps: |
|
||||
if ($env:build -eq "scons") {
|
||||
if(-not(Test-Path $env:PIP_PATH)) {
|
||||
echo "Download from $env:PIP_URL"
|
||||
Start-FileDownload $env:PIP_URL
|
||||
}
|
||||
if(-not(Test-Path $env:PYWIN32_PATH)) {
|
||||
echo "Download from $env:PYWIN32_URL"
|
||||
Start-FileDownload $env:PYWIN32_URL
|
||||
}
|
||||
}
|
||||
- bin/ci/windows/install-dependencies.bat
|
||||
|
||||
# Download dependencies if appveyor didn't restore them from the cache.
|
||||
# Use 7zip to unzip.
|
||||
- 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"
|
||||
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.
|
||||
# Dump it so we can verify correct behavior.
|
||||
- ps: |
|
||||
if (Test-Path 'C:/rippled_deps15.01/versions.txt') {
|
||||
cat 'C:/rippled_deps15.01/versions.txt'
|
||||
if (Test-Path "C:/$env:RIPPLED_DEPS_PATH/versions.txt") {
|
||||
cat "C:/$env:RIPPLED_DEPS_PATH/versions.txt"
|
||||
}
|
||||
|
||||
# TODO: This is giving me grief
|
||||
@@ -73,17 +89,46 @@ build_script:
|
||||
- '"%VS140COMNTOOLS%../../VC/vcvarsall.bat" x86_amd64'
|
||||
# Show which version of the compiler we are using.
|
||||
- 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:
|
||||
# Put our executable in a place where npm test can find it.
|
||||
- ps: cp build/msvc.debug/rippled.exe build
|
||||
- ps: ls build
|
||||
- ps: |
|
||||
if ($env:build -eq "scons") {
|
||||
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:
|
||||
# Run the unit tests
|
||||
- build\\rippled --unittest
|
||||
- ps: |
|
||||
& {
|
||||
# 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
|
||||
# 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
|
||||
set -e
|
||||
# processes launched or upon any unbound variable.
|
||||
# We use set -x to print commands before running them to help with
|
||||
# debugging.
|
||||
set -ex
|
||||
__dirname=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
echo "using CC: $CC"
|
||||
echo "using TARGET: $TARGET"
|
||||
export RIPPLED_PATH="$PWD/build/$CC.$TARGET/rippled"
|
||||
echo "using RIPPLED_PATH: $RIPPLED_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
|
||||
|
||||
# Ensure APP defaults to rippled if it's not set.
|
||||
: ${APP:=rippled}
|
||||
if [[ ${BUILD:-scons} == "cmake" ]]; then
|
||||
echo "cmake building ${APP}"
|
||||
CMAKE_TARGET=$CC.$TARGET
|
||||
if [[ ${CI:-} == true ]]; then
|
||||
CMAKE_TARGET=$CMAKE_TARGET.ci
|
||||
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
|
||||
# (-f so never err)
|
||||
rm -f build/rippled
|
||||
rm -f build/${APP}
|
||||
|
||||
# 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
|
||||
export PATH=$PATH:$LCOV_ROOT/usr/bin
|
||||
@@ -36,7 +70,7 @@ gdb -return-child-result -quiet -batch \
|
||||
-ex run \
|
||||
-ex "thread apply all backtrace full" \
|
||||
-ex "quit" \
|
||||
--args $RIPPLED_PATH --unittest
|
||||
--args $APP_PATH --unittest
|
||||
|
||||
if [[ $TARGET == "coverage" ]]; then
|
||||
# Create test coverage data file
|
||||
@@ -45,16 +79,14 @@ if [[ $TARGET == "coverage" ]]; then
|
||||
# Combine baseline and test coverage data
|
||||
lcov -a baseline.info -a tests.info -o lcov-all.info
|
||||
|
||||
# Only report on src/ripple files
|
||||
lcov -e "lcov-all.info" "*/src/ripple/*" -o lcov.pre.info
|
||||
# Included files
|
||||
lcov -e "lcov-all.info" "${LCOV_FILES}" -o lcov.pre.info
|
||||
|
||||
# Exclude */src/test directory
|
||||
lcov --remove lcov.pre.info "*/src/ripple/test/*" -o lcov.info
|
||||
# Excluded files
|
||||
lcov --remove lcov.pre.info "${LCOV_EXCLUDE_FILES}" -o lcov.info
|
||||
|
||||
# Push the results (lcov.info) to codecov
|
||||
codecov -X gcov # don't even try and look for .gcov files ;)
|
||||
fi
|
||||
|
||||
# Run NPM tests
|
||||
npm install --progress=false
|
||||
npm test --rippled=$RIPPLED_PATH
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#!/bin/bash -u
|
||||
# Exit if anything fails.
|
||||
set -e
|
||||
# Exit if anything fails. Echo commands to aid debugging.
|
||||
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.
|
||||
# Put an appropriate symlink at the front of the path.
|
||||
mkdir -v $HOME/bin
|
||||
@@ -13,16 +18,34 @@ done
|
||||
if [[ -n ${CLANG_VER:-} ]]; then
|
||||
# There are cases where the directory exists, but the exe is not available.
|
||||
# Use this workaround for now.
|
||||
if [[ ! -x llvm-${LLVM_VERSION}/bin/llvm-config ]] && [[ -d llvm-${LLVM_VERSION} ]]; then
|
||||
rm -fr llvm-${LLVM_VERSION}
|
||||
if [[ ! -x ${TWD}/llvm-${LLVM_VERSION}/bin/llvm-config && -d ${TWD}/llvm-${LLVM_VERSION} ]]; then
|
||||
rm -fr ${TWD}/llvm-${LLVM_VERSION}
|
||||
fi
|
||||
if [[ ! -d llvm-${LLVM_VERSION} ]]; then
|
||||
mkdir llvm-${LLVM_VERSION}
|
||||
if [[ ! -d ${TWD}/llvm-${LLVM_VERSION} ]]; then
|
||||
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"
|
||||
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
|
||||
llvm-${LLVM_VERSION}/bin/llvm-config --version;
|
||||
export LLVM_CONFIG="llvm-${LLVM_VERSION}/bin/llvm-config";
|
||||
fi
|
||||
|
||||
# What versions are we ACTUALLY running?
|
||||
@@ -30,11 +53,6 @@ if [ -x $HOME/bin/g++ ]; then
|
||||
$HOME/bin/g++ -v
|
||||
fi
|
||||
|
||||
# Avoid `spurious errors` caused by ~/.npm permission issues
|
||||
# Does it already exist? Who owns? What permissions?
|
||||
ls -lah ~/.npm || mkdir ~/.npm
|
||||
# Make sure we own it
|
||||
chown -Rc $USER ~/.npm
|
||||
pip install --user https://github.com/codecov/codecov-python/archive/master.zip
|
||||
|
||||
bash bin/sh/install-boost.sh
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
representation of the context.
|
||||
|
||||
|
||||
@@ -49,3 +49,4 @@ sfSequence = field_code(STI_UINT32, 4)
|
||||
sfPublicKey = field_code(STI_VL, 1)
|
||||
sfSigningPubKey = field_code(STI_VL, 3)
|
||||
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 ed25519
|
||||
import ecdsa
|
||||
import hashlib
|
||||
from ripple.util import Base58
|
||||
from ripple.ledger import SField
|
||||
|
||||
ED25519_BYTE = chr(0xed)
|
||||
WRAP_COLUMNS = 60
|
||||
WRAP_COLUMNS = 72
|
||||
|
||||
USAGE = """\
|
||||
Usage:
|
||||
@@ -22,12 +23,9 @@ Usage:
|
||||
check <key>
|
||||
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
|
||||
number, validator public key, and master secret key.
|
||||
|
||||
verify <sequence> <validator-public> <signature> <master-public>
|
||||
Verify hex-encoded manifest signature with master public key.
|
||||
number and keys.
|
||||
"""
|
||||
|
||||
def prepend_length_byte(b):
|
||||
@@ -44,17 +42,17 @@ def make_seed(urandom=os.urandom):
|
||||
return urandom(16)
|
||||
|
||||
def make_ed25519_keypair(urandom=os.urandom):
|
||||
private_key = urandom(32)
|
||||
return private_key, ed25519.publickey(private_key)
|
||||
sk = urandom(32)
|
||||
return sk, ed25519.publickey(sk)
|
||||
|
||||
def make_ecdsa_keypair():
|
||||
def make_ecdsa_keypair(urandom=None):
|
||||
# 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.
|
||||
vk = private_key.get_verifying_key()
|
||||
sig = private_key.sign('message')
|
||||
vk = sk.get_verifying_key()
|
||||
sig = sk.sign('message')
|
||||
assert vk.verify(sig, 'message')
|
||||
return private_key, vk
|
||||
return sk, vk
|
||||
|
||||
def make_seed_from_passphrase(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.
|
||||
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([
|
||||
SField.sfSequence,
|
||||
to_int32(seq),
|
||||
SField.sfPublicKey, # Master public key.
|
||||
prepend_length_byte(public_key),
|
||||
SField.sfSigningPubKey, # Ephemeral public key.
|
||||
prepend_length_byte(validator_public_key)])
|
||||
SField.sfPublicKey,
|
||||
prepend_length_byte(master_pk),
|
||||
SField.sfSigningPubKey,
|
||||
prepend_length_byte(validation_pk)])
|
||||
|
||||
def sign_manifest(manifest, private_key, public_key):
|
||||
sig = ed25519.signature('MAN\0' + manifest, private_key, public_key)
|
||||
return manifest + SField.sfSignature + prepend_length_byte(sig)
|
||||
def sign_manifest(manifest, validation_sk, master_sk, master_pk):
|
||||
"""sign a validator manifest
|
||||
|
||||
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):
|
||||
if s:
|
||||
@@ -83,72 +121,64 @@ def wrap(s, cols=WRAP_COLUMNS):
|
||||
return s
|
||||
|
||||
def create_ed_keys(urandom=os.urandom):
|
||||
private_key, public_key = make_ed25519_keypair(urandom)
|
||||
public_key_human = Base58.encode_version(
|
||||
Base58.VER_NODE_PUBLIC, ED25519_BYTE + public_key)
|
||||
private_key_human = Base58.encode_version(
|
||||
Base58.VER_NODE_PRIVATE, private_key)
|
||||
return public_key_human, private_key_human
|
||||
sk, pk = make_ed25519_keypair(urandom)
|
||||
pk_human = Base58.encode_version(
|
||||
Base58.VER_NODE_PUBLIC, ED25519_BYTE + pk)
|
||||
sk_human = Base58.encode_version(
|
||||
Base58.VER_NODE_PRIVATE, sk)
|
||||
return pk_human, sk_human
|
||||
|
||||
def create_ed_public_key(private_key_human):
|
||||
v, private_key = Base58.decode_version(private_key_human)
|
||||
check_master_secret(v, private_key)
|
||||
def create_ed_public_key(sk_human):
|
||||
v, sk = Base58.decode_version(sk_human)
|
||||
check_secret_key(v, sk)
|
||||
|
||||
public_key = ed25519.publickey(private_key)
|
||||
public_key_human = Base58.encode_version(
|
||||
Base58.VER_NODE_PUBLIC, ED25519_BYTE + public_key)
|
||||
return public_key_human
|
||||
pk = ed25519.publickey(sk)
|
||||
pk_human = Base58.encode_version(
|
||||
Base58.VER_NODE_PUBLIC, ED25519_BYTE + pk)
|
||||
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)
|
||||
if len(validator_public_key) != 33:
|
||||
raise ValueError('Validator key should be length 33, is %s' %
|
||||
len(validator_public_key))
|
||||
b = ord(validator_public_key[0])
|
||||
if len(pk) != 33:
|
||||
raise ValueError('Validation public key should be length 33, is %s' %
|
||||
len(pk))
|
||||
b = ord(pk[0])
|
||||
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)
|
||||
if len(private_key) != 32:
|
||||
if len(sk) != 32:
|
||||
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, validator_public_key = Base58.decode_version(validator_public_key_human)
|
||||
check_validator_public(v, validator_public_key)
|
||||
v, validation_sk_str = Base58.decode_version(validation_sk_human)
|
||||
check_secret_key(v, validation_sk_str)
|
||||
validation_sk = ecdsa.SigningKey.from_string(validation_sk_str, curve=ecdsa.SECP256k1)
|
||||
|
||||
v, private_key = Base58.decode_version(private_key_human)
|
||||
check_master_secret(v, private_key)
|
||||
v, master_sk = Base58.decode_version(master_sk_human)
|
||||
check_secret_key(v, master_sk)
|
||||
|
||||
pk = ed25519.publickey(private_key)
|
||||
pk = ed25519.publickey(master_sk)
|
||||
apk = ED25519_BYTE + pk
|
||||
m = make_manifest(apk, validator_public_key, seq)
|
||||
m1 = sign_manifest(m, private_key, pk)
|
||||
m = make_manifest(apk, validation_pk, seq)
|
||||
m1 = sign_manifest(m, validation_sk, master_sk, pk)
|
||||
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.
|
||||
def perform_create(urandom=os.urandom, print=print):
|
||||
public, private = create_ed_keys(urandom)
|
||||
print('[validator_keys]', public, '', '[master_secret]', private, sep='\n')
|
||||
pk, sk = create_ed_keys(urandom)
|
||||
print('[validator_keys]', pk, '', '[master_secret]', sk, sep='\n')
|
||||
|
||||
def perform_create_public(private_key_human, print=print):
|
||||
public_key_human = create_ed_public_key(private_key_human)
|
||||
def perform_create_public(sk_human, print=print):
|
||||
pk_human = create_ed_public_key(sk_human)
|
||||
print(
|
||||
'[validator_keys]',public_key_human, '',
|
||||
'[master_secret]', private_key_human, sep='\n')
|
||||
'[validator_keys]',pk_human, '',
|
||||
'[master_secret]', sk_human, sep='\n')
|
||||
|
||||
def perform_check(s, print=print):
|
||||
version, b = Base58.decode_version(s)
|
||||
@@ -157,32 +187,29 @@ def perform_check(s, print=print):
|
||||
assert Base58.encode_version(version, b) == s
|
||||
|
||||
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(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(
|
||||
seq, validator_public_key_human, public_key_human, signature, print=print):
|
||||
seq, validation_pk_human, master_pk_human, signature, print=print):
|
||||
verify_signature(
|
||||
int(seq), validator_public_key_human, public_key_human, signature)
|
||||
print('Signature valid for', public_key_human)
|
||||
int(seq), validation_pk_human, master_pk_human, signature)
|
||||
print('Signature valid for', master_pk_human)
|
||||
|
||||
# Externally visible versions of functions.
|
||||
def create(private_key_human=None):
|
||||
if private_key_human:
|
||||
perform_create_public(private_key_human)
|
||||
def create(sk_human=None):
|
||||
if sk_human:
|
||||
perform_create_public(sk_human)
|
||||
else:
|
||||
perform_create()
|
||||
|
||||
def check(s):
|
||||
perform_check(s)
|
||||
|
||||
def sign(seq, validator_public_key_human, private_key_human):
|
||||
perform_sign(seq, validator_public_key_human, private_key_human)
|
||||
|
||||
def verify(seq, validator_public_key_human, public_key_human, signature):
|
||||
perform_verify(seq, validator_public_key_human, public_key_human, signature)
|
||||
def sign(seq, validation_pk_human, validation_sk_human, master_sk_human):
|
||||
perform_sign(seq, validation_pk_human, validation_sk_human, master_sk_human)
|
||||
|
||||
def usage(*errors):
|
||||
if errors:
|
||||
@@ -190,7 +217,7 @@ def usage(*errors):
|
||||
print(USAGE)
|
||||
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):
|
||||
if not args:
|
||||
|
||||
@@ -10,14 +10,7 @@ BINARY = 'nN9kfUnKTf7PpgLG'
|
||||
|
||||
class test_Sign(TestCase):
|
||||
SEQUENCE = 23
|
||||
SIGNATURE = (
|
||||
'JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2'
|
||||
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJM'
|
||||
'zqkBJwDz30b2SkxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA')
|
||||
VALIDATOR_KEY_HUMAN = 'n9JijuoCv8ubEy5ag3LiX3hyq27GaLJsitZPbQ6APkwx2MkUXq8E'
|
||||
SIGNATURE_HEX = (
|
||||
'0a1546caa29c887f9fcb5e6143ea101b31fb5895a5cdfa24939301c66ff51794'
|
||||
'a0b729e0ebbf576f2cc7cdb9f68c2366324a53b8e1ecf16f3c17bebbdb8d7102')
|
||||
|
||||
def setUp(self):
|
||||
self.results = []
|
||||
@@ -59,13 +52,17 @@ class test_Sign(TestCase):
|
||||
'\xef*\x97\x16n<\xa6\xf2\xe4\xfb\xfc\xcd\x80P[\xf1s\x06verify')
|
||||
|
||||
def test_sign_manifest(self):
|
||||
ssk, spk = Sign.make_ecdsa_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(
|
||||
s, 'manifestv@\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')
|
||||
s, 'manifestvF0D\x02 \x04\x85\x95p\x0f\xb8\x17\x7f\xdf\xdd\x04'
|
||||
'\xaa+\x16q1W\xf6\xfd\xe8X\xb12l\xd5\xc3\xf1\xd6\x05\x1b\x1c\x9a'
|
||||
'\x02 \x18\\.(o\xa8 \xeb\x87\xfa&~\xbd\xe6,\xfb\xa61\xd1\xcd\xcd'
|
||||
'\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):
|
||||
wrap = lambda s: Sign.wrap(s, 5)
|
||||
@@ -93,23 +90,21 @@ class test_Sign(TestCase):
|
||||
public = (Base58.VER_NODE_PUBLIC, '\x02' + (32 * 'v'))
|
||||
private = (Base58.VER_NODE_PRIVATE, 32 * 'k')
|
||||
|
||||
Sign.check_validator_public(*public)
|
||||
Sign.check_master_secret(*private)
|
||||
Sign.check_validation_public_key(*public)
|
||||
Sign.check_secret_key(*private)
|
||||
|
||||
return (Base58.encode_version(*public), Base58.encode_version(*private))
|
||||
|
||||
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(
|
||||
signature,
|
||||
'JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2'
|
||||
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJM'
|
||||
'zqkBJwDz30b2SkxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA')
|
||||
|
||||
def test_verify_signature(self):
|
||||
Sign.verify_signature(self.SEQUENCE, self.VALIDATOR_KEY_HUMAN,
|
||||
'nHUUaKHpxyRP4TZZ79tTpXuTpoM8pRNs5crZpGVA5jdrjib5easY',
|
||||
self.SIGNATURE_HEX)
|
||||
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkYwRAIgXyobHA8sDQxmDJNLE6HI'
|
||||
'aARlzvcd79/wT068e113gUkCIHkI540JQT2LHwAD7/y3wFE5X3lEXMfgZRkpLZTx'
|
||||
'kpticBJAzo5VrUEr0U47sHvuIjbrINLCTM6pAScA899G9kpMWexbXv1ceIbTP5JH'
|
||||
'1HyQmsZsROTeHR0irojvYgx7JLaiAA==')
|
||||
|
||||
def test_check(self):
|
||||
public = Base58.encode_version(Base58.VER_NODE_PRIVATE, 32 * 'k')
|
||||
@@ -143,17 +138,12 @@ class test_Sign(TestCase):
|
||||
|
||||
def test_sign(self):
|
||||
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.results,
|
||||
[[['[validation_manifest]'], {}],
|
||||
[['JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmo\n'
|
||||
'VCdIw6nMhAnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dn\n'
|
||||
'Z2dnZ2dkDOjlWtQSvRTjuwe+4iNusg0sJMzqkBJwDz30b2S\n'
|
||||
'kxZ7Fte/Vx4htM/kkfUfJCaxmxE5N4dHSKuiO9iDHsktqIA'],
|
||||
[['JAAAABdxIe2DIKUZd9jDjKikknxnDfWCHkSXYZReFenvsmoVCdIw6nMhAnZ2dnZ2dnZ2dnZ2\n'
|
||||
'dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dkYwRAIgXyobHA8sDQxmDJNLE6HIaARlzvcd79/wT068\n'
|
||||
'e113gUkCIHkI540JQT2LHwAD7/y3wFE5X3lEXMfgZRkpLZTxkpticBJAzo5VrUEr0U47sHvu\n'
|
||||
'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:
|
||||
# Execute unit tests under gdb
|
||||
- gdb -return-child-result -quiet -batch -ex "set env MALLOC_CHECK_=3" -ex "set print thread-events off" -ex run -ex "thread apply all backtrace full" -ex "quit" --args build/clang.debug/rippled --unittest
|
||||
- npm install --progress=false
|
||||
- |
|
||||
echo "exports.default_server_config = {\"rippled_path\" : \"$HOME/rippled/build/clang.debug/rippled\"};" > test/config.js
|
||||
- npm test
|
||||
|
||||
@@ -22,10 +22,10 @@ master key pair:
|
||||
Sample output:
|
||||
```
|
||||
[validator_keys]
|
||||
nHUSSzGw4A9zEmFtK2Q2NcWDH9xmGdXMHc1MsVej3QkLTgvDNeBr
|
||||
nHDwNP6jbJgVKj5zSEjMn8SJhTnPV54Fx5sSiNpwqLbb42nmh3Ln
|
||||
|
||||
[master_secret]
|
||||
pnxayCakmZRQE2qhEVRbFjiWCunReSbN1z64vPL36qwyLgogyYc
|
||||
paamfhAn5m1NM4UUu5mmvVaHQy8Fb65bkpbaNrvKwX3YMKdjzi2
|
||||
```
|
||||
|
||||
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
|
||||
{
|
||||
"result" : {
|
||||
"status" : "success",
|
||||
"validation_key" : "TOO EDNA SHUN FEUD STAB JOAN BIAS FLEA WISE BOHR LOSS WEEK",
|
||||
"validation_public_key" : "n9JzKV3ZrcZ3DW5pwjakj4hpijJ9oMiyrPDGJc3mpsndL6Gf3zwd",
|
||||
"validation_seed" : "sahzkAajS2dyhjXg2yovjdZhXmjsx"
|
||||
"status" : "success",
|
||||
"validation_key" : "MIN HEAT NUN FAWN HIP KAHN BORG PHI BALK ANN TWIG RACY",
|
||||
"validation_private_key" : "pn6kTqE4WyeRQzZrRp5FnJ5J2vLdSCB5KD3DEyfVw6C9woDBfED",
|
||||
"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]
|
||||
sahzkAajS2dyhjXg2yovjdZhXmjsx
|
||||
# validation_public_key: n9JzKV3ZrcZ3DW5pwjakj4hpijJ9oMiyrPDGJc3mpsndL6Gf3zwd
|
||||
sh8bLqqkGBknGcsgRTrFMxcciwytm
|
||||
# validation_public_key: n9LtZ9haqYMbzJ92cDd3pu3Lko6uEznrXuYea3ehuhVcwDHF5coX
|
||||
# sequence number: 1
|
||||
```
|
||||
|
||||
A manifest is a signed message used to inform other servers of this validator's
|
||||
ephemeral public key. A manifest contains a sequence number, the new ephemeral
|
||||
public key, and it is signed with the master secret key. The sequence number
|
||||
should be higher than the previous sequence number (if it is not, the manifest
|
||||
will be ignored). Usually the previous sequence number will be incremented by
|
||||
one. Use the `manifest` script to create a manifest. It has the form:
|
||||
public key, and it is signed with both the ephemeral and master secret keys.
|
||||
The sequence number should be higher than the previous sequence number (if it
|
||||
is not, the manifest will be ignored). Usually the previous sequence number
|
||||
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:
|
||||
|
||||
```
|
||||
$ bin/manifest sign 1 n9JzKV3Z...L6Gf3zwd pnxayCak...yLgogyYc
|
||||
$ bin/manifest sign 1 n9LtZ9ha...wDHF5coX pn6kTqE4...9woDBfED paamfhAn...YMKdjzi2
|
||||
```
|
||||
|
||||
Sample output:
|
||||
|
||||
```
|
||||
[validation_manifest]
|
||||
JAAAAAFxIe2PEzNhe996gykB1PJQNoDxvr/Y0XhDELw8d/i
|
||||
Fcgz3A3MhAjqhKsgZTmK/3BPEI+kzjV1p9ip7pl/AtF7CKd
|
||||
NSfAH9dkCxezV6apS4FLYzAcQilONx315HvebwAB/pLPaM4
|
||||
2sWCEppSuLNKN/JJjTABOo9tmAiNnnstF83yvecKMJzniwN
|
||||
JAAAAAFxIe3t8rIb4Ba8JHI97CbwpxmTq0LhN/7ZAbsNaSwrbHaypHMhAzTuu07YGOvVvB3+
|
||||
aS0jhP+q0TVgTjGJKhx+yTY1Da3ddkYwRAIgDkmIt3dPNsfeCH3ApMZgpwqG4JwtIlKEymqK
|
||||
S7v+VqkCIFQXg20ZMpXXT86vmLdlmPspgeUN1scWsuFoPYUUJywycBJAl93+/bZbfZ4quTeM
|
||||
5y80/OSIcVoWPcHajwrAl68eiAW4MVFeJXvShXNfnT+XsxMjDh0VpOkhvyp971i1MgjBAA==
|
||||
```
|
||||
|
||||
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
|
||||
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
|
||||
# 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]
|
||||
|
||||
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 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
[/
|
||||
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
|
||||
@@ -14,14 +12,26 @@
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
]
|
||||
|
||||
#ifndef RIPPLE_TEST_MAO_H_INCLUDED
|
||||
#define RIPPLE_TEST_MAO_H_INCLUDED
|
||||
[library rippled
|
||||
[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/
|
||||
node_modules/
|
||||
cov-int/
|
||||
nohup.out
|
||||
venv/
|
||||
bin64/
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
sudo: false
|
||||
language: cpp
|
||||
|
||||
env:
|
||||
global:
|
||||
- LLVM_VERSION=3.8.0
|
||||
# Maintenance note: to move to a new version
|
||||
# of boost, update both BOOST_ROOT and BOOST_URL.
|
||||
# Note that for simplicity, BOOST_ROOT's final
|
||||
@@ -9,8 +11,8 @@ env:
|
||||
# to boost's .tar.gz.
|
||||
- LCOV_ROOT=$HOME/lcov
|
||||
- VALGRIND_ROOT=$HOME/valgrind-install
|
||||
- BOOST_ROOT=$HOME/boost_1_60_0
|
||||
- BOOST_URL='http://downloads.sourceforge.net/project/boost/boost/1.60.0/boost_1_60_0.tar.gz?r=https%3A%2F%2Fsourceforge.net%2Fprojects%2Fboost%2Ffiles%2Fboost%2F1.60.0%2Fboost_1_60_0.tar.gz&ts=1460417589&use_mirror=netix'
|
||||
- BOOST_ROOT=$HOME/boost_1_61_0
|
||||
- BOOST_URL='http://sourceforge.net/projects/boost/files/boost/1.61.0/boost_1_61_0.tar.gz'
|
||||
packages: &gcc5_pkgs
|
||||
- gcc-5
|
||||
- g++-5
|
||||
@@ -27,63 +29,56 @@ packages: &gcc5_pkgs
|
||||
- autotools-dev
|
||||
- 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:
|
||||
include:
|
||||
# GCC/Coverage
|
||||
# GCC/Coverage/Autobahn (if master or develop branch)
|
||||
- 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
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
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
|
||||
- compiler: clang
|
||||
env: GCC_VER=5 VARIANT=usan CLANG_VER=3.8 ADDRESS_MODEL=64 UBSAN_OPTIONS='print_stacktrace=1'
|
||||
addons: &ao_clang38
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8']
|
||||
packages: *clang38_pkgs
|
||||
env:
|
||||
- GCC_VER=5
|
||||
- VARIANT=usan
|
||||
- CLANG_VER=3.8
|
||||
- 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
|
||||
- compiler: clang
|
||||
env: GCC_VER=5 VARIANT=asan CLANG_VER=3.8 ADDRESS_MODEL=64
|
||||
addons: *ao_clang38
|
||||
env:
|
||||
- GCC_VER=5
|
||||
- VARIANT=asan
|
||||
- CLANG_VER=3.8
|
||||
- ADDRESS_MODEL=64
|
||||
- PATH=$PWD/llvm-$LLVM_VERSION/bin:$PATH
|
||||
addons: *ao_gcc5
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $BOOST_ROOT
|
||||
- $VALGRIND_ROOT
|
||||
- llvm-$LLVM_VERSION
|
||||
- cmake
|
||||
|
||||
before_install:
|
||||
- scripts/install-dependencies.sh
|
||||
|
||||
script:
|
||||
- scripts/build-and-test.sh
|
||||
- travis_retry scripts/build-and-test.sh
|
||||
|
||||
after_script:
|
||||
- cat nohup.out || echo "nohup.out already deleted"
|
||||
|
||||
@@ -1,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)
|
||||
|
||||
if (WIN32)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4 /wd4100 /D_SCL_SECURE_NO_WARNINGS=1 /D_CRT_SECURE_NO_WARNINGS=1")
|
||||
if (MSVC)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /MP /W4 /wd4100 /bigobj /D _WIN32_WINNT=0x0601 /D _SCL_SECURE_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
||||
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /Oi /Ot /GL /MT")
|
||||
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Oi /Ot /MT")
|
||||
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
||||
set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
|
||||
# for RelWithDebInfo builds, disable incremental linking
|
||||
# since CMake sets it ON by default for that build type and it
|
||||
# causes warnings
|
||||
string (REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" replacement_flags
|
||||
${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO})
|
||||
set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO ${replacement_flags})
|
||||
|
||||
else()
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
find_package(Boost REQUIRED COMPONENTS coroutine context thread filesystem program_options system)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||
link_directories(${Boost_LIBRARY_DIR})
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads)
|
||||
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -g -std=c++11 -Wall -Wpedantic")
|
||||
"${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter")
|
||||
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)
|
||||
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})
|
||||
else()
|
||||
string(REGEX REPLACE ^${rootdir} ${folder} groupname ${curdir})
|
||||
#set(groupname ${curdir})
|
||||
string(REPLACE "/" "\\" groupname ${groupname})
|
||||
source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
|
||||
endif()
|
||||
@@ -51,14 +99,22 @@ include_directories (include)
|
||||
file(GLOB_RECURSE BEAST_INCLUDES
|
||||
${PROJECT_SOURCE_DIR}/include/beast/*.hpp
|
||||
${PROJECT_SOURCE_DIR}/include/beast/*.ipp
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE EXTRAS_INCLUDES
|
||||
${PROJECT_SOURCE_DIR}/extras/beast/*.hpp
|
||||
${PROJECT_SOURCE_DIR}/extras/beast/*.ipp
|
||||
)
|
||||
|
||||
add_subdirectory (examples)
|
||||
if (NOT OPENSSL_FOUND)
|
||||
message("OpenSSL not found. Not building examples/ssl")
|
||||
else()
|
||||
add_subdirectory (examples/ssl)
|
||||
endif()
|
||||
|
||||
add_subdirectory (test)
|
||||
add_subdirectory (test/core)
|
||||
add_subdirectory (test/http)
|
||||
add_subdirectory (test/websocket)
|
||||
|
||||
#enable_testing()
|
||||
add_subdirectory (test/zlib)
|
||||
|
||||
@@ -37,7 +37,7 @@ else if [ os.name ] = HAIKU
|
||||
if [ os.name ] = NT
|
||||
{
|
||||
lib ssl : : <name>ssleay32 ;
|
||||
lib crypto : : <name>libeay32 ;
|
||||
lib crypto : : <name>libeay32 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -87,19 +87,20 @@ project beast
|
||||
<library>/boost/coroutine//boost_coroutine
|
||||
<library>/boost/filesystem//boost_filesystem
|
||||
<library>/boost/program_options//boost_program_options
|
||||
# <library>ssl
|
||||
# <library>crypto
|
||||
<define>BOOST_ALL_NO_LIB=1
|
||||
<define>BOOST_SYSTEM_NO_DEPRECATED=1
|
||||
<threading>multi
|
||||
<link>static
|
||||
<runtime-link>shared
|
||||
<debug-symbols>on
|
||||
<toolset>gcc:<cxxflags>-std=c++11
|
||||
<toolset>gcc:<cxxflags>-Wno-unused-variable
|
||||
<toolset>gcc:<cxxflags>-Wno-unused-parameter
|
||||
<toolset>clang:<cxxflags>-std=c++11
|
||||
<toolset>clang:<cxxflags>-Wno-unused-parameter
|
||||
<toolset>gcc:<cxxflags>-Wno-unused-variable # Temporary until we can figure out -isystem
|
||||
<toolset>clang:<cxxflags>-Wno-unused-variable # Temporary until we can figure out -isystem
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
||||
<toolset>msvc:<cxxflags>"/wd4100 /bigobj"
|
||||
<toolset>msvc,<variant>release:<cxxflags>"/Ob2 /Oi /Ot"
|
||||
<os>LINUX:<define>_XOPEN_SOURCE=600
|
||||
<os>LINUX:<define>_GNU_SOURCE=1
|
||||
<os>SOLARIS:<define>_XOPEN_SOURCE=500
|
||||
@@ -112,12 +113,7 @@ project beast
|
||||
<os>NT,<toolset>gcc:<library>ws2_32
|
||||
<os>NT,<toolset>gcc:<library>mswsock
|
||||
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
|
||||
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
|
||||
<os>HPUX:<library>ipv6
|
||||
<os>QNXNTO:<library>socket
|
||||
<os>HAIKU:<library>network
|
||||
: usage-requirements
|
||||
<include>.
|
||||
:
|
||||
build-dir bin
|
||||
;
|
||||
|
||||
@@ -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://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/license-boost-brightgreen.svg)](LICENSE_1_0.txt)
|
||||
|
||||
Beast provides implementations of the HTTP and WebSocket protocols
|
||||
built on top of Boost.Asio and other parts of boost.
|
||||
# HTTP and WebSocket implementations built on Boost.Asio
|
||||
|
||||
Requirements:
|
||||
---
|
||||
|
||||
* Boost
|
||||
* C++11 or greater
|
||||
* OpenSSL (optional)
|
||||
## Beast at CppCon 2016
|
||||
|
||||
This software is currently in beta: interfaces are subject to change. For
|
||||
recent changes see [CHANGELOG](CHANGELOG).
|
||||
Presentation
|
||||
(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
|
||||
[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:
|
||||
```C++
|
||||
#include <beast/to_string.hpp>
|
||||
#include <beast/core/to_string.hpp>
|
||||
#include <beast/websocket.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <iostream>
|
||||
@@ -34,22 +163,22 @@ 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::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);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
ws.handshake(host, "/");
|
||||
ws.write(boost::asio::buffer("Hello, world!"));
|
||||
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||
|
||||
// Receive WebSocket message, print and close using beast
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(beast::websocket::close_code::normal);
|
||||
std::cout << to_string(sb.data()) << "\n";
|
||||
std::cout << beast::to_string(sb.data()) << "\n";
|
||||
}
|
||||
```
|
||||
|
||||
@@ -57,6 +186,7 @@ Example HTTP program:
|
||||
```C++
|
||||
#include <beast/http.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@@ -65,35 +195,37 @@ 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::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;
|
||||
beast::http::request<beast::http::empty_body> req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
||||
req.headers.replace("User-Agent", "Beast");
|
||||
req.fields.replace("Host", host + ":" +
|
||||
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||
req.fields.replace("User-Agent", "Beast");
|
||||
beast::http::prepare(req);
|
||||
beast::http::write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
beast::streambuf sb;
|
||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
||||
beast::http::response<beast::http::streambuf_body> resp;
|
||||
beast::http::read(sock, sb, resp);
|
||||
std::cout << resp;
|
||||
}
|
||||
```
|
||||
|
||||
Links:
|
||||
## License
|
||||
|
||||
* [Home](http://vinniefalco.github.io/)
|
||||
* [Repository](https://github.com/vinniefalco/Beast)
|
||||
* [Documentation](http://vinniefalco.github.io/beast/)
|
||||
* [Autobahn.testsuite results](http://vinniefalco.github.io/autobahn/index.html)
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file [LICENSE_1_0.txt](LICENSE_1_0.txt) or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
## Contact
|
||||
|
||||
Please report issues or questions here:
|
||||
https://github.com/vinniefalco/Beast/issues
|
||||
|
||||
@@ -18,6 +18,8 @@ Core:
|
||||
* Complete allocator testing in basic_streambuf
|
||||
|
||||
WebSocket:
|
||||
* Minimize sizeof(websocket::stream)
|
||||
* Move check for message size limit to account for compression
|
||||
* more invokable unit test coverage
|
||||
* More control over the HTTP request and response during handshakes
|
||||
* optimized versions of key/masking, choose prepared_key size
|
||||
|
||||
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)
|
||||
]
|
||||
|
||||
[section:design Design choices]
|
||||
[section:design Design Choices]
|
||||
|
||||
[block '''
|
||||
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||
<member><link linkend="beast.design.http">HTTP FAQ</link></member>
|
||||
<member><link linkend="beast.design.websocket">WebSocket FAQ</link></member>
|
||||
<member><link linkend="beast.design.websocketpp">Comparison to Zaphoyd Studios WebSocket++</link></member>
|
||||
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||
''']
|
||||
|
||||
The implementations are driven by business needs of cryptocurrency server
|
||||
applications ([@https://ripple.com Ripple] written in C++. These
|
||||
needs were not met by existing solutions so new code was written. The new
|
||||
code tries to avoid design flaws encountered in the already-existing software
|
||||
applications (e.g. [@https://ripple.com Ripple]) written in C++. These
|
||||
needs were not met by existing solutions so Beast was written from scratch
|
||||
as a solution. Beast's design philosophy avoids flaws exhibited by other
|
||||
libraries:
|
||||
|
||||
* Don't try to do too much.
|
||||
|
||||
* Don't sacrifice performance.
|
||||
|
||||
* Don't do too much, otherwise interfaces become rigid.
|
||||
* Mimic Boost.Asio; familiarity breeds confidence.
|
||||
|
||||
* Symmetric interfaces (client and server the same, or close to it).
|
||||
* Role-symmetric interfaces; client and server the same (or close to it).
|
||||
|
||||
* Emulate Boost.Asio interfaces as much as possible, since Asio is
|
||||
proven and it is familiar to users.
|
||||
* Leave important decisions to the user, such as allocating memory or
|
||||
managing flow control.
|
||||
|
||||
* Let library users make the important decisions such as how to
|
||||
allocate memory or how to leverage flow control.
|
||||
|
||||
Beast uses the [link beast.types.DynamicBuffer [*`DynamicBuffer`]] concept
|
||||
presented in the Netwoking TS, and relies heavily on the Boost.Asio
|
||||
[*`ConstBufferSequence`] and [*`MutableBufferSequence`] concepts for passing
|
||||
buffers to functions. The authors have found the dynamic buffer and buffer
|
||||
sequence interfaces to be optimal for interacting with Asio, and for other
|
||||
tasks such as incremental parsing of data in buffers (for example, parsing
|
||||
websocket frames stored in a [link beast.ref.static_streambuf `static_streambuf`]).
|
||||
Beast uses the __DynamicBuffer__ concept presented in the Networking TS
|
||||
(__N4588__), and relies heavily on the Boost.Asio __ConstBufferSequence__
|
||||
and __MutableBufferSequence__ concepts for passing buffers to functions.
|
||||
The authors have found the dynamic buffer and buffer sequence interfaces to
|
||||
be optimal for interacting with Asio, and for other tasks such as incremental
|
||||
parsing of data in buffers (for example, parsing websocket frames stored
|
||||
in a [link beast.ref.static_streambuf `static_streambuf`]).
|
||||
|
||||
During the development of Beast the authors have studied other software
|
||||
packages and in particular the comments left during the Boost Review process
|
||||
of other packages offering similar functionality. In this section we attempt
|
||||
to address those issues.
|
||||
of other packages offering similar functionality. In this section and the
|
||||
FAQs that follow we attempt to answer those questions that are also applicable
|
||||
to Beast.
|
||||
|
||||
[variablelist
|
||||
[[
|
||||
"I would also like to see instances of this library being used
|
||||
in production. That would give some evidence that the design
|
||||
works in practice.""
|
||||
works in practice."
|
||||
][
|
||||
Beast.HTTP and Beast.WebSocket will be used in [*rippled], an
|
||||
asynchronous peer to peer server that implements the
|
||||
[*Ripple Consensus Protocol]. These servers are deployed in multiple
|
||||
production environments, with banks in many countries running client
|
||||
applications that connect to [*rippled].
|
||||
Beast.HTTP and Beast.WebSocket are production ready and currently
|
||||
running on public servers receiving traffic and handling millions of
|
||||
dollars worth of financial transactions daily. The servers run [*rippled],
|
||||
open source software ([@https://github.com/ripple/rippled repository])
|
||||
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`].
|
||||
The HTTP interface is further driven by the needs of the WebSocket module,
|
||||
as a WebSocket session requires a HTTP Upgrade handshake exchange at the
|
||||
start. Other design goals:
|
||||
|
||||
* Don't try to invent a complete web server or client
|
||||
* Keep it simple.
|
||||
|
||||
* Have simple free functions to send and receive messages.
|
||||
* Stay low level; don't invent a whole web server or client.
|
||||
|
||||
* Allow the message object to be customized,
|
||||
* Allow for customizations, if the user needs it.
|
||||
|
||||
[variablelist
|
||||
|
||||
[[
|
||||
"Some more advanced examples, e.g. including TLS with client/server
|
||||
certificates would help.""
|
||||
certificates would help."
|
||||
][
|
||||
The HTTP interface doesn't try to reinvent the wheel, it just uses
|
||||
the `boost::asio::ip::tcp::socket` or `boost::asio::ssl::stream` that
|
||||
@@ -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
|
||||
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),
|
||||
etc.
|
||||
etc."
|
||||
][
|
||||
Beast.HTTP does not provide direct facilities for implementing TLS
|
||||
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
|
||||
which higher abstractions such as the aforementioned HTTP service or
|
||||
cgi-gateway can be built.
|
||||
|
||||
One of the example programs implements a simple HTTP server that
|
||||
delivers files from the filesystem.
|
||||
]]
|
||||
|
||||
[[
|
||||
"You should send a 100-continue to ask for the rest of the body if required."
|
||||
][
|
||||
These behaviors are best left to the calling software. A future library
|
||||
can build on Beast.HTTP to provide these behaviors.
|
||||
The Beast interface needs to support this functionality (by allowing this
|
||||
special case of partial message parsing and serialization). Specifically,
|
||||
it should let callers read the request up to just before the body,
|
||||
and let callers write the request up to just before the body. However,
|
||||
making use of this behavior should be up to callers (since Beast is low
|
||||
level).
|
||||
]]
|
||||
|
||||
[[
|
||||
"What about HTTP/2?""
|
||||
"What about HTTP/2?"
|
||||
][
|
||||
Many reviewers feel that HTTP/2 support is an essential feature of
|
||||
a HTTP library. The authors agree that HTTP/2 is important but also
|
||||
@@ -143,13 +161,13 @@ start. Other design goals:
|
||||
and 1.1.
|
||||
|
||||
The Beast.HTTP message model is suitable for HTTP/2 and can be re-used.
|
||||
The IEFT HTTP Working Group adopted message compatiblity with HTTP/1.x
|
||||
The IETF HTTP Working Group adopted message compatiblity with HTTP/1.x
|
||||
as an explicit goal. A parser can simply emit full headers after
|
||||
decoding the compressed HTTP/2 headers. The stream ID is not logicaly
|
||||
decoding the compressed HTTP/2 headers. The stream ID is not logically
|
||||
part of the message but rather message metadata and should be
|
||||
communicated out-of-band (see below). HTTP/2 sessions begin with a
|
||||
traditional HTTP/1.1 Upgrade similar in fashion to the WebSocket
|
||||
upgrade. A HTTP/2 implementation can use existing Beast.HTTP primitives
|
||||
upgrade. An HTTP/2 implementation can use existing Beast.HTTP primitives
|
||||
to perform this handshake.
|
||||
|
||||
Free functions for HTTP/2 sessions are not possible because of the
|
||||
@@ -165,34 +183,40 @@ start. Other design goals:
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:websocket WebSocket]
|
||||
|
||||
|
||||
[section:websocket WebSocket FAQ]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[
|
||||
What about message compression?
|
||||
][
|
||||
The feature is not currently present in the library, but the choice
|
||||
of type requirements for buffers passed to the read functions have been
|
||||
made with compression in mind. There is the plan to add this feature;
|
||||
however, we feel that even without compression users can begin taking
|
||||
advantage of the WebSocket protocol immediately with this library.
|
||||
The author is currently porting ZLib 1.2.8 to modern, header-only C++11
|
||||
that does not use macros or try to support ancient architectures. This
|
||||
deflate implementation will be available as its own individually
|
||||
usable interface, and also will be used to power Beast WebSocket's
|
||||
permessage-deflate implementation, due Q1 of 2017.
|
||||
|
||||
However, Beast currently has sufficient functionality that users can
|
||||
begin taking advantage of the WebSocket protocol using this library
|
||||
immediately.
|
||||
]]
|
||||
|
||||
[[
|
||||
Where is the TLS/SSL interface?
|
||||
][
|
||||
The `websocket::stream` just wraps the socket or stream that you
|
||||
provide (for example, a `boost::asio::ip::tcp::socket` or a
|
||||
`boost::asio::ssl::stream`). You establish your TLS connection
|
||||
using the interface on `ssl::stream` like shown in all of the Asio
|
||||
examples, they construct your `websocket::stream` around it.
|
||||
It works perfectly fine - Beast.WebSocket doesn't try to reinvent the
|
||||
wheel or put a fresh coat of interface paint on the `ssl::stream`.
|
||||
The `websocket::stream` wraps the socket or stream that you provide
|
||||
(for example, a `boost::asio::ip::tcp::socket` or a
|
||||
`boost::asio::ssl::stream`). You establish your TLS connection using the
|
||||
interface on `ssl::stream` like shown in all of the Asio examples, then
|
||||
construct your `websocket::stream` around it. It works perfectly fine;
|
||||
Beast.WebSocket doesn't try to reinvent the wheel or put a fresh coat of
|
||||
interface paint on the `ssl::stream`.
|
||||
|
||||
The WebSocket implementation [*does] 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
|
||||
[link beast.ref.websocket__teardown `teardown`] and
|
||||
[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 user-defined next layer types.
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
[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]
|
||||
|
||||
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)
|
||||
]
|
||||
|
||||
[section:http HTTP]
|
||||
[/
|
||||
ideas:
|
||||
- complete send request walkthrough (client)
|
||||
- complete receive response walkthrough (client)
|
||||
- complete receive request walkthrough (server)
|
||||
- complete send response walkthrough (server)
|
||||
|
||||
Beast.HTTP offers programmers simple and performant models of HTTP messages and
|
||||
- Introduce concepts from simple to complex
|
||||
- Smooth progression of new ideas building on the previous ideas
|
||||
|
||||
- do we show a simplified message with collapsed fields?
|
||||
- do we introduce `header` or `message` first?
|
||||
|
||||
|
||||
contents:
|
||||
Message (and header, fields)
|
||||
Create request
|
||||
Create response
|
||||
Algorithms
|
||||
Write
|
||||
Read
|
||||
Parse
|
||||
Examples
|
||||
Send Request
|
||||
Receive Response
|
||||
Receive Request
|
||||
Send Response
|
||||
Advanced
|
||||
Responding to HEAD
|
||||
Expect: 100-continue
|
||||
Body (user defined)
|
||||
|
||||
|
||||
section beast.http.examples Examples
|
||||
|
||||
note
|
||||
In the example code which follows, `socket` refers to an object of type
|
||||
`boost::asio::ip::tcp::socket` which is currently connected to a remote peer.
|
||||
]
|
||||
|
||||
|
||||
|
||||
[section:http Using HTTP]
|
||||
|
||||
[block '''
|
||||
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||
<member><link linkend="beast.http.message">Message</link></member>
|
||||
<member><link linkend="beast.http.fields">Fields</link></member>
|
||||
<member><link linkend="beast.http.body">Body</link></member>
|
||||
<member><link linkend="beast.http.algorithms">Algorithms</link></member>
|
||||
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||
''']
|
||||
|
||||
Beast offers programmers simple and performant models of HTTP messages and
|
||||
their associated operations including synchronous and asynchronous reading and
|
||||
writing of messages in the HTTP/1 wire format using Boost.Asio.
|
||||
|
||||
The HTTP protocol is described fully in
|
||||
[@https://tools.ietf.org/html/rfc7230 rfc7230]
|
||||
|
||||
|
||||
|
||||
[section:motivation Motivation]
|
||||
|
||||
The HTTP protocol is pervasive in network applications. As C++ is a logical
|
||||
choice for high performance network servers, there is great utility in solid
|
||||
building blocks for manipulating, sending, and receiving HTTP messages
|
||||
compliant with the Hypertext Transfer Protocol and the supplements that
|
||||
follow. Unfortunately reliable implementations or industry standards do not
|
||||
exist in C++.
|
||||
|
||||
Beast.HTTP is built on Boost.Asio and uses its own robust header-only HTTP/1
|
||||
message parser modeled after the nodejs http-parser (written in C). A proposal
|
||||
to add networking functionality to the C++ standard library, based on
|
||||
Boost.Asio, is under consideration by the standards committee. Since the final
|
||||
approved networking interface for the C++ standard library will likely closely
|
||||
resemble the current interface of Boost.Asio, it is logical for Beast.HTTP to
|
||||
use Boost.Asio as its network transport.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:scope Scope]
|
||||
|
||||
This library is designed to be a building block for creating higher level
|
||||
libraries. It is not designed to be end-user facing. There is no convenient
|
||||
class that implements the core of a web server, nor is there a convenient
|
||||
class to quickly perform common operations such as fetching a file or
|
||||
connecting and retrieving a document from a secure connection. These
|
||||
use-cases are important, but this library does not try to do that. Instead,
|
||||
it offers primitives that can be used to build those user-facing algorithms.
|
||||
|
||||
A HTTP message (referred to hereafter as "message") contains request or
|
||||
response specific attributes, a series of zero or more name/value pairs
|
||||
(collectively termed "headers"), and a series of octets called the message
|
||||
body which may be zero in length. The HTTP protocol defines the client and
|
||||
server roles: clients send messages called requests and servers send back
|
||||
messages called responses. `http::message` models both requests and responses.
|
||||
Beast aims to offer this functionality:
|
||||
|
||||
* [*Model]: Provide a universal HTTP message class model.
|
||||
|
||||
* [*Build]: Construct a new message and manipulate its contents.
|
||||
|
||||
* [*Parse]: Deserialize a message from a network or memory stream in HTTP/1 wire format.
|
||||
|
||||
* [*Serialize]: Serialize a message into a network or memory stream in HTTP/1 wire format.
|
||||
|
||||
[note The documentation which follows assumes familiarity with
|
||||
both Boost.Asio and the HTTP protocol specification described in
|
||||
[@https://tools.ietf.org/html/rfc7230 rfc7230] ]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:usage Usage]
|
||||
writing of messages and headers in the HTTP/1 wire format using Boost.Asio.
|
||||
|
||||
[note
|
||||
Sample code and identifiers mentioned in this section are written
|
||||
as if the following declarations are in effect:
|
||||
The following documentation assumes familiarity with both Boost.Asio
|
||||
and the HTTP protocol specification described in __rfc7230__. Sample code
|
||||
and identifiers mentioned in this section are written as if the following
|
||||
declarations are in effect:
|
||||
```
|
||||
#include <beast/core.hpp>
|
||||
#include <beast/http.hpp>
|
||||
using namespace beast;
|
||||
using namespace beast::http;
|
||||
```
|
||||
]
|
||||
|
||||
|
||||
|
||||
In the paragraphs that follow we describe the available interfaces for
|
||||
performing typical operations such as interacting with a HTTP server
|
||||
or handling simple requests. Subsequent sections cover the message model
|
||||
and its customization points in more depth, for advanced applications.
|
||||
|
||||
[heading Declarations]
|
||||
|
||||
To do anything, a message must be declared. The message class template
|
||||
requires at mininum, a value indicating whether the message is a request
|
||||
(versus a response), and a `Body` type. The choice of `Body` determines the
|
||||
kind of container used to represent the message body. Here we will
|
||||
declare a request that has a `std::string` for the body container:
|
||||
[section:message Message]
|
||||
|
||||
The HTTP protocol defines the client and server roles: clients send messages
|
||||
called requests and servers send back messages called responses. A HTTP message
|
||||
(referred to hereafter as "message") contains request or response specific
|
||||
attributes (contained in the "Start Line"), a series of zero or more name/value
|
||||
pairs (collectively termed "Fields"), and an optional series of octets called
|
||||
the message body which may be zero in length. The start line for a HTTP request
|
||||
includes a string called the method, a string called the URL, and a version
|
||||
number indicating HTTP/1.0 or HTTP/1.1. For a response, the start line contains
|
||||
an integer status code and a string called the reason phrase. Alternatively, a
|
||||
HTTP message can be viewed as two parts: a header, followed by a body.
|
||||
|
||||
[note
|
||||
The Reason-Phrase is obsolete as of rfc7230.
|
||||
]
|
||||
|
||||
The __header__ class template models the header for HTTP/1 and HTTP/2 messages.
|
||||
This class template is a family of specializations, one for requests and one
|
||||
for responses, depending on the [*`isRequest`] template value.
|
||||
The [*`Fields`] template type determines the type of associative container
|
||||
used to store the field values. The provided __basic_fields__ class template
|
||||
and __fields__ type alias are typical choices for the [*`Fields`] type, but
|
||||
advanced applications may supply user defined types which meet the requirements.
|
||||
The __message__ class template models the header and optional body for HTTP/1
|
||||
and HTTP/2 requests and responses. It is derived from the __header__ class
|
||||
template with the same shared template parameters, and adds the `body` data
|
||||
member. The message class template requires an additional template argument
|
||||
type [*`Body`]. This type controls the container used to represent the body,
|
||||
if any, as well as the algorithms needed to serialize and parse bodies of
|
||||
that type.
|
||||
|
||||
This illustration shows the declarations and members of the __header__ and
|
||||
__message__ class templates, as well as the inheritance relationship:
|
||||
|
||||
[$images/message.png [width 650px] [height 390px]]
|
||||
|
||||
For notational convenience, these template type aliases are provided which
|
||||
supply typical choices for the [*`Fields`] type:
|
||||
```
|
||||
http::message<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
|
||||
messages. These two statements declare a request and a response respectively:
|
||||
```
|
||||
http::request<http::string_body> req;
|
||||
http::response<http::string_body> resp;
|
||||
```
|
||||
The code examples below show how to create and fill in a request and response
|
||||
object:
|
||||
|
||||
[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.
|
||||
Request and response objects have some common members, and some members unique
|
||||
to the message type. These statements set all the members in each message:
|
||||
```
|
||||
http::request<http::string_body> req;
|
||||
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 = "";
|
||||
In the serialized format of a HTTP message, the header is represented as a
|
||||
series of text lines ending in CRLF (`"\r\n"`). The end of the header is
|
||||
indicated by a line containing only CRLF. Here are examples of serialized HTTP
|
||||
request and response objects. The objects created above will produce these
|
||||
results when serialized. Note that only the response has a body:
|
||||
|
||||
http::response<http::string_body> resp;
|
||||
resp.status = 404;
|
||||
resp.reason = "Not Found";
|
||||
resp.version = 10; // HTTP/1.0
|
||||
resp.headers.insert("Server", "Beast.HTTP");
|
||||
resp.body = "The requested resource was not found.";
|
||||
```
|
||||
[table Serialized HTTP Request and Response
|
||||
[[HTTP Request] [HTTP Response]]
|
||||
[[
|
||||
```
|
||||
GET /index.htm HTTP/1.1\r\n
|
||||
Accept: text/html\r\n
|
||||
Connection: keep-alive\r\n
|
||||
User-Agent: Beast\r\n
|
||||
\r\n
|
||||
```
|
||||
][
|
||||
```
|
||||
200 OK HTTP/1.1\r\n
|
||||
Server: Beast\r\n
|
||||
Content-Length: 4\r\n
|
||||
\r\n
|
||||
****
|
||||
```
|
||||
]]]
|
||||
|
||||
The 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
|
||||
pairs in the message. These statements change the values of the headers
|
||||
in the message passed:
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
[section:fields Fields]
|
||||
|
||||
The [*`Fields`] type represents a container that can set or retrieve the
|
||||
fields in a message. Beast provides the
|
||||
[link beast.ref.http__basic_fields `basic_fields`] class which serves
|
||||
the needs for most users. It supports modification and inspection of values.
|
||||
The field names are not case-sensitive.
|
||||
|
||||
These statements change the values of the headers in the message passed:
|
||||
```
|
||||
template<class Body>
|
||||
void set_fields(http::request<Body>& req)
|
||||
void set_fields(request<Body>& req)
|
||||
{
|
||||
if(! req.exists("User-Agent"))
|
||||
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
|
||||
`Body` template argument type, this could be a writable container. The
|
||||
following types, provided by the library, are suitable choices for the
|
||||
`Body` type:
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:body Body]
|
||||
|
||||
The message [*`Body`] template parameter controls both the type of the data
|
||||
member of the resulting message object, and the algorithms used during parsing
|
||||
and serialization. Beast provides three very common [*`Body`] types:
|
||||
|
||||
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
|
||||
Used in GET requests where there is no message body. Example:
|
||||
```
|
||||
http::request<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
|
||||
@@ -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
|
||||
used in the examples:
|
||||
```
|
||||
http::response<http::string_body> resp;
|
||||
static_assert(std::is_same<decltype(resp.body), std::string>::value);
|
||||
resp.body = "Here is the data you requested";
|
||||
response<string_body> res;
|
||||
static_assert(std::is_same<decltype(res.body), std::string>::value);
|
||||
res.body = "Here is the data you requested";
|
||||
```
|
||||
|
||||
* [link beast.ref.http__streambuf_body [*`streambuf_body`:]] A body with a
|
||||
`value_type` of [link beast.ref.streambuf `streambuf`]: an efficient storage
|
||||
object which uses multiple octet arrays of varying lengths to represent data.
|
||||
|
||||
[heading Sockets]
|
||||
[heading Advanced]
|
||||
|
||||
The library provides simple free functions modeled after Boost.Asio to
|
||||
send and receive messages on TCP/IP sockets, SSL streams, or any object
|
||||
which meets the Boost.Asio type requirements (SyncReadStream, SyncWriteStream,
|
||||
AsyncReadStream, and AsyncWriteStream depending on the types of operations
|
||||
performed). To send messages synchronously, use one of the `http:write`
|
||||
functions:
|
||||
User-defined types are possible for the message body, where the type meets the
|
||||
[link beast.ref.Body [*`Body`]] requirements. This simplified class declaration
|
||||
shows the customization points available to user-defined body types:
|
||||
|
||||
[$images/body.png [width 510px] [height 210px]]
|
||||
|
||||
* [*`value_type`]: Determines the type of the
|
||||
[link beast.ref.http__message.body `message::body`] member. If this
|
||||
type defines default construction, move, copy, or swap, then message objects
|
||||
declared with this [*`Body`] will have those operations defined.
|
||||
|
||||
* [*`reader`]: An optional nested type meeting the requirements of
|
||||
[link beast.ref.Reader [*`Reader`]]. If present, this defines the algorithm
|
||||
used for parsing bodies of this type.
|
||||
|
||||
* [*`writer`]: An optional nested type meeting the requirements of
|
||||
[link beast.ref.Writer [*`Writer`]]. If present, this defines the algorithm
|
||||
used for serializing bodies of this type.
|
||||
|
||||
The examples included with this library provide a Body implementation that
|
||||
serializing message bodies that come from a file.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:algorithms Algorithms]
|
||||
|
||||
Algorithms are provided to serialize and deserialize HTTP/1 messages on
|
||||
streams.
|
||||
|
||||
* [link beast.ref.http__read [*read]]: Deserialize a HTTP/1 __header__ or __message__ from a stream.
|
||||
* [link beast.ref.http__write [*write]]: Serialize a HTTP/1 __header__ or __message__ to a stream.
|
||||
|
||||
Asynchronous versions of these algorithms are also available:
|
||||
|
||||
* [link beast.ref.http__async_read [*async_read]]: Deserialize a HTTP/1 __header__ or __message__ asynchronously from a stream.
|
||||
* [link beast.ref.http__async_write [*async_write]]: Serialize a HTTP/1 __header__ or __message__ asynchronously to a stream.
|
||||
|
||||
[heading Using Sockets]
|
||||
|
||||
The free function algorithms are modeled after Boost.Asio to send and receive
|
||||
messages on TCP/IP sockets, SSL streams, or any object which meets the
|
||||
Boost.Asio type requirements (__SyncReadStream__, __SyncWriteStream__,
|
||||
__AsyncReadStream__, and __AsyncWriteStream__ depending on the types of
|
||||
operations performed). To send messages synchronously, use one of the
|
||||
[link beast.ref.http__write `write`] functions:
|
||||
```
|
||||
void send_request(boost::asio::ip::tcp::socket& sock)
|
||||
{
|
||||
http::request<http::empty_body> req({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
|
||||
boost::system::error:code ec;
|
||||
http::write(sock, req, ec);
|
||||
write(sock, req, ec);
|
||||
if(ec)
|
||||
std::cerr << "error writing http message: " << ec.message();
|
||||
}
|
||||
@@ -213,27 +322,27 @@ An asynchronous interface is available:
|
||||
```
|
||||
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
|
||||
after the end of the message if they are present (the alternative is to read
|
||||
a single byte at a time which is unsuitable for performance reasons). To
|
||||
store and re-use these extra bytes on subsequent messages, the read interface
|
||||
requires an additional 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
|
||||
stored in the streambuf parameter for use in a subsequent call to read:
|
||||
```
|
||||
boost::asio::streambuf sb;
|
||||
...
|
||||
http::response<http::string_body> resp;
|
||||
http::read(sock, sb, resp); // Throws exception on error
|
||||
response<string_body> res;
|
||||
read(sock, sb, res); // Throws exception on error
|
||||
...
|
||||
// Alternatively
|
||||
boost::system::error:code ec;
|
||||
http::read(sock, sb, resp, ec);
|
||||
read(sock, sb, res, ec);
|
||||
if(ec)
|
||||
std::cerr << "error reading http message: " << ec.message();
|
||||
```
|
||||
@@ -245,116 +354,28 @@ called:
|
||||
void handle_read(boost::system::error_code);
|
||||
...
|
||||
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
|
||||
[link beast.ref.streambuf `beast::streambuf`], which meets the requirements of
|
||||
[*`DynamicBuffer`] and is optimized for performance:
|
||||
__streambuf__, which meets the requirements of __DynamicBuffer__ and
|
||||
is optimized for performance:
|
||||
```
|
||||
void handle_read(boost::system::error_code);
|
||||
...
|
||||
beast::streambuf sb;
|
||||
http::response<http::string_body> resp;
|
||||
http::read(sock, sb, resp);
|
||||
response<string_body> res;
|
||||
read(sock, sb, res);
|
||||
```
|
||||
|
||||
The `read` implementation can use any object meeting the requirements of
|
||||
[link beast.types.DynamicBuffer [*`DynamicBuffer`]], allowing callers to define custom
|
||||
__DynamicBuffer__, allowing callers to define custom
|
||||
memory management strategies used by the implementation.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:advanced Advanced]
|
||||
|
||||
The spectrum of hardware and software platforms which perform these typical
|
||||
HTTP operations is vast, ranging from powerful servers in large datacenters
|
||||
to tiny resource-limited embedded devices. No single concrete implementation
|
||||
of a class intended to model messages can efficiently serve all needs.
|
||||
For example, an object that minimizes resources during parsing may not be
|
||||
able to edit and change headers dynamically. A message that represents the
|
||||
message body as a disk file may support sending but not parsing. Many efficient
|
||||
and correct models of messages exist, supporting some or all of the
|
||||
operations listed above.
|
||||
|
||||
[heading Message model]
|
||||
|
||||
The message class template and provided Body types are suitable for casual
|
||||
library users. This section explains the message model for advanced users
|
||||
who wish to take control over aspects of the implementation. We introduce
|
||||
customization points for the header and body via class template arguments.
|
||||
This illustration shows more detail about the
|
||||
[link beast.ref.http__message [*`message`]] class template (boilerplate
|
||||
present in the actual declaration has been removed for clarity):
|
||||
|
||||
[$images/message.png [width 580px] [height 225px]]
|
||||
|
||||
The default constructor, move special members, and copy special members are
|
||||
all defaulted. A message is movable, copyable, or default constructible based
|
||||
on the capabilities of its template arguments.
|
||||
|
||||
Messages modeled in this fashion are ['complete], containing all of the
|
||||
information required to perform the supported set of operations. They are
|
||||
['first-class types], returnable from functions and composable. HTTP
|
||||
requests and responses are distinct types, allowing functions to be
|
||||
overloaded on the type of message.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:headers Headers Type]
|
||||
|
||||
The `Headers` type represents the field/value pairs present in every HTTP
|
||||
message. These types implement the
|
||||
[link beast.types.FieldSequence [*`FieldSequence`]]
|
||||
concept. The value type of a field sequence is an object meeting the
|
||||
requirements of [link beast.types.Field [*`Field`]]. The implementation can
|
||||
serialize any instance of `Headers` that meets the field sequence requirements.
|
||||
This example shows a function which returns `true` if the specified field
|
||||
sequence has a connect field:
|
||||
```
|
||||
template<class FieldSequence>
|
||||
bool
|
||||
has_connect(FieldSequence const& fs)
|
||||
{
|
||||
return std::find_if(fs.begin(), fs.end(),
|
||||
[&](auto const& field)
|
||||
{
|
||||
return ci_equal(field.name(), "Connect");
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:body Body Type]
|
||||
|
||||
The `Body` template argument in the `message` class must meet the
|
||||
[link beast.types.Body [*`Body`] requirements]. It provides customization
|
||||
of the data member in the message, the algorithm for parsing, and the
|
||||
algorithm for serialization:
|
||||
|
||||
[$images/body.png [width 510px] [height 210px]]
|
||||
|
||||
Instances of the optional nested types `writer` and `reader` perform
|
||||
serialization and deserialization of the message body. If either or
|
||||
both of these types are present, the message becomes serializable, parsable,
|
||||
or both. They model [link beast.types.Reader [*`Reader`]] and
|
||||
[link beast.types.Writer [*`Writer`]] respectively.
|
||||
|
||||
For specialized applications, users may implement their own types which
|
||||
meet the requirements. The examples included with this library provide a
|
||||
Body implementation used to serve files in a HTTP server.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
BIN
src/beast/doc/images/CppCon2016.pdf
Normal file
BIN
src/beast/doc/images/CppCon2016.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)
|
||||
-->
|
||||
|
||||
<section id="index">
|
||||
<section id="beast.index">
|
||||
<title>Index</title>
|
||||
<index/>
|
||||
</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)
|
||||
#
|
||||
@@ -6,7 +6,7 @@
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
mkdir -p ../bin/doc/xml
|
||||
doxygen beast.dox
|
||||
doxygen source.dox
|
||||
cd ../bin/doc/xml
|
||||
xsltproc combine.xslt index.xml > all.xml
|
||||
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"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry valign="center" namest="a" nameend="b">
|
||||
<entry valign="center" namest="a" nameend="c">
|
||||
<bridgehead renderas="sect2">HTTP</bridgehead>
|
||||
</entry>
|
||||
<entry valign="center" namest="c" nameend="d">
|
||||
<entry valign="center" namest="d" nameend="d">
|
||||
<bridgehead renderas="sect2">WebSocket</bridgehead>
|
||||
</entry>
|
||||
</row>
|
||||
@@ -30,52 +30,82 @@
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__basic_dynabuf_body">basic_dynabuf_body</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_headers">basic_headers</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_fields">basic_fields</link></member>
|
||||
<member><link linkend="beast.ref.http__basic_parser_v1">basic_parser_v1</link></member>
|
||||
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
|
||||
<member><link linkend="beast.ref.http__headers">headers</link></member>
|
||||
<member><link linkend="beast.ref.http__fields">fields</link></member>
|
||||
<member><link linkend="beast.ref.http__header">header</link></member>
|
||||
<member><link linkend="beast.ref.http__header_parser_v1">header_parser_v1</link></member>
|
||||
<member><link linkend="beast.ref.http__message">message</link></member>
|
||||
<member><link linkend="beast.ref.http__parser_v1">parser_v1</link></member>
|
||||
<member><link linkend="beast.ref.http__request">request</link></member>
|
||||
<member><link linkend="beast.ref.http__request_header">request_header</link></member>
|
||||
<member><link linkend="beast.ref.http__response">response</link></member>
|
||||
<member><link linkend="beast.ref.http__response_header">response_header</link></member>
|
||||
<member><link linkend="beast.ref.http__resume_context">resume_context</link></member>
|
||||
<member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member>
|
||||
<member><link linkend="beast.ref.http__string_body">string_body</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<bridgehead renderas="sect3">rfc7230</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
||||
<member><link linkend="beast.ref.http__headers_max_size">headers_max_size</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Parser">is_Parser</link></member>
|
||||
<member><link linkend="beast.ref.http__is_ReadableBody">is_ReadableBody</link></member>
|
||||
<member><link linkend="beast.ref.http__is_WritableBody">is_WritableBody</link></member>
|
||||
|
||||
<member><link linkend="beast.ref.http__ext_list">ext_list</link></member>
|
||||
<member><link linkend="beast.ref.http__param_list">param_list</link></member>
|
||||
<member><link linkend="beast.ref.http__token_list">token_list</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
|
||||
<member><link linkend="beast.ref.http__async_read">async_read</link></member>
|
||||
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
|
||||
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
|
||||
<member><link linkend="beast.ref.http__chunk_encode">chunk_encode</link></member>
|
||||
<member><link linkend="beast.ref.http__chunk_encode_final">chunk_encode_final</link></member>
|
||||
<member><link linkend="beast.ref.http__swap">swap</link></member>
|
||||
<member><link linkend="beast.ref.http__is_keep_alive">is_keep_alive</link></member>
|
||||
<member><link linkend="beast.ref.http__is_upgrade">is_upgrade</link></member>
|
||||
<member><link linkend="beast.ref.http__operator_ls_">operator<<</link></member>
|
||||
<member><link linkend="beast.ref.http__parse">parse</link></member>
|
||||
<member><link linkend="beast.ref.http__prepare">prepare</link></member>
|
||||
<member><link linkend="beast.ref.http__read">read</link></member>
|
||||
<member><link linkend="beast.ref.http__swap">swap</link></member>
|
||||
<member><link linkend="beast.ref.http__reason_string">reason_string</link></member>
|
||||
<member><link linkend="beast.ref.http__with_body">with_body</link></member>
|
||||
<member><link linkend="beast.ref.http__write">write</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Parser">is_Parser</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Reader">is_Reader</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Writer">is_Writer</link></member>
|
||||
<member><link linkend="beast.ref.http__has_reader">has_reader</link></member>
|
||||
<member><link linkend="beast.ref.http__has_writer">has_writer</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__header_max_size">header_max_size</link></member>
|
||||
<member><link linkend="beast.ref.http__body_max_size">body_max_size</link></member>
|
||||
<member><link linkend="beast.ref.http__skip_body">skip_body</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__body_what">body_what</link></member>
|
||||
<member><link linkend="beast.ref.http__connection">connection</link></member>
|
||||
<member><link linkend="beast.ref.http__no_content_length">no_content_length</link></member>
|
||||
<member><link linkend="beast.ref.http__parse_error">parse_error</link></member>
|
||||
<member><link linkend="beast.ref.http__parse_flag">parse_flag</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.types.Body">Body</link></member>
|
||||
<member><link linkend="beast.types.Field">Field</link></member>
|
||||
<member><link linkend="beast.types.FieldSequence">FieldSequence</link></member>
|
||||
<member><link linkend="beast.types.Parser">Parser</link></member>
|
||||
<member><link linkend="beast.types.Reader">Reader</link></member>
|
||||
<member><link linkend="beast.types.Writer">Writer</link></member>
|
||||
<member><link linkend="beast.ref.Body">Body</link></member>
|
||||
<member><link linkend="beast.ref.Field">Field</link></member>
|
||||
<member><link linkend="beast.ref.FieldSequence">FieldSequence</link></member>
|
||||
<member><link linkend="beast.ref.Parser">Parser</link></member>
|
||||
<member><link linkend="beast.ref.Reader">Reader</link></member>
|
||||
<member><link linkend="beast.ref.Writer">Writer</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
@@ -85,25 +115,24 @@
|
||||
<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__reason_string">reason_string</link></member>
|
||||
<member><link linkend="beast.ref.websocket__teardown_tag">teardown_tag</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__auto_fragment_size">auto_fragment_size</link></member>
|
||||
<member><link linkend="beast.ref.websocket__decorate">decorate</link></member>
|
||||
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</link></member>
|
||||
<member><link linkend="beast.ref.websocket__mask_buffer_size">mask_buffer_size</link></member>
|
||||
<member><link linkend="beast.ref.websocket__message_type">message_type</link></member>
|
||||
<member><link linkend="beast.ref.websocket__pong_callback">pong_callback</link></member>
|
||||
<member><link linkend="beast.ref.websocket__read_buffer_size">read_buffer_size</link></member>
|
||||
<member><link linkend="beast.ref.websocket__read_message_max">read_message_max</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__async_teardown">async_teardown</link></member>
|
||||
<member><link linkend="beast.ref.websocket__teardown">teardown</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Options</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__auto_fragment">auto_fragment</link></member>
|
||||
<member><link linkend="beast.ref.websocket__decorate">decorate</link></member>
|
||||
<member><link linkend="beast.ref.websocket__keep_alive">keep_alive</link></member>
|
||||
<member><link linkend="beast.ref.websocket__message_type">message_type</link></member>
|
||||
<member><link linkend="beast.ref.websocket__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>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.websocket__close_code">close_code</link></member>
|
||||
@@ -119,11 +148,15 @@
|
||||
<colspec colname="b"/>
|
||||
<colspec colname="c"/>
|
||||
<colspec colname="d"/>
|
||||
<colspec colname="e"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry valign="center" namest="a" nameend="d">
|
||||
<bridgehead renderas="sect2">Core</bridgehead>
|
||||
</entry>
|
||||
<entry valign="center" namest="e" nameend="e">
|
||||
<bridgehead renderas="sect2">ZLib</bridgehead>
|
||||
</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -136,9 +169,12 @@
|
||||
<member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member>
|
||||
<member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member>
|
||||
<member><link linkend="beast.ref.dynabuf_readstream">dynabuf_readstream</link></member>
|
||||
<member><link linkend="beast.ref.errc">errc</link></member>
|
||||
<member><link linkend="beast.ref.error_category">error_category</link></member>
|
||||
<member><link linkend="beast.ref.error_code">error_code</link></member>
|
||||
<member><link linkend="beast.ref.error_condition">error_condition</link></member>
|
||||
<member><link linkend="beast.ref.handler_alloc">handler_alloc</link></member>
|
||||
<member><link linkend="beast.ref.prepared_buffers">prepared_buffers</link></member>
|
||||
<member><link linkend="beast.ref.handler_ptr">handler_ptr</link></member>
|
||||
<member><link linkend="beast.ref.static_streambuf">static_streambuf</link></member>
|
||||
<member><link linkend="beast.ref.static_streambuf_n">static_streambuf_n</link></member>
|
||||
<member><link linkend="beast.ref.static_string">static_string</link></member>
|
||||
@@ -151,18 +187,15 @@
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.bind_handler">bind_handler</link></member>
|
||||
<member><link linkend="beast.ref.buffer_cat">buffer_cat</link></member>
|
||||
<member><link linkend="beast.ref.consumed_buffers">consumed_buffers</link></member>
|
||||
<member><link linkend="beast.ref.prepare_buffer">prepare_buffer</link></member>
|
||||
<member><link linkend="beast.ref.prepare_buffers">prepare_buffers</link></member>
|
||||
<member><link linkend="beast.ref.to_string">to_string</link></member>
|
||||
|
||||
<member><link linkend="beast.ref.write">write</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
|
||||
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
|
||||
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
|
||||
<member><link linkend="beast.ref.is_AsyncStream">is_AsyncStream</link></member>
|
||||
@@ -179,11 +212,29 @@
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.types.streams.AsyncStream">AsyncStream</link></member>
|
||||
<member><link linkend="beast.types.BufferSequence">BufferSequence</link></member>
|
||||
<member><link linkend="beast.types.DynamicBuffer">DynamicBuffer</link></member>
|
||||
<member><link linkend="beast.types.streams.Stream">Stream</link></member>
|
||||
<member><link linkend="beast.types.streams.SyncStream">SyncStream</link></member>
|
||||
<member><link linkend="beast.ref.streams.AsyncStream">AsyncStream</link></member>
|
||||
<member><link linkend="beast.ref.BufferSequence">BufferSequence</link></member>
|
||||
<member><link linkend="beast.ref.DynamicBuffer">DynamicBuffer</link></member>
|
||||
<member><link linkend="beast.ref.streams.Stream">Stream</link></member>
|
||||
<member><link linkend="beast.ref.streams.SyncStream">SyncStream</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.zlib__deflate_stream">deflate_stream</link></member>
|
||||
<member><link linkend="beast.ref.zlib__inflate_stream">inflate_stream</link></member>
|
||||
<member><link linkend="beast.ref.zlib__z_params">z_params</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.zlib__deflate_upper_bound">deflate_upper_bound</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.zlib__error">error</link></member>
|
||||
<member><link linkend="beast.ref.zlib__Flush">Flush</link></member>
|
||||
<member><link linkend="beast.ref.zlib__Strategy">Strategy</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
|
||||
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"/>
|
||||
@@ -31,8 +31,6 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:ref Reference]
|
||||
|
||||
</xsl:text>
|
||||
<xsl:for-each select="
|
||||
compounddef[@kind = 'class' or @kind = 'struct'] |
|
||||
@@ -59,7 +57,6 @@
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:for-each>
|
||||
<xsl:text>
[endsect]</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
<!--========== Utilities ==========-->
|
||||
@@ -165,7 +162,7 @@
|
||||
<xsl:text>``['implementation-defined]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$type='void_or_deduced'">
|
||||
<xsl:text>``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]``</xsl:text>
|
||||
<xsl:text>__void_or_deduced__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="$type"/>
|
||||
@@ -198,6 +195,18 @@
|
||||
select="concat(substring-before($name, '::'), '__', substring-after($name, '::'))"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="substring($name, string-length($name) - 1) = '<<'">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
select="concat(substring-before($name, '<<'), '_ls_')"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="substring($name, string-length($name) - 1) = '>>'">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
select="concat(substring-before($name, '>>'), '_rs_')"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, '=')">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
@@ -270,10 +279,10 @@
|
||||
select="concat(substring-before($name, '*'), '_star_', substring-after($name, '*'))"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, '~')">
|
||||
<xsl:when test="starts-with($name, '~')">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
select="concat(substring-before($name, '~'), '_', substring-after($name, '~'))"/>
|
||||
select="concat(substring-after($name, '~'), '_dtor_')"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, ' ')">
|
||||
@@ -1055,10 +1064,26 @@
|
||||
</xsl:for-each>
|
||||
<xsl:text>]
</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="count(sectiondef[@kind='public-attrib' or @kind='public-static-attrib']) > 0">
|
||||
<xsl:if test="count(sectiondef[@kind='public-static-attrib']) > 0">
|
||||
<xsl:text>[heading Static Data Members]
</xsl:text>
|
||||
<xsl:text>[table
 [[Name][Description]]
</xsl:text>
|
||||
<xsl:for-each select="sectiondef[@kind='public-static-attrib']/memberdef" mode="class-table">
|
||||
<xsl:sort select="name"/>
|
||||
<xsl:text> [
</xsl:text>
|
||||
<xsl:text> [[link beast.ref.</xsl:text>
|
||||
<xsl:value-of select="$class-id"/>.<xsl:value-of select="name"/>
|
||||
<xsl:text> [*</xsl:text>
|
||||
<xsl:value-of select="name"/>
|
||||
<xsl:text>]]]
 [
 </xsl:text>
|
||||
<xsl:value-of select="briefdescription"/>
|
||||
<xsl:text>
 ]
 ]
</xsl:text>
|
||||
</xsl:for-each>
|
||||
<xsl:text>]
</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="count(sectiondef[@kind='public-attrib']) > 0">
|
||||
<xsl:text>[heading Data Members]
</xsl:text>
|
||||
<xsl:text>[table
 [[Name][Description]]
</xsl:text>
|
||||
<xsl:for-each select="sectiondef[@kind='public-attrib' or @kind='public-static-attrib']/memberdef" mode="class-table">
|
||||
<xsl:for-each select="sectiondef[@kind='public-attrib']/memberdef" mode="class-table">
|
||||
<xsl:sort select="name"/>
|
||||
<xsl:text> [
</xsl:text>
|
||||
<xsl:text> [[link beast.ref.</xsl:text>
|
||||
@@ -1528,47 +1553,50 @@
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="type = 'class AsyncStream'">
|
||||
<xsl:text>class ``[link beast.types.streams.AsyncStream [*AsyncStream]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.streams.AsyncStream [*AsyncStream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class AsyncReadStream'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]``</xsl:text>
|
||||
<xsl:text>class __AsyncReadStream__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class AsyncWriteStream'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]``</xsl:text>
|
||||
<xsl:text>class __AsyncWriteStream__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class Body'">
|
||||
<xsl:text>class ``[link beast.types.Body [*Body]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.Body [*Body]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class BufferSequence'">
|
||||
<xsl:text>class ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="(type = 'class' or type = 'class...') and declname = 'BufferSequence'">
|
||||
<xsl:value-of select="type"/>
|
||||
<xsl:text> ``[link beast.types.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||
<xsl:text> ``[link beast.ref.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'CompletionHandler' or type = 'class CompletionHandler'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]``</xsl:text>
|
||||
<xsl:text>class __CompletionHandler__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'ConstBufferSequence' or type = 'class ConstBufferSequence'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]``</xsl:text>
|
||||
<xsl:text>class __ConstBufferSequence__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'DynamicBuffer' or type = 'class DynamicBuffer'">
|
||||
<xsl:text>class ``[link beast.types.DynamicBuffer [*DynamicBuffer]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.DynamicBuffer [*DynamicBuffer]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'MutableBufferSequence' or type = 'class MutableBufferSequence'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]``</xsl:text>
|
||||
<xsl:text>class __MutableBufferSequence__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Parser' or type = 'class Parser'">
|
||||
<xsl:text>class ``[link beast.ref.Parser [*Parser]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Stream' or type = 'class Stream'">
|
||||
<xsl:text>class ``[link beast.types.streams.Stream [*Stream]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.streams.Stream [*Stream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="type = 'class SyncStream'">
|
||||
<xsl:text>class ``[link beast.types.streams.SyncStream [*SyncStream]]``</xsl:text>
|
||||
<xsl:text>class ``[link beast.ref.streams.SyncStream [*SyncStream]]``</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'SyncReadStream' or type = 'class SyncReadStream'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]``</xsl:text>
|
||||
<xsl:text>class __SyncReadStream__</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'SyncWriteStream' or type = 'class SyncWriteStream'">
|
||||
<xsl:text>class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]``</xsl:text>
|
||||
<xsl:text>class __SyncWriteStream__</xsl:text>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="declname = 'T'">
|
||||
@@ -1682,6 +1710,14 @@
|
||||
</xsl:choose>
|
||||
<xsl:text>```
</xsl:text>
|
||||
<xsl:for-each select="../memberdef[name = $unqualified-name]">
|
||||
<xsl:if test="position() > 1">
|
||||
<xsl:text>
</xsl:text>
|
||||
<xsl:if test=" not(briefdescription = preceding-sibling::*/briefdescription)">
|
||||
<xsl:text>```
</xsl:text>
|
||||
<xsl:apply-templates select="briefdescription" mode="markup"/>
|
||||
<xsl:text>```
</xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:if>
|
||||
<xsl:variable name="stripped-type">
|
||||
<xsl:call-template name="cleanup-type">
|
||||
<xsl:with-param name="name" select="type"/>
|
||||
|
||||
@@ -107,52 +107,8 @@ INPUT = \
|
||||
../include/beast/core \
|
||||
../include/beast/http \
|
||||
../include/beast/websocket \
|
||||
../include/beast/doc_debug.hpp \
|
||||
|
||||
../include/beast/async_completion.hpp \
|
||||
../include/beast/basic_streambuf.hpp \
|
||||
../include/beast/bind_handler.hpp \
|
||||
../include/beast/buffer_cat.hpp \
|
||||
../include/beast/buffers_adapter.hpp \
|
||||
../include/beast/consuming_buffers.hpp \
|
||||
../include/beast/handler_alloc.hpp \
|
||||
../include/beast/http.hpp \
|
||||
../include/beast/placeholders.hpp \
|
||||
../include/beast/prepare_buffers.hpp \
|
||||
../include/beast/static_streambuf.hpp \
|
||||
../include/beast/streambuf.hpp \
|
||||
../include/beast/streambuf_readstream.hpp \
|
||||
../include/beast/to_string.hpp \
|
||||
../include/beast/type_check.hpp \
|
||||
../include/beast/websocket.hpp \
|
||||
../include/beast/write_streambuf.hpp \
|
||||
../include/beast/http/basic_headers.hpp \
|
||||
../include/beast/http/basic_parser_v1.hpp \
|
||||
../include/beast/http/body_writer.hpp \
|
||||
../include/beast/http/chunk_encode.hpp \
|
||||
../include/beast/http/empty_body.hpp \
|
||||
../include/beast/http/error.hpp \
|
||||
../include/beast/http/fields.hpp \
|
||||
../include/beast/http/headers.hpp \
|
||||
../include/beast/http/message.hpp \
|
||||
../include/beast/http/message_v1.hpp \
|
||||
../include/beast/http/method.hpp \
|
||||
../include/beast/http/parse_error.hpp \
|
||||
../include/beast/http/parser.hpp \
|
||||
../include/beast/http/read.hpp \
|
||||
../include/beast/http/resume_context.hpp \
|
||||
../include/beast/http/rfc2616.hpp \
|
||||
../include/beast/http/streambuf_body.hpp \
|
||||
../include/beast/http/string_body.hpp \
|
||||
../include/beast/http/type_check.hpp \
|
||||
../include/beast/http/write.hpp \
|
||||
../include/beast/websocket/error.hpp \
|
||||
../include/beast/websocket/option.hpp \
|
||||
../include/beast/websocket/rfc6455.hpp \
|
||||
../include/beast/websocket/ssl.hpp \
|
||||
../include/beast/websocket/static_string.hpp \
|
||||
../include/beast/websocket/stream.hpp \
|
||||
../include/beast/websocket/teardown.hpp \
|
||||
../include/beast/zlib \
|
||||
../extras/beast/doc_debug.hpp
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS =
|
||||
@@ -5,7 +5,11 @@
|
||||
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:
|
||||
|
||||
@@ -22,17 +26,12 @@ In this table:
|
||||
will be not movable or not copyable.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`X:value_type{}`]
|
||||
[]
|
||||
[`DefaultConstructible`]
|
||||
]
|
||||
[
|
||||
[`Body::reader`]
|
||||
[]
|
||||
[
|
||||
If present, a type meeting the requirements of
|
||||
[link beast.types.Reader [*`Reader`]].
|
||||
[link beast.ref.Reader [*`Reader`]].
|
||||
Provides an implementation to parse the body.
|
||||
]
|
||||
]
|
||||
@@ -41,7 +40,7 @@ In this table:
|
||||
[]
|
||||
[
|
||||
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.
|
||||
]
|
||||
]
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
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:
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:DynamicBuffer DynamicBuffer]
|
||||
[section:DynamicBuffer DynamicBuffer requirements]
|
||||
|
||||
A dynamic buffer encapsulates memory storage that may be automatically resized
|
||||
as required, where the memory is divided into an input sequence followed by an
|
||||
@@ -27,7 +27,7 @@ implementation strategies:
|
||||
|
||||
* A sequence of one or more octet arrays of varying sizes. Additional octet
|
||||
array objects are appended to the sequence to accommodate changes in the
|
||||
size of the character sequence. This is the implementation approached
|
||||
size of the character sequence. This is the implementation approach
|
||||
currently offered by [link beast.ref.basic_streambuf `basic_streambuf`].
|
||||
|
||||
In the table below:
|
||||
@@ -88,7 +88,7 @@ In the table below:
|
||||
]
|
||||
[
|
||||
[`a.prepare(n)`]
|
||||
[`X:mutable_buffers_type`]
|
||||
[`X::mutable_buffers_type`]
|
||||
[
|
||||
Returns a mutable buffer sequence u representing the output sequence,
|
||||
and where `buffer_size(u) == n`. The dynamic buffer reallocates memory
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
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.
|
||||
|
||||
|
||||
@@ -5,16 +5,17 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:FieldSequence FieldSequence]
|
||||
[section:FieldSequence FieldSequence requirements]
|
||||
|
||||
A [*`FieldSequence`] is an iterable container whose value type meets
|
||||
the requirements of [link beast.types.Field [*`Field`]].
|
||||
A [*FieldSequence] is an iterable container whose value type meets
|
||||
the requirements of [link beast.ref.Field [*Field]]. Objects that meet
|
||||
these requirements become serializable by the implementation.
|
||||
|
||||
In this table:
|
||||
|
||||
* `X` denotes a type that meets the requirements of [*`FieldSequence`].
|
||||
* `X` denotes a type that meets the requirements of [*FieldSequence].
|
||||
|
||||
* `a` is a value of type `X`.
|
||||
* `c` is a value of type `X const`.
|
||||
|
||||
[table FieldSequence requirements
|
||||
[[operation][type][semantics, pre/post-conditions]]
|
||||
@@ -22,25 +23,33 @@ In this table:
|
||||
[`X::value_type`]
|
||||
[]
|
||||
[
|
||||
A type that meets the requirements of `Field`.
|
||||
A type that meets the requirements of [link beast.ref.Field [*Field]].
|
||||
]
|
||||
]
|
||||
[
|
||||
[`X::const_iterator`]
|
||||
[]
|
||||
[
|
||||
A type that meets the requirements of `ForwardIterator`.
|
||||
An iterator type whose `reference` type meets the
|
||||
requirements of [link beast.ref.Field [*Field]], and which
|
||||
satisfies all the requirements of [*ForwardIterator],
|
||||
except that:
|
||||
|
||||
[ordered_list
|
||||
[there is no requirement that `operator->` is provided, and]
|
||||
[there is no requirement that `reference` be a reference type.]
|
||||
]
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.begin()`]
|
||||
[`c.begin()`]
|
||||
[`X::const_iterator`]
|
||||
[
|
||||
Returns an iterator to the beginning of the field sequence.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.end()`]
|
||||
[`c.end()`]
|
||||
[`X::const_iterator`]
|
||||
[
|
||||
Returns an iterator to the end of the field sequence.
|
||||
|
||||
@@ -5,19 +5,22 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:Parser Parser]
|
||||
[section:Parser Parser requirements]
|
||||
|
||||
A [*`Parser`] is used to deserialize HTTP/1 messages from [link beast.types.streams streams].
|
||||
Objects of this type are used with [link beast.ref.http__parse http::parse] and
|
||||
[link beast.ref.http__async_parse http::async_parse].
|
||||
A [*Parser] is used to deserialize objects from
|
||||
[link beast.ref.streams streams]. Objects of this type are used with
|
||||
[link beast.ref.http__parse http::parse] and
|
||||
[link beast.ref.http__async_parse http::async_parse]. The definition of
|
||||
an object, and the predicate defining when the parse is complete, are
|
||||
determined by the implementation.
|
||||
|
||||
In this table:
|
||||
|
||||
* `X` denotes a type meeting the requirements of [*`Parser`].
|
||||
* `X` denotes a type meeting the requirements of [*Parser].
|
||||
|
||||
* `a` denotes a value of type `X`.
|
||||
|
||||
* `b` is a value meeting the requirements of [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConvertibleToConstBuffer.html [*`ConvertibleToConstBuffer`]].
|
||||
* `b` is a value meeting the requirements of __ConstBufferSequence__.
|
||||
|
||||
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
||||
|
||||
@@ -27,18 +30,18 @@ In this table:
|
||||
[`a.complete()`]
|
||||
[`bool`]
|
||||
[
|
||||
Returns `true` when a complete HTTP/1 message has been parsed.
|
||||
Returns `true` when parsing is complete.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.write(b, ec)`]
|
||||
[`std::size_t`]
|
||||
[
|
||||
Parses the octets in the specified input buffer sequentially until
|
||||
an error occurs, the end of the buffer is reached, or a complete
|
||||
HTTP/1 message has been parsed. If an error occurs, `ec` is set
|
||||
to the error code and parsing stops. This function returns the
|
||||
number of bytes consumed from the input buffer.
|
||||
Sequentially parses the octets in the specified input buffer sequence
|
||||
until an error occurs, the end of the buffer is reached, or parsing is
|
||||
complete. Upon success, this function returns the number of bytes used
|
||||
from the input. If an error occurs, `ec` is set to the error code and
|
||||
parsing stops.
|
||||
]
|
||||
]
|
||||
[
|
||||
@@ -48,9 +51,9 @@ In this table:
|
||||
Indicates to the parser that no more octets will be available.
|
||||
Typically this function is called when the end of stream is reached.
|
||||
For example, if a call to `boost::asio::ip::tcp::socket::read_some`
|
||||
generates a `boost::asio::error::eof` error. Some HTTP/1 messages
|
||||
determine the end of the message body by an end of file marker or
|
||||
closing of the connection.
|
||||
generates a `boost::asio::error::eof` error. Some objects, such as
|
||||
certain HTTP/1 messages, determine the end of the message body by
|
||||
an end of file marker or closing of the connection.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:Reader Reader]
|
||||
[section:Reader Reader requirements]
|
||||
|
||||
Parser implementations will construct the corresponding `reader` object
|
||||
during the parse. This customization point allows the Body to determine
|
||||
the strategy for storing incoming message body data.
|
||||
Parsers provided by the implementation will construct the corresponding
|
||||
`reader` object during parsing. This customization point allows the
|
||||
Body to determine the strategy for storing incoming message body data.
|
||||
|
||||
In this table:
|
||||
|
||||
@@ -17,15 +17,14 @@ In this table:
|
||||
|
||||
* `a` denotes a value of type `X`.
|
||||
|
||||
* `p` is any pointer.
|
||||
|
||||
* `n` is a value convertible to `std::size_t`.
|
||||
|
||||
* `ec` is a value of type `error_code&`.
|
||||
* `p` is a `void const*` to valid memory of at least `n` bytes.
|
||||
|
||||
* `m` denotes a value of type `message const&` where
|
||||
`std::is_same<decltype(m.body), Body::value_type>:value == true`
|
||||
* `ec` is a value of type [link beast.ref.error_code `error_code&`].
|
||||
|
||||
* `m` denotes a value of type `message&` where
|
||||
`std::is_same<decltype(m.body), Body::value_type>::value == true`.
|
||||
|
||||
[table Reader requirements
|
||||
[[operation] [type] [semantics, pre/post-conditions]]
|
||||
@@ -33,22 +32,38 @@ In this table:
|
||||
[`X a(m);`]
|
||||
[]
|
||||
[
|
||||
`a` is constructible from `m`. The lifetime of `m` is
|
||||
guaranteed to end no earlier than after `a` is destroyed.
|
||||
`a` is constructible from `m`. The lifetime of `m` is guaranteed
|
||||
to end no earlier than after `a` is destroyed. The constructor
|
||||
will be called after all headers have been stored in `m`, and
|
||||
before any body data is deserialized. This function must be
|
||||
`noexcept`.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.init(ec)`]
|
||||
[`void`]
|
||||
[
|
||||
Called immediately after construction. If the function sets
|
||||
an error code in `ec`, the parse is aborted and the error is
|
||||
propagated to the caller. This function must be `noexcept`.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.write(p, n, ec)`]
|
||||
[`void`]
|
||||
[
|
||||
Deserializes the input sequence into the body.
|
||||
If `ec` is set, the deserialization is aborted and the error
|
||||
is returned to the caller.
|
||||
Deserializes the input sequence into the body. If `ec` is set,
|
||||
the deserialization is aborted and the error is propagated to
|
||||
the caller. If the message headers specify a chunked transfer
|
||||
encoding, the reader will receive the decoded version of the
|
||||
body. This function must be `noexcept`.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[note Definitions for required `Reader` member functions should be declared
|
||||
inline so the generated code becomes part of the implementation. ]
|
||||
[note
|
||||
Definitions for required `Reader` member functions should be declared
|
||||
inline so the generated code can become part of the implementation.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:streams Streams]
|
||||
[section:streams Streams requirements]
|
||||
|
||||
Stream types represent objects capable of performing synchronous or
|
||||
asynchronous I/O. They are based on concepts from `boost::asio`.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:Writer Writer]
|
||||
[section:Writer Writer requirements]
|
||||
|
||||
A `Writer` serializes the message body. The implementation creates an instance
|
||||
of this type when serializing a message, and calls into it zero or more times
|
||||
@@ -28,13 +28,13 @@ In this table:
|
||||
* `m` denotes a value of type `message const&` where
|
||||
`std::is_same<decltype(m.body), Body::value_type>:value == true`.
|
||||
|
||||
* `rc` is an object of type [link beast.ref.http__resume_context resume_context].
|
||||
* `rc` is an object of type [link beast.ref.http__resume_context `resume_context`].
|
||||
|
||||
* `ec` is a value of type `error_code&`.
|
||||
* `ec` is a value of type [link beast.ref.error_code `error_code&`]
|
||||
|
||||
* `wf` is a [*write function]: a function object of unspecified type provided
|
||||
by the implementation which accepts any value meeting the requirements
|
||||
of `ConstBufferSequence` as its single parameter.
|
||||
of __ConstBufferSequence__ as its single parameter.
|
||||
|
||||
[table Writer requirements
|
||||
[[operation] [type] [semantics, pre/post-conditions]]
|
||||
@@ -42,17 +42,18 @@ In this table:
|
||||
[`X a(m);`]
|
||||
[]
|
||||
[
|
||||
`a` is constructible from `m`. The lifetime of `m` is
|
||||
guaranteed to end no earlier than after `a` is destroyed.
|
||||
`a` is constructible from `m`. The lifetime of `m` is guaranteed
|
||||
to end no earlier than after `a` is destroyed. This function must
|
||||
be `noexcept`.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a.init(ec)`]
|
||||
[`void`]
|
||||
[
|
||||
Called immediately after construction.
|
||||
If `ec` is set, the serialization is aborted and the error
|
||||
is propagated to the caller.
|
||||
Called immediately after construction. If the function sets an
|
||||
error code in `ec`, the serialization is aborted and the error
|
||||
is propagated to the caller. This function must be `noexcept`.
|
||||
]
|
||||
]
|
||||
[
|
||||
@@ -67,31 +68,33 @@ In this table:
|
||||
the serialized message body will be sent unmodified, with the
|
||||
error `boost::asio::error::eof` returned to the caller, to notify
|
||||
they should close the connection to indicate the end of the message.
|
||||
This function must be `noexcept`.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a(rc, ec, wf)`]
|
||||
[`a.write(rc, ec, wf)`]
|
||||
[`boost::tribool`]
|
||||
[
|
||||
Called repeatedly after `init` succeeds.
|
||||
`wf` is a function object which takes as its single parameter,
|
||||
any value meeting the requirements of `ConstBufferSequence`.
|
||||
Buffers provided by the `writer` to this [*write function] must
|
||||
remain valid until the next member function of `writer` is
|
||||
Called repeatedly after `init` succeeds. `wf` is a function object
|
||||
which takes as its single parameter any value meeting the requirements
|
||||
of __ConstBufferSequence__. Buffers provided to this write function
|
||||
must remain valid until the next member function of `writer` is
|
||||
invoked (which may be the destructor). This function returns `true`
|
||||
to indicate all message body data has been written, or `false`
|
||||
if there is more body data. If the return value is
|
||||
`boost::indeterminate`, the implementation will suspend the operation
|
||||
until the writer invokes `rc`. It is the writers responsibility when
|
||||
returning `boost::indeterminate`, to acquire ownership of the
|
||||
`resume_context` via move construction and eventually call it or else
|
||||
undefined behavior results.
|
||||
to indicate all message body data has been written, or `false` if
|
||||
there is more body data. If the return value is `boost::indeterminate`,
|
||||
the implementation will suspend the operation until the writer invokes
|
||||
`rc`. It is the writers responsibility when returning
|
||||
`boost::indeterminate`, to acquire ownership of `rc` via move
|
||||
construction and eventually call it or else undefined behavior
|
||||
results. This function must be `noexcept`.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[note Definitions for required `Writer` member functions should be declared
|
||||
inline so the generated code becomes part of the implementation. ]
|
||||
[note
|
||||
Definitions for required `Writer` member functions should be declared
|
||||
inline so the generated code can become part of the implementation.
|
||||
]
|
||||
|
||||
Exemplar:
|
||||
```
|
||||
@@ -109,7 +112,7 @@ public:
|
||||
*/
|
||||
template<bool isRequest, class Body, class Headers>
|
||||
explicit
|
||||
writer(message<isRequest, Body, Headers> const& msg);
|
||||
writer(message<isRequest, Body, Headers> const& msg) noexcept;
|
||||
|
||||
/** Initialize the writer.
|
||||
|
||||
@@ -119,7 +122,7 @@ public:
|
||||
@param ec Contains the error code if any errors occur.
|
||||
*/
|
||||
void
|
||||
init(error_code& ec);
|
||||
init(error_code& ec) noexcept;
|
||||
|
||||
/** Returns the content length.
|
||||
|
||||
@@ -128,8 +131,8 @@ public:
|
||||
use chunk-encoding or terminate the connection to indicate the end
|
||||
of the message.
|
||||
*/
|
||||
std::size_t
|
||||
content_length() const;
|
||||
std::uint64_t
|
||||
content_length() noexcept;
|
||||
|
||||
/** Write zero or one buffer representing the message body.
|
||||
|
||||
@@ -172,7 +175,10 @@ public:
|
||||
*/
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, WriteFunction&& write);
|
||||
write(
|
||||
resume_context&&,
|
||||
error_code&,
|
||||
WriteFunction&& wf) noexcept;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
@@ -7,6 +7,21 @@
|
||||
|
||||
[section:websocket WebSocket]
|
||||
|
||||
[block '''
|
||||
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
|
||||
<member><link linkend="beast.websocket.creation">Creation</link></member>
|
||||
<member><link linkend="beast.websocket.connections">Making connections</link></member>
|
||||
<member><link linkend="beast.websocket.handshaking">Handshaking</link></member>
|
||||
<member><link linkend="beast.websocket.messages">Messages</link></member>
|
||||
<member><link linkend="beast.websocket.frames">Frames</link></member>
|
||||
<member><link linkend="beast.websocket.control">Control Frames</link></member>
|
||||
<member><link linkend="beast.websocket.buffers">Buffers</link></member>
|
||||
<member><link linkend="beast.websocket.async">Asynchronous interface</link></member>
|
||||
<member><link linkend="beast.websocket.io_service">The io_service</link></member>
|
||||
<member><link linkend="beast.websocket.threads">Thread Safety</link></member>
|
||||
</simplelist></entry></row></tbody></tgroup></informaltable>
|
||||
''']
|
||||
|
||||
The WebSocket Protocol enables two-way communication between a client
|
||||
running untrusted code in a controlled environment to a remote host that has
|
||||
opted-in to communications from that code. The protocol consists of an opening
|
||||
@@ -22,77 +37,57 @@ C++ approach.
|
||||
The WebSocket protocol is described fully in
|
||||
[@https://tools.ietf.org/html/rfc6455 rfc6455]
|
||||
|
||||
|
||||
|
||||
[section:motivation Motivation]
|
||||
|
||||
Today's web applications increasingly rely on alternatives to standard HTTP
|
||||
to achieve performance and/or responsiveness. While WebSocket implementations
|
||||
are widely available in common web development languages such as Javascript,
|
||||
good implementations in C++ are scarce. A survey of existing C++ WebSocket
|
||||
solutions reveals interfaces which lack symmetry, impose performance penalties,
|
||||
and needlessly restrict implementation strategies.
|
||||
|
||||
Beast.WebSocket is built on Boost.Asio, a robust cross platform networking
|
||||
framework that is part of Boost and also offered as a standalone library.
|
||||
A proposal to add networking functionality to the C++ standard library,
|
||||
based on Boost.Asio, is under consideration by the standards committee.
|
||||
Since the final approved networking interface for the C++ standard library
|
||||
will likely closely resemble the current interface of Boost.Asio, it is
|
||||
logical for Beast.WebSocket to use Boost.Asio as its network transport.
|
||||
|
||||
Beast.WebSocket takes advantage of Boost.Asio's extensible asynchronous
|
||||
model, handler allocation, and handler invocation hooks. Calls to
|
||||
Beast.WebSocket asynchronous initiation functions allow callers the choice
|
||||
of using a completion handler, stackful or stackless coroutines, futures,
|
||||
or user defined customizations (for example, Boost.Fiber). The
|
||||
implementation uses handler invocation hooks
|
||||
([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]),
|
||||
providing execution guarantees on composed operations in a manner
|
||||
identical to Boost.Asio. The implementation also uses handler allocation hooks
|
||||
([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`])
|
||||
when allocating memory internally for composed operations.
|
||||
|
||||
There is no need for inheritance or virtual members in a
|
||||
[link beast.ref.websocket__stream `beast::websocket::stream`].
|
||||
All operations are templated and transparent to the compiler, allowing for
|
||||
maximum inlining and optimization.
|
||||
|
||||
[note The documentation which follows assumes familiarity with
|
||||
both Boost.Asio and the WebSocket protocol specification described in
|
||||
[@https://tools.ietf.org/html/rfc6455 rfc6455] ]
|
||||
|
||||
[endsect]
|
||||
[note
|
||||
The following documentation assumes familiarity with both
|
||||
Boost.Asio and the WebSocket protocol specification described in __rfc6455__.
|
||||
]
|
||||
|
||||
|
||||
|
||||
[section:creating Creating the socket]
|
||||
|
||||
[section:creation Creation]
|
||||
|
||||
The interface to Beast's WebSocket implementation is a single template
|
||||
class [link beast.ref.websocket__stream `beast::websocket::stream`] which
|
||||
wraps a "next layer" object. The next layer object must meet the requirements
|
||||
of [link beast.types.streams.SyncStream [*`SyncReadStream`]] if synchronous
|
||||
of [link beast.ref.streams.SyncStream [*`SyncReadStream`]] if synchronous
|
||||
operations are performed, or
|
||||
[link beast.types.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
||||
[link beast.ref.streams.AsyncStream [*`AsyncStream`]] if asynchronous
|
||||
operations are performed, or both. Arguments supplied during construction are
|
||||
passed to next layer's constructor. Here we declare two websockets which have
|
||||
ownership of the next layer:
|
||||
passed to next layer's constructor. Here we declare a websocket stream over
|
||||
a TCP/IP socket with ownership of the socket:
|
||||
```
|
||||
boost::asio::io_service ios;
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
|
||||
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);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||
```
|
||||
|
||||
[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
|
||||
to wrap an object that already exists. This socket can be moved in:
|
||||
```
|
||||
boost::asio::ip::tcp::socket&& sock;
|
||||
...
|
||||
beast::websocket::stream<
|
||||
boost::asio::ip::tcp::socket> ws(std::move(sock));
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{std::move(sock)};
|
||||
```
|
||||
|
||||
Or, the wrapper can be constructed with a non-owning reference. In
|
||||
@@ -101,36 +96,37 @@ underlying socket being wrapped:
|
||||
```
|
||||
boost::asio::ip::tcp::socket sock;
|
||||
...
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
```
|
||||
|
||||
The layer being wrapped can be accessed through the websocket's "next layer",
|
||||
permitting callers to interact directly with its interface.
|
||||
```
|
||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
||||
beast::websocket::stream<
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws(ios, ctx);
|
||||
boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23};
|
||||
beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> ws{ios, ctx};
|
||||
...
|
||||
ws.next_layer().shutdown(); // ssl::stream shutdown
|
||||
```
|
||||
|
||||
[important Initiating read and write operations on the next layer while
|
||||
websocket operations are being performed can break invariants, and
|
||||
result in undefined behavior. ]
|
||||
[warning
|
||||
Initiating read and write operations on the next layer while
|
||||
stream operations are being performed can break invariants, and
|
||||
result in undefined behavior.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:connecting Making connections]
|
||||
[section:connections Making connections]
|
||||
|
||||
Connections are established by using the interfaces which already exist
|
||||
for the next layer. For example, making an outgoing connection:
|
||||
```
|
||||
std::string const host = "mywebapp.com";
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::ip::tcp::resolver r(ios);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
boost::asio::ip::tcp::resolver r{ios};
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||
boost::asio::connect(ws.next_layer(),
|
||||
r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"}));
|
||||
```
|
||||
@@ -139,12 +135,14 @@ Accepting an incoming connection:
|
||||
```
|
||||
void do_accept(boost::asio::ip::tcp::acceptor& acceptor)
|
||||
{
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(acceptor.get_io_service());
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{acceptor.get_io_service()};
|
||||
acceptor.accept(ws.next_layer());
|
||||
}
|
||||
```
|
||||
|
||||
[note Examples use synchronous interfaces for clarity of exposition. ]
|
||||
[note
|
||||
Examples use synchronous interfaces for clarity of exposition.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -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
|
||||
indicating that the request was accepted and that the connection has
|
||||
been upgraded. The HTTP Upgrade request must include the Host HTTP field,
|
||||
and the URI of the resource to request. `handshake` is used to send the
|
||||
and the URI of the resource to request.
|
||||
[link beast.ref.websocket__stream.handshake `handshake`] is used to send the
|
||||
request with the required host and resource strings.
|
||||
```
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||
...
|
||||
ws.set_option(beast::websocket::keep_alive(true));
|
||||
ws.handshake("ws.example.com:80", "/cgi-bin/bitcoin-prices");
|
||||
```
|
||||
|
||||
The [link beast.ref.websocket__stream `beast::websocket::stream`] automatically
|
||||
The [link beast.ref.websocket__stream `stream`] automatically
|
||||
handles receiving and processing the HTTP response to the handshake request.
|
||||
The call to handshake is successful if a HTTP response is received with the
|
||||
101 "Switching Protocols" status code. On failure, an error is returned or an
|
||||
@@ -175,7 +174,7 @@ open for a subsequent handshake attempt
|
||||
Performing a handshake for an incoming websocket upgrade request operates
|
||||
similarly. If the handshake fails, an error is returned or exception thrown:
|
||||
```
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws(ios);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||
...
|
||||
ws.accept();
|
||||
```
|
||||
@@ -190,7 +189,7 @@ void do_accept(boost::asio::ip::tcp::socket& sock)
|
||||
boost::asio::streambuf sb;
|
||||
boost::asio::read_until(sock, sb, "\r\n\r\n");
|
||||
...
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws(sock);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
ws.accept(sb.data());
|
||||
...
|
||||
}
|
||||
@@ -203,10 +202,10 @@ void do_accept(boost::asio::ip::tcp::socket& sock)
|
||||
{
|
||||
boost::asio::streambuf sb;
|
||||
beast::http::request<http::empty_body> request;
|
||||
beast::http::read(sock, request);
|
||||
beast::http::read(sock, sb, request);
|
||||
if(beast::http::is_upgrade(request))
|
||||
{
|
||||
websocket::stream<ip::tcp::socket&> ws(sock);
|
||||
websocket::stream<ip::tcp::socket&> ws{sock};
|
||||
ws.accept(request);
|
||||
...
|
||||
}
|
||||
@@ -227,17 +226,19 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
||||
{
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode::value op;
|
||||
ws.read(sb);
|
||||
ws.read(op, sb);
|
||||
|
||||
ws.set_option(beast::websocket::message_type(op));
|
||||
ws.set_option(beast::websocket::message_type{op});
|
||||
ws.write(sb.data());
|
||||
sb.consume(sb.size());
|
||||
}
|
||||
```
|
||||
|
||||
[important Calls to [link beast.ref.websocket__stream.set_option `set_option`]
|
||||
must be made from the same implicit or explicit strand as that used to perform
|
||||
other operations. ]
|
||||
[important
|
||||
Calls to [link beast.ref.websocket__stream.set_option `set_option`]
|
||||
must be made from the same implicit or explicit strand as that used
|
||||
to perform other operations.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -265,9 +266,9 @@ void echo(beast::websocket::stream<boost::asio::ip::tcp::socket>& ws)
|
||||
if(fi.fin)
|
||||
break;
|
||||
}
|
||||
ws.set_option(beast::websocket::message_type(fi.op));
|
||||
ws.set_option(beast::websocket::message_type{fi.op});
|
||||
beast::consuming_buffers<
|
||||
beast::streambuf::const_buffers_type> cb(sb.data());
|
||||
beast::streambuf::const_buffers_type> cb{sb.data()};
|
||||
for(;;)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
@@ -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
|
||||
WebSocket control frames such as ping, pong, and close. Pings are replied
|
||||
to as soon as possible, pongs are delivered to the pong callback. The receipt
|
||||
of a close frame initiates the WebSocket close procedure, eventually resulting
|
||||
in the error code [link beast.ref.websocket__error `error::closed`] being
|
||||
delivered to the caller in a subsequent read operation, assuming no other error
|
||||
Control frames are small (less than 128 bytes) messages entirely contained
|
||||
in an individual WebSocket frame. They may be sent at any time by either
|
||||
peer on an established connection, and can appear in between continuation
|
||||
frames for a message. There are three types of control frames: ping, pong,
|
||||
and close.
|
||||
|
||||
A sent ping indicates a request that the sender wants to receive a pong. A
|
||||
pong is a response to a ping. Pongs may be sent unsolicited, at any time.
|
||||
One use for an unsolicited pong is to inform the remote peer that the
|
||||
session is still active after a long period of inactivity. A close frame
|
||||
indicates that the remote peer wishes to close the WebSocket connection.
|
||||
The connection is considered gracefully closed when each side has sent
|
||||
and received a close frame.
|
||||
|
||||
During read operations, Beast automatically reads and processes control
|
||||
frames. Pings are replied to as soon as possible with a pong, received
|
||||
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.
|
||||
|
||||
To ensure timely delivery of control frames, large messages are broken up
|
||||
into smaller sized frames. The implementation chooses the size and number
|
||||
of the frames making up the message. The automatic fragment size option
|
||||
gives callers control over the size of these frames:
|
||||
```
|
||||
...
|
||||
ws.set_option(beast::websocket::auto_fragment_size(8192));
|
||||
```
|
||||
A consequence of this automatic behavior is that caller-initiated read
|
||||
operations can cause socket writes. However, these writes will not
|
||||
compete with caller-initiated write operations. For the purposes of
|
||||
correctness with respect to the stream invariants, caller-initiated
|
||||
read operations still only count as a read. This means that callers can
|
||||
have a simultaneous active read and write operation in progress, while
|
||||
the implementation also automatically handles control frames.
|
||||
|
||||
The WebSocket protocol defines a procedure and control message for initiating
|
||||
a close of the session. Handling of close initiated by the remote end of the
|
||||
connection is performed automatically. To manually initiate a close, use
|
||||
[link beast.ref.websocket__stream.close `close`]:
|
||||
```
|
||||
ws.close();
|
||||
```
|
||||
[heading Ping and Pong Frames]
|
||||
|
||||
[note To receive the [link beast.ref.websocket__error `error::closed`]
|
||||
error, a read operation is required. ]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:pongs Pong messages]
|
||||
Ping and pong messages are control frames which may be sent at any time
|
||||
by either peer on an established WebSocket connection. They are sent
|
||||
using the functions
|
||||
[link beast.ref.websocket__stream.ping `ping`] and
|
||||
[link beast.ref.websocket__stream.pong `pong`].
|
||||
|
||||
To receive pong control frames, callers may register a "pong callback" using
|
||||
[link beast.ref.websocket__stream.set_option `set_option`]:
|
||||
|
||||
the following signature:
|
||||
[link beast.ref.websocket__stream.set_option `set_option`]. The object provided
|
||||
with this option should be callable with the following signature:
|
||||
```
|
||||
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
|
||||
pongs, a synchronous or asynchronous stream read function must be active.
|
||||
|
||||
[note When an asynchronous read function receives a pong, the the pong callback
|
||||
is invoked in the same manner as that used to invoke the final completion
|
||||
handler of the corresponding read function.]
|
||||
[note
|
||||
When an asynchronous read function receives a pong, the the pong
|
||||
callback is invoked in the same manner as that used to invoke the
|
||||
final completion handler of the corresponding read function.
|
||||
]
|
||||
|
||||
[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]
|
||||
|
||||
@@ -358,7 +400,7 @@ handler of the corresponding read function.]
|
||||
|
||||
Because calls to read data may return a variable amount of bytes, the
|
||||
interface to calls that read data require an object that meets the requirements
|
||||
of [link beast.types.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on
|
||||
of [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on
|
||||
[@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
|
||||
|
||||
The implementation does not perform queueing or buffering of messages. If
|
||||
@@ -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
|
||||
not thread safe. Callers are responsible for synchronizing operations on the
|
||||
|
||||
@@ -1,49 +1,52 @@
|
||||
# Part of Beast
|
||||
|
||||
GroupSources(extras/beast beast)
|
||||
GroupSources(extras/beast extras)
|
||||
GroupSources(include/beast beast)
|
||||
|
||||
GroupSources(examples "/")
|
||||
|
||||
add_executable (http-crawl
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
urls_large_data.hpp
|
||||
urls_large_data.cpp
|
||||
http_crawl.cpp
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(http-crawl ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(http-crawl ${Boost_LIBRARIES} Threads::Threads)
|
||||
endif()
|
||||
|
||||
add_executable (http-server
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
file_body.hpp
|
||||
mime_type.hpp
|
||||
http_async_server.hpp
|
||||
http_stream.hpp
|
||||
http_stream.ipp
|
||||
http_sync_server.hpp
|
||||
http_server.cpp
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(http-server ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(http-server ${Boost_LIBRARIES} Threads::Threads)
|
||||
endif()
|
||||
|
||||
add_executable (http-example
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
http_example.cpp
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(http-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(http-example ${Boost_LIBRARIES} Threads::Threads)
|
||||
endif()
|
||||
|
||||
add_executable (websocket-example
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
websocket_example.cpp
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(websocket-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(websocket-example ${Boost_LIBRARIES} Threads::Threads)
|
||||
endif()
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
|
||||
import os ;
|
||||
|
||||
exe http-crawl :
|
||||
http_crawl.cpp
|
||||
urls_large_data.cpp
|
||||
@@ -23,4 +21,3 @@ exe http-example :
|
||||
exe websocket-example :
|
||||
websocket_example.cpp
|
||||
;
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
|
||||
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -23,7 +26,7 @@ struct file_body
|
||||
|
||||
class writer
|
||||
{
|
||||
std::uint64_t size_;
|
||||
std::uint64_t size_ = 0;
|
||||
std::uint64_t offset_ = 0;
|
||||
std::string const& path_;
|
||||
FILE* file_ = nullptr;
|
||||
@@ -34,8 +37,8 @@ struct file_body
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
writer(message<isRequest, file_body, Headers> const& m) noexcept
|
||||
template<bool isRequest, class Fields>
|
||||
writer(message<isRequest, file_body, Fields> const& m) noexcept
|
||||
: path_(m.body)
|
||||
{
|
||||
}
|
||||
@@ -58,14 +61,15 @@ struct file_body
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
content_length() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
write(resume_context&&, error_code&,
|
||||
WriteFunction&& wf) noexcept
|
||||
{
|
||||
if(size_ - offset_ < sizeof(buf_))
|
||||
buf_len_ = static_cast<std::size_t>(
|
||||
@@ -75,7 +79,7 @@ struct file_body
|
||||
auto const nread = fread(buf_, 1, sizeof(buf_), file_);
|
||||
(void)nread;
|
||||
offset_ += buf_len_;
|
||||
write(boost::asio::buffer(buf_, buf_len_));
|
||||
wf(boost::asio::buffer(buf_, buf_len_));
|
||||
return offset_ >= size_;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,10 +9,15 @@
|
||||
#define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
|
||||
|
||||
#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/streambuf.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@@ -29,20 +34,22 @@ class http_async_server
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
using req_type = request_v1<string_body>;
|
||||
using resp_type = response_v1<file_body>;
|
||||
using req_type = request<string_body>;
|
||||
using resp_type = response<file_body>;
|
||||
|
||||
std::mutex m_;
|
||||
bool log_ = true;
|
||||
boost::asio::io_service ios_;
|
||||
socket_type sock_;
|
||||
boost::asio::ip::tcp::acceptor acceptor_;
|
||||
socket_type sock_;
|
||||
std::string root_;
|
||||
std::vector<std::thread> thread_;
|
||||
|
||||
public:
|
||||
http_async_server(endpoint_type const& ep,
|
||||
int threads, std::string const& root)
|
||||
: sock_(ios_)
|
||||
, acceptor_(ios_)
|
||||
std::size_t threads, std::string const& root)
|
||||
: acceptor_(ios_)
|
||||
, sock_(ios_)
|
||||
, root_(root)
|
||||
{
|
||||
acceptor_.open(ep.protocol());
|
||||
@@ -53,7 +60,7 @@ public:
|
||||
std::bind(&http_async_server::on_accept, this,
|
||||
beast::asio::placeholders::error));
|
||||
thread_.reserve(threads);
|
||||
for(int i = 0; i < threads; ++i)
|
||||
for(std::size_t i = 0; i < threads; ++i)
|
||||
thread_.emplace_back(
|
||||
[&] { ios_.run(); });
|
||||
}
|
||||
@@ -67,13 +74,118 @@ public:
|
||||
t.join();
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void
|
||||
log(Args const&... args)
|
||||
{
|
||||
if(log_)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
log_args(args...);
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
{
|
||||
int id_;
|
||||
stream<socket_type> stream_;
|
||||
streambuf sb_;
|
||||
socket_type sock_;
|
||||
http_async_server& server_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
std::string root_;
|
||||
req_type req_;
|
||||
|
||||
public:
|
||||
@@ -82,16 +194,22 @@ private:
|
||||
peer& operator=(peer&&) = delete;
|
||||
peer& operator=(peer const&) = delete;
|
||||
|
||||
explicit
|
||||
peer(socket_type&& sock, std::string const& root)
|
||||
: stream_(std::move(sock))
|
||||
, strand_(stream_.get_io_service())
|
||||
, root_(root)
|
||||
peer(socket_type&& sock, http_async_server& server)
|
||||
: sock_(std::move(sock))
|
||||
, server_(server)
|
||||
, strand_(sock_.get_io_service())
|
||||
{
|
||||
static int n = 0;
|
||||
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()
|
||||
{
|
||||
do_read();
|
||||
@@ -99,81 +217,90 @@ private:
|
||||
|
||||
void do_read()
|
||||
{
|
||||
stream_.async_read(req_, strand_.wrap(
|
||||
async_read(sock_, sb_, req_, strand_.wrap(
|
||||
std::bind(&peer::on_read, shared_from_this(),
|
||||
asio::placeholders::error)));
|
||||
}
|
||||
|
||||
void on_read(error_code ec)
|
||||
void on_read(error_code const& ec)
|
||||
{
|
||||
if(ec)
|
||||
return fail(ec, "read");
|
||||
do_read();
|
||||
auto path = req_.url;
|
||||
if(path == "/")
|
||||
path = "/index.html";
|
||||
path = root_ + path;
|
||||
path = server_.root_ + path;
|
||||
if(! boost::filesystem::exists(path))
|
||||
{
|
||||
response_v1<string_body> resp;
|
||||
resp.status = 404;
|
||||
resp.reason = "Not Found";
|
||||
resp.version = req_.version;
|
||||
resp.headers.replace("Server", "http_async_server");
|
||||
resp.body = "The file '" + path + "' was not found";
|
||||
prepare(resp);
|
||||
stream_.async_write(std::move(resp),
|
||||
response<string_body> res;
|
||||
res.status = 404;
|
||||
res.reason = "Not Found";
|
||||
res.version = req_.version;
|
||||
res.fields.insert("Server", "http_async_server");
|
||||
res.fields.insert("Content-Type", "text/html");
|
||||
res.body = "The file '" + path + "' was not found";
|
||||
prepare(res);
|
||||
async_write(sock_, std::move(res),
|
||||
std::bind(&peer::on_write, shared_from_this(),
|
||||
asio::placeholders::error));
|
||||
return;
|
||||
}
|
||||
resp_type resp;
|
||||
resp.status = 200;
|
||||
resp.reason = "OK";
|
||||
resp.version = req_.version;
|
||||
resp.headers.replace("Server", "http_async_server");
|
||||
resp.headers.replace("Content-Type", "text/html");
|
||||
resp.body = path;
|
||||
prepare(resp);
|
||||
stream_.async_write(std::move(resp),
|
||||
std::bind(&peer::on_write, shared_from_this(),
|
||||
asio::placeholders::error));
|
||||
try
|
||||
{
|
||||
resp_type res;
|
||||
res.status = 200;
|
||||
res.reason = "OK";
|
||||
res.version = req_.version;
|
||||
res.fields.insert("Server", "http_async_server");
|
||||
res.fields.insert("Content-Type", mime_type(path));
|
||||
res.body = path;
|
||||
prepare(res);
|
||||
async_write(sock_, std::move(res),
|
||||
std::bind(&peer::on_write, shared_from_this(),
|
||||
asio::placeholders::error));
|
||||
}
|
||||
catch(std::exception const& e)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if(ec)
|
||||
fail(ec, "write");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
do_read();
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
maybe_throw(error_code ec, std::string what)
|
||||
fail(error_code ec, std::string what)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, what);
|
||||
throw ec;
|
||||
}
|
||||
log(what, ": ", ec.message(), "\n");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -181,12 +308,13 @@ private:
|
||||
{
|
||||
if(! acceptor_.is_open())
|
||||
return;
|
||||
maybe_throw(ec, "accept");
|
||||
if(ec)
|
||||
return fail(ec, "accept");
|
||||
socket_type sock(std::move(sock_));
|
||||
acceptor_.async_accept(sock_,
|
||||
std::bind(&http_async_server::on_accept, this,
|
||||
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)
|
||||
//
|
||||
|
||||
#include "http_stream.hpp"
|
||||
#include "urls_large_data.hpp"
|
||||
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/http.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using namespace beast::http;
|
||||
@@ -31,23 +33,24 @@ int main(int, char const*[])
|
||||
ip::tcp::resolver r(ios);
|
||||
auto it = r.resolve(
|
||||
ip::tcp::resolver::query{host, "http"});
|
||||
stream<ip::tcp::socket> hs(ios);
|
||||
connect(hs.lowest_layer(), it);
|
||||
auto ep = hs.lowest_layer().remote_endpoint();
|
||||
request_v1<empty_body> req;
|
||||
ip::tcp::socket sock(ios);
|
||||
connect(sock, it);
|
||||
auto ep = sock.remote_endpoint();
|
||||
request<empty_body> req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.headers.insert("Host", host +
|
||||
std::string(":") + std::to_string(ep.port()));
|
||||
req.headers.insert("User-Agent", "beast/http");
|
||||
req.fields.insert("Host", host + std::string(":") +
|
||||
boost::lexical_cast<std::string>(ep.port()));
|
||||
req.fields.insert("User-Agent", "beast/http");
|
||||
prepare(req);
|
||||
hs.write(req);
|
||||
response_v1<string_body> resp;
|
||||
hs.read(resp);
|
||||
std::cout << resp;
|
||||
write(sock, req);
|
||||
response<string_body> res;
|
||||
streambuf sb;
|
||||
beast::http::read(sock, sb, res);
|
||||
std::cout << res;
|
||||
}
|
||||
catch(boost::system::system_error const& ec)
|
||||
catch(beast::system_error const& ec)
|
||||
{
|
||||
std::cerr << host << ": " << ec.what();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <beast/http.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@@ -15,24 +16,25 @@ 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::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;
|
||||
beast::http::request<beast::http::empty_body> req;
|
||||
req.method = "GET";
|
||||
req.url = "/";
|
||||
req.version = 11;
|
||||
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
|
||||
req.headers.replace("User-Agent", "Beast");
|
||||
req.fields.replace("Host", host + ":" +
|
||||
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||
req.fields.replace("User-Agent", "Beast");
|
||||
beast::http::prepare(req);
|
||||
beast::http::write(sock, req);
|
||||
|
||||
// Receive and print HTTP response using beast
|
||||
beast::streambuf sb;
|
||||
beast::http::response_v1<beast::http::streambuf_body> resp;
|
||||
beast::http::response<beast::http::streambuf_body> resp;
|
||||
beast::http::read(sock, sb, resp);
|
||||
std::cout << resp;
|
||||
}
|
||||
|
||||
@@ -20,34 +20,26 @@ int main(int ac, char const* av[])
|
||||
po::options_description desc("Options");
|
||||
|
||||
desc.add_options()
|
||||
("root,r", po::value<std::string>()->implicit_value("."),
|
||||
("root,r", po::value<std::string>()->default_value("."),
|
||||
"Set the root directory for serving files")
|
||||
("port,p", po::value<std::uint16_t>()->implicit_value(8080),
|
||||
("port,p", po::value<std::uint16_t>()->default_value(8080),
|
||||
"Set the port number for the server")
|
||||
("ip", po::value<std::string>()->implicit_value("0.0.0.0"),
|
||||
("ip", po::value<std::string>()->default_value("0.0.0.0"),
|
||||
"Set the IP address to bind to, \"0.0.0.0\" for all")
|
||||
("threads,n", po::value<std::size_t>()->implicit_value(4),
|
||||
("threads,n", po::value<std::size_t>()->default_value(4),
|
||||
"Set the number of threads to use")
|
||||
("sync,s", "Launch a synchronous server")
|
||||
;
|
||||
po::variables_map vm;
|
||||
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||
|
||||
std::string root = ".";
|
||||
if(vm.count("root"))
|
||||
root = vm["root"].as<std::string>();
|
||||
std::string root = vm["root"].as<std::string>();
|
||||
|
||||
std::uint16_t port = 8080;
|
||||
if(vm.count("port"))
|
||||
port = vm["port"].as<std::uint16_t>();
|
||||
std::uint16_t port = vm["port"].as<std::uint16_t>();
|
||||
|
||||
std::string ip = "0.0.0.0";
|
||||
if(vm.count("ip"))
|
||||
ip = vm["ip"].as<std::string>();
|
||||
std::string ip = vm["ip"].as<std::string>();
|
||||
|
||||
std::size_t threads = 4;
|
||||
if(vm.count("threads"))
|
||||
threads = vm["threads"].as<std::size_t>();
|
||||
std::size_t threads = vm["threads"].as<std::size_t>();
|
||||
|
||||
bool sync = vm.count("sync") > 0;
|
||||
|
||||
@@ -57,8 +49,13 @@ int main(int ac, char const* av[])
|
||||
endpoint_type ep{address_type::from_string(ip), port};
|
||||
|
||||
if(sync)
|
||||
{
|
||||
http_sync_server server(ep, root);
|
||||
beast::test::sig_wait();
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
|
||||
#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 <cstdint>
|
||||
#include <cstdio>
|
||||
@@ -18,6 +21,7 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <iostream>
|
||||
@@ -31,9 +35,11 @@ class http_sync_server
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
using req_type = request_v1<string_body>;
|
||||
using resp_type = response_v1<file_body>;
|
||||
using req_type = request<string_body>;
|
||||
using resp_type = response<file_body>;
|
||||
|
||||
bool log_ = true;
|
||||
std::mutex m_;
|
||||
boost::asio::io_service ios_;
|
||||
socket_type sock_;
|
||||
boost::asio::ip::tcp::acceptor acceptor_;
|
||||
@@ -65,21 +71,43 @@ public:
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void
|
||||
fail(error_code ec, std::string what)
|
||||
log(Args const&... args)
|
||||
{
|
||||
std::cerr <<
|
||||
what << ": " << ec.message() << std::endl;
|
||||
if(log_)
|
||||
{
|
||||
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
|
||||
maybe_throw(error_code ec, std::string what)
|
||||
fail(error_code ec, std::string what)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, what);
|
||||
throw ec;
|
||||
}
|
||||
log(what, ": ", ec.message(), "\n");
|
||||
}
|
||||
|
||||
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
|
||||
@@ -109,7 +137,8 @@ public:
|
||||
{
|
||||
if(! acceptor_.is_open())
|
||||
return;
|
||||
maybe_throw(ec, "accept");
|
||||
if(ec)
|
||||
return fail(ec, "accept");
|
||||
static int id_ = 0;
|
||||
std::thread{lambda{++id_, *this, std::move(sock_)}}.detach();
|
||||
acceptor_.async_accept(sock_,
|
||||
@@ -118,23 +147,15 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
fail(int id, error_code const& ec)
|
||||
do_peer(int id, socket_type&& sock0)
|
||||
{
|
||||
if(ec != boost::asio::error::operation_aborted &&
|
||||
ec != boost::asio::error::eof)
|
||||
std::cerr <<
|
||||
"#" << std::to_string(id) << " " << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
do_peer(int id, socket_type&& sock)
|
||||
{
|
||||
http::stream<socket_type> hs(std::move(sock));
|
||||
socket_type sock(std::move(sock0));
|
||||
streambuf sb;
|
||||
error_code ec;
|
||||
for(;;)
|
||||
{
|
||||
req_type req;
|
||||
hs.read(req, ec);
|
||||
http::read(sock, sb, req, ec);
|
||||
if(ec)
|
||||
break;
|
||||
auto path = req.url;
|
||||
@@ -143,28 +164,48 @@ public:
|
||||
path = root_ + path;
|
||||
if(! boost::filesystem::exists(path))
|
||||
{
|
||||
response_v1<string_body> resp;
|
||||
resp.status = 404;
|
||||
resp.reason = "Not Found";
|
||||
resp.version = req.version;
|
||||
resp.headers.replace("Server", "http_sync_server");
|
||||
resp.body = "The file '" + path + "' was not found";
|
||||
prepare(resp);
|
||||
hs.write(resp, ec);
|
||||
response<string_body> res;
|
||||
res.status = 404;
|
||||
res.reason = "Not Found";
|
||||
res.version = req.version;
|
||||
res.fields.insert("Server", "http_sync_server");
|
||||
res.fields.insert("Content-Type", "text/html");
|
||||
res.body = "The file '" + path + "' was not found";
|
||||
prepare(res);
|
||||
write(sock, res, ec);
|
||||
if(ec)
|
||||
break;
|
||||
return;
|
||||
}
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
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::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);
|
||||
beast::websocket::stream<boost::asio::ip::tcp::socket&> ws{sock};
|
||||
ws.handshake(host, "/");
|
||||
ws.write(boost::asio::buffer("Hello, world!"));
|
||||
ws.write(boost::asio::buffer(std::string("Hello, world!")));
|
||||
|
||||
// Receive WebSocket message, print and close using beast
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(beast::websocket::close_code::normal);
|
||||
std::cout << to_string(sb.data()) << "\n";
|
||||
std::cout << beast::to_string(sb.data()) << "\n";
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
namespace beast {
|
||||
namespace test {
|
||||
|
||||
enum error
|
||||
enum class error
|
||||
{
|
||||
fail_error = 1
|
||||
};
|
||||
@@ -77,14 +77,15 @@ inline
|
||||
error_code
|
||||
make_error_code(error ev)
|
||||
{
|
||||
return error_code{static_cast<int>(ev),
|
||||
detail::get_error_category()};
|
||||
return error_code{
|
||||
static_cast<std::underlying_type<error>::type>(ev),
|
||||
detail::get_error_category()};
|
||||
}
|
||||
|
||||
/** A countdown to simulated failure.
|
||||
|
||||
On the Nth operation, the class will fail with the specified
|
||||
error code, or the default error code of @ref fail_error.
|
||||
error code, or the default error code of @ref error::fail_error.
|
||||
*/
|
||||
class fail_counter
|
||||
{
|
||||
@@ -100,7 +101,7 @@ public:
|
||||
*/
|
||||
explicit
|
||||
fail_counter(std::size_t n,
|
||||
error_code ev = make_error_code(fail_error))
|
||||
error_code ev = make_error_code(error::fail_error))
|
||||
: n_(n)
|
||||
, ec_(ev)
|
||||
{
|
||||
|
||||
@@ -161,19 +161,21 @@ public:
|
||||
|
||||
friend
|
||||
void
|
||||
teardown(fail_stream<NextLayer>& stream,
|
||||
boost::system::error_code& ec)
|
||||
teardown(websocket::teardown_tag,
|
||||
fail_stream<NextLayer>& stream,
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
if(stream.pfc_->fail(ec))
|
||||
return;
|
||||
websocket_helpers::call_teardown(stream.next_layer(), ec);
|
||||
beast::websocket_helpers::call_teardown(stream.next_layer(), ec);
|
||||
}
|
||||
|
||||
template<class TeardownHandler>
|
||||
friend
|
||||
void
|
||||
async_teardown(fail_stream<NextLayer>& stream,
|
||||
TeardownHandler&& handler)
|
||||
async_teardown(websocket::teardown_tag,
|
||||
fail_stream<NextLayer>& stream,
|
||||
TeardownHandler&& handler)
|
||||
{
|
||||
error_code ec;
|
||||
if(stream.pfc_->fail(ec))
|
||||
@@ -182,7 +184,7 @@ public:
|
||||
bind_handler(std::move(handler), ec));
|
||||
return;
|
||||
}
|
||||
websocket_helpers::call_async_teardown(
|
||||
beast::websocket_helpers::call_async_teardown(
|
||||
stream.next_layer(), std::forward<TeardownHandler>(handler));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef 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/error.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
|
||||