diff --git a/CMakeLists.txt b/CMakeLists.txt index 0182195e..bc48b8bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,9 +46,6 @@ include_directories (${Boost_INCLUDE_DIR}) find_package (Qt5 REQUIRED COMPONENTS Core Gui Widgets Test ${PLATFORM_QT_PACKAGES}) include_directories (${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Test_INCLUDE_DIRS}) -find_package (cppnetlib) -include_directories (${CPPNETLIB_INCLUDE_DIRS}) - include_directories (${OPENCL_INCLUDE_DIRS}) add_library (ed25519 @@ -72,6 +69,9 @@ endif () add_subdirectory (gtest) include_directories ("gtest/include") +add_subdirectory (cpp-netlib) +include_directories ("cpp-netlib") + add_library (cryptopp cryptopp/3way.cpp cryptopp/adler32.cpp @@ -344,19 +344,19 @@ else (WIN32) set (PLATFORM_WALLET_LIBS) endif (WIN32) -target_link_libraries (core_test node secure lmdb xxhash ed25519 argon2 blake2 cryptopp gtest_main gtest ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_THREAD_LIBRARY} ${CPPNETLIB_LIBRARIES} ${PLATFORM_LIBS}) +target_link_libraries (core_test node secure lmdb xxhash ed25519 argon2 blake2 cryptopp gtest_main gtest cppnetlib-uri cppnetlib-server-parsers cppnetlib-client-connections ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_THREAD_LIBRARY} ${PLATFORM_LIBS}) -target_link_libraries (slow_test node secure lmdb xxhash ed25519 argon2 blake2 cryptopp gtest_main gtest ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_THREAD_LIBRARY} ${CPPNETLIB_LIBRARIES} ${PLATFORM_LIBS}) +target_link_libraries (slow_test node secure lmdb xxhash ed25519 argon2 blake2 cryptopp gtest_main gtest cppnetlib-uri cppnetlib-server-parsers cppnetlib-client-connections ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_THREAD_LIBRARY} ${PLATFORM_LIBS}) -target_link_libraries (rai_node node secure lmdb xxhash ed25519 argon2 blake2 cryptopp ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_THREAD_LIBRARY} ${CPPNETLIB_LIBRARIES} ${PLATFORM_LIBS}) +target_link_libraries (rai_node node secure lmdb xxhash ed25519 argon2 blake2 cryptopp cppnetlib-uri cppnetlib-server-parsers cppnetlib-client-connections ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_THREAD_LIBRARY} ${PLATFORM_LIBS}) -target_link_libraries (rai_landing node secure lmdb xxhash ed25519 argon2 blake2 cryptopp ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_THREAD_LIBRARY} ${CPPNETLIB_LIBRARIES} ${PLATFORM_LIBS}) +target_link_libraries (rai_landing node secure lmdb xxhash ed25519 argon2 blake2 cryptopp cppnetlib-uri cppnetlib-server-parsers cppnetlib-client-connections ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_THREAD_LIBRARY} ${PLATFORM_LIBS}) -target_link_libraries (qt_test node secure lmdb xxhash ed25519 qt argon2 blake2 cryptopp gtest ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_THREAD_LIBRARY} ${CPPNETLIB_LIBRARIES} Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Test ${QT_QTGUI_LIBRARY} ${PLATFORM_LIBS}) +target_link_libraries (qt_test node secure lmdb xxhash ed25519 qt argon2 blake2 cryptopp gtest cppnetlib-uri cppnetlib-server-parsers cppnetlib-client-connections ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_THREAD_LIBRARY} Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Test ${QT_QTGUI_LIBRARY} ${PLATFORM_LIBS}) -target_link_libraries (rai_wallet node secure lmdb xxhash ed25519 qt argon2 blake2 cryptopp ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_THREAD_LIBRARY} ${CPPNETLIB_LIBRARIES} Qt5::Core Qt5::Gui Qt5::Widgets ${QT_QTGUI_LIBRARY} ${PLATFORM_LIBS} ${PLATFORM_WALLET_LIBS}) +target_link_libraries (rai_wallet node secure lmdb xxhash ed25519 qt argon2 blake2 cryptopp cppnetlib-uri cppnetlib-server-parsers cppnetlib-client-connections ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_THREAD_LIBRARY} Qt5::Core Qt5::Gui Qt5::Widgets ${QT_QTGUI_LIBRARY} ${PLATFORM_LIBS} ${PLATFORM_WALLET_LIBS}) -target_link_libraries (qt_system node secure lmdb xxhash ed25519 qt argon2 blake2 cryptopp gtest ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_THREAD_LIBRARY} ${CPPNETLIB_LIBRARIES} Qt5::Core Qt5::Gui Qt5::Widgets ${QT_QTGUI_LIBRARY} ${PLATFORM_LIBS}) +target_link_libraries (qt_system node secure lmdb xxhash ed25519 qt argon2 blake2 cryptopp gtest cppnetlib-uri cppnetlib-server-parsers cppnetlib-client-connections ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_LOG_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LOG_SETUP_LIBRARY} ${Boost_THREAD_LIBRARY} Qt5::Core Qt5::Gui Qt5::Widgets ${QT_QTGUI_LIBRARY} ${PLATFORM_LIBS}) set (CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE) if (APPLE) diff --git a/cpp-netlib/.clang-format b/cpp-netlib/.clang-format new file mode 100644 index 00000000..c82fea5e --- /dev/null +++ b/cpp-netlib/.clang-format @@ -0,0 +1,38 @@ +BasedOnStyle: Google +AccessModifierOffset: -1 +ConstructorInitializerIndentWidth: 4 +AlignEscapedNewlinesLeft: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakTemplateDeclarations: true +AlwaysBreakBeforeMultilineStrings: true +BreakBeforeBinaryOperators: false +BreakConstructorInitializersBeforeComma: false +BinPackParameters: true +ColumnLimit: 80 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +DerivePointerBinding: true +ExperimentalAutoDetectBinPacking: false +IndentCaseLabels: true +MaxEmptyLinesToKeep: 1 +ObjCSpaceBeforeProtocolList: false +PenaltyBreakComment: 60 +PenaltyBreakString: 1000 +PenaltyBreakFirstLessLess: 120 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerBindsToType: true +SpacesBeforeTrailingComments: 2 +Cpp11BracedListStyle: true +Standard: Auto +IndentWidth: 2 +TabWidth: 4 +UseTab: false +BreakBeforeBraces: Attach +IndentFunctionDeclarationAfterType: true +SpacesInParentheses: false +SpaceInEmptyParentheses: false +SpacesInCStyleCastParentheses: false +SpaceAfterControlStatementKeyword: true diff --git a/cpp-netlib/.gitignore b/cpp-netlib/.gitignore new file mode 100644 index 00000000..f8f6375a --- /dev/null +++ b/cpp-netlib/.gitignore @@ -0,0 +1,11 @@ +*.cmake +*.swp +*.pyc +CMakeCache.txt +CMakeFiles +Makefile +Testing +*.gch +libs/mime/test/mime-roundtrip +*.a +_build diff --git a/cpp-netlib/.travis.yml b/cpp-netlib/.travis.yml new file mode 100644 index 00000000..3a6796d0 --- /dev/null +++ b/cpp-netlib/.travis.yml @@ -0,0 +1,55 @@ +language: + - cpp + +compiler: + - gcc + - clang + +env: + - BOOST_VER=1.54.0 BUILD_SHARED_LIBS="ON" CMAKE_BUILD_TYPE="Release" ENABLE_HTTPS="ON" + - BOOST_VER=1.54.0 BUILD_SHARED_LIBS="OFF" CMAKE_BUILD_TYPE="Release" ENABLE_HTTPS="ON" + - BOOST_VER=1.54.0 BUILD_SHARED_LIBS="ON" CMAKE_BUILD_TYPE="Debug" ENABLE_HTTPS="ON" + - BOOST_VER=1.54.0 BUILD_SHARED_LIBS="OFF" CMAKE_BUILD_TYPE="Debug" ENABLE_HTTPS="ON" + - BOOST_VER=1.55.0 BUILD_SHARED_LIBS="ON" CMAKE_BUILD_TYPE="Release" ENABLE_HTTPS="ON" + - BOOST_VER=1.55.0 BUILD_SHARED_LIBS="OFF" CMAKE_BUILD_TYPE="Release" ENABLE_HTTPS="ON" + - BOOST_VER=1.55.0 BUILD_SHARED_LIBS="ON" CMAKE_BUILD_TYPE="Debug" ENABLE_HTTPS="ON" + - BOOST_VER=1.55.0 BUILD_SHARED_LIBS="OFF" CMAKE_BUILD_TYPE="Debug" ENABLE_HTTPS="ON" + - BOOST_VER=1.54.0 BUILD_SHARED_LIBS="ON" CMAKE_BUILD_TYPE="Release" ENABLE_HTTPS="OFF" + - BOOST_VER=1.54.0 BUILD_SHARED_LIBS="OFF" CMAKE_BUILD_TYPE="Release" ENABLE_HTTPS="OFF" + - BOOST_VER=1.54.0 BUILD_SHARED_LIBS="ON" CMAKE_BUILD_TYPE="Debug" ENABLE_HTTPS="OFF" + - BOOST_VER=1.54.0 BUILD_SHARED_LIBS="OFF" CMAKE_BUILD_TYPE="Debug" ENABLE_HTTPS="OFF" + - BOOST_VER=1.55.0 BUILD_SHARED_LIBS="ON" CMAKE_BUILD_TYPE="Release" ENABLE_HTTPS="OFF" + - BOOST_VER=1.55.0 BUILD_SHARED_LIBS="OFF" CMAKE_BUILD_TYPE="Release" ENABLE_HTTPS="OFF" + - BOOST_VER=1.55.0 BUILD_SHARED_LIBS="ON" CMAKE_BUILD_TYPE="Debug" ENABLE_HTTPS="OFF" + - BOOST_VER=1.55.0 BUILD_SHARED_LIBS="OFF" CMAKE_BUILD_TYPE="Debug" ENABLE_HTTPS="OFF" + +before_install: + - if [ "${CXX}" == "g++" ] || [ ${BUILD_SHARED_LIBS} = "OFF" ]; then + sudo add-apt-repository ppa:boost-latest/ppa --yes; + sudo apt-get update; + fi + - if [ "${CXX}" == "clang++" ] && [ ${BUILD_SHARED_LIBS} = "ON" ]; then + svn export http://svn.boost.org/svn/boost/tags/release/Boost_${BOOST_VER//./_} ../boost_${BOOST_VER//./_}; + export BOOST_ROOT=$TRAVIS_BUILD_DIR/../boost_${BOOST_VER//./_}; + fi + +install: + - if [ "${CXX}" == "g++" ] || [ ${BUILD_SHARED_LIBS} = "OFF" ]; then + sudo apt-get install libboost${BOOST_VER/%.0/}-all-dev; + fi + - if [ "${CXX}" == "clang++" ] && [ ${BUILD_SHARED_LIBS} = "ON" ]; then + cd $BOOST_ROOT; + ./bootstrap.sh --with-toolset=$CC; + ./b2 -j4 --stagedir=.; + cd -; + fi + +script: + - cmake -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} + -DCPP-NETLIB_ENABLE_HTTPS=${ENABLE_HTTPS} + - make + - make test + +after_failure: + - cat Testing/Temporary/LastTest.log diff --git a/cpp-netlib/.ycm_extra_conf.py b/cpp-netlib/.ycm_extra_conf.py new file mode 100644 index 00000000..85cf36ad --- /dev/null +++ b/cpp-netlib/.ycm_extra_conf.py @@ -0,0 +1,72 @@ +# Copyright 2013 Google, Inc. +# Copyright 2013 Dean Michael Berris +# 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) +# +# Project-wide configuration for YouCompleteMe Vim plugin. +# +# Based off of Valloric's .ycm_conf_extra.py for YouCompleteMe: +# https://github.com/Valloric/YouCompleteMe/blob/master/cpp/ycm/.ycm_extra_conf.py +# + +import os +import ycm_core + +flags = [ + '-Wall', + '-Wextra', + '-Werror', + '-std=c++03', + '-isystem', + '.', + '-isystem', + '/usr/include', + '-isystem', + '/usr/include/c++/4.6', + '-isystem', + '/usr/include/clang/3.0/include', + '-isystem', + '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/c++/v1', + '-I', + os.environ['BOOST_ROOT'], + # Always enable debugging for the project when building for semantic + # completion. + '-DBOOST_NETWORK_DEBUG', + ] + +def DirectoryOfThisScript(): + return os.path.dirname(os.path.abspath(__file__)) + + +def MakeRelativePathsInFlagsAbsolute(flags, working_directory): + if not working_directory: + return list(flags) + new_flags = [] + make_next_absolute = False + path_flags = ['-isystem', '-I', '-iquote', '--sysroot='] + for flag in flags: + new_flag = flag + if make_next_absolute: + make_next_absolute = False + if not flag.startswith('/'): + new_flag = os.path.join(working_directory, flag) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + if flag.startswith(path_flag): + path = flag[len(path_flag):] + new_flag = path_flag + os.path.join(working_directory, path) + break + + if new_flag: + new_flags.append(new_flag) + return new_flags + + +def FlagsForFile(filename): + relative_to = DirectoryOfThisScript() + final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to) + return {'flags': final_flags, 'do_cache': True } diff --git a/cpp-netlib/CMakeLists.txt b/cpp-netlib/CMakeLists.txt new file mode 100644 index 00000000..aa0792d4 --- /dev/null +++ b/cpp-netlib/CMakeLists.txt @@ -0,0 +1,150 @@ +# Copyright (c) Dean Michael Berris 2010. +# 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) + +cmake_minimum_required(VERSION 2.8) +project(CPP-NETLIB) + +option( CPP-NETLIB_BUILD_SHARED_LIBS "Build cpp-netlib as shared libraries." OFF ) +option( CPP-NETLIB_BUILD_TESTS "Build the cpp-netlib project tests." OFF) +option( CPP-NETLIB_BUILD_EXPERIMENTS "Build the cpp-netlib project experiments." OFF) +option( CPP-NETLIB_BUILD_EXAMPLES "Build the cpp-netlib project examples." OFF) +option( CPP-NETLIB_ENABLE_HTTPS "Build cpp-netlib with support for https if OpenSSL is found." OFF) + +include(GNUInstallDirs) + +# determine install path for CMake config files +if(WIN32 AND NOT CYGWIN) + set(DEF_INSTALL_CMAKE_DIR CMake) +else() + set(DEF_INSTALL_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/cppnetlib) +endif() +set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") + +# Make relative cmake install path absolute (needed later on) +if(NOT IS_ABSOLUTE "${INSTALL_CMAKE_DIR}") + set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}") +endif() + + +if(CPP-NETLIB_BUILD_SHARED_LIBS OR BUILD_SHARED_LIBS) + message (STATUS "Linking boost testing libs dynamically...") + set(Boost_USE_STATIC_LIBS OFF) + set(CPP-NETLIB_BUILD_SHARED_LIBS ON) + set(BUILD_SHARED_LIBS ON) + add_definitions(-DBOOST_TEST_DYN_LINK) +else() + set(Boost_USE_STATIC_LIBS ON) + set(CPP-NETLIB_BUILD_SHARED_LIBS OFF) + set(BUILD_SHARED_LIBS OFF) +endif() + +set(Boost_USE_MULTI_THREADED ON) +find_package( Boost 1.54.0 + REQUIRED unit_test_framework system regex date_time thread filesystem + program_options chrono atomic ) + +if (CPP-NETLIB_ENABLE_HTTPS) + find_package( OpenSSL ) +endif() + +find_package( Threads ) +set(CMAKE_VERBOSE_MAKEFILE true) + +set(CPPNETLIB_VERSION_MAJOR 0) # MUST bump this whenever we make ABI-incompatible changes +set(CPPNETLIB_VERSION_MINOR 11) +set(CPPNETLIB_VERSION_PATCH 1) +set(CPPNETLIB_VERSION_STRING ${CPPNETLIB_VERSION_MAJOR}.${CPPNETLIB_VERSION_MINOR}.${CPPNETLIB_VERSION_PATCH}) + +if (CMAKE_BUILD_TYPE MATCHES Debug) + add_definitions(-DBOOST_NETWORK_DEBUG) +endif() + +if (OPENSSL_FOUND) + add_definitions(-DBOOST_NETWORK_ENABLE_HTTPS) + include_directories(${OPENSSL_INCLUDE_DIR}) +endif() + +if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +elseif (${CMAKE_CXX_COMPILER_ID} MATCHES Clang) + if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # We want to link in C++11 mode if we're using Clang and on OS X. + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -ftemplate-depth=256 -std=c++11 -stdlib=libc++") + else() + # We just add the -Wall and a high enough template depth + # flag for Clang in other systems. + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -ftemplate-depth=256") + endif() +endif() + + +if (Boost_FOUND) + if (MSVC) + add_definitions(-D_SCL_SECURE_NO_WARNINGS) + endif(MSVC) + if (WIN32) + add_definitions(-D_WIN32_WINNT=0x0501) + endif(WIN32) + include_directories(${Boost_INCLUDE_DIRS}) + enable_testing() + add_subdirectory(libs/network/src) + if (CPP-NETLIB_BUILD_TESTS) + add_subdirectory(libs/network/test) + endif (CPP-NETLIB_BUILD_TESTS) + if (CPP-NETLIB_BUILD_EXPERIMENTS) + add_subdirectory(libs/network/experiment) + endif (CPP-NETLIB_BUILD_EXPERIMENTS) + if (NOT MSVC AND CPP-NETLIB_BUILD_TESTS) + add_subdirectory(libs/mime/test) + endif(NOT MSVC AND CPP-NETLIB_BUILD_TESTS) + if (CPP-NETLIB_BUILD_EXAMPLES) + add_subdirectory(libs/network/example) + endif (CPP-NETLIB_BUILD_EXAMPLES) +endif(Boost_FOUND) + +if (MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") +endif() + +enable_testing() + +install(DIRECTORY boost DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +### +## Export Targets +# (so cpp-netlib can be easily used by other CMake projects) +# [see http://www.cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file] + +# Add all targets to the build-tree export set +export(TARGETS cppnetlib-client-connections cppnetlib-server-parsers cppnetlib-uri + FILE "${PROJECT_BINARY_DIR}/cppnetlibTargets.cmake") +# Export the package for use from the build-tree +# (this registers the build-tree with a global CMake-registry) +export(PACKAGE cppnetlib) +# Create the cppnetlibConfig.cmake and cppnetlibConfigVersion files +file(RELATIVE_PATH REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" + "${CMAKE_INSTALL_FULL_INCLUDEDIR}") +# ... for the build tree +set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}" ${Boost_INCLUDE_DIRS}) +configure_file(cppnetlibConfig.cmake.in + "${PROJECT_BINARY_DIR}/cppnetlibConfig.cmake" @ONLY) +# ... for the install tree +set(CONF_INCLUDE_DIRS "\${CPPNETLIB_CMAKE_DIR}/${REL_INCLUDE_DIR}") +set(CONF_INCLUDE_DIRS ${CONF_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) +configure_file(cppnetlibConfig.cmake.in + "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cppnetlibConfig.cmake" @ONLY) +# ... for both +configure_file(cppnetlibConfigVersion.cmake.in + "${PROJECT_BINARY_DIR}/cppnetlibConfigVersion.cmake" @ONLY) +# Install the cppnetlibConfig.cmake and cppnetlibConfigVersion.cmake +install(FILES + "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cppnetlibConfig.cmake" + "${PROJECT_BINARY_DIR}/cppnetlibConfigVersion.cmake" + DESTINATION "${INSTALL_CMAKE_DIR}" + COMPONENT dev) +# Install the export set for use with the install-tree +install(EXPORT cppnetlibTargets + DESTINATION "${INSTALL_CMAKE_DIR}" + COMPONENT dev) diff --git a/cpp-netlib/LICENSE_1_0.txt b/cpp-netlib/LICENSE_1_0.txt new file mode 100644 index 00000000..36b7cd93 --- /dev/null +++ b/cpp-netlib/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/cpp-netlib/RATIONALE.txt b/cpp-netlib/RATIONALE.txt new file mode 100644 index 00000000..c9e8960f --- /dev/null +++ b/cpp-netlib/RATIONALE.txt @@ -0,0 +1,64 @@ +C++ Networking Library +Goals and Scope + + +Objectives +---------- + + o Develop a high quality, portable, easy to use C++ networking library + + o Enable users to easily extend the library + + o Lower the barrier to entry for cross-platform network-aware C++ + applications + + +Goals +----- + + * Implement a simple message implementation which can be used in + network protocol-specific routines for inter-operability and + to provide a generic interface to manipulating network-oriented + messages. + + * Implement easy to use protocol client libraries such as (but not + limited to): + + - HTTP 1.0/1.1 + - (E)SMTP + - SNMP + - ICMP + + * Implement an easy to embed HTTP server container type that supports + most modern HTTP 1.1 features. + + * Implement an efficient easy to use URI class/parser. + + * Implement a fully compliant cross-platform asynchronous DNS resolver + either as a wrapper to external (C) libraries, or as hand-rolled + implementation. + + * Implement a MIME handler which builds message objects from either + data retrieved from the network or other sources and create + text/binary representations from existing message objects intended + for transport over the network. + + +Scope +----- + + * The library will provide a generic message class which is intended + to be the common message type used by the protocol libraries. + + * The library will only contain client implementations for the various + supported protocols. + + * The library will use only STL and Boost C++ library components, + utilities, and libraries throughout the implementation. + + * The library will strive to use C++ templates and template + metaprogramming techniques in order to not require the building of + external shared/static libraries. In other words, the library will be + header-only and compliant with the C++ standard. + + diff --git a/cpp-netlib/README.rst b/cpp-netlib/README.rst new file mode 100644 index 00000000..b0f21976 --- /dev/null +++ b/cpp-netlib/README.rst @@ -0,0 +1,160 @@ +C++ Network Library +=================== + +Introduction +------------ + +cpp-netlib is a collection of network related routines/implementations +geared towards providing a robust cross-platform networking library. +cpp-netlib offers the following implementations: + + * Common Message Type -- A generic message type which can be used + to encapsulate and store message related information, used by all + network implementations as the primary means of data exchange. + * Network protocol message parsers -- A collection of parsers which + generate message objects from strings. + * Adapters and Wrappers -- A collection of Adapters and wrappers aimed + towards making the message type STL friendly. + * Network protocol client and server implementations -- A collection + of network protocol implementations that include embeddable client + and server types. + +This library is released under the Boost Software License (please see +http://boost.org/LICENSE_1_0.txt or the accompanying LICENSE_1_0.txt file +for the full text. + +Downloading cpp-netlib +---------------------- + +You can find official release packages of the library at:: + + http://github.com/cpp-netlib/cpp-netlib/downloads + +Building and Installing +----------------------- + +Building with CMake +~~~~~~~~~~~~~~~~~~~ + +To build the libraries and run the tests with CMake, you will need to +have CMake version 2.8 or higher installed appropriately in your +system. + +:: + + $ cmake --version + cmake version 2.8.1 + +Inside the cpp-netlib directory, you can issue the following statements to +configure and generate the Makefiles, and build the tests:: + + $ cd ~/cpp-netlib # we're assuming it's where cpp-netlib is + $ cmake -DCMAKE_BUILD_TYPE=Debug \ + > -DCMAKE_C_COMPILER=clang \ + > -DCMAKE_CXX_COMPILER=clang++ \ + > . + +Once CMake is done with generating the Makefiles and configuring the project, +you can now build the tests and run them:: + + $ cd ~/cpp-netlib + $ make + $ make test + +If for some reason some of the tests fail, you can send the files in +``Testing/Temporary/`` as attachments to the cpp-netlib `developers mailing +list`_. + +.. _`developers mailing list`: cpp-netlib@googlegroups.com + +Building with Boost.Build +~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you don't already have Boost.Build set up on your system, follow the steps +indicated in the Boost Getting Started Guide [#]_ -- you will particularly want +to copy the ``bjam`` executable to a directory that is already in your ``PATH`` +so that you don't have to go hunting for it all the time. A good place to put it +is in ``/usr/local/bin``. + +.. [#] http://www.boost.org/doc/libs/release/more/getting_started/ + +Building and running the tests can be as simple as doing the following:: + + $ cd ~/cpp-netlib + $ bjam + +Doing this will already build all the tests and run them as they are built. In +case you encounter any problems and would like to report it to the developers, +please do the following:: + + $ cd ~/cpp-netlib + $ bjam 2>&1 >build-test.log + +And then attach the ``build-test.log`` file to the email you will send to the +cpp-netlib `developers mailing list`_. + +.. _`developers mailing list`: cpp-netlib@googlegroups.com + +Running Tests +------------- + +If you want to run the tests that come with cpp-netlib, there are a few things +you will need. These are: + + * A compiler (GCC 4.x, Clang 2.8, MSVC 2008) + * A build tool (CMake [#]_ recommended, Boost.Build also an option) + * OpenSSL headers (optional) + +.. note:: This assumes that you have cpp-netlib at the top-level of + your home directory. + [#] http://www.cmake.org/ + +Hacking on cpp-netlib +--------------------- + +cpp-netlib is being developed with the git_ distributed SCM system. +cpp-netlib is hosted on GitHub_ following the GitHub recommended practice of +forking the repository and submitting pull requests to the source repository. +You can read more about the forking_ process and submitting `pull requests`_ if +you're not familiar with either process yet. + +.. _git: http://git-scm.com/ +.. _GitHub: http://github.com/ +.. _forking: http://help.github.com/forking/ +.. _`pull requests`: http://help.github.com/pull-requests/ + +Because cpp-netlib is released under the `Boost Software License`_ it is +recommended that any file you make changes to bear your copyright notice +alongside the original authors' copyright notices on the file. Typically the +copyright notices are at the top of each file in the project. + +.. _`Boost Software License`: http://www.boost.org/LICENSE_1_0.txt + +At the time of writing, there are no coding conventions being followed but if +you write in the general style that is already existing in the project that +would be greatly appreciated. Copious amounts of comments will be called out, +but code that is not self-explanatory typically at least requires a rationale +documentation in comments explaining "why" the code is written that way. + +The main "upstream" repository is the one hosted by the original maintainer of +the project (Dean Michael Berris) at http://github.com/mikhailberis/cpp-netlib. +The "official" release repository is maintained at +http://github.com/cpp-netlib/cpp-netlib -- which is a fork of the upstream +repository. It is recommended that forks be made against the upstream repostory +and pull requests be submitted against the upstream repository so that patches +and other implementations can be curated by the original maintainer. + +Contact and Support +------------------- + +In case you have any questions or would like to make feature requests, you can +contact the development team through the `developers mailing list`_ +or by filing issues at http://github.com/cpp-netlib/cpp-netlib/issues. + +.. _`developers mailing list`: cpp-netlib@googlegroups.com + +You can reach the maintainers of the project through:: + + Dean Michael Berris (dberris@google.com) + + Glyn Matthews (glyn.matthews@gmail.com) diff --git a/cpp-netlib/boost/mime.hpp b/cpp-netlib/boost/mime.hpp new file mode 100644 index 00000000..e45d59c1 --- /dev/null +++ b/cpp-netlib/boost/mime.hpp @@ -0,0 +1,832 @@ +// +// Copyright Marshall Clow 2009-2010 +// 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 _BOOST_MIME_HPP +#define _BOOST_MIME_HPP + +#include +#include +#include +#include + +#include +#include +#include // pulls in all of Phoenix +#include +#include + +#include +#include +#include +#include + +// #define DUMP_MIME_DATA 1 + +namespace boost { +namespace mime { + +// Errors are reported using this exception class +class mime_parsing_error : public std::runtime_error { + public: + explicit mime_parsing_error(const std::string &msg) + : std::runtime_error(msg) {} +}; + +template +class basic_mime; + +namespace detail { + +static const char *k_crlf = "\015\012"; +static const char *k_package_name = "Proposed.Boost.Mime"; +static const char *k_package_version = "0.1"; +static const char *k_content_type_header = "Content-Type"; +static const char *k_mime_version_header = "Mime-Version"; + +struct default_types { + typedef std::string string_type; + // typedef std::pair < std::string, string_type > header_type; + typedef std::vector body_type; +}; + +template +struct find_mime_header { + find_mime_header(const char *str) : searchFor(str) {} + bool operator()(const std::pair &val) const { + return boost::iequals(val.first, searchFor); + } + + private: + const char *searchFor; +}; + +#ifdef DUMP_MIME_DATA +struct tracer { + tracer(const char *fn) : fn_(fn) { std::cout << "->" << fn_ << std::endl; } + ~tracer() { std::cout << "<-" << fn_ << std::endl; } + const char *fn_; +}; +#else +struct tracer { + tracer(const char *) {} + ~tracer() {} +}; +#endif + +// Parsing a Content-Type header +typedef std::pair phrase_t; +typedef std::vector phrase_container_t; +struct mime_content_type { + std::string type; + std::string sub_type; + phrase_container_t phrases; +}; + +namespace qi = boost::spirit::qi; +namespace phx = boost::phoenix; +using boost::spirit::_val; +using boost::spirit::_1; + +template +struct mime_header_parser : qi::grammar { + mime_header_parser() : mime_header_parser::base_type(mime_headerList) { + mime_headerList = *(mime_header) >> crlf; + mime_header = token >> qi::lit(':') >> value >> crlf; + token = qi::char_("a-zA-Z") >> *qi::char_("a-zA-Z_0-9\\-"); + + // In Classifieds/000001, a header begins with a CRLF + value = (valuePart[_val = _1] | qi::eps) >> + *(valueCont[_val += "\015\012" + _1]); + valueCont = crlf >> contWS[_val += _1] >> valuePart[_val += _1]; + valuePart = +qi::char_("\t -~"); + + contWS = +qi::char_(" \t"); + crlf = qi::lit(k_crlf); + + /* mime_headerList.name("mime-header-list"); + mime_header.name ("mime-header"); + token.name ("mime-token"); + valuePart.name ("mime-value-part"); + value.name ("mime-value"); + + qi::on_error ( mime_headerList, + std::cout + << phoenix::val("Error! Expecting ") + << qi::labels::_4 + << phoenix::val(" here: \"") + << phoenix::construct(qi::labels::_3, + qi::labels::_2) + << phoenix::val("\"") + << std::endl + ); + */ + } + + qi::rule mime_headerList; + qi::rule mime_header; + qi::rule token, value, valueCont, valuePart, contWS; + qi::rule crlf; +}; + +template +static Container read_headers(Iterator &begin, Iterator end) { + tracer t(__func__); + Container retVal; + + mime_header_parser mh_parser; + bool b = qi::parse(begin, end, mh_parser, retVal); + if (!b) throw mime_parsing_error("Failed to parse headers"); + +#ifdef DUMP_MIME_DATA + std::cout << "******Headers*******" << std::endl; + for (typename Container::const_iterator iter = retVal.begin(); + iter != retVal.end(); ++iter) { + std::string val = iter->second; + size_t idx; + while (std::string::npos != (idx = val.find(k_crlf))) + val.replace(idx, std::strlen(k_crlf), "\n"); + std::cout << iter->first << ": " << val << std::endl; + } + std::cout << std::endl << "******Headers*******" << std::endl; +#endif + + return retVal; +} + +// The structure of a Content-Type mime header is taken from RFC 2045 +// http://www.ietf.org/rfc/rfc2045.txt, section 5.1 + +template +struct mime_content_type_parser : qi::grammar { + mime_content_type_parser() + : mime_content_type_parser::base_type(content_type_header) { + content_type_header = *qi::lit(' ') >> part >> '/' >> sub_part >> *phrase; + + part = token | extension_token; + sub_part = token | extension_token; + + phrase = qi::lit(';') >> +ws >> attribute >> '=' >> value >> *ws; + ws = qi::char_(" \t") | line_sep | comment; + line_sep = qi::lexeme[qi::lit(k_crlf)]; + + attribute = token.alias(); + value = token | quoted_string; + + token = +(qi::char_(" -~") - qi::char_(" ()<>@,;:\\\"/[]?=")); + comment = qi::lit('(') >> +(qi::char_(" -~") - ')') >> qi::lit(')'); + quoted_string = qi::lit('"') >> +(qi::char_(" -~") - '"') >> qi::lit('"'); + extension_token = qi::char_("Xx") >> qi::lit('-') >> token; + } + + qi::rule content_type_header; + qi::rule phrase; + qi::rule part, sub_part, token, attribute, value, + quoted_string, extension_token; + qi::rule ws, line_sep, comment; +}; + +template +mime_content_type parse_content_type(const string_type &theHeader) { + tracer t(__func__); + mime_content_type retVal; + typename string_type::const_iterator first = theHeader.begin(); + mime_content_type_parser ct_parser; + bool b = qi::parse(first, theHeader.end(), ct_parser, retVal); + if (!b) throw mime_parsing_error("Failed to parse the 'Content-Type' header"); + + return retVal; +} + +template +static string_type get_ct_value(const string_type &ctString, const char *key) { + tracer t(__func__); + mime_content_type mc = parse_content_type(ctString); + for (phrase_container_t::const_iterator iter = mc.phrases.begin(); + iter != mc.phrases.end(); ++iter) + if (boost::iequals(iter->first, key)) return iter->second; + + throw std::runtime_error( + str(boost::format("Couldn't find Content-Type phrase (%s)") % key)); +} + +// Replace this with a spirit thing later. +// we're looking for '; boundary="".*' +std::string get_boundary(const std::string &ctString) { + tracer t(__func__); + return get_ct_value(ctString, "boundary"); +} + +// Read the body of a multipart +// Return a Container of containers, where the first is the actual +// body, +// and the rest are the sub-parts. +// Note that the body of the multipart can be empty. +// If this is the case, then the first separator need not have a crlf + +// if the marker is "abcde", we could have: +// Note that the separators are really CRLF--abcdeCRLF and +// CRLF--abcde--CRLF +// +// multipart body +// --abcde +// sub part #1 +// --abcde +// sub part #2 +// --abcde-- +// +// ** or ** +// In this case, the first separator is --abcdeCRLF +// +// --abcde (no multipart body!) +// sub part #1 +// --abcde +// sub part #2 +// --abcde-- + +typedef std::vector sub_part_t; +typedef std::vector sub_parts_t; + +template +struct multipart_body_type { + bool prolog_is_missing; + bodyContainer body_prolog; + sub_parts_t sub_parts; + bodyContainer body_epilog; +}; + +// Parse a mulitpart body. +// Either "--boundaryCRLF" -- in which case the body is empty +// or "CRLF--boundaryCRLF" -- in which +// case we return the sequence +// +// I am deliberately not checking for a termination separator here +template +struct multipart_body_parser : qi::grammar { + multipart_body_parser(const std::string &boundary, bool &isMissing) + : multipart_body_parser::base_type(mimeBody), m_is_missing(isMissing) { + m_is_missing = false; + // Thanks to Michael Caisse for the hint to get this working + mimeBody %= + bareSep[phx::ref(m_is_missing) = true] | (+(qi::char_ - sep) >> sep); + bareSep = qi::lit("--") >> boundary >> crlf; + sep = crlf >> bareSep; + crlf = qi::lit(k_crlf); + } + + bool &m_is_missing; + qi::rule mimeBody; + qi::rule bareSep, sep, crlf; +}; + +// Break up a multi-part into its' constituent sub parts. +template +struct multipart_part_parser : qi::grammar { + multipart_part_parser(const std::string &boundary) + : multipart_part_parser::base_type(mimeParts) { + mimeParts = (+(qi::char_ - sep) % (sep >> crlf)) > terminator; + sep = crlf >> qi::lit("--") >> boundary; + terminator = sep >> qi::lit("--") >> crlf; + crlf = qi::lit(k_crlf); + } + qi::rule mimeParts; + qi::rule sep, terminator, crlf; +}; + +template +static void read_multipart_body(Iterator &begin, Iterator end, + multipart_body_type &mp_body, + const std::string &separator) { + tracer t(__func__); + typedef bodyContainer innerC; + innerC mpBody; + multipart_body_parser mb_parser(separator, + mp_body.prolog_is_missing); + if (!qi::parse(begin, end, mb_parser, mp_body.body_prolog)) + throw mime_parsing_error("Failed to parse mime body(1)"); + + multipart_part_parser mp_parser(separator); + if (!qi::parse(begin, end, mp_parser, mp_body.sub_parts)) + throw mime_parsing_error("Failed to parse mime body(2)"); + std::copy(begin, end, std::back_inserter(mp_body.body_epilog)); + +#ifdef DUMP_MIME_DATA + std::cout << std::endl << ">>****Multipart Body*******" << std::endl; + std::cout << str(boost::format( + "Body size %d, sub part count = %d, trailer size " + "= %d %s") % + mp_body.body_prolog.size() % mp_body.sub_parts.size() % + mp_body.body_epilog.size() % + (mp_body.prolog_is_missing ? "(missing)" : "")) << std::endl; + std::cout << std::endl << "****** Multipart Body Prolog *******" << std::endl; + std::copy(mp_body.body_prolog.begin(), mp_body.body_prolog.end(), + std::ostream_iterator(std::cout)); + std::cout << std::endl << "****** Multipart Body Epilog *******" << std::endl; + std::copy(mp_body.body_epilog.begin(), mp_body.body_epilog.end(), + std::ostream_iterator(std::cout)); + std::cout << std::endl << "<<****Multipart Body*******" << std::endl; +#endif +} + +template +static Container read_simplepart_body(Iterator &begin, Iterator end) { + tracer t(__func__); + Container retVal; + std::copy(begin, end, std::back_inserter(retVal)); + +#ifdef DUMP_MIME_DATA + std::cout << std::endl << ">>****SinglePart Body*******" << std::endl; + std::cout << str(boost::format("Body size %d") % retVal.size()) << std::endl; + std::copy(retVal.begin(), retVal.end(), + std::ostream_iterator(std::cout)); + std::cout << std::endl << "<<****SinglePart Body*******" << std::endl; +#endif + return retVal; +} + +// FIXME: Need to break the headers at 80 chars... +template +void write_headers(std::ostream &out, const headerList &headers) { + if (headers.size() > 0) { + for (typename headerList::const_iterator iter = headers.begin(); + iter != headers.end(); ++iter) + out << iter->first << ':' << iter->second << detail::k_crlf; + } + out << detail::k_crlf; +} + +template +void write_body(std::ostream &out, const bodyContainer &body) { + std::copy(body.begin(), body.end(), std::ostream_iterator(out)); +} + +inline void write_boundary(std::ostream &out, std::string boundary, bool isLast, + bool leadingCR = true) { + if (leadingCR) out << detail::k_crlf; + out << "--" << boundary; + if (isLast) out << "--"; + out << detail::k_crlf; +} + +template +static boost::shared_ptr > parse_mime( + Iterator &begin, Iterator end, + const char *default_content_type = "text/plain"); +} + +template +class basic_mime { + public: + typedef enum { + simple_part, + multi_part, + message_part + } part_kind; + // Types for headers + typedef typename traits::string_type string_type; + typedef std::pair headerEntry; + typedef std::list headerList; + typedef typename headerList::iterator headerIter; + typedef typename headerList::const_iterator constHeaderIter; + + // Types for the parts + typedef boost::shared_ptr mimePtr; + typedef std::vector partList; + typedef typename partList::iterator partIter; + typedef typename partList::const_iterator constPartIter; + + // Type for the body + typedef typename traits::body_type bodyContainer; + typedef boost::shared_ptr mimeBody; + + // ----------------------------------------------------------- + // Constructors, destructor, assignment, and swap + // ----------------------------------------------------------- + + basic_mime(const char *type, const char *subtype) + : m_body_prolog_is_missing(false), + m_body(new bodyContainer), + m_body_epilog(new bodyContainer) { + if (NULL == type || NULL == subtype || 0 == std::strlen(type) || + 0 == std::strlen(subtype)) + throw std::runtime_error( + "Can't create a mime part w/o a type or subtype"); + + // We start with just two headers, "Content-Type:" and "Mime-Version" + // Everything else is optional. + m_part_kind = part_kind_from_string_pair(type, subtype); + std::string ctString = str(boost::format("%s/%s") % type % subtype); + set_header_value(detail::k_content_type_header, ctString); + set_header_value(detail::k_mime_version_header, + str(boost::format("1.0 (%s %s)") % detail::k_package_name % + detail::k_package_version)); + } + + basic_mime(const headerList &theHeaders, + const string_type &default_content_type) + : m_body_prolog_is_missing(false), + m_body(new bodyContainer), + m_body_epilog(new bodyContainer), + m_default_content_type(default_content_type) { + string_type ct = m_default_content_type; + + constHeaderIter found = std::find_if( + theHeaders.begin(), theHeaders.end(), + detail::find_mime_header(detail::k_content_type_header)); + if (found != theHeaders.end()) ct = found->second; + + detail::mime_content_type mct = detail::parse_content_type(ct); + m_part_kind = part_kind_from_string_pair(mct.type, mct.sub_type); + m_headers = theHeaders; + } + + basic_mime(const basic_mime &rhs) + : m_part_kind(rhs.m_part_kind), + m_headers(rhs.m_headers), + m_body_prolog_is_missing(rhs.m_body_prolog_is_missing), + m_body(new bodyContainer(*rhs.m_body)), + m_body_epilog(new bodyContainer(*rhs.m_body_epilog)), + /* m_subparts ( rhs.m_subparts ), */ m_default_content_type( + rhs.m_default_content_type) { + // Copy the parts -- not just the shared pointers + for (typename partList::const_iterator iter = rhs.subpart_begin(); + iter != rhs.subpart_end(); ++iter) + m_subparts.push_back(mimePtr(new basic_mime(**iter))); + } + + // Simple, copy constructor-based assignment + // If this is not efficient enough, then I can optimize it later + basic_mime &operator=(const basic_mime &rhs) { + basic_mime temp(rhs); + this->swap(temp); + return *this; + } + + void swap(basic_mime &rhs) throw() { + std::swap(m_part_kind, rhs.m_part_kind); + std::swap(m_headers, rhs.m_headers); + std::swap(m_body_prolog_is_missing, rhs.m_body_prolog_is_missing); + std::swap(m_body, rhs.m_body); + std::swap(m_body_epilog, rhs.m_body_epilog); + std::swap(m_subparts, rhs.m_subparts); + std::swap(m_default_content_type, rhs.m_default_content_type); + } + + ~basic_mime() {} + + // What kind of part is this (simple, multi, message) + part_kind get_part_kind() const { return m_part_kind; } + + // Sub-part information + // FIXME: Need some error checking here + // No sub-parts for simple parts, for example. + size_t part_count() const { return m_subparts.size(); } + + boost::shared_ptr operator[](std::size_t idx) const { + check_subpart_index(idx); + return m_subparts[idx]; + } + + void append_part(boost::shared_ptr newPart) { + check_subpart_append(); + m_subparts.push_back(newPart); + } + + partIter subpart_begin() { return m_subparts.begin(); } + partIter subpart_end() { return m_subparts.end(); } + constPartIter subpart_begin() const { return m_subparts.begin(); } + constPartIter subpart_end() const { return m_subparts.end(); } + + // Reading the raw headers + headerIter header_begin() { return m_headers.begin(); } + headerIter header_end() { return m_headers.end(); } + constHeaderIter header_begin() const { return m_headers.begin(); } + constHeaderIter header_end() const { return m_headers.end(); } + + // ----------------------------------------------------------- + // Header manipulation + // ----------------------------------------------------------- + + // The 'tag' part of the header is still a std::string + bool header_exists(const char *key) const { + return header_end() != find_header(key); + } + + string_type header_value(const char *key) const { + constHeaderIter found = find_header(key); + if (found == header_end()) + throw std::runtime_error("'header_value' not found"); + return found->second; + } + + void set_header_value(const char *key, const string_type &value, + bool replace = false) { + if (!replace) + m_headers.push_back(std::make_pair(std::string(key), value)); + else { + headerIter found = find_header(key); + if (found == m_headers.end()) + throw std::runtime_error("'header_value' not found - can't replace"); + found->second = value; + } + } + + string_type get_content_type_header() const { + constHeaderIter found = find_header(detail::k_content_type_header); + return found != header_end() ? found->second : m_default_content_type; + } + + string_type get_content_type() const { + detail::mime_content_type mct = + detail::parse_content_type(get_content_type_header()); + return string_type(mct.type) + '/' + mct.sub_type; + } + + // Special purpose helper routine + void append_phrase_to_content_type(const char *key, + const string_type &value) { + headerIter found = find_header(detail::k_content_type_header); + + // Create a Content-Type header if there isn't one + if (m_headers.end() == found) { + m_headers.push_back(std::make_pair( + std::string(detail::k_content_type_header), m_default_content_type)); + found = find_header(detail::k_content_type_header); + } + + detail::mime_content_type mct = detail::parse_content_type(found->second); + detail::phrase_container_t::const_iterator p_found = + std::find_if(mct.phrases.begin(), mct.phrases.end(), + detail::find_mime_header(key)); + if (p_found != mct.phrases.end()) + throw std::runtime_error("phrase already exists"); + found->second += str(boost::format("; %s=\"%s\"") % key % value); + } + + // Body get/set methods + mimeBody body() const { return m_body; } + mimeBody body_prolog() const { return m_body; } + mimeBody body_epilog() const { return m_body_epilog; } + + std::size_t body_size() const { return m_body->size(); } + + template + void set_body(Iterator begin, Iterator end) { + bodyContainer temp; + std::copy(begin, end, std::back_inserter(temp)); + m_body->swap(temp); + } + + void set_body(const char *contents, size_t sz) { + set_body(contents, contents + sz); + } + void set_body(std::istream &in) { + set_body(std::istream_iterator(in), std::istream_iterator()); + } + void set_body(const bodyContainer &new_body) { *m_body = new_body; } + + void set_multipart_prolog_is_missing(bool isMissing) { + m_body_prolog_is_missing = isMissing; + } + void set_body_prolog(const bodyContainer &new_body_prolog) { + *m_body = new_body_prolog; + } + void set_body_epilog(const bodyContainer &new_body_epilog) { + *m_body_epilog = new_body_epilog; + } + + // ----------------------------------------------------------- + // Output + // ----------------------------------------------------------- + void stream_out(std::ostream &out) { // called by operator << + if (m_part_kind == simple_part) { + detail::write_headers(out, m_headers); + detail::write_body(out, *m_body); + } else if (m_part_kind == message_part) { + if (m_subparts.size() != 1) + throw std::runtime_error( + "message part w/wrong number of sub-parts - should be 1"); + + detail::write_headers(out, m_headers); + m_subparts[0]->stream_out(out); + } else { // multi-part + // Find or invent a boundary string + std::string boundary; + try { + boundary = detail::get_boundary(get_content_type_header()); + } + catch (std::runtime_error &) { + // FIXME: Make boundary strings (more?) unique + boundary = str(boost::format("------=_NextPart-%s.%08ld") % + detail::k_package_name % std::clock()); + append_phrase_to_content_type("boundary", boundary); + } + + // If the body prolog is missing, we don't want a CRLF on the front + // of the first sub-part. + // Note that there's a (subtle) difference between an zero length + // body and a missing one. + // See the comments in the parser code for more information. + detail::write_headers(out, m_headers); + bool writeCR = body_prolog()->size() > 0 || !m_body_prolog_is_missing; + detail::write_body(out, *body_prolog()); + for (typename partList::const_iterator iter = m_subparts.begin(); + iter != m_subparts.end(); ++iter) { + detail::write_boundary(out, boundary, false, writeCR); + (*iter)->stream_out(out); + writeCR = true; + } + detail::write_boundary(out, boundary, true); + detail::write_body(out, *body_epilog()); + } + // out << detail::k_crlf; + } + + // Build a simple mime part + template + static basic_mime make_simple_part(const char *type, const char *subtype, + Iterator begin, Iterator end) { + basic_mime retval(type, subtype); + retval.set_body(begin, end); + return retval; + } + + // Build a mime part from a pair of iterators + template + static boost::shared_ptr > parse_mime(Iterator &begin, + Iterator end) { + return detail::parse_mime(begin, end); + } + + // Build a mime part from a stream + static boost::shared_ptr parse_mime(std::istream &in) { + boost::spirit::istream_iterator first(in); + boost::spirit::istream_iterator last; + return parse_mime(first, last); + } + + private: + basic_mime(); // Can't create a part w/o a type + + headerIter find_header(const char *key) { + return std::find_if(header_begin(), header_end(), + detail::find_mime_header(key)); + } + + constHeaderIter find_header(const char *key) const { + return std::find_if(header_begin(), header_end(), + detail::find_mime_header(key)); + } + + static part_kind part_kind_from_string_pair(const std::string &type, + const std::string &sub_type) { + if (boost::iequals(type, "multipart")) return multi_part; + + part_kind retVal = simple_part; + // I expect that this will get more complicated as time goes on.... + // + // message/delivery-status is a simple type. + // RFC 3464 defines message/delivery-status + // + // The body of a message/delivery-status consists of one or more + // "fields" formatted according to the ABNF of RFC 822 header + //"fields" + // (see [RFC822]). + if (boost::iequals(type, "message")) + if (!boost::iequals(sub_type, "delivery-status")) retVal = message_part; + return retVal; + } + + void check_subpart_index(size_t idx) const { + if (get_part_kind() == simple_part) + throw std::runtime_error("Simple Mime parts don't have sub-parts"); + else if (get_part_kind() == multi_part) { + if (idx >= m_subparts.size()) + throw std::runtime_error( + str(boost::format( + "Trying to access part %d (of %d) sub-part to a " + "multipart/xxx mime part") % + idx % m_subparts.size())); + } else { // message-part + if (get_part_kind() == message_part) + if (m_subparts.size() > 1) + throw std::runtime_error( + "How did a message/xxx mime parts get more than one " + "sub-part?"); + + if (idx >= m_subparts.size()) + throw std::runtime_error( + str(boost::format( + "Trying to access part %d (of %d) sub-part to a " + "message/xxx mime part") % + idx % m_subparts.size())); + } + } + + void check_subpart_append() const { + if (get_part_kind() == simple_part) + throw std::runtime_error("Simple Mime parts don't have sub-parts"); + else if (get_part_kind() == message_part) { + if (m_subparts.size() > 0) + throw std::runtime_error( + "Can't add a second sub-part to a message/xxx mime part"); + } + // else { /* Multi-part */ } // We can always add to a multi-part + } + + part_kind m_part_kind; + headerList m_headers; + bool m_body_prolog_is_missing; // only for multiparts + mimeBody m_body; + mimeBody m_body_epilog; // only for multiparts + partList m_subparts; // only for multiparts or message + string_type m_default_content_type; +}; + +namespace detail { + +template +static boost::shared_ptr > parse_mime( + Iterator &begin, Iterator end, const char *default_content_type) { + tracer t(__func__); + typedef typename boost::mime::basic_mime mime_part; + + shared_ptr retVal(new mime_part( + detail::read_headers(begin, end), + default_content_type)); + + std::string content_type = retVal->get_content_type(); + +#ifdef DUMP_MIME_DATA + std::cout << "Content-Type: " << content_type << std::endl; + std::cout << str(boost::format("retVal->get_part_kind () = %d") % + ((int)retVal->get_part_kind())) << std::endl; +#endif + + if (retVal->get_part_kind() == mime_part::simple_part) + retVal->set_body(detail::read_simplepart_body< + typename mime_part::bodyContainer, Iterator>(begin, end)); + else if (retVal->get_part_kind() == mime_part::message_part) { + // If we've got a message/xxxx, then there is no body, and we have + // a single + // embedded mime_part (which, of course, could be a multipart) + retVal->append_part(parse_mime(begin, end)); + } else /* multi_part */ { + // Find or invent a boundary string + std::string part_separator = + detail::get_boundary(retVal->get_content_type_header()); + const char *cont_type = boost::iequals(content_type, "multipart/digest") + ? "message/rfc822" + : "text/plain"; + + detail::multipart_body_type body_and_subParts; + detail::read_multipart_body(begin, end, body_and_subParts, part_separator); + + retVal->set_body_prolog(body_and_subParts.body_prolog); + retVal->set_multipart_prolog_is_missing( + body_and_subParts.prolog_is_missing); + for (typename sub_parts_t::const_iterator iter = + body_and_subParts.sub_parts.begin(); + iter != body_and_subParts.sub_parts.end(); ++iter) { + typedef typename sub_part_t::const_iterator iter_type; + iter_type b = iter->begin(); + iter_type e = iter->end(); + retVal->append_part(parse_mime(b, e, cont_type)); + } + retVal->set_body_epilog(body_and_subParts.body_epilog); + } + + return retVal; +} +} + +// ----------------------------------------------------------- +// +// Streaming +// +// ----------------------------------------------------------- + +template +inline std::ostream &operator<<(std::ostream &stream, + basic_mime &part) { + part.stream_out(stream); + return stream; +} + +template +inline std::ostream &operator<<(std::ostream &stream, + boost::shared_ptr > part) { + return stream << *part; +} +} +} + +BOOST_FUSION_ADAPT_STRUCT(boost::mime::detail::mime_content_type, + (std::string, type)(std::string, sub_type)( + boost::mime::detail::phrase_container_t, phrases)) + +#endif // _BOOST_MIME_HPP diff --git a/cpp-netlib/boost/network.hpp b/cpp-netlib/boost/network.hpp new file mode 100644 index 00000000..79399894 --- /dev/null +++ b/cpp-netlib/boost/network.hpp @@ -0,0 +1,17 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_HPP__ +#define __NETWORK_HPP__ + +// Include all headers in network/ +// Author: Dean Michael Berris +// Date: May 20, 2007 + +#include // message type implementation +#include // protocols implementation + +#endif // __NETWORK_HPP__ diff --git a/cpp-netlib/boost/network/constants.hpp b/cpp-netlib/boost/network/constants.hpp new file mode 100644 index 00000000..6aa7e45d --- /dev/null +++ b/cpp-netlib/boost/network/constants.hpp @@ -0,0 +1,140 @@ +#ifndef BOOST_NETWORK_CONSTANTS_HPP_20100808 +#define BOOST_NETWORK_CONSTANTS_HPP_20100808 + +// Copyright 2010 (C) Dean Michael Berris +// 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 +#include +#include + +namespace boost { +namespace network { + +namespace impl { +template +struct constants_narrow { + + static char const* crlf() { + static char crlf_[] = {'\r', '\n', 0}; + return crlf_; + } + + static char const* dot() { + static char dot_[] = {'.', 0}; + return dot_; + } + + static char dot_char() { return '.'; } + + static char const* http_slash() { + static char http_slash_[] = {'H', 'T', 'T', 'P', '/', 0}; + return http_slash_; + } + + static char const* space() { + static char space_[] = {' ', 0}; + return space_; + } + + static char space_char() { return ' '; } + + static char const* slash() { + static char slash_[] = {'/', 0}; + return slash_; + } + + static char slash_char() { return '/'; } + + static char const* host() { + static char host_[] = {'H', 'o', 's', 't', 0}; + return host_; + } + + static char const* colon() { + static char colon_[] = {':', 0}; + return colon_; + } + + static char colon_char() { return ':'; } + + static char const* accept() { + static char accept_[] = {'A', 'c', 'c', 'e', 'p', 't', 0}; + return accept_; + } + + static char const* default_accept_mime() { + static char mime_[] = {'*', '/', '*', 0}; + return mime_; + } + + static char const* accept_encoding() { + static char accept_encoding_[] = {'A', 'c', 'c', 'e', 'p', 't', '-', 'E', + 'n', 'c', 'o', 'd', 'i', 'n', 'g', 0}; + return accept_encoding_; + } + + static char const* default_accept_encoding() { + static char default_accept_encoding_[] = { + 'i', 'd', 'e', 'n', 't', 'i', 't', 'y', ';', 'q', '=', + '1', '.', '0', ',', ' ', '*', ';', 'q', '=', '0', 0}; + return default_accept_encoding_; + } + + static char const* user_agent() { + static char user_agent_[] = {'U', 's', 'e', 'r', '-', 'A', + 'g', 'e', 'n', 't', 0}; + return user_agent_; + } + + static char const* cpp_netlib_slash() { + static char cpp_netlib_slash_[] = {'c', 'p', 'p', '-', 'n', 'e', + 't', 'l', 'i', 'b', '/', 0}; + return cpp_netlib_slash_; + } + + static char question_mark_char() { return '?'; } + + static char hash_char() { return '#'; } + + static char const* connection() { + static char connection_[] = {'C', 'o', 'n', 'n', 'e', 'c', + 't', 'i', 'o', 'n', 0}; + return connection_; + } + + static char const* close() { + static char close_[] = {'C', 'l', 'o', 's', 'e', 0}; + return close_; + } + + static char const* https() { + static char https_[] = "https"; + return https_; + } +}; + +template +struct constants_wide { + + static wchar_t const* https() { + static wchar_t https_[] = L"https"; + return https_; + } +}; +} + +template +struct constants + : mpl::if_< + is_default_string, impl::constants_narrow, + typename mpl::if_, impl::constants_wide, + unsupported_tag >::type>::type {}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_CONSTANTS_HPP_20100808 diff --git a/cpp-netlib/boost/network/detail/debug.hpp b/cpp-netlib/boost/network/detail/debug.hpp new file mode 100644 index 00000000..093ca551 --- /dev/null +++ b/cpp-netlib/boost/network/detail/debug.hpp @@ -0,0 +1,27 @@ +#ifndef BOOST_NETWORK_DEBUG_HPP_20110410 +#define BOOST_NETWORK_DEBUG_HPP_20110410 + +// (c) Copyright 2011 Dean Michael Berris. +// 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) + +/** BOOST_NETWORK_MESSAGE is a debugging macro used by cpp-netlib to + print out network-related errors through standard error. This is + only useful when BOOST_NETWORK_DEBUG is turned on. Otherwise + the macro amounts to a no-op. +*/ +#ifdef BOOST_NETWORK_DEBUG +#include +#ifndef BOOST_NETWORK_MESSAGE +#define BOOST_NETWORK_MESSAGE(msg) \ + std::cerr << "[DEBUG " << __FILE__ << ':' << __LINE__ << "]: " << msg \ + << std::endl; +#endif +#else +#ifndef BOOST_NETWORK_MESSAGE +#define BOOST_NETWORK_MESSAGE(msg) +#endif +#endif + +#endif /* end of include guard: BOOST_NETWORK_DEBUG_HPP_20110410 */ diff --git a/cpp-netlib/boost/network/detail/directive_base.hpp b/cpp-netlib/boost/network/detail/directive_base.hpp new file mode 100644 index 00000000..e405642e --- /dev/null +++ b/cpp-netlib/boost/network/detail/directive_base.hpp @@ -0,0 +1,34 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_DETAIL_DIRECTIVE_BASE_HPP__ +#define __NETWORK_DETAIL_DIRECTIVE_BASE_HPP__ + +/** Defines the base type from which all directives inherit + * to allow friend access to message and other types' internals. + */ +namespace boost { +namespace network { +namespace detail { + +template +struct directive_base { + typedef Tag tag; + // explicit directive_base(basic_message & message_) + // : _message(message_) + protected: + ~directive_base() {}; // can only be extended + + // mutable basic_message & _message; +}; + +} // namespace detail + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_DETAIL_DIRECTIVE_BASE_HPP__ diff --git a/cpp-netlib/boost/network/detail/wrapper_base.hpp b/cpp-netlib/boost/network/detail/wrapper_base.hpp new file mode 100644 index 00000000..12793dfe --- /dev/null +++ b/cpp-netlib/boost/network/detail/wrapper_base.hpp @@ -0,0 +1,41 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_DETAIL_WRAPPER_BASE_HPP__ +#define __NETWORK_DETAIL_WRAPPER_BASE_HPP__ + +namespace boost { +namespace network { + +namespace detail { + +template +struct wrapper_base { + explicit wrapper_base(Message& message_) : _message(message_) {}; + + protected: + ~wrapper_base() {}; // for extending only + + Message& _message; +}; + +template +struct wrapper_base_const { + explicit wrapper_base_const(Message const& message_) : _message(message_) {} + + protected: + ~wrapper_base_const() {}; // for extending only + + Message const& _message; +}; + +} // namespace detail + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_DETAIL_WRAPPER_BASE_HPP__ diff --git a/cpp-netlib/boost/network/include/http/client.hpp b/cpp-netlib/boost/network/include/http/client.hpp new file mode 100644 index 00000000..3abc042e --- /dev/null +++ b/cpp-netlib/boost/network/include/http/client.hpp @@ -0,0 +1,13 @@ +#ifndef BOOST_NETWORK_INCLUDE_HTTP_CLIENT_HPP_ +#define BOOST_NETWORK_INCLUDE_HTTP_CLIENT_HPP_ + +// Copyright 2009 Dean Michael Berris +// 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) +// +// This is the modular include file for using the HTTP Client + +#include + +#endif // BOOST_NETWORK_INCLUDE_HTTP_CLIENT_HPP_ diff --git a/cpp-netlib/boost/network/include/http/server.hpp b/cpp-netlib/boost/network/include/http/server.hpp new file mode 100644 index 00000000..021eefe0 --- /dev/null +++ b/cpp-netlib/boost/network/include/http/server.hpp @@ -0,0 +1,13 @@ +#ifndef BOOST_NETWORK_INCLUDE_HTTP_SERVER_HPP_ +#define BOOST_NETWORK_INCLUDE_HTTP_SERVER_HPP_ + +// Copyright 2010 Dean Michael Berris +// 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) +// +// This is the modular include file for using the HTTP Client + +#include + +#endif diff --git a/cpp-netlib/boost/network/include/message.hpp b/cpp-netlib/boost/network/include/message.hpp new file mode 100644 index 00000000..77d10d42 --- /dev/null +++ b/cpp-netlib/boost/network/include/message.hpp @@ -0,0 +1,14 @@ +#ifndef BOOST_NETWORK_INCLUDE_MESSAGE_HPP_ +#define BOOST_NETWORK_INCLUDE_MESSAGE_HPP_ + +// Copyright 2009 Dean Michael Berris +// 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) +// +// This is the modular include file for using the basic message type + +#include +#include + +#endif // BOOST_NETWORK_INCLUDE_MESSAGE_HPP_ diff --git a/cpp-netlib/boost/network/message.hpp b/cpp-netlib/boost/network/message.hpp new file mode 100644 index 00000000..f0519d87 --- /dev/null +++ b/cpp-netlib/boost/network/message.hpp @@ -0,0 +1,135 @@ +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_HPP__ +#define __NETWORK_MESSAGE_HPP__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/** message.hpp + * + * This header file implements the common message type which + * all networking implementations under the boost::network + * namespace. The common message type allows for easy message + * construction and manipulation suited for networked + * application development. + */ +namespace boost { +namespace network { + +/** The common message type. + */ +template +struct basic_message { + public: + typedef Tag tag; + + typedef typename headers_container::type headers_container_type; + typedef typename headers_container_type::value_type header_type; + typedef typename string::type string_type; + + basic_message() : _headers(), _body(), _source(), _destination() {} + + basic_message(const basic_message& other) + : _headers(other._headers), + _body(other._body), + _source(other._source), + _destination(other._destination) {} + + basic_message& operator=(basic_message rhs) { + rhs.swap(*this); + return *this; + } + + void swap(basic_message& other) { + std::swap(other._headers, _headers); + std::swap(other._body, _body); + std::swap(other._source, _source); + std::swap(other._destination, _destination); + } + + headers_container_type& headers() { return _headers; } + + void headers(headers_container_type const& headers_) const { + _headers = headers_; + } + + void add_header(typename headers_container_type::value_type const& pair_) + const { + _headers.insert(pair_); + } + + void remove_header(typename headers_container_type::key_type const& key) + const { + _headers.erase(key); + } + + headers_container_type const& headers() const { return _headers; } + + string_type& body() { return _body; } + + void body(string_type const& body_) const { _body = body_; } + + string_type const& body() const { return _body; } + + string_type& source() { return _source; } + + void source(string_type const& source_) const { _source = source_; } + + string_type const& source() const { return _source; } + + string_type& destination() { return _destination; } + + void destination(string_type const& destination_) const { + _destination = destination_; + } + + string_type const& destination() const { return _destination; } + + private: + friend struct detail::directive_base; + friend struct detail::wrapper_base >; + + mutable headers_container_type _headers; + mutable string_type _body; + mutable string_type _source; + mutable string_type _destination; +}; + +template +inline void swap(basic_message& left, basic_message& right) { + // swap for ADL + left.swap(right); +} + +// Commenting this out as we don't need to do this anymore. +// BOOST_CONCEPT_ASSERT((Message +// >)); +// BOOST_CONCEPT_ASSERT((Message +// >)); +typedef basic_message message; +typedef basic_message wmessage; + +} // namespace network +} // namespace boost + +#endif // __NETWORK_MESSAGE_HPP__ diff --git a/cpp-netlib/boost/network/message/directives.hpp b/cpp-netlib/boost/network/message/directives.hpp new file mode 100644 index 00000000..11db46af --- /dev/null +++ b/cpp-netlib/boost/network/message/directives.hpp @@ -0,0 +1,36 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_DIRECTIVES_HPP__ +#define __NETWORK_MESSAGE_DIRECTIVES_HPP__ + +#include +#include +#include + +namespace boost { +namespace network { + +template +inline basic_message& operator<<(basic_message& message_, + Directive const& directive) { + directive(message_); + return message_; +} + +BOOST_NETWORK_STRING_DIRECTIVE(source, source_, message.source(source_), + message.source = source_); +BOOST_NETWORK_STRING_DIRECTIVE(destination, destination_, + message.destination(destination_), + message.destination = destination_); +BOOST_NETWORK_STRING_DIRECTIVE(body, body_, message.body(body_), + message.body = body_); + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_MESSAGE_DIRECTIVES_HPP__ diff --git a/cpp-netlib/boost/network/message/directives/detail/string_directive.hpp b/cpp-netlib/boost/network/message/directives/detail/string_directive.hpp new file mode 100644 index 00000000..33d288a7 --- /dev/null +++ b/cpp-netlib/boost/network/message/directives/detail/string_directive.hpp @@ -0,0 +1,59 @@ +#ifndef BOOST_NETWORK_MESSAGE_DIRECTIVES_DETAIL_STRING_DIRECTIVE_HPP_20100915 +#define BOOST_NETWORK_MESSAGE_DIRECTIVES_DETAIL_STRING_DIRECTIVE_HPP_20100915 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include +#include +#include +#include +#include +#include + +/** + * + * To create your own string directive, you can use the preprocessor macro + * BOOST_NETWORK_STRING_DIRECTIVE which takes three parameters: the name of + * the directive, a name for the variable to use in the directive visitor, + * and the body to be implemented in the visitor. An example directive for + * setting the source of a message would look something like this given the + * BOOST_NETWORK_STRING_DIRECTIVE macro: + * + * BOOST_NETWORK_STRING_DIRECTIVE(source, source_, + * message.source(source_) + * , message.source=source_); + * + */ + +#ifndef BOOST_NETWORK_STRING_DIRECTIVE +#define BOOST_NETWORK_STRING_DIRECTIVE(name, value, body, pod_body) \ + template \ + struct name##_directive { \ + ValueType const& value; \ + explicit name##_directive(ValueType const& value_) : value(value_) {} \ + name##_directive(name##_directive const& other) : value(other.value) {} \ + template class Message> \ + typename enable_if, void>::type operator()( \ + Message& message) const { \ + pod_body; \ + } \ + template class Message> \ + typename enable_if >, void>::type operator()( \ + Message& message) const { \ + body; \ + } \ + }; \ + \ + template \ + inline name##_directive name(T const& input) { \ + return name##_directive(input); \ + } +#endif /* BOOST_NETWORK_STRING_DIRECTIVE */ + +#endif /* BOOST_NETWORK_MESSAGE_DIRECTIVES_DETAIL_STRING_DIRECTIVE_HPP_20100915 \ + */ diff --git a/cpp-netlib/boost/network/message/directives/detail/string_value.hpp b/cpp-netlib/boost/network/message/directives/detail/string_value.hpp new file mode 100644 index 00000000..8a3fa7d2 --- /dev/null +++ b/cpp-netlib/boost/network/message/directives/detail/string_value.hpp @@ -0,0 +1,33 @@ +#ifndef BOOST_NETWORK_MESSAGE_DIRECTIVES_DETAIL_STRING_VALUE_HPP_20100915 +#define BOOST_NETWORK_MESSAGE_DIRECTIVES_DETAIL_STRING_VALUE_HPP_20100915 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace detail { + +template +struct string_value + : mpl::if_, boost::shared_future::type>, + typename mpl::if_< + mpl::or_, is_same, + is_same >, + typename string::type, unsupported_tag >::type> {}; + +} /* detail */ +} /* network */ +} /* boost */ + +#endif /* BOOST_NETWORK_MESSAGE_DIRECTIVES_DETAIL_STRING_VALUE_HPP_20100915 */ diff --git a/cpp-netlib/boost/network/message/directives/header.hpp b/cpp-netlib/boost/network/message/directives/header.hpp new file mode 100644 index 00000000..da1f8e2a --- /dev/null +++ b/cpp-netlib/boost/network/message/directives/header.hpp @@ -0,0 +1,76 @@ + +// Copyright Dean Michael Berris 2007-2010. +// 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 __NETWORK_MESSAGE_DIRECTIVES_HEADER_HPP__ +#define __NETWORK_MESSAGE_DIRECTIVES_HEADER_HPP__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { + +namespace impl { + +template +struct header_directive { + + explicit header_directive(KeyType const& header_name, + ValueType const& header_value) + : _header_name(header_name), _header_value(header_value) {}; + + template + struct pod_directive { + template + static void eval(Message const& message, T1 const& key, T2 const& value) { + typedef typename Message::headers_container_type::value_type value_type; + value_type value_ = {key, value}; + message.headers.insert(message.headers.end(), value_); + } + }; + + template + struct normal_directive { + template + static void eval(Message const& message, T1 const& key, T2 const& value) { + typedef typename Message::headers_container_type::value_type value_type; + message.add_header(value_type(key, value)); + } + }; + + template + struct directive_impl + : mpl::if_, + pod_directive, normal_directive >::type {}; + + template + void operator()(Message const& msg) const { + directive_impl::eval(msg, _header_name, _header_value); + } + + private: + KeyType const& _header_name; + ValueType const& _header_value; +}; + +} // namespace impl + +template +inline impl::header_directive header(T1 const& header_name, + T2 const& header_value) { + return impl::header_directive(header_name, header_value); +} +} // namespace network +} // namespace boost + +#endif // __NETWORK_MESSAGE_DIRECTIVES_HEADER_HPP__ diff --git a/cpp-netlib/boost/network/message/directives/remove_header.hpp b/cpp-netlib/boost/network/message/directives/remove_header.hpp new file mode 100644 index 00000000..0961436a --- /dev/null +++ b/cpp-netlib/boost/network/message/directives/remove_header.hpp @@ -0,0 +1,48 @@ + +// Copyright Dean Michael Berris 2008. +// 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 NETWORK_MESSAGE_DIRECTIVES_REMOVE_HEADER_HPP +#define NETWORK_MESSAGE_DIRECTIVES_REMOVE_HEADER_HPP + +#include + +namespace boost { +namespace network { + +template +struct basic_message; + +namespace impl { +template +struct remove_header_directive { + + explicit remove_header_directive(T header_name) + : header_name_(header_name) {}; + + template + void operator()(basic_message& msg) const { + msg.headers().erase(header_name_); + } + + private: + mutable T header_name_; +}; + +} // namespace impl + +inline impl::remove_header_directive remove_header( + std::string header_name) { + return impl::remove_header_directive(header_name); +} + +inline impl::remove_header_directive remove_header( + std::wstring header_name) { + return impl::remove_header_directive(header_name); +} +} // namespace network +} // namespace boost + +#endif // NETWORK_MESSAGE_DIRECTIVES_REMOVE_HEADER_HPP diff --git a/cpp-netlib/boost/network/message/message_concept.hpp b/cpp-netlib/boost/network/message/message_concept.hpp new file mode 100644 index 00000000..6abac861 --- /dev/null +++ b/cpp-netlib/boost/network/message/message_concept.hpp @@ -0,0 +1,66 @@ + +#ifndef BOOST_NETWORK_MESSAGE_MESSAGE_CONCEPT_HPP_20100903 +#define BOOST_NETWORK_MESSAGE_MESSAGE_CONCEPT_HPP_20100903 + +// Copyright (c) Glyn Matthews 2010. +// Copyright 2010 (c) Dean Michael Berris. +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { + +template +struct Message : DefaultConstructible, CopyConstructible, Assignable { + typedef typename M::string_type string_type; + typedef typename M::headers_container_type headers_container_type; + + BOOST_CONCEPT_USAGE(Message) { + M message_; + swap(message, message_); + + typedef typename traits::body::type body_type; + typedef typename traits::source::type source_type; + typedef typename traits::destination::type destination_type; + + headers_container_type headers_ = headers(message); + string_type body_ = body(message); + string_type source_ = source(message); + string_type destination_ = destination(message); + + message << source(source_type()) << destination(destination_type()) + << header(string_type(), string_type()) << body(body_type()); + + add_header(message, string_type(), string_type()); + remove_header(message, string_type()); + clear_headers(message); + source(message, source_type()); + destination(message, destination_type()); + body(message, body_type()); + + (void)headers_; + (void)body_; + (void)source_; + (void)destination_; + } + + private: + M message; +}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_MESSAGE_MESSAGE_CONCEPT_HPP_20100903 diff --git a/cpp-netlib/boost/network/message/modifiers/add_header.hpp b/cpp-netlib/boost/network/message/modifiers/add_header.hpp new file mode 100644 index 00000000..51889a68 --- /dev/null +++ b/cpp-netlib/boost/network/message/modifiers/add_header.hpp @@ -0,0 +1,54 @@ + +#ifndef BOOST_NETWORK_MESSAGE_MODIFIER_ADD_HEADER_HPP_20100824 +#define BOOST_NETWORK_MESSAGE_MODIFIER_ADD_HEADER_HPP_20100824 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include +#include +#include +#include + +namespace boost { +namespace network { + +namespace impl { +template +inline typename enable_if< + mpl::and_ >, mpl::not_ > >, void>::type +add_header(Message& message, KeyType const& key, ValueType const& value, Tag) { + message.headers().insert(std::make_pair(key, value)); +} + +template +inline typename enable_if >, is_async >, + void>::type +add_header(Message& message, KeyType const& key, ValueType const& value, Tag) { + typedef typename Message::header_type header_type; + message.add_header(header_type(key, value)); +} + +template +inline typename enable_if, void>::type add_header( + Message& message, KeyType const& key, ValueType const& value, Tag) { + typename Message::header_type header = {key, value}; + message.headers.insert(message.headers.end(), header); +} +} + +template class Message, class KeyType, + class ValueType> +inline void add_header(Message& message, KeyType const& key, + ValueType const& value) { + impl::add_header(message, key, value, Tag()); +} + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_MESSAGE_MODIFIER_ADD_HEADER_HPP_20100824 diff --git a/cpp-netlib/boost/network/message/modifiers/body.hpp b/cpp-netlib/boost/network/message/modifiers/body.hpp new file mode 100644 index 00000000..1fc1d347 --- /dev/null +++ b/cpp-netlib/boost/network/message/modifiers/body.hpp @@ -0,0 +1,35 @@ +#ifndef BOOST_NETWORK_MODIFIERS_BODY_HPP_20100824 +#define BOOST_NETWORK_MODIFIERS_BODY_HPP_20100824 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include + +namespace boost { +namespace network { + +template class Message, class ValueType> +inline void body_impl(Message& message, ValueType const& body, tags::pod) { + message.body = body; +} + +template class Message, class ValueType> +inline void body_impl(Message& message, ValueType const& body, + tags::normal) { + message.body(body); +} + +template class Message, class ValueType> +inline void body(Message& message, ValueType const& body_) { + body_impl(message, body_, typename pod_or_normal::type()); +} + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_MODIFIERS_BODY_HPP_20100824 diff --git a/cpp-netlib/boost/network/message/modifiers/clear_headers.hpp b/cpp-netlib/boost/network/message/modifiers/clear_headers.hpp new file mode 100644 index 00000000..74991dc6 --- /dev/null +++ b/cpp-netlib/boost/network/message/modifiers/clear_headers.hpp @@ -0,0 +1,55 @@ +#ifndef BOOST_NETWORK_MESSAGE_MODIFIER_CLEAR_HEADERS_HPP_20100824 +#define BOOST_NETWORK_MESSAGE_MODIFIER_CLEAR_HEADERS_HPP_20100824 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include +#include +#include +#include +#include + +namespace boost { +namespace network { + +namespace impl { +template +inline typename enable_if< + mpl::and_ >, mpl::not_ > >, void>::type +clear_headers(Message const &message, Tag const &) { + (typename Message::headers_container_type()).swap(message.headers()); +} + +template +inline typename enable_if, void>::type clear_headers( + Message const &message, Tag const &) { + (typename Message::headers_container_type()).swap(message.headers); +} + +template +inline typename enable_if >, is_async >, + void>::type +clear_headers(Message const &message, Tag const &) { + boost::promise header_promise; + boost::shared_future headers_future( + header_promise.get_future()); + message.headers(headers_future); + header_promise.set_value(typename Message::headers_container_type()); +} + +} // namespace impl + +template class Message> +inline void clear_headers(Message const &message) { + impl::clear_headers(message, Tag()); +} + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_MESSAGE_MODIFIER_CLEAR_HEADERS_HPP_20100824 diff --git a/cpp-netlib/boost/network/message/modifiers/destination.hpp b/cpp-netlib/boost/network/message/modifiers/destination.hpp new file mode 100644 index 00000000..2d461ee6 --- /dev/null +++ b/cpp-netlib/boost/network/message/modifiers/destination.hpp @@ -0,0 +1,41 @@ + +#ifndef BOOST_NETWORK_MESSAGE_MODIFIER_DESTINATION_HPP_20100824 +#define BOOST_NETWORK_MESSAGE_MODIFIER_DESTINATION_HPP_20100824 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include + +namespace boost { +namespace network { + +namespace impl { + +template +inline void destination(Message const &message, ValueType const &destination_, + Tag const &, mpl::false_ const &) { + message.destination(destination_); +} + +template +inline void destination(Message const &message, ValueType const &destination_, + Tag const &, mpl::true_ const &) { + message.destination(destination_); +} +} + +template class Message, class ValueType> +inline void destination(Message const &message, + ValueType const &destination_) { + impl::destination(message, destination_, Tag(), is_async()); +} + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_MESSAGE_MODIFIER_DESTINATION_HPP_20100824 diff --git a/cpp-netlib/boost/network/message/modifiers/remove_header.hpp b/cpp-netlib/boost/network/message/modifiers/remove_header.hpp new file mode 100644 index 00000000..57a94fef --- /dev/null +++ b/cpp-netlib/boost/network/message/modifiers/remove_header.hpp @@ -0,0 +1,65 @@ + +#ifndef BOOST_NETWORK_MESSAGE_MODIFIER_REMOVE_HEADER_HPP_20100824 +#define BOOST_NETWORK_MESSAGE_MODIFIER_REMOVE_HEADER_HPP_20100824 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include +#include +#include +#include +#include + +namespace boost { +namespace network { + +namespace impl { + +template +inline typename enable_if< + mpl::and_ >, mpl::not_ > >, void>::type +remove_header(Message& message, KeyType const& key, Tag) { + message.headers().erase(key); +} + +template +inline typename enable_if >, is_async >, + void>::type +remove_header(Message& message, KeyType const& key, Tag) { + message.remove_header(key); +} + +template +struct iequals_pred { + KeyType const& key; + iequals_pred(KeyType const& key) : key(key) {} + template + bool operator()(Header& other) const { + return boost::iequals(key, name(other)); + } +}; + +template +inline typename enable_if, void>::type remove_header( + Message& message, KeyType const& key, Tag) { + message.headers.erase( + boost::remove_if(message.headers, iequals_pred(key)), + message.headers.end()); +} + +} // namespace impl + +template class Message, class KeyType> +inline void remove_header(Message& message, KeyType const& key) { + impl::remove_header(message, key, Tag()); +} + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_MESSAGE_MODIFIER_REMOVE_HEADER_HPP_20100824 diff --git a/cpp-netlib/boost/network/message/modifiers/source.hpp b/cpp-netlib/boost/network/message/modifiers/source.hpp new file mode 100644 index 00000000..dfaca051 --- /dev/null +++ b/cpp-netlib/boost/network/message/modifiers/source.hpp @@ -0,0 +1,40 @@ + +#ifndef BOOST_NETWORK_MESSAGE_MODIFIER_SOURCE_HPP_20100824 +#define BOOST_NETWORK_MESSAGE_MODIFIER_SOURCE_HPP_20100824 + +// Copyright 2010 (c) Dean Michael Berris +// 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 + +namespace boost { +namespace network { + +namespace impl { + +template +inline void source(Message const &message, ValueType const &source_, + Tag const &, mpl::false_ const &) { + message.source(source_); +} + +template +inline void source(Message const &message, ValueType const &source_, + Tag const &, mpl::true_ const &) { + message.source(source_); +} + +} // namespace impl + +template class Message, class ValueType> +inline void source(Message const &message, ValueType const &source_) { + impl::source(message, source_, Tag(), is_async()); +} + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_MESSAGE_MODIFIER_SOURCE_HPP_20100824 diff --git a/cpp-netlib/boost/network/message/traits/body.hpp b/cpp-netlib/boost/network/message/traits/body.hpp new file mode 100644 index 00000000..17f682db --- /dev/null +++ b/cpp-netlib/boost/network/message/traits/body.hpp @@ -0,0 +1,43 @@ + +#ifndef BOOST_NETWORK_MESSAGE_TRAITS_BODY_HPP_20100903 +#define BOOST_NETWORK_MESSAGE_TRAITS_BODY_HPP_20100903 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include +#include +#include +#include + +namespace boost { +namespace network { + +namespace traits { + +template +struct unsupported_tag; + +template +struct body + : mpl::if_< + is_async, + boost::shared_future::type>, + typename mpl::if_< + mpl::or_, + is_same, + is_same >, + typename string::type, + unsupported_tag >::type> {}; + +} // namespace traits + +} /* network */ + +} /* boost */ + +#endif // BOOST_NETWORK_MESSAGE_TRAITS_BODY_HPP_20100903 diff --git a/cpp-netlib/boost/network/message/traits/destination.hpp b/cpp-netlib/boost/network/message/traits/destination.hpp new file mode 100644 index 00000000..1016cdfb --- /dev/null +++ b/cpp-netlib/boost/network/message/traits/destination.hpp @@ -0,0 +1,42 @@ + +#ifndef BOOST_NETWORK_MESSAGE_TRAITS_DESTINATION_HPP_20100903 +#define BOOST_NETWORK_MESSAGE_TRAITS_DESTINATION_HPP_20100903 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include +#include +#include + +namespace boost { +namespace network { + +namespace traits { + +template +struct unsupported_tag; + +template +struct destination + : mpl::if_< + is_async, + boost::shared_future::type>, + typename mpl::if_< + mpl::or_, + is_same, + is_same >, + typename string::type, + unsupported_tag >::type> {}; + +} // namespace traits + +} /* network */ + +} /* boost */ + +#endif // BOOST_NETWORK_MESSAGE_TRAITS_DESTINATION_HPP_20100903 diff --git a/cpp-netlib/boost/network/message/traits/headers.hpp b/cpp-netlib/boost/network/message/traits/headers.hpp new file mode 100644 index 00000000..8f6f5549 --- /dev/null +++ b/cpp-netlib/boost/network/message/traits/headers.hpp @@ -0,0 +1,56 @@ + +#ifndef BOOST_NETWORK_MESSAGE_TRAITS_HEADERS_HPP_20100903 +#define BOOST_NETWORK_MESSAGE_TRAITS_HEADERS_HPP_20100903 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { + +namespace traits { + +template +struct unsupported_tag; + +template +struct header_key + : mpl::if_< + is_async, + boost::shared_future::type>, + typename mpl::if_< + mpl::or_, + is_same, + is_same >, + typename string::type, + unsupported_tag >::type> {}; + +template +struct header_value + : mpl::if_< + is_async, + boost::shared_future::type>, + typename mpl::if_< + mpl::or_, + is_same, + is_same >, + typename string::type, + unsupported_tag >::type> {}; + +} // namespace traits + +} /* network */ + +} /* boost */ + +#endif // BOOST_NETWORK_MESSAGE_TRAITS_HEADERS_HPP_20100903 diff --git a/cpp-netlib/boost/network/message/traits/source.hpp b/cpp-netlib/boost/network/message/traits/source.hpp new file mode 100644 index 00000000..f1b8c2fb --- /dev/null +++ b/cpp-netlib/boost/network/message/traits/source.hpp @@ -0,0 +1,41 @@ +#ifndef BOOST_NETWORK_MESSAGE_TRAITS_SOURCE_HPP_20100903 +#define BOOST_NETWORK_MESSAGE_TRAITS_SOURCE_HPP_20100903 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include +#include +#include + +namespace boost { +namespace network { + +namespace traits { + +template +struct unsupported_tag; + +template +struct source + : mpl::if_< + is_async, + boost::shared_future::type>, + typename mpl::if_< + mpl::or_, + is_same, + is_same >, + typename string::type, + unsupported_tag >::type> {}; + +} // namespace traits + +} /* network */ + +} /* boost */ + +#endif // BOOST_NETWORK_MESSAGE_TRAITS_SOURCE_HPP_20100903 diff --git a/cpp-netlib/boost/network/message/transformers.hpp b/cpp-netlib/boost/network/message/transformers.hpp new file mode 100644 index 00000000..0b990dfa --- /dev/null +++ b/cpp-netlib/boost/network/message/transformers.hpp @@ -0,0 +1,53 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_TRANSFORMERS_HPP__ +#define __NETWORK_MESSAGE_TRANSFORMERS_HPP__ + +/** transformers.hpp + * + * Pulls in all the transformers files. + */ +#include +#include +#include + +#include + +namespace boost { +namespace network { +namespace impl { +template +struct get_real_algorithm { + typedef typename boost::function_traits< + typename boost::remove_pointer::type>::result_type:: + template type::type>::result_type> type; +}; + +template +struct transform_impl : public get_real_algorithm::type {}; +} // namspace impl + +template +inline impl::transform_impl transform(Algorithm, + Selector) { + return impl::transform_impl(); +} + +template +inline basic_message& operator<<( + basic_message& msg_, + impl::transform_impl const& transformer) { + transformer(msg_); + return msg_; +} + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_MESSAGE_TRANSFORMERS_HPP__ diff --git a/cpp-netlib/boost/network/message/transformers/selectors.hpp b/cpp-netlib/boost/network/message/transformers/selectors.hpp new file mode 100644 index 00000000..4b7a3963 --- /dev/null +++ b/cpp-netlib/boost/network/message/transformers/selectors.hpp @@ -0,0 +1,55 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_TRANSFORMERS_SELECTORS_HPP__ +#define __NETWORK_MESSAGE_TRANSFORMERS_SELECTORS_HPP__ + +namespace boost { +namespace network { +namespace selectors { +struct source_selector; +struct destination_selector; +} // namespace selectors + +selectors::source_selector source_(selectors::source_selector); +selectors::destination_selector destination_(selectors::destination_selector); + +namespace selectors { +struct source_selector { + private: + source_selector() {}; + source_selector(source_selector const &) {}; + friend source_selector boost::network::source_(source_selector); +}; + +struct destination_selector { + private: + destination_selector() {}; + destination_selector(destination_selector const &) {}; + friend destination_selector boost::network::destination_( + destination_selector); +}; +} // namespace selectors + +typedef selectors::source_selector (*source_selector_t)( + selectors::source_selector); +typedef selectors::destination_selector (*destination_selector_t)( + selectors::destination_selector); + +inline selectors::source_selector source_(selectors::source_selector) { + return selectors::source_selector(); +} + +inline selectors::destination_selector destination_( + selectors::destination_selector) { + return selectors::destination_selector(); +} + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_MESSAGE_TRANSFORMERS_SELECTORS_HPP__ diff --git a/cpp-netlib/boost/network/message/transformers/to_lower.hpp b/cpp-netlib/boost/network/message/transformers/to_lower.hpp new file mode 100644 index 00000000..4979f1b1 --- /dev/null +++ b/cpp-netlib/boost/network/message/transformers/to_lower.hpp @@ -0,0 +1,86 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_TRANSFORMERS_TO_LOWER_HPP__ +#define __NETWORK_MESSAGE_TRANSFORMERS_TO_LOWER_HPP__ + +#include + +/** to_lower.hpp + * + * Implements the to_lower transformer. This applies + * the to_lower string algorithm to a string, which + * is selected by the appropriate selector. + * + * This defines a type, to be applied using template + * metaprogramming on the selected string target. + */ +namespace boost { +namespace network { + +namespace impl { + +template +struct to_lower_transformer {}; + +template <> +struct to_lower_transformer { + template + void operator()(basic_message &message_) const { + boost::to_lower(message_.source()); + } + + protected: + ~to_lower_transformer() {} +}; + +template <> +struct to_lower_transformer { + template + void operator()(basic_message &message_) const { + boost::to_lower(message_.destination()); + } + + protected: + ~to_lower_transformer() {}; +}; + +} // namespace impl + +namespace detail { +struct to_lower_placeholder_helper; +} + +detail::to_lower_placeholder_helper to_lower_( + detail::to_lower_placeholder_helper); + +namespace detail { + +struct to_lower_placeholder_helper { + template + struct type : public impl::to_lower_transformer {}; + + private: + to_lower_placeholder_helper() {} + to_lower_placeholder_helper(to_lower_placeholder_helper const &) {} + friend to_lower_placeholder_helper boost::network::to_lower_( + to_lower_placeholder_helper); +}; +} + +typedef detail::to_lower_placeholder_helper (*to_lower_placeholder)( + detail::to_lower_placeholder_helper); + +inline detail::to_lower_placeholder_helper to_lower_( + detail::to_lower_placeholder_helper) { + return detail::to_lower_placeholder_helper(); +} + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_MESSAGE_TRANSFORMERS_TO_LOWER_HPP__ diff --git a/cpp-netlib/boost/network/message/transformers/to_upper.hpp b/cpp-netlib/boost/network/message/transformers/to_upper.hpp new file mode 100644 index 00000000..6e41ef7f --- /dev/null +++ b/cpp-netlib/boost/network/message/transformers/to_upper.hpp @@ -0,0 +1,86 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_TRANSFORMERS_TO_UPPER_HPP__ +#define __NETWORK_MESSAGE_TRANSFORMERS_TO_UPPER_HPP__ + +#include + +/** to_upper.hpp + * + * Implements the to_upper transformer. This applies + * the to_upper string algorithm to a string, which + * is selected by the appropriate selector. + * + * This defines a type, to be applied using template + * metaprogramming on the selected string target. + */ +namespace boost { +namespace network { + +namespace impl { + +template +struct to_upper_transformer {}; + +template <> +struct to_upper_transformer { + template + void operator()(basic_message &message_) const { + boost::to_upper(message_.source()); + } + + protected: + ~to_upper_transformer() {}; +}; + +template <> +struct to_upper_transformer { + template + void operator()(basic_message &message_) const { + boost::to_upper(message_.destination()); + } + + protected: + ~to_upper_transformer() {}; +}; + +} // namespace impl + +namespace detail { +struct to_upper_placeholder_helper; +} + +detail::to_upper_placeholder_helper to_upper_( + detail::to_upper_placeholder_helper); + +namespace detail { + +struct to_upper_placeholder_helper { + template + struct type : public impl::to_upper_transformer {}; + + private: + to_upper_placeholder_helper() {} + to_upper_placeholder_helper(to_upper_placeholder_helper const &) {} + friend to_upper_placeholder_helper boost::network::to_upper_( + to_upper_placeholder_helper); +}; +} + +typedef detail::to_upper_placeholder_helper (*to_upper_placeholder)( + detail::to_upper_placeholder_helper); + +inline detail::to_upper_placeholder_helper to_upper_( + detail::to_upper_placeholder_helper) { + return detail::to_upper_placeholder_helper(); +} + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_MESSAGE_TRANSFORMERS_TO_UPPER_HPP__ diff --git a/cpp-netlib/boost/network/message/wrappers.hpp b/cpp-netlib/boost/network/message/wrappers.hpp new file mode 100644 index 00000000..47b87f05 --- /dev/null +++ b/cpp-netlib/boost/network/message/wrappers.hpp @@ -0,0 +1,19 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_WRAPPERS_HPP__ +#define __NETWORK_MESSAGE_WRAPPERS_HPP__ + +/** wrappers.hpp + * + * Pulls in all the wrapper header files. + */ +#include +#include +#include +#include + +#endif // __NETWORK_MESSAGE_WRAPPERS_HPP__ diff --git a/cpp-netlib/boost/network/message/wrappers/body.hpp b/cpp-netlib/boost/network/message/wrappers/body.hpp new file mode 100644 index 00000000..4dd1d5eb --- /dev/null +++ b/cpp-netlib/boost/network/message/wrappers/body.hpp @@ -0,0 +1,105 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_WRAPPERS_BODY_HPP__ +#define __NETWORK_MESSAGE_WRAPPERS_BODY_HPP__ + +#include +#include +#include + +namespace boost { +namespace network { + +template +struct body_range { + typedef typename boost::iterator_range< + typename Message::string_type::const_iterator> type; +}; + +namespace impl { +template +struct body_wrapper : public detail::wrapper_base > { + typedef basic_message message_type; + typedef typename string::type string_type; + typedef detail::wrapper_base > wrapper_base; + + explicit body_wrapper(basic_message& message_) + : wrapper_base(message_) {}; + + operator string_type() const { + return string_type(wrapper_base::_message.body()); + }; + + std::size_t size() const { return wrapper_base::_message.body().size(); } + + operator boost::iterator_range< + typename boost::range_iterator::type>() const { + return boost::make_iterator_range(wrapper_base::_message.body()); + } + + typename string_type::const_iterator begin() const { + return wrapper_base::_message.body().begin(); + } + + typename string_type::const_iterator end() const { + return wrapper_base::_message.body().end(); + } +}; + +template +struct body_wrapper_const + : public detail::wrapper_base_const > { + typedef basic_message message_type; + typedef typename string::type string_type; + typedef detail::wrapper_base_const > wrapper_base; + + explicit body_wrapper_const(basic_message const& message_) + : wrapper_base(message_) {}; + + operator string_type() const { + return string_type(wrapper_base::_message.body()); + } + + std::size_t size() const { return wrapper_base::_message.body().size(); } + + operator boost::range_iterator() const { + return boost::make_iterator_range(wrapper_base::_message.body()); + } +}; + +template +inline std::ostream& operator<<(std::ostream& os, + body_wrapper const& body) { + os << static_cast::string_type>(body); + return os; +} + +template +inline std::ostream& operator<<(std::ostream& os, + body_wrapper_const const& body) { + os << static_cast::string_type>(body); + return os; +} + +} // namespace impl + +template +inline impl::body_wrapper const body(basic_message& message_) { + return impl::body_wrapper(message_); +} + +template +inline impl::body_wrapper_const const body( + basic_message const& message_) { + return impl::body_wrapper_const(message_); +} + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_MESSAGE_WRAPPERS_BODY_HPP__ diff --git a/cpp-netlib/boost/network/message/wrappers/destination.hpp b/cpp-netlib/boost/network/message/wrappers/destination.hpp new file mode 100644 index 00000000..fe11dffd --- /dev/null +++ b/cpp-netlib/boost/network/message/wrappers/destination.hpp @@ -0,0 +1,42 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_WRAPPERS_DESTINATION_HPP__ +#define __NETWORK_MESSAGE_WRAPPERS_DESTINATION_HPP__ + +#include + +namespace boost { +namespace network { + +namespace impl { +template +struct destination_wrapper + : public detail::wrapper_base > { + typedef Tag tag; + typedef basic_message message_type; + typedef typename string::type string_type; + typedef detail::wrapper_base > wrapper_base; + + explicit destination_wrapper(message_type& message_) + : wrapper_base(message_) {}; + + operator string_type() const { + return string_type(wrapper_base::_message.destination()); + }; +}; +} // namespace impl + +template +inline typename string::type destination(basic_message& message_) { + return impl::destination_wrapper(message_); +} + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_MESSAGE_WRAPPERS_DESTINATION_HPP__ diff --git a/cpp-netlib/boost/network/message/wrappers/headers.hpp b/cpp-netlib/boost/network/message/wrappers/headers.hpp new file mode 100644 index 00000000..5efeb94e --- /dev/null +++ b/cpp-netlib/boost/network/message/wrappers/headers.hpp @@ -0,0 +1,101 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_WRAPPERS_HEADERS_HPP__ +#define __NETWORK_MESSAGE_WRAPPERS_HEADERS_HPP__ + +#include +#include +#include +#include +#include + +namespace boost { +namespace network { + +/// Template metaprogram to get the range type for a message +template +struct headers_range { + typedef typename headers_container::type + headers_container_type; + typedef typename boost::iterator_range< + typename headers_container_type::const_iterator> type; +}; + +template +struct basic_message; + +/** headers wrapper for messages. + * + * This exposes an interface similar to a map, indexable + * using operator[] taking a string as the index and returns + * a range of iterators (std::pair) + * whose keys are all equal to the index string. + * + * This type is also convertible to a + * headers_range >::type + * Which allows for full range support. + * + * The type is also convertible to a + * headers_container::type + * Which copies the headers from the wrapped message. + * + */ +namespace impl { +template +struct headers_wrapper + : public detail::wrapper_base_const > { + typedef Tag tag; + typedef basic_message message_type; + typedef typename string::type string_type; + typedef typename headers_range::type range_type; + typedef typename headers_container::type headers_container_type; + typedef typename headers_container_type::const_iterator const_iterator; + typedef typename headers_container_type::iterator iterator; + typedef detail::wrapper_base_const > wrapper_base; + + explicit headers_wrapper(basic_message const& message_) + : wrapper_base(message_) {}; + + range_type operator[](string_type const& key) const { + return headers_wrapper::_message.headers().equal_range(key); + }; + + typename message_type::headers_container_type::size_type count( + string_type const& key) const { + return headers_wrapper::_message.headers().count(key); + }; + + const_iterator begin() const { + return headers_wrapper::_message.headers().begin(); + }; + + const_iterator end() const { + return headers_wrapper::_message.headers().end(); + }; + + operator range_type() { + return make_iterator_range(headers_wrapper::_message.headers().begin(), + headers_wrapper::_message.headers().end()); + }; + + operator headers_container_type() { + return headers_wrapper::_message.headers(); + } +}; +} // namespace impl + +/// Factory method to create the right wrapper object +template +inline impl::headers_wrapper headers(basic_message const& message_) { + return impl::headers_wrapper(message_); +} + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_MESSAGE_WRAPPERS_HEADERS_HPP__ diff --git a/cpp-netlib/boost/network/message/wrappers/source.hpp b/cpp-netlib/boost/network/message/wrappers/source.hpp new file mode 100644 index 00000000..40d7e9b3 --- /dev/null +++ b/cpp-netlib/boost/network/message/wrappers/source.hpp @@ -0,0 +1,41 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_MESSAGE_WRAPPERS_SOURCE_HPP__ +#define __NETWORK_MESSAGE_WRAPPERS_SOURCE_HPP__ + +#include + +namespace boost { +namespace network { + +namespace impl { +template +struct source_wrapper : public detail::wrapper_base > { + typedef Tag tag; + typedef basic_message message_type; + typedef typename string::type string_type; + typedef detail::wrapper_base > wrapper_base; + + explicit source_wrapper(basic_message& message_) + : wrapper_base(message_) {}; + + operator string_type() const { + return string_type(wrapper_base::_message.source()); + }; +}; +} // namespace impl + +template +inline typename string::type source(basic_message& message_) { + return impl::source_wrapper(message_); +} + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_MESSAGE_WRAPPERS_SOURCE_HPP__ diff --git a/cpp-netlib/boost/network/message_fwd.hpp b/cpp-netlib/boost/network/message_fwd.hpp new file mode 100644 index 00000000..08eaf46c --- /dev/null +++ b/cpp-netlib/boost/network/message_fwd.hpp @@ -0,0 +1,18 @@ +// Copyright (c) Glyn Matthews 2008. +// 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 __2008817MESSAGE_FWD_INC__ +#define __2008817MESSAGE_FWD_INC__ + +namespace boost { +namespace network { + +template +struct basic_message; + +} // namespace boost +} // namespace network + +#endif // __2008817MESSAGE_FWD_INC__ diff --git a/cpp-netlib/boost/network/protocol.hpp b/cpp-netlib/boost/network/protocol.hpp new file mode 100644 index 00000000..758e8aa1 --- /dev/null +++ b/cpp-netlib/boost/network/protocol.hpp @@ -0,0 +1,16 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_PROTOCOLS_20070908_1_HPP__ +#define __NETWORK_PROTOCOLS_20070908_1_HPP__ + +// Include all protocol implementation headers in protocol/* +// Author: Dean Michael Berris +// Date Created: Oct. 08, 2007 + +#include // include HTTP implementation + +#endif // __NETWORK_PROTOCOLS_20070908-1_HPP__ diff --git a/cpp-netlib/boost/network/protocol/http.hpp b/cpp-netlib/boost/network/protocol/http.hpp new file mode 100644 index 00000000..d3ede696 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http.hpp @@ -0,0 +1,19 @@ + +// Copyright Dean Michael Berris 2007, 2008. +// 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 __NETWORK_PROTOCOL_HTTP_20070908_1_HPP__ +#define __NETWORK_PROTOCOL_HTTP_20070908_1_HPP__ + +// Include HTTP implementation headers +// Author: Dean Michael Berris +// Date Created: Oct. 08, 2007 + +#include +#include +#include +#include + +#endif // __NETWORK_PROTOCOL_HTTP_20070908-1_HPP__ diff --git a/cpp-netlib/boost/network/protocol/http/algorithms/linearize.hpp b/cpp-netlib/boost/network/protocol/http/algorithms/linearize.hpp new file mode 100644 index 00000000..d0347fd0 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/algorithms/linearize.hpp @@ -0,0 +1,192 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_ALGORITHMS_LINEARIZE_HPP_20101028 +#define BOOST_NETWORK_PROTOCOL_HTTP_ALGORITHMS_LINEARIZE_HPP_20101028 + +// Copyright 2010 Dean Michael Berris. +// Copyright 2014 Jussi Lyytinen +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct linearize_header { + typedef typename string::type string_type; + + template + struct result; + + template + struct result { + typedef string_type type; + }; + + template + BOOST_CONCEPT_REQUIRES(((Header::type>)), + (string_type)) + operator()(ValueType& header) { + typedef typename ostringstream::type output_stream; + typedef constants consts; + output_stream header_line; + header_line << name(header) << consts::colon() << consts::space() + << value(header) << consts::crlf(); + return header_line.str(); + } +}; + +template +BOOST_CONCEPT_REQUIRES(((ClientRequest)), (OutputIterator)) + linearize(Request const& request, + typename Request::string_type const& method, + unsigned version_major, unsigned version_minor, + OutputIterator oi) { + typedef typename Request::tag Tag; + typedef constants consts; + typedef typename string::type string_type; + static string_type http_slash = consts::http_slash(), + accept = consts::accept(), + accept_mime = consts::default_accept_mime(), + accept_encoding = consts::accept_encoding(), + default_accept_encoding = + consts::default_accept_encoding(), + crlf = consts::crlf(), host = consts::host(), + connection = consts::connection(), close = consts::close(); + boost::copy(method, oi); + *oi = consts::space_char(); + if (request.path().empty() || request.path()[0] != consts::slash_char()) + *oi = consts::slash_char(); + boost::copy(request.path(), oi); + if (!request.query().empty()) { + *oi = consts::question_mark_char(); + boost::copy(request.query(), oi); + } + if (!request.anchor().empty()) { + *oi = consts::hash_char(); + boost::copy(request.anchor(), oi); + } + *oi = consts::space_char(); + boost::copy(http_slash, oi); + string_type version_major_str = + boost::lexical_cast(version_major), + version_minor_str = + boost::lexical_cast(version_minor); + boost::copy(version_major_str, oi); + *oi = consts::dot_char(); + boost::copy(version_minor_str, oi); + boost::copy(crlf, oi); + + // We need to determine whether we've seen any of the following headers + // before setting the defaults. We use a bitset to keep track of the + // defaulted headers. + enum { + ACCEPT, + ACCEPT_ENCODING, + HOST, + CONNECTION, + MAX + }; + std::bitset found_headers; + static char const* defaulted_headers[][2] = { + {consts::accept(), consts::accept() + std::strlen(consts::accept())}, + {consts::accept_encoding(), + consts::accept_encoding() + std::strlen(consts::accept_encoding())}, + {consts::host(), consts::host() + std::strlen(consts::host())}, + {consts::connection(), + consts::connection() + std::strlen(consts::connection())}}; + + typedef typename headers_range::type headers_range; + typedef typename range_value::type headers_value; + BOOST_FOREACH(const headers_value & header, headers(request)) { + string_type header_name = name(header), header_value = value(header); + // Here we check that we have not seen an override to the defaulted + // headers. + for (int header_index = 0; header_index < MAX; ++header_index) + if (std::distance(header_name.begin(), header_name.end()) == + std::distance(defaulted_headers[header_index][0], + defaulted_headers[header_index][1]) && + std::equal(header_name.begin(), header_name.end(), + defaulted_headers[header_index][0], + algorithm::is_iequal())) + found_headers.set(header_index, true); + + // We ignore empty headers. + if (header_value.empty()) continue; + boost::copy(header_name, oi); + *oi = consts::colon_char(); + *oi = consts::space_char(); + boost::copy(header_value, oi); + boost::copy(crlf, oi); + } + + if (!found_headers[HOST]) { + boost::copy(host, oi); + *oi = consts::colon_char(); + *oi = consts::space_char(); + boost::copy(request.host(), oi); + boost::optional port_ = +#if (_MSC_VER >= 1600 && BOOST_VERSION > 105500) + port(request).as_optional(); +#else + port(request); +#endif + if (port_) { + string_type port_str = boost::lexical_cast(*port_); + *oi = consts::colon_char(); + boost::copy(port_str, oi); + } + boost::copy(crlf, oi); + } + + if (!found_headers[ACCEPT]) { + boost::copy(accept, oi); + *oi = consts::colon_char(); + *oi = consts::space_char(); + boost::copy(accept_mime, oi); + boost::copy(crlf, oi); + } + + if (version_major == 1u && version_minor == 1u && + !found_headers[ACCEPT_ENCODING]) { + boost::copy(accept_encoding, oi); + *oi = consts::colon_char(); + *oi = consts::space_char(); + boost::copy(default_accept_encoding, oi); + boost::copy(crlf, oi); + } + + if (!connection_keepalive::value && !found_headers[CONNECTION]) { + boost::copy(connection, oi); + *oi = consts::colon_char(); + *oi = consts::space_char(); + boost::copy(close, oi); + boost::copy(crlf, oi); + } + + boost::copy(crlf, oi); + typename body_range::type body_data = body(request).range(); + return boost::copy(body_data, oi); +} + +} /* http */ + +} /* net */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_ALGORITHMS_LINEARIZE_HPP_20101028 */ diff --git a/cpp-netlib/boost/network/protocol/http/client.hpp b/cpp-netlib/boost/network/protocol/http/client.hpp new file mode 100644 index 00000000..1e315a8f --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client.hpp @@ -0,0 +1,72 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_20091215 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_20091215 + +// Copyright Dean Michael Berris 2007-2010. +// 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_client : basic_client_facade { + private: + typedef basic_client_facade + base_facade_type; + + public: + typedef basic_request request; + typedef basic_response response; + typedef typename string::type string_type; + typedef Tag tag_type; + typedef client_options options; + + // Constructors + // ================================================================= + // This constructor takes a single options argument of type + // client_options. See boost/network/protocol/http/client/options.hpp + // for more details. + explicit basic_client(options const& options) : base_facade_type(options) {} + + // This default constructor sets up the default options. + basic_client() : base_facade_type(options()) {} + // + // ================================================================= +}; + +#ifndef BOOST_NETWORK_HTTP_CLIENT_DEFAULT_TAG +#define BOOST_NETWORK_HTTP_CLIENT_DEFAULT_TAG tags::http_async_8bit_udp_resolve +#endif + +typedef basic_client client; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_20091215 diff --git a/cpp-netlib/boost/network/protocol/http/client/async_impl.hpp b/cpp-netlib/boost/network/protocol/http/client/async_impl.hpp new file mode 100644 index 00000000..1c0eb1fe --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/async_impl.hpp @@ -0,0 +1,109 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_ASYNC_IMPL_HPP_20100623 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_ASYNC_IMPL_HPP_20100623 + +// Copyright Dean Michael Berris 2010. +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_client_impl; + +namespace impl { +template +struct async_client + : connection_policy::type { + typedef typename connection_policy::type + connection_base; + typedef typename resolver::type resolver_type; + typedef typename string::type string_type; + + typedef function const&, + system::error_code const&)> body_callback_function_type; + + typedef function body_generator_function_type; + + async_client(bool cache_resolved, bool follow_redirect, + bool always_verify_peer, int timeout, + boost::shared_ptr service, + optional const& certificate_filename, + optional const& verify_path, + optional const& certificate_file, + optional const& private_key_file, + optional const& ciphers, long ssl_options) + : connection_base(cache_resolved, follow_redirect, timeout), + service_ptr(service.get() + ? service + : boost::make_shared()), + service_(*service_ptr), + resolver_(service_), + sentinel_(new boost::asio::io_service::work(service_)), + certificate_filename_(certificate_filename), + verify_path_(verify_path), + certificate_file_(certificate_file), + private_key_file_(private_key_file), + ciphers_(ciphers), + ssl_options_(ssl_options), + always_verify_peer_(always_verify_peer) { + connection_base::resolver_strand_.reset( + new boost::asio::io_service::strand(service_)); + if (!service) + lifetime_thread_.reset(new boost::thread( + boost::bind(&boost::asio::io_service::run, &service_))); + } + + ~async_client() throw() { sentinel_.reset(); } + + void wait_complete() { + sentinel_.reset(); + if (lifetime_thread_.get()) { + lifetime_thread_->join(); + lifetime_thread_.reset(); + } + } + + basic_response const request_skeleton( + basic_request const& request_, string_type const& method, + bool get_body, body_callback_function_type callback, + body_generator_function_type generator) { + typename connection_base::connection_ptr connection_; + connection_ = connection_base::get_connection( + resolver_, request_, always_verify_peer_, certificate_filename_, + verify_path_, certificate_file_, private_key_file_, ciphers_, + ssl_options_); + return connection_->send_request(method, request_, get_body, callback, + generator); + } + + boost::shared_ptr service_ptr; + boost::asio::io_service& service_; + resolver_type resolver_; + boost::shared_ptr sentinel_; + boost::shared_ptr lifetime_thread_; + optional certificate_filename_; + optional verify_path_; + optional certificate_file_; + optional private_key_file_; + optional ciphers_; + long ssl_options_; + bool always_verify_peer_; +}; +} // namespace impl +} // namespace http +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_ASYNC_IMPL_HPP_20100623 diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/async_base.hpp b/cpp-netlib/boost/network/protocol/http/client/connection/async_base.hpp new file mode 100644 index 00000000..ada856a2 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/async_base.hpp @@ -0,0 +1,80 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_IMPL_ASYNC_CONNECTION_BASE_20100529 +#define BOOST_NETWORK_PROTOCOL_HTTP_IMPL_ASYNC_CONNECTION_BASE_20100529 + +// Copryight 2013 Google, Inc. +// Copyright 2010 Dean Michael Berris +// Copyright 2010 (C) Sinefunc, Inc. +// 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 +#include +#include +#include + +namespace boost { +namespace network { +namespace http { +namespace impl { + +template +struct async_connection_base { + typedef async_connection_base this_type; + typedef typename resolver_policy::type resolver_base; + typedef typename resolver_base::resolver_type resolver_type; + typedef typename resolver_base::resolve_function resolve_function; + typedef typename string::type string_type; + typedef basic_request request; + typedef basic_response response; + typedef iterator_range char_const_range; + typedef function + body_callback_function_type; + typedef function body_generator_function_type; + typedef shared_ptr connection_ptr; + + // This is the factory function which constructs the appropriate async + // connection implementation with the correct delegate chosen based on + // the + // tag. + static connection_ptr new_connection( + resolve_function resolve, resolver_type &resolver, bool follow_redirect, + bool always_verify_peer, bool https, int timeout, + optional certificate_filename = optional(), + optional const &verify_path = optional(), + optional certificate_file = optional(), + optional private_key_file = optional(), + optional ciphers = optional(), + long ssl_options = 0) { + typedef http_async_connection + async_connection; + typedef typename delegate_factory::type delegate_factory_type; + connection_ptr temp; + temp.reset(new async_connection( + resolver, resolve, follow_redirect, timeout, + delegate_factory_type::new_connection_delegate( + resolver.get_io_service(), https, always_verify_peer, + certificate_filename, verify_path, certificate_file, + private_key_file, ciphers, ssl_options))); + BOOST_ASSERT(temp.get() != 0); + return temp; + } + + // This is the pure virtual entry-point for all asynchronous + // connections. + virtual response start(request const &request, string_type const &method, + bool get_body, body_callback_function_type callback, + body_generator_function_type generator) = 0; + + virtual ~async_connection_base() {} +}; + +} // namespace impl + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_IMPL_ASYNC_CONNECTION_BASE_20100529 diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/async_normal.hpp b/cpp-netlib/boost/network/protocol/http/client/connection/async_normal.hpp new file mode 100644 index 00000000..f5590d7f --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/async_normal.hpp @@ -0,0 +1,509 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_ASYNC_CONNECTION_HPP_20100601 +#define BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_ASYNC_CONNECTION_HPP_20100601 + +// Copyright 2010 (C) Dean Michael Berris +// Copyright 2010 (C) Sinefunc, Inc. +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google,Inc. +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace network { +namespace http { +namespace impl { + +template +struct async_connection_base; + +namespace placeholders = boost::asio::placeholders; + +template +struct http_async_connection + : async_connection_base, + protected http_async_protocol_handler, + boost::enable_shared_from_this< + http_async_connection > { + typedef async_connection_base base; + typedef http_async_protocol_handler + protocol_base; + typedef typename base::resolver_type resolver_type; + typedef typename base::resolver_base::resolver_iterator resolver_iterator; + typedef typename base::resolver_base::resolver_iterator_pair + resolver_iterator_pair; + typedef typename base::response response; + typedef typename base::string_type string_type; + typedef typename base::request request; + typedef typename base::resolver_base::resolve_function resolve_function; + typedef typename base::body_callback_function_type + body_callback_function_type; + typedef typename base::body_generator_function_type + body_generator_function_type; + typedef http_async_connection this_type; + typedef typename delegate_factory::type delegate_factory_type; + typedef typename delegate_factory_type::connection_delegate_ptr + connection_delegate_ptr; + + http_async_connection(resolver_type& resolver, resolve_function resolve, + bool follow_redirect, int timeout, + connection_delegate_ptr delegate) + : timeout_(timeout), + timer_(resolver.get_io_service()), + is_timedout_(false), + follow_redirect_(follow_redirect), + resolver_(resolver), + resolve_(resolve), + request_strand_(resolver.get_io_service()), + delegate_(delegate) {} + + // This is the main entry point for the connection/request pipeline. + // We're + // overriding async_connection_base<...>::start(...) here which is + // called + // by the client. + virtual response start(request const& request, string_type const& method, + bool get_body, body_callback_function_type callback, + body_generator_function_type generator) { + response response_; + this->init_response(response_, get_body); + linearize(request, method, version_major, version_minor, + std::ostreambuf_iterator::type>( + &command_streambuf)); + this->method = method; + boost::uint16_t port_ = port(request); + string_type host_ = host(request); + boost::uint16_t source_port = request.source_port(); + + resolve_(resolver_, host_, port_, + request_strand_.wrap(boost::bind( + &this_type::handle_resolved, this_type::shared_from_this(), + host_, port_, source_port, get_body, callback, + generator, boost::arg<1>(), boost::arg<2>()))); + if (timeout_ > 0) { + timer_.expires_from_now(boost::posix_time::seconds(timeout_)); + timer_.async_wait(request_strand_.wrap( + boost::bind(&this_type::handle_timeout, this_type::shared_from_this(), + boost::arg<1>()))); + } + return response_; + } + + private: + http_async_connection(http_async_connection const&); // = delete + + void set_errors(boost::system::error_code const& ec) { + boost::system::system_error error(ec); + this->version_promise.set_exception(boost::copy_exception(error)); + this->status_promise.set_exception(boost::copy_exception(error)); + this->status_message_promise.set_exception(boost::copy_exception(error)); + this->headers_promise.set_exception(boost::copy_exception(error)); + this->source_promise.set_exception(boost::copy_exception(error)); + this->destination_promise.set_exception(boost::copy_exception(error)); + this->body_promise.set_exception(boost::copy_exception(error)); + this->timer_.cancel(); + } + + void handle_timeout(boost::system::error_code const& ec) { + if (!ec) delegate_->disconnect(); + is_timedout_ = true; + } + + void handle_resolved(string_type host, boost::uint16_t port, boost::uint16_t source_port, bool get_body, + body_callback_function_type callback, + body_generator_function_type generator, + boost::system::error_code const& ec, + resolver_iterator_pair endpoint_range) { + if (!ec && !boost::empty(endpoint_range)) { + // Here we deal with the case that there was an error encountered + // and + // that there's still more endpoints to try connecting to. + resolver_iterator iter = boost::begin(endpoint_range); + asio::ip::tcp::endpoint endpoint(iter->endpoint().address(), port); + delegate_->connect( + endpoint, host, source_port, + request_strand_.wrap(boost::bind( + &this_type::handle_connected, this_type::shared_from_this(), host, + port, source_port, get_body, callback, generator, + std::make_pair(++iter, resolver_iterator()), + placeholders::error))); + } else { + set_errors(ec ? ec : boost::asio::error::host_not_found); + boost::iterator_range range; + if (callback) callback(range, ec); + } + } + + void handle_connected(string_type host, boost::uint16_t port, boost::uint16_t source_port, bool get_body, + body_callback_function_type callback, + body_generator_function_type generator, + resolver_iterator_pair endpoint_range, + boost::system::error_code const& ec) { + if (is_timedout_) { + set_errors(asio::error::timed_out); + } else if (!ec) { + BOOST_ASSERT(delegate_.get() != 0); + delegate_->write( + command_streambuf, + request_strand_.wrap(boost::bind( + &this_type::handle_sent_request, this_type::shared_from_this(), + get_body, callback, generator, placeholders::error, + placeholders::bytes_transferred))); + } else { + if (!boost::empty(endpoint_range)) { + resolver_iterator iter = boost::begin(endpoint_range); + asio::ip::tcp::endpoint endpoint(iter->endpoint().address(), port); + delegate_->connect( + endpoint, host, source_port, + request_strand_.wrap(boost::bind( + &this_type::handle_connected, this_type::shared_from_this(), + host, port, source_port, get_body, callback, generator, + std::make_pair(++iter, resolver_iterator()), + placeholders::error))); + } else { + set_errors(ec ? ec : boost::asio::error::host_not_found); + boost::iterator_range range; + if (callback) callback(range, ec); + } + } + } + + enum state_t { + version, + status, + status_message, + headers, + body + }; + + void handle_sent_request(bool get_body, body_callback_function_type callback, + body_generator_function_type generator, + boost::system::error_code const& ec, + std::size_t bytes_transferred) { + // TODO(dberris): review parameter necessity. + (void)bytes_transferred; + + if (!is_timedout_ && !ec) { + if (generator) { + // Here we write some more data that the generator provides, + // before + // we wait for data from the server. + string_type chunk; + if (generator(chunk)) { + // At this point this means we have more data to write, so we + // write + // it out. + std::copy(chunk.begin(), chunk.end(), + std::ostreambuf_iterator::type>( + &command_streambuf)); + delegate_->write( + command_streambuf, + request_strand_.wrap(boost::bind( + &this_type::handle_sent_request, + this_type::shared_from_this(), get_body, callback, generator, + placeholders::error, placeholders::bytes_transferred))); + return; + } + } + delegate_->read_some( + boost::asio::mutable_buffers_1(this->part.c_array(), + this->part.size()), + request_strand_.wrap(boost::bind( + &this_type::handle_received_data, this_type::shared_from_this(), + version, get_body, callback, placeholders::error, + placeholders::bytes_transferred))); + } else { + set_errors(is_timedout_ ? asio::error::timed_out : ec); + } + } + + void handle_received_data(state_t state, bool get_body, + body_callback_function_type callback, + boost::system::error_code const& ec, + std::size_t bytes_transferred) { + static const long short_read_error = 335544539; + bool is_ssl_short_read_error = +#ifdef BOOST_NETWORK_ENABLE_HTTPS + ec.category() == asio::error::ssl_category && + ec.value() == short_read_error; +#else + false && short_read_error; +#endif + if (!is_timedout_ && + (!ec || ec == boost::asio::error::eof || is_ssl_short_read_error)) { + logic::tribool parsed_ok; + size_t remainder; + switch (state) { + case version: + if (ec == boost::asio::error::eof) return; + parsed_ok = this->parse_version( + delegate_, + request_strand_.wrap(boost::bind( + &this_type::handle_received_data, + this_type::shared_from_this(), version, get_body, callback, + placeholders::error, placeholders::bytes_transferred)), + bytes_transferred); + if (!parsed_ok || indeterminate(parsed_ok)) return; + case status: + if (ec == boost::asio::error::eof) return; + parsed_ok = this->parse_status( + delegate_, + request_strand_.wrap(boost::bind( + &this_type::handle_received_data, + this_type::shared_from_this(), status, get_body, callback, + placeholders::error, placeholders::bytes_transferred)), + bytes_transferred); + if (!parsed_ok || indeterminate(parsed_ok)) return; + case status_message: + if (ec == boost::asio::error::eof) return; + parsed_ok = this->parse_status_message( + delegate_, request_strand_.wrap(boost::bind( + &this_type::handle_received_data, + this_type::shared_from_this(), status_message, + get_body, callback, placeholders::error, + placeholders::bytes_transferred)), + bytes_transferred); + if (!parsed_ok || indeterminate(parsed_ok)) return; + case headers: + if (ec == boost::asio::error::eof) return; + // In the following, remainder is the number of bytes that + // remain + // in the buffer. We need this in the body processing to make + // sure + // that the data remaining in the buffer is dealt with before + // another call to get more data for the body is scheduled. + fusion::tie(parsed_ok, remainder) = this->parse_headers( + delegate_, + request_strand_.wrap(boost::bind( + &this_type::handle_received_data, + this_type::shared_from_this(), headers, get_body, callback, + placeholders::error, placeholders::bytes_transferred)), + bytes_transferred); + + if (!parsed_ok || indeterminate(parsed_ok)) return; + + if (!get_body) { + // We short-circuit here because the user does not + // want to get the body (in the case of a HEAD + // request). + this->body_promise.set_value(""); + this->destination_promise.set_value(""); + this->source_promise.set_value(""); + this->part.assign('\0'); + this->response_parser_.reset(); + return; + } + + if (callback) { + // Here we deal with the spill-over data from the + // headers processing. This means the headers data + // has already been parsed appropriately and we're + // looking to treat everything that remains in the + // buffer. + typename protocol_base::buffer_type::const_iterator begin = + this->part_begin; + typename protocol_base::buffer_type::const_iterator end = begin; + std::advance(end, remainder); + + // We're setting the body promise here to an empty string + // because + // this can be used as a signaling mechanism for the user to + // determine that the body is now ready for processing, even + // though the callback is already provided. + this->body_promise.set_value(""); + + // The invocation of the callback is synchronous to allow us + // to + // wait before scheduling another read. + callback(make_iterator_range(begin, end), ec); + + delegate_->read_some( + boost::asio::mutable_buffers_1(this->part.c_array(), + this->part.size()), + request_strand_.wrap(boost::bind( + &this_type::handle_received_data, + this_type::shared_from_this(), body, get_body, callback, + placeholders::error, placeholders::bytes_transferred))); + } else { + // Here we handle the body data ourself and append to an + // ever-growing string buffer. + this->parse_body( + delegate_, + request_strand_.wrap(boost::bind( + &this_type::handle_received_data, + this_type::shared_from_this(), body, get_body, callback, + placeholders::error, placeholders::bytes_transferred)), + remainder); + } + return; + case body: + if (ec == boost::asio::error::eof || is_ssl_short_read_error) { + // Here we're handling the case when the connection has been + // closed from the server side, or at least that the end of + // file + // has been reached while reading the socket. This signals + // the end + // of the body processing chain. + if (callback) { + typename protocol_base::buffer_type::const_iterator + begin = this->part.begin(), + end = begin; + std::advance(end, bytes_transferred); + + // We call the callback function synchronously passing the + // error + // condition (in this case, end of file) so that it can + // handle + // it appropriately. + callback(make_iterator_range(begin, end), ec); + } else { + string_type body_string; + std::swap(body_string, this->partial_parsed); + body_string.append(this->part.begin(), bytes_transferred); + if (this->is_chunk_encoding) + this->body_promise.set_value(parse_chunk_encoding(body_string)); + else + this->body_promise.set_value(body_string); + } + // TODO set the destination value somewhere! + this->destination_promise.set_value(""); + this->source_promise.set_value(""); + this->part.assign('\0'); + this->response_parser_.reset(); + this->timer_.cancel(); + } else { + // This means the connection has not been closed yet and we + // want + // to get more + // data. + if (callback) { + // Here we have a body_handler callback. Let's invoke the + // callback from here and make sure we're getting more + // data + // right after. + typename protocol_base::buffer_type::const_iterator begin = + this->part.begin(); + typename protocol_base::buffer_type::const_iterator end = begin; + std::advance(end, bytes_transferred); + callback(make_iterator_range(begin, end), ec); + delegate_->read_some( + boost::asio::mutable_buffers_1(this->part.c_array(), + this->part.size()), + request_strand_.wrap(boost::bind( + &this_type::handle_received_data, + this_type::shared_from_this(), body, get_body, callback, + placeholders::error, placeholders::bytes_transferred))); + } else { + // Here we don't have a body callback. Let's + // make sure that we deal with the remainder + // from the headers part in case we do have data + // that's still in the buffer. + this->parse_body( + delegate_, + request_strand_.wrap(boost::bind( + &this_type::handle_received_data, + this_type::shared_from_this(), body, get_body, callback, + placeholders::error, placeholders::bytes_transferred)), + bytes_transferred); + } + } + return; + default: + BOOST_ASSERT(false && "Bug, report this to the developers!"); + } + } else { + boost::system::system_error error(is_timedout_ ? asio::error::timed_out + : ec); + this->source_promise.set_exception(boost::copy_exception(error)); + this->destination_promise.set_exception(boost::copy_exception(error)); + switch (state) { + case version: + this->version_promise.set_exception(boost::copy_exception(error)); + case status: + this->status_promise.set_exception(boost::copy_exception(error)); + case status_message: + this->status_message_promise.set_exception( + boost::copy_exception(error)); + case headers: + this->headers_promise.set_exception(boost::copy_exception(error)); + case body: + if (!callback) { + // N.B. if callback is non-null, then body_promise has + // already been set to value "" to indicate body is + // handled by streaming handler so no exception should be set + this->body_promise.set_exception(boost::copy_exception(error)); + } + break; + default: + BOOST_ASSERT(false && "Bug, report this to the developers!"); + } + } + } + + string_type parse_chunk_encoding(string_type& body_string) { + string_type body; + string_type crlf = "\r\n"; + + typename string_type::iterator begin = body_string.begin(); + for (typename string_type::iterator iter = + std::search(begin, body_string.end(), crlf.begin(), crlf.end()); + iter != body_string.end(); + iter = + std::search(begin, body_string.end(), crlf.begin(), crlf.end())) { + string_type line(begin, iter); + if (line.empty()) break; + std::stringstream stream(line); + int len; + stream >> std::hex >> len; + std::advance(iter, 2); + if (!len) break; + if (len <= body_string.end() - iter) { + body.insert(body.end(), iter, iter + len); + std::advance(iter, len + 2); + } + begin = iter; + } + + return body; + } + + int timeout_; + boost::asio::deadline_timer timer_; + bool is_timedout_; + bool follow_redirect_; + resolver_type& resolver_; + resolve_function resolve_; + boost::asio::io_service::strand request_strand_; + connection_delegate_ptr delegate_; + boost::asio::streambuf command_streambuf; + string_type method; +}; + +} // namespace impl +} // namespace http +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_ASYNC_CONNECTION_HPP_20100601 diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/async_protocol_handler.hpp b/cpp-netlib/boost/network/protocol/http/client/connection/async_protocol_handler.hpp new file mode 100644 index 00000000..7c8792ae --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/async_protocol_handler.hpp @@ -0,0 +1,356 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_ASYNC_PROTOCOL_HANDLER_HPP_ +#define BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_ASYNC_PROTOCOL_HANDLER_HPP_ + +// Copyright 2010 (C) Dean Michael Berris +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 +#include + +namespace boost { +namespace network { +namespace http { +namespace impl { + +template +struct http_async_protocol_handler { + protected: + typedef typename string::type string_type; + +#ifdef BOOST_NETWORK_DEBUG + struct debug_escaper { + string_type& string; + explicit debug_escaper(string_type& string_) : string(string_) {} + debug_escaper(debug_escaper const& other) : string(other.string) {} + void operator()(typename string_type::value_type input) { + if (!algorithm::is_print()(input)) { + typename ostringstream::type escaped_stream; + if (input == '\r') { + string.append("\\r"); + } else if (input == '\n') { + string.append("\\n"); + } else { + escaped_stream << "\\x" << static_cast(input); + string.append(escaped_stream.str()); + } + } else { + string.push_back(input); + } + } + }; +#endif + + template + void init_response(ResponseType& response_, bool get_body) { + // TODO(dberris): review parameter necessity. + (void)get_body; + + boost::shared_future source_future( + source_promise.get_future()); + source(response_, source_future); + + boost::shared_future destination_future( + destination_promise.get_future()); + destination(response_, destination_future); + + boost::shared_future::type> headers_future( + headers_promise.get_future()); + headers(response_, headers_future); + + boost::shared_future body_future(body_promise.get_future()); + body(response_, body_future); + + boost::shared_future version_future( + version_promise.get_future()); + version(response_, version_future); + + boost::shared_future status_future( + status_promise.get_future()); + status(response_, status_future); + + boost::shared_future status_message_future( + status_message_promise.get_future()); + status_message(response_, status_message_future); + } + + struct to_http_headers { + typedef typename string::type string_type; + template + string_type const operator()(U const& pair) const { + typedef typename ostringstream::type ostringstream_type; + typedef constants constants; + ostringstream_type header_line; + header_line << pair.first << constants::colon() << constants::space() + << pair.second << constants::crlf(); + return header_line.str(); + } + }; + + template + logic::tribool parse_version(Delegate& delegate_, Callback callback, + size_t bytes) { + logic::tribool parsed_ok; + part_begin = part.begin(); + typename buffer_type::const_iterator part_end = part.begin(); + std::advance(part_end, bytes); + typename boost::iterator_range + result_range, + input_range = boost::make_iterator_range(part_begin, part_end); + fusion::tie(parsed_ok, result_range) = response_parser_.parse_until( + response_parser_type::http_version_done, input_range); + if (parsed_ok == true) { + string_type version; + std::swap(version, partial_parsed); + version.append(boost::begin(result_range), boost::end(result_range)); + algorithm::trim(version); + version_promise.set_value(version); + part_begin = boost::end(result_range); + } else if (parsed_ok == false) { +#ifdef BOOST_NETWORK_DEBUG + string_type escaped; + debug_escaper escaper(escaped); + std::for_each(part_begin, part_end, escaper); + BOOST_NETWORK_MESSAGE("[parser:" << response_parser_.state() + << "] buffer contents: \"" << escaped + << "\""); +#endif + std::runtime_error error("Invalid Version Part."); + version_promise.set_exception(boost::copy_exception(error)); + status_promise.set_exception(boost::copy_exception(error)); + status_message_promise.set_exception(boost::copy_exception(error)); + headers_promise.set_exception(boost::copy_exception(error)); + source_promise.set_exception(boost::copy_exception(error)); + destination_promise.set_exception(boost::copy_exception(error)); + body_promise.set_exception(boost::copy_exception(error)); + } else { + partial_parsed.append(boost::begin(result_range), + boost::end(result_range)); + part_begin = part.begin(); + delegate_->read_some( + boost::asio::mutable_buffers_1(part.c_array(), part.size()), + callback); + } + return parsed_ok; + } + + template + logic::tribool parse_status(Delegate& delegate_, Callback callback, + size_t bytes) { + logic::tribool parsed_ok; + typename buffer_type::const_iterator part_end = part.begin(); + std::advance(part_end, bytes); + typename boost::iterator_range + result_range, + input_range = boost::make_iterator_range(part_begin, part_end); + fusion::tie(parsed_ok, result_range) = response_parser_.parse_until( + response_parser_type::http_status_done, input_range); + if (parsed_ok == true) { + string_type status; + std::swap(status, partial_parsed); + status.append(boost::begin(result_range), boost::end(result_range)); + trim(status); + boost::uint16_t status_int = lexical_cast(status); + status_promise.set_value(status_int); + part_begin = boost::end(result_range); + } else if (parsed_ok == false) { +#ifdef BOOST_NETWORK_DEBUG + string_type escaped; + debug_escaper escaper(escaped); + std::for_each(part_begin, part_end, escaper); + BOOST_NETWORK_MESSAGE("[parser:" << response_parser_.state() + << "] buffer contents: \"" << escaped + << "\""); +#endif + std::runtime_error error("Invalid status part."); + status_promise.set_exception(boost::copy_exception(error)); + status_message_promise.set_exception(boost::copy_exception(error)); + headers_promise.set_exception(boost::copy_exception(error)); + source_promise.set_exception(boost::copy_exception(error)); + destination_promise.set_exception(boost::copy_exception(error)); + body_promise.set_exception(boost::copy_exception(error)); + } else { + partial_parsed.append(boost::begin(result_range), + boost::end(result_range)); + part_begin = part.begin(); + delegate_->read_some( + boost::asio::mutable_buffers_1(part.c_array(), part.size()), + callback); + } + return parsed_ok; + } + + template + logic::tribool parse_status_message(Delegate& delegate_, Callback callback, + size_t bytes) { + logic::tribool parsed_ok; + typename buffer_type::const_iterator part_end = part.begin(); + std::advance(part_end, bytes); + typename boost::iterator_range + result_range, + input_range = boost::make_iterator_range(part_begin, part_end); + fusion::tie(parsed_ok, result_range) = response_parser_.parse_until( + response_parser_type::http_status_message_done, input_range); + if (parsed_ok == true) { + string_type status_message; + std::swap(status_message, partial_parsed); + status_message.append(boost::begin(result_range), + boost::end(result_range)); + algorithm::trim(status_message); + status_message_promise.set_value(status_message); + part_begin = boost::end(result_range); + } else if (parsed_ok == false) { +#ifdef BOOST_NETWORK_DEBUG + string_type escaped; + debug_escaper escaper(escaped); + std::for_each(part_begin, part_end, escaper); + BOOST_NETWORK_MESSAGE("[parser:" << response_parser_.state() + << "] buffer contents: \"" << escaped + << "\""); +#endif + std::runtime_error error("Invalid status message part."); + status_message_promise.set_exception(boost::copy_exception(error)); + headers_promise.set_exception(boost::copy_exception(error)); + source_promise.set_exception(boost::copy_exception(error)); + destination_promise.set_exception(boost::copy_exception(error)); + body_promise.set_exception(boost::copy_exception(error)); + } else { + partial_parsed.append(boost::begin(result_range), + boost::end(result_range)); + part_begin = part.begin(); + delegate_->read_some( + boost::asio::mutable_buffers_1(part.c_array(), part.size()), + callback); + } + return parsed_ok; + } + + void parse_headers_real(string_type& headers_part) { + typename boost::iterator_range + input_range = boost::make_iterator_range(headers_part), + result_range; + logic::tribool parsed_ok; + response_parser_type headers_parser( + response_parser_type::http_header_line_done); + typename headers_container::type headers; + std::pair header_pair; + while (!boost::empty(input_range)) { + fusion::tie(parsed_ok, result_range) = headers_parser.parse_until( + response_parser_type::http_header_colon, input_range); + if (headers_parser.state() != response_parser_type::http_header_colon) + break; + header_pair.first = + string_type(boost::begin(result_range), boost::end(result_range)); + input_range.advance_begin(boost::distance(result_range)); + fusion::tie(parsed_ok, result_range) = headers_parser.parse_until( + response_parser_type::http_header_line_done, input_range); + header_pair.second = + string_type(boost::begin(result_range), boost::end(result_range)); + input_range.advance_begin(boost::distance(result_range)); + + trim(header_pair.first); + if (header_pair.first.size() > 1) { + header_pair.first.erase(header_pair.first.size() - 1); + } + trim(header_pair.second); + headers.insert(header_pair); + } + // determine if the body parser will need to handle chunked encoding + typename headers_range >::type transfer_encoding_range = + headers.equal_range("Transfer-Encoding"); + is_chunk_encoding = + !boost::empty(transfer_encoding_range) && + boost::iequals(boost::begin(transfer_encoding_range)->second, + "chunked"); + headers_promise.set_value(headers); + } + + template + fusion::tuple parse_headers(Delegate& delegate_, + Callback callback, + size_t bytes) { + logic::tribool parsed_ok; + typename buffer_type::const_iterator part_end = part.begin(); + std::advance(part_end, bytes); + typename boost::iterator_range + result_range, + input_range = boost::make_iterator_range(part_begin, part_end); + fusion::tie(parsed_ok, result_range) = response_parser_.parse_until( + response_parser_type::http_headers_done, input_range); + if (parsed_ok == true) { + string_type headers_string; + std::swap(headers_string, partial_parsed); + headers_string.append(boost::begin(result_range), + boost::end(result_range)); + part_begin = boost::end(result_range); + this->parse_headers_real(headers_string); + } else if (parsed_ok == false) { +// We want to output the contents of the buffer that caused +// the error in debug builds. +#ifdef BOOST_NETWORK_DEBUG + string_type escaped; + debug_escaper escaper(escaped); + std::for_each(part_begin, part_end, escaper); + BOOST_NETWORK_MESSAGE("[parser:" << response_parser_.state() + << "] buffer contents: \"" << escaped + << "\" consumed length: " + << boost::distance(result_range)); +#endif + std::runtime_error error("Invalid header part."); + headers_promise.set_exception(boost::copy_exception(error)); + body_promise.set_exception(boost::copy_exception(error)); + source_promise.set_exception(boost::copy_exception(error)); + destination_promise.set_exception(boost::copy_exception(error)); + } else { + partial_parsed.append(boost::begin(result_range), + boost::end(result_range)); + part_begin = part.begin(); + delegate_->read_some( + boost::asio::mutable_buffers_1(part.c_array(), part.size()), + callback); + } + return fusion::make_tuple( + parsed_ok, std::distance(boost::end(result_range), part_end)); + } + + template + void parse_body(Delegate& delegate_, Callback callback, size_t bytes) { + // TODO: we should really not use a string for the partial body + // buffer. + partial_parsed.append(part_begin, bytes); + part_begin = part.begin(); + delegate_->read_some( + boost::asio::mutable_buffers_1(part.c_array(), part.size()), callback); + } + + typedef response_parser response_parser_type; + // TODO: make 1024 go away and become a configurable value. + typedef boost::array::type, 1024> buffer_type; + + response_parser_type response_parser_; + boost::promise version_promise; + boost::promise status_promise; + boost::promise status_message_promise; + boost::promise::type> headers_promise; + boost::promise source_promise; + boost::promise destination_promise; + boost::promise body_promise; + buffer_type part; + typename buffer_type::const_iterator part_begin; + string_type partial_parsed; + bool is_chunk_encoding; +}; + +} /* impl */ + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_ASYNC_PROTOCOL_HANDLER_HPP_20101015 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/connection_delegate.hpp b/cpp-netlib/boost/network/protocol/http/client/connection/connection_delegate.hpp new file mode 100644 index 00000000..79fa1ca4 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/connection_delegate.hpp @@ -0,0 +1,37 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_CONNECTION_DELEGATE_HPP_ +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_CONNECTION_DELEGATE_HPP_ + +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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) + +namespace boost { +namespace network { +namespace http { +namespace impl { + +struct connection_delegate { + virtual void connect(asio::ip::tcp::endpoint &endpoint, std::string host, boost::uint16_t source_port, + function handler) = 0; + virtual void write( + asio::streambuf &command_streambuf, + function handler) = 0; + virtual void read_some( + asio::mutable_buffers_1 const &read_buffer, + function handler) = 0; + virtual void disconnect() = 0; + virtual ~connection_delegate() {} +}; + +} /* impl */ + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_CONNECTION_DELEGATE_HPP_ \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/connection_delegate_factory.hpp b/cpp-netlib/boost/network/protocol/http/client/connection/connection_delegate_factory.hpp new file mode 100644 index 00000000..425cc27e --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/connection_delegate_factory.hpp @@ -0,0 +1,62 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_DELEGATE_FACTORY_HPP_20110819 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_DELEGATE_FACTORY_HPP_20110819 + +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 +#include +#include +#ifdef BOOST_NETWORK_ENABLE_HTTPS +#include +#endif /* BOOST_NETWORK_ENABLE_HTTPS */ + +namespace boost { +namespace network { +namespace http { +namespace impl { + +struct ssl_delegate; + +struct normal_delegate; + +template +struct connection_delegate_factory { + typedef shared_ptr connection_delegate_ptr; + typedef typename string::type string_type; + + // This is the factory method that actually returns the delegate + // instance. + // TODO Support passing in proxy settings when crafting connections. + static connection_delegate_ptr new_connection_delegate( + asio::io_service& service, bool https, bool always_verify_peer, + optional certificate_filename, + optional verify_path, optional certificate_file, + optional private_key_file, optional ciphers, + long ssl_options) { + connection_delegate_ptr delegate; + if (https) { +#ifdef BOOST_NETWORK_ENABLE_HTTPS + delegate.reset(new ssl_delegate( + service, always_verify_peer, certificate_filename, verify_path, + certificate_file, private_key_file, ciphers, ssl_options)); +#else + BOOST_THROW_EXCEPTION(std::runtime_error("HTTPS not supported.")); +#endif /* BOOST_NETWORK_ENABLE_HTTPS */ + } else { + delegate.reset(new normal_delegate(service)); + } + return delegate; + } +}; + +} /* impl */ +} /* http */ +} /* network */ +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_DELEGATE_FACTORY_HPP_20110819 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/normal_delegate.hpp b/cpp-netlib/boost/network/protocol/http/client/connection/normal_delegate.hpp new file mode 100644 index 00000000..ae6ace33 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/normal_delegate.hpp @@ -0,0 +1,54 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_NORMAL_DELEGATE_20110819 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_NORMAL_DELEGATE_20110819 + +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { +namespace impl { + +struct normal_delegate : connection_delegate { + normal_delegate(asio::io_service &service); + + virtual void connect(asio::ip::tcp::endpoint &endpoint, std::string host, boost::uint16_t source_port, + function handler); + virtual void write( + asio::streambuf &command_streambuf, + function handler); + virtual void read_some( + asio::mutable_buffers_1 const &read_buffer, + function handler); + virtual void disconnect(); + ~normal_delegate(); + + private: + asio::io_service &service_; + scoped_ptr socket_; + + normal_delegate(normal_delegate const &); // = delete + normal_delegate &operator=(normal_delegate); // = delete +}; + +} /* impl */ + +} /* http */ + +} /* network */ + +} /* boost */ + +#ifdef BOOST_NETWORK_NO_LIB +#include +#endif /* BOOST_NETWORK_NO_LIB */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_NORMAL_DELEGATE_20110819 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/normal_delegate.ipp b/cpp-netlib/boost/network/protocol/http/client/connection/normal_delegate.ipp new file mode 100644 index 00000000..bc41d9c6 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/normal_delegate.ipp @@ -0,0 +1,57 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_NORMAL_DELEGATE_IPP_20110819 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_NORMAL_DELEGATE_IPP_20110819 + +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 +#include +#include +#include +#include +#include + +boost::network::http::impl::normal_delegate::normal_delegate( + asio::io_service &service) + : service_(service) {} + +void boost::network::http::impl::normal_delegate::connect( + asio::ip::tcp::endpoint &endpoint, std::string host, boost::uint16_t source_port, + function handler) { + + // TODO(dberris): review parameter necessity. + (void)host; + + socket_.reset(new asio::ip::tcp::socket(service_)); + socket_->async_connect(endpoint, handler); +} + +void boost::network::http::impl::normal_delegate::write( + asio::streambuf &command_streambuf, + function handler) { + asio::async_write(*socket_, command_streambuf, handler); +} + +void boost::network::http::impl::normal_delegate::read_some( + asio::mutable_buffers_1 const &read_buffer, + function handler) { + socket_->async_read_some(read_buffer, handler); +} + +void boost::network::http::impl::normal_delegate::disconnect() { + if (socket_.get() && socket_->is_open()) { + boost::system::error_code ignored; + socket_->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored); + if (!ignored) { + socket_->close(ignored); + } + } +} + +boost::network::http::impl::normal_delegate::~normal_delegate() {} + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_NORMAL_DELEGATE_IPP_20110819 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/ssl_delegate.hpp b/cpp-netlib/boost/network/protocol/http/client/connection/ssl_delegate.hpp new file mode 100644 index 00000000..712fc517 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/ssl_delegate.hpp @@ -0,0 +1,76 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_SSL_DELEGATE_20110819 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_SSL_DELEGATE_20110819 + +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { +namespace impl { + +struct ssl_delegate : connection_delegate, + enable_shared_from_this { + ssl_delegate(asio::io_service &service, bool always_verify_peer, + optional certificate_filename, + optional verify_path, + optional certificate_file, + optional private_key_file, + optional ciphers, long ssl_options); + + virtual void connect(asio::ip::tcp::endpoint &endpoint, std::string host, boost::uint16_t source_port, + function handler); + virtual void write( + asio::streambuf &command_streambuf, + function handler); + virtual void read_some( + asio::mutable_buffers_1 const &read_buffer, + function handler); + virtual void disconnect(); + ~ssl_delegate(); + + private: + asio::io_service &service_; + optional certificate_filename_; + optional verify_path_; + optional certificate_file_; + optional private_key_file_; + optional ciphers_; + long ssl_options_; + scoped_ptr context_; + scoped_ptr tcp_socket_; + scoped_ptr > socket_; + bool always_verify_peer_; + + ssl_delegate(ssl_delegate const &); // = delete + ssl_delegate &operator=(ssl_delegate); // = delete + + void handle_connected(system::error_code const &ec, + function handler); +}; + +} /* impl */ + +} /* http */ + +} /* network */ + +} /* boost */ + +#ifdef BOOST_NETWORK_NO_LIB +#include +#endif /* BOOST_NETWORK_NO_LIB */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_SSL_DELEGATE_20110819 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/ssl_delegate.ipp b/cpp-netlib/boost/network/protocol/http/client/connection/ssl_delegate.ipp new file mode 100644 index 00000000..71161ba4 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/ssl_delegate.ipp @@ -0,0 +1,113 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_SSL_DELEGATE_IPP_20110819 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_SSL_DELEGATE_IPP_20110819 + +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 +#include +#include + +boost::network::http::impl::ssl_delegate::ssl_delegate( + asio::io_service &service, bool always_verify_peer, + optional certificate_filename, + optional verify_path, + optional certificate_file, + optional private_key_file, + optional ciphers, + long ssl_options) + : service_(service), + certificate_filename_(certificate_filename), + verify_path_(verify_path), + certificate_file_(certificate_file), + private_key_file_(private_key_file), + ciphers_(ciphers), + ssl_options_(ssl_options), + always_verify_peer_(always_verify_peer) {} + +void boost::network::http::impl::ssl_delegate::connect( + asio::ip::tcp::endpoint &endpoint, std::string host, boost::uint16_t source_port, + function handler) { + context_.reset( + new asio::ssl::context(service_, asio::ssl::context::sslv23_client)); + if (ciphers_) { + ::SSL_CTX_set_cipher_list(context_->native_handle(), ciphers_->c_str()); + } + if (ssl_options_ != 0) { + context_->set_options(ssl_options_); + } + if (certificate_filename_ || verify_path_) { + context_->set_verify_mode(asio::ssl::context::verify_peer); + if (certificate_filename_) + context_->load_verify_file(*certificate_filename_); + if (verify_path_) context_->add_verify_path(*verify_path_); + } else { + if (always_verify_peer_) { + context_->set_verify_mode(asio::ssl::context::verify_peer); + // use openssl default verify paths. uses openssl environment variables + // SSL_CERT_DIR, SSL_CERT_FILE + context_->set_default_verify_paths(); + } else + context_->set_verify_mode(asio::ssl::context::verify_none); + } + if (certificate_file_) + context_->use_certificate_file(*certificate_file_, + boost::asio::ssl::context::pem); + if (private_key_file_) + context_->use_private_key_file(*private_key_file_, + boost::asio::ssl::context::pem); + + tcp_socket_.reset(new asio::ip::tcp::socket(service_, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), source_port))); + socket_.reset( + new asio::ssl::stream(*(tcp_socket_.get()), *context_)); + + if (always_verify_peer_) + socket_->set_verify_callback(boost::asio::ssl::rfc2818_verification(host)); + socket_->lowest_layer().async_connect( + endpoint, + ::boost::bind( + &boost::network::http::impl::ssl_delegate::handle_connected, + boost::network::http::impl::ssl_delegate::shared_from_this(), + asio::placeholders::error, handler)); +} + +void boost::network::http::impl::ssl_delegate::handle_connected( + system::error_code const &ec, + function handler) { + if (!ec) { + socket_->async_handshake(asio::ssl::stream_base::client, handler); + } else { + handler(ec); + } +} + +void boost::network::http::impl::ssl_delegate::write( + asio::streambuf &command_streambuf, + function handler) { + asio::async_write(*socket_, command_streambuf, handler); +} + +void boost::network::http::impl::ssl_delegate::read_some( + asio::mutable_buffers_1 const &read_buffer, + function handler) { + socket_->async_read_some(read_buffer, handler); +} + +void boost::network::http::impl::ssl_delegate::disconnect() { + if (socket_.get() && socket_->lowest_layer().is_open()) { + boost::system::error_code ignored; + socket_->lowest_layer().shutdown( + boost::asio::ip::tcp::socket::shutdown_both, ignored); + if (!ignored) { + socket_->lowest_layer().close(ignored); + } + } +} + +boost::network::http::impl::ssl_delegate::~ssl_delegate() {} + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_SSL_DELEGATE_IPP_20110819 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/sync_base.hpp b/cpp-netlib/boost/network/protocol/http/client/connection/sync_base.hpp new file mode 100644 index 00000000..4b81220f --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/sync_base.hpp @@ -0,0 +1,302 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_IMPL_SYNC_CONNECTION_BASE_20091217 +#define BOOST_NETWORK_PROTOCOL_HTTP_IMPL_SYNC_CONNECTION_BASE_20091217 + +// Copyright 2013 Google, Inc. +// Copyright 2009 Dean Michael Berris +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef BOOST_NETWORK_ENABLE_HTTPS +#include +#endif + +namespace boost { +namespace network { +namespace http { +namespace impl { + +template +struct sync_connection_base_impl { + protected: + typedef typename resolver_policy::type resolver_base; + typedef typename resolver_base::resolver_type resolver_type; + typedef typename string::type string_type; + typedef function + resolver_function_type; + + template + void init_socket(Socket& socket_, resolver_type& resolver_, + string_type const& hostname, string_type const& port, + resolver_function_type resolve_) { + using boost::asio::ip::tcp; + boost::system::error_code error = boost::asio::error::host_not_found; + typename resolver_type::iterator endpoint_iterator, end; + boost::tie(endpoint_iterator, end) = resolve_(resolver_, hostname, port); + while (error && endpoint_iterator != end) { + socket_.close(); + socket_.connect(tcp::endpoint(endpoint_iterator->endpoint().address(), + endpoint_iterator->endpoint().port()), + error); + ++endpoint_iterator; + } + + if (error) throw boost::system::system_error(error); + } + + template + void read_status(Socket& socket_, basic_response& response_, + boost::asio::streambuf& response_buffer) { + boost::asio::read_until(socket_, response_buffer, "\r\n"); + std::istream response_stream(&response_buffer); + string_type http_version; + unsigned int status_code; + string_type status_message; + response_stream >> http_version >> status_code; + std::getline(response_stream, status_message); + trim_left(status_message); + trim_right_if(status_message, boost::is_space() || boost::is_any_of("\r")); + + if (!response_stream || http_version.substr(0, 5) != "HTTP/") + throw std::runtime_error("Invalid response"); + + response_ << http::version(http_version) << http::status(status_code) + << http::status_message(status_message); + } + + template + void read_headers(Socket& socket_, basic_response& response_, + boost::asio::streambuf& response_buffer) { + boost::asio::read_until(socket_, response_buffer, "\r\n\r\n"); + std::istream response_stream(&response_buffer); + string_type header_line, name; + while (std::getline(response_stream, header_line) && header_line != "\r") { + trim_right_if(header_line, boost::is_space() || boost::is_any_of("\r")); + typename string_type::size_type colon_offset; + if (header_line.size() && header_line[0] == ' ') { + assert(!name.empty()); + if (name.empty()) + throw std::runtime_error(std::string("Malformed header: ") + + header_line); + response_ << header(name, trim_left_copy(header_line)); + } else if ((colon_offset = header_line.find_first_of(':')) != + string_type::npos) { + name = header_line.substr(0, colon_offset); + response_ << header(name, header_line.substr(colon_offset + 2)); + } + } + } + + template + void send_request_impl(Socket& socket_, string_type const& method, + boost::asio::streambuf& request_buffer) { + // TODO(dberris): review parameter necessity. + (void)method; + + write(socket_, request_buffer); + } + + template + void read_body_normal(Socket& socket_, basic_response& response_, + boost::asio::streambuf& response_buffer, + typename ostringstream::type& body_stream) { + // TODO(dberris): review parameter necessity. + (void)response_; + + boost::system::error_code error; + if (response_buffer.size() > 0) body_stream << &response_buffer; + + while (boost::asio::read(socket_, response_buffer, + boost::asio::transfer_at_least(1), error)) { + body_stream << &response_buffer; + } + } + + template + void read_body_transfer_chunk_encoding( + Socket& socket_, basic_response& response_, + boost::asio::streambuf& response_buffer, + typename ostringstream::type& body_stream) { + boost::system::error_code error; + // look for the content-length header + typename headers_range >::type content_length_range = + headers(response_)["Content-Length"]; + if (boost::empty(content_length_range)) { + typename headers_range >::type + transfer_encoding_range = headers(response_)["Transfer-Encoding"]; + if (boost::empty(transfer_encoding_range)) { + read_body_normal(socket_, response_, response_buffer, body_stream); + return; + } + if (boost::iequals(boost::begin(transfer_encoding_range)->second, + "chunked")) { + bool stopping = false; + do { + std::size_t chunk_size_line = + read_until(socket_, response_buffer, "\r\n", error); + if ((chunk_size_line == 0) && (error != boost::asio::error::eof)) + throw boost::system::system_error(error); + std::size_t chunk_size = 0; + string_type data; + { + std::istream chunk_stream(&response_buffer); + std::getline(chunk_stream, data); + typename istringstream::type chunk_size_stream(data); + chunk_size_stream >> std::hex >> chunk_size; + } + if (chunk_size == 0) { + stopping = true; + if (!read_until(socket_, response_buffer, "\r\n", error) && + (error != boost::asio::error::eof)) + throw boost::system::system_error(error); + } else { + bool stopping_inner = false; + do { + if (response_buffer.size() < (chunk_size + 2)) { + std::size_t bytes_to_read = + (chunk_size + 2) - response_buffer.size(); + std::size_t chunk_bytes_read = + read(socket_, response_buffer, + boost::asio::transfer_at_least(bytes_to_read), error); + if (chunk_bytes_read == 0) { + if (error != boost::asio::error::eof) + throw boost::system::system_error(error); + stopping_inner = true; + } + } + + std::istreambuf_iterator eos; + std::istreambuf_iterator stream_iterator(&response_buffer); + for (; chunk_size > 0 && stream_iterator != eos; --chunk_size) + body_stream << *stream_iterator++; + response_buffer.consume(2); + } while (!stopping_inner && chunk_size != 0); + + if (chunk_size != 0) + throw std::runtime_error( + "Size mismatch between tranfer encoding chunk data " + "size and declared chunk size."); + } + } while (!stopping); + } else + throw std::runtime_error("Unsupported Transfer-Encoding."); + } else { + size_t already_read = response_buffer.size(); + if (already_read) body_stream << &response_buffer; + size_t length = + lexical_cast(boost::begin(content_length_range)->second) - + already_read; + if (length == 0) return; + size_t bytes_read = 0; + while ((bytes_read = boost::asio::read(socket_, response_buffer, + boost::asio::transfer_at_least(1), + error))) { + body_stream << &response_buffer; + length -= bytes_read; + if ((length <= 0) || error) break; + } + } + } + + template + void read_body(Socket& socket_, basic_response& response_, + boost::asio::streambuf& response_buffer) { + typename ostringstream::type body_stream; + // TODO tag dispatch based on whether it's HTTP 1.0 or HTTP 1.1 + if (version_major == 1 && version_minor == 0) { + read_body_normal(socket_, response_, response_buffer, body_stream); + } else if (version_major == 1 && version_minor == 1) { + if (response_.version() == "HTTP/1.0") + read_body_normal(socket_, response_, response_buffer, body_stream); + else + read_body_transfer_chunk_encoding(socket_, response_, response_buffer, + body_stream); + } else { + throw std::runtime_error("Unsupported HTTP version number."); + } + + response_ << network::body(body_stream.str()); + } +}; + +template +struct sync_connection_base { + typedef typename resolver_policy::type resolver_base; + typedef typename resolver_base::resolver_type resolver_type; + typedef typename string::type string_type; + typedef function + resolver_function_type; + typedef function body_generator_function_type; + + // FIXME make the certificate filename and verify path parameters be + // optional + // ranges + static sync_connection_base* + new_connection( + resolver_type& resolver, resolver_function_type resolve, bool https, + bool always_verify_peer, int timeout, + optional const& certificate_filename = + optional(), + optional const& verify_path = optional(), + optional const& certificate_file = + optional(), + optional const& private_key_file = + optional(), + optional const& ciphers = optional(), + long ssl_options = 0) { + if (https) { +#ifdef BOOST_NETWORK_ENABLE_HTTPS + return dynamic_cast< + sync_connection_base*>( + new https_sync_connection( + resolver, resolve, always_verify_peer, timeout, + certificate_filename, verify_path, certificate_file, + private_key_file, ciphers, ssl_options)); +#else + throw std::runtime_error("HTTPS not supported."); +#endif + } + return dynamic_cast< + sync_connection_base*>( + new http_sync_connection( + resolver, resolve, timeout)); + } + + virtual void init_socket(string_type const& hostname, + string_type const& port) = 0; + virtual void send_request_impl(string_type const& method, + basic_request const& request_, + body_generator_function_type generator) = 0; + virtual void read_status(basic_response& response_, + boost::asio::streambuf& response_buffer) = 0; + virtual void read_headers(basic_response& response_, + boost::asio::streambuf& response_buffer) = 0; + virtual void read_body(basic_response& response_, + boost::asio::streambuf& response_buffer) = 0; + virtual bool is_open() = 0; + virtual void close_socket() = 0; + virtual ~sync_connection_base() {} + + protected: + sync_connection_base() {} +}; + +} // namespace impl +} // namespace http +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_IMPL_SYNC_CONNECTION_BASE_20091217 diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/sync_normal.hpp b/cpp-netlib/boost/network/protocol/http/client/connection/sync_normal.hpp new file mode 100644 index 00000000..e9d3f326 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/sync_normal.hpp @@ -0,0 +1,134 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_SYNC_CONNECTION_20100601 +#define BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_SYNC_CONNECTION_20100601 + +// Copyright 2013 Google, Inc. +// Copyright 2010 (C) Dean Michael Berris +// Copyright 2010 (C) Sinefunc, Inc. +// 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 +#include + +#include + +namespace boost { +namespace network { +namespace http { +namespace impl { + +template +struct sync_connection_base_impl; + +template +struct sync_connection_base; + +template +struct http_sync_connection + : public virtual sync_connection_base, + sync_connection_base_impl, + boost::enable_shared_from_this< + http_sync_connection > { + typedef typename resolver_policy::type resolver_base; + typedef typename resolver_base::resolver_type resolver_type; + typedef typename string::type string_type; + typedef function + resolver_function_type; + typedef http_sync_connection this_type; + typedef sync_connection_base_impl + connection_base; + typedef function body_generator_function_type; + + http_sync_connection(resolver_type& resolver, resolver_function_type resolve, + int timeout) + : connection_base(), + timeout_(timeout), + timer_(resolver.get_io_service()), + resolver_(resolver), + resolve_(resolve), + socket_(resolver.get_io_service()) {} + + void init_socket(string_type const& hostname, string_type const& port) { + connection_base::init_socket(socket_, resolver_, hostname, port, resolve_); + } + + void send_request_impl(string_type const& method, + basic_request const& request_, + body_generator_function_type generator) { + boost::asio::streambuf request_buffer; + linearize( + request_, method, version_major, version_minor, + std::ostreambuf_iterator::type>(&request_buffer)); + connection_base::send_request_impl(socket_, method, request_buffer); + if (generator) { + string_type chunk; + while (generator(chunk)) { + std::copy(chunk.begin(), chunk.end(), + std::ostreambuf_iterator::type>( + &request_buffer)); + chunk.clear(); + connection_base::send_request_impl(socket_, method, request_buffer); + } + } + if (timeout_ > 0) { + timer_.expires_from_now(boost::posix_time::seconds(timeout_)); + timer_.async_wait(boost::bind(&this_type::handle_timeout, + this_type::shared_from_this(), + boost::arg<1>())); + } + } + + void read_status(basic_response& response_, + boost::asio::streambuf& response_buffer) { + connection_base::read_status(socket_, response_, response_buffer); + } + + void read_headers(basic_response& response, + boost::asio::streambuf& response_buffer) { + connection_base::read_headers(socket_, response, response_buffer); + } + + void read_body(basic_response& response_, + boost::asio::streambuf& response_buffer) { + connection_base::read_body(socket_, response_, response_buffer); + typename headers_range >::type connection_range = + headers(response_)["Connection"]; + if (version_major == 1 && version_minor == 1 && !boost::empty(connection_range) && + boost::iequals(boost::begin(connection_range)->second, "close")) { + close_socket(); + } else if (version_major == 1 && version_minor == 0) { + close_socket(); + } + } + + bool is_open() { return socket_.is_open(); } + + void close_socket() { + timer_.cancel(); + if (!is_open()) return; + boost::system::error_code ignored; + socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored); + if (ignored) return; + socket_.close(ignored); + } + + private: + void handle_timeout(boost::system::error_code const& ec) { + if (!ec) close_socket(); + } + + int timeout_; + boost::asio::deadline_timer timer_; + resolver_type& resolver_; + resolver_function_type resolve_; + boost::asio::ip::tcp::socket socket_; +}; + +} // namespace impl +} // nmaespace http +} // namespace network +} // nmaespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTP_SYNC_CONNECTION_20100 diff --git a/cpp-netlib/boost/network/protocol/http/client/connection/sync_ssl.hpp b/cpp-netlib/boost/network/protocol/http/client/connection/sync_ssl.hpp new file mode 100644 index 00000000..7561289d --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/connection/sync_ssl.hpp @@ -0,0 +1,184 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTPS_SYNC_CONNECTION_HTTP_20100601 +#define BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTPS_SYNC_CONNECTION_HTTP_20100601 + +// Copyright 2013 Google, Inc. +// Copyright 2010 (C) Dean Michael Berris +// Copyright 2010 (C) Sinefunc, Inc. +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { +namespace impl { + +template +struct sync_connection_base_impl; + +template +struct sync_connection_base; + +template +struct https_sync_connection + : public virtual sync_connection_base, + sync_connection_base_impl, + boost::enable_shared_from_this< + https_sync_connection > { + typedef typename resolver_policy::type resolver_base; + typedef typename resolver_base::resolver_type resolver_type; + typedef typename string::type string_type; + typedef function + resolver_function_type; + typedef https_sync_connection this_type; + typedef sync_connection_base_impl + connection_base; + typedef function body_generator_function_type; + + // FIXME make the certificate filename and verify path parameters be + // optional ranges + https_sync_connection( + resolver_type& resolver, resolver_function_type resolve, + bool always_verify_peer, int timeout, + optional const& certificate_filename = + optional(), + optional const& verify_path = optional(), + optional const& certificate_file = optional(), + optional const& private_key_file = optional(), + optional const& ciphers = optional(), + long ssl_options = 0) + : connection_base(), + timeout_(timeout), + timer_(resolver.get_io_service()), + resolver_(resolver), + resolve_(resolve), + context_(resolver.get_io_service(), + boost::asio::ssl::context::sslv23_client), + socket_(resolver.get_io_service(), context_) { + if (ciphers) { + ::SSL_CTX_set_cipher_list(context_.native_handle(), ciphers->c_str()); + } + if (ssl_options != 0) { + context_.set_options(ssl_options); + } + if (certificate_filename || verify_path) { + context_.set_verify_mode(boost::asio::ssl::context::verify_peer); + // FIXME make the certificate filename and verify path parameters + // be + // optional ranges + if (certificate_filename) + context_.load_verify_file(*certificate_filename); + if (verify_path) context_.add_verify_path(*verify_path); + } else { + if (always_verify_peer) + context_.set_verify_mode(boost::asio::ssl::context_base::verify_peer); + else + context_.set_verify_mode(boost::asio::ssl::context_base::verify_none); + } + if (certificate_file) + context_.use_certificate_file(*certificate_file, + boost::asio::ssl::context::pem); + if (private_key_file) + context_.use_private_key_file(*private_key_file, + boost::asio::ssl::context::pem); + } + + void init_socket(string_type const& hostname, string_type const& port) { + connection_base::init_socket(socket_.lowest_layer(), resolver_, hostname, + port, resolve_); + socket_.handshake(boost::asio::ssl::stream_base::client); + } + + void send_request_impl(string_type const& method, + basic_request const& request_, + body_generator_function_type generator) { + boost::asio::streambuf request_buffer; + linearize( + request_, method, version_major, version_minor, + std::ostreambuf_iterator::type>(&request_buffer)); + connection_base::send_request_impl(socket_, method, request_buffer); + if (generator) { + string_type chunk; + while (generator(chunk)) { + std::copy(chunk.begin(), chunk.end(), + std::ostreambuf_iterator::type>( + &request_buffer)); + chunk.clear(); + connection_base::send_request_impl(socket_, method, request_buffer); + } + } + if (timeout_ > 0) { + timer_.expires_from_now(boost::posix_time::seconds(timeout_)); + timer_.async_wait(boost::bind(&this_type::handle_timeout, + this_type::shared_from_this(), + boost::arg<1>())); + } + } + + void read_status(basic_response& response_, + boost::asio::streambuf& response_buffer) { + connection_base::read_status(socket_, response_, response_buffer); + } + + void read_headers(basic_response& response_, + boost::asio::streambuf& response_buffer) { + connection_base::read_headers(socket_, response_, response_buffer); + } + + void read_body(basic_response& response_, + boost::asio::streambuf& response_buffer) { + connection_base::read_body(socket_, response_, response_buffer); + typename headers_range >::type connection_range = + headers(response_)["Connection"]; + if (version_major == 1 && version_minor == 1 && !boost::empty(connection_range) && + boost::iequals(boost::begin(connection_range)->second, "close")) { + close_socket(); + } else if (version_major == 1 && version_minor == 0) { + close_socket(); + } + } + + bool is_open() { return socket_.lowest_layer().is_open(); } + + void close_socket() { + timer_.cancel(); + boost::system::error_code ignored; + socket_.lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, + ignored); + if (ignored) return; + socket_.lowest_layer().close(ignored); + } + + ~https_sync_connection() { close_socket(); } + + private: + void handle_timeout(boost::system::error_code const& ec) { + if (!ec) close_socket(); + } + + int timeout_; + boost::asio::deadline_timer timer_; + resolver_type& resolver_; + resolver_function_type resolve_; + boost::asio::ssl::context context_; + boost::asio::ssl::stream socket_; +}; + +} // namespace impl +} // namespace http +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTPS_SYNC_CONNECTION_HTTP_20100601 diff --git a/cpp-netlib/boost/network/protocol/http/client/facade.hpp b/cpp-netlib/boost/network/protocol/http/client/facade.hpp new file mode 100644 index 00000000..68c02ce1 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/facade.hpp @@ -0,0 +1,174 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_FACADE_HPP_20100623 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_FACADE_HPP_20100623 + +// Copyright 2013 Google, Inc. +// Copyright 2010 Dean Michael Berris +// 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 +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +template +struct basic_response; + +template +struct basic_client_facade { + + typedef typename string::type string_type; + typedef basic_request request; + typedef basic_response response; + typedef basic_client_impl pimpl_type; + typedef function const&, + system::error_code const&)> body_callback_function_type; + typedef function body_generator_function_type; + + explicit basic_client_facade(client_options const& options) { + init_pimpl(options); + } + + ~basic_client_facade() { pimpl->wait_complete(); } + + response head(request const& request) { + return pimpl->request_skeleton(request, "HEAD", false, + body_callback_function_type(), + body_generator_function_type()); + } + + response get(request const& request, + body_callback_function_type body_handler = + body_callback_function_type()) { + return pimpl->request_skeleton(request, "GET", true, body_handler, + body_generator_function_type()); + } + + response post(request request, string_type const& body = string_type(), + string_type const& content_type = string_type(), + body_callback_function_type body_handler = + body_callback_function_type(), + body_generator_function_type body_generator = + body_generator_function_type()) { + if (body != string_type()) { + request << remove_header("Content-Length") + << header("Content-Length", + boost::lexical_cast(body.size())) + << boost::network::body(body); + } + typename headers_range >::type content_type_headers = + headers(request)["Content-Type"]; + if (content_type != string_type()) { + if (!boost::empty(content_type_headers)) + request << remove_header("Content-Type"); + request << header("Content-Type", content_type); + } else { + if (boost::empty(content_type_headers)) { + typedef typename char_::type char_type; + static char_type content_type[] = "x-application/octet-stream"; + request << header("Content-Type", content_type); + } + } + return pimpl->request_skeleton(request, "POST", true, body_handler, + body_generator); + } + + response post(request const& request, + body_generator_function_type body_generator, + body_callback_function_type callback = + body_generator_function_type()) { + return pimpl->request_skeleton(request, "POST", true, callback, + body_generator); + } + + response post(request const& request, body_callback_function_type callback, + body_generator_function_type body_generator = + body_generator_function_type()) { + return post(request, string_type(), string_type(), callback, + body_generator); + } + + response post(request const& request, string_type const& body, + body_callback_function_type callback, + body_generator_function_type body_generator = + body_generator_function_type()) { + return post(request, body, string_type(), callback, body_generator); + } + + response put(request request, string_type const& body = string_type(), + string_type const& content_type = string_type(), + body_callback_function_type body_handler = + body_callback_function_type(), + body_generator_function_type body_generator = + body_generator_function_type()) { + if (body != string_type()) { + request << remove_header("Content-Length") + << header("Content-Length", + boost::lexical_cast(body.size())) + << boost::network::body(body); + } + typename headers_range >::type content_type_headers = + headers(request)["Content-Type"]; + if (content_type != string_type()) { + if (!boost::empty(content_type_headers)) + request << remove_header("Content-Type"); + request << header("Content-Type", content_type); + } else { + if (boost::empty(content_type_headers)) { + typedef typename char_::type char_type; + static char_type content_type[] = "x-application/octet-stream"; + request << header("Content-Type", content_type); + } + } + return pimpl->request_skeleton(request, "PUT", true, body_handler, + body_generator); + } + + response put(request const& request, body_callback_function_type callback, + body_generator_function_type body_generator = + body_generator_function_type()) { + return put(request, string_type(), string_type(), callback, body_generator); + } + + response put(request const& request, string_type body, + body_callback_function_type callback, + body_generator_function_type body_generator = + body_generator_function_type()) { + return put(request, body, string_type(), callback, body_generator); + } + + response delete_(request const& request, + body_callback_function_type body_handler = + body_callback_function_type()) { + return pimpl->request_skeleton(request, "DELETE", true, body_handler, + body_generator_function_type()); + } + + void clear_resolved_cache() { pimpl->clear_resolved_cache(); } + + protected: + boost::shared_ptr pimpl; + + void init_pimpl(client_options const& options) { + pimpl.reset(new pimpl_type( + options.cache_resolved(), options.follow_redirects(), + options.always_verify_peer(), options.openssl_certificate(), + options.openssl_verify_path(), options.openssl_certificate_file(), + options.openssl_private_key_file(), options.openssl_ciphers(), + options.openssl_options(), options.io_service(), options.timeout())); + } +}; + +} // namespace http +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_FACADE_HPP_20100623 diff --git a/cpp-netlib/boost/network/protocol/http/client/macros.hpp b/cpp-netlib/boost/network/protocol/http/client/macros.hpp new file mode 100644 index 00000000..c64cc7a0 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/macros.hpp @@ -0,0 +1,19 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_MACROS_HPP_20110430 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_MACROS_HPP_20110430 + +// Copyright 2011 Dean Michael Berris . +// 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 +#include + +#ifndef BOOST_NETWORK_HTTP_BODY_CALLBACK +#define BOOST_NETWORK_HTTP_BODY_CALLBACK(function_name, range_name, \ + error_name) \ + void function_name(boost::iterator_range const& range_name, \ + boost::system::error_code const& error_name) +#endif + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_MACROS_HPP_20110430 */ diff --git a/cpp-netlib/boost/network/protocol/http/client/options.hpp b/cpp-netlib/boost/network/protocol/http/client/options.hpp new file mode 100644 index 00000000..8207dcaa --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/options.hpp @@ -0,0 +1,181 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_OPTIONS_HPP_20130128 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_OPTIONS_HPP_20130128 + +#include +#include +#include +#include + +// Copyright 2013 Google, Inc. +// Copyright 2013 Dean Michael Berris +// 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) + +namespace boost { +namespace network { +namespace http { + +template +struct client_options { + typedef typename string::type string_type; + + client_options() + : cache_resolved_(false), + follow_redirects_(false), + openssl_certificate_(), + openssl_verify_path_(), + openssl_certificate_file_(), + openssl_private_key_file_(), + openssl_ciphers_(), + openssl_options_(0), + io_service_(), + always_verify_peer_(false), + timeout_(0) {} + + client_options(client_options const& other) + : cache_resolved_(other.cache_resolved_), + follow_redirects_(other.follow_redirects_), + openssl_certificate_(other.openssl_certificate_), + openssl_verify_path_(other.openssl_verify_path_), + openssl_certificate_file_(other.openssl_certificate_file_), + openssl_private_key_file_(other.openssl_private_key_file_), + openssl_ciphers_(other.openssl_ciphers_), + openssl_options_(other.openssl_options_), + io_service_(other.io_service_), + always_verify_peer_(other.always_verify_peer_), + timeout_(other.timeout_) {} + + client_options& operator=(client_options other) { + other.swap(*this); + return *this; + } + + void swap(client_options& other) { + using std::swap; + swap(cache_resolved_, other.cache_resolved_); + swap(follow_redirects_, other.follow_redirects_); + swap(openssl_certificate_, other.openssl_certificate_); + swap(openssl_verify_path_, other.openssl_verify_path_); + swap(openssl_certificate_file_, other.openssl_certificate_file_); + swap(openssl_private_key_file_, other.openssl_private_key_file_); + swap(openssl_ciphers_, other.openssl_ciphers_); + swap(openssl_options_, other.openssl_options_); + swap(io_service_, other.io_service_); + swap(always_verify_peer_, other.always_verify_peer_); + swap(timeout_, other.timeout_); + } + + client_options& cache_resolved(bool v) { + cache_resolved_ = v; + return *this; + } + + client_options& follow_redirects(bool v) { + follow_redirects_ = v; + return *this; + } + + client_options& openssl_certificate(string_type const& v) { + openssl_certificate_ = v; + return *this; + } + + client_options& openssl_verify_path(string_type const& v) { + openssl_verify_path_ = v; + return *this; + } + + client_options& openssl_certificate_file(string_type const& v) { + openssl_certificate_file_ = v; + return *this; + } + + client_options& openssl_private_key_file(string_type const& v) { + openssl_private_key_file_ = v; + return *this; + } + + client_options& openssl_ciphers(string_type const& v) { + openssl_ciphers_ = v; + return *this; + } + + client_options& openssl_options(long o) { + openssl_options_ = o; + return *this; + } + + client_options& io_service(boost::shared_ptr v) { + io_service_ = v; + return *this; + } + + client_options& always_verify_peer(bool v) { + always_verify_peer_ = v; + return *this; + } + + client_options& timeout(int v) { + timeout_ = v; + return *this; + } + + bool cache_resolved() const { return cache_resolved_; } + + bool follow_redirects() const { return follow_redirects_; } + + boost::optional openssl_certificate() const { + return openssl_certificate_; + } + + boost::optional openssl_verify_path() const { + return openssl_verify_path_; + } + + boost::optional openssl_certificate_file() const { + return openssl_certificate_file_; + } + + boost::optional openssl_private_key_file() const { + return openssl_private_key_file_; + } + + boost::optional openssl_ciphers() const { + return openssl_ciphers_; + } + + long openssl_options() const { return openssl_options_; } + + boost::shared_ptr io_service() const { + return io_service_; + } + + bool always_verify_peer() const { return always_verify_peer_; } + + int timeout() const { return timeout_; } + + private: + bool cache_resolved_; + bool follow_redirects_; + boost::optional openssl_certificate_; + boost::optional openssl_verify_path_; + boost::optional openssl_certificate_file_; + boost::optional openssl_private_key_file_; + boost::optional openssl_ciphers_; + long openssl_options_; + boost::shared_ptr io_service_; + bool always_verify_peer_; + int timeout_; +}; + +template +inline void swap(client_options& a, client_options& b) { + a.swap(b); +} + +} /* http */ +} /* network */ +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_OPTIONS_HPP_20130128 */ diff --git a/cpp-netlib/boost/network/protocol/http/client/pimpl.hpp b/cpp-netlib/boost/network/protocol/http/client/pimpl.hpp new file mode 100644 index 00000000..d66aa387 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/pimpl.hpp @@ -0,0 +1,90 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_PIMPL_HPP_20100623 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_PIMPL_HPP_20100623 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_client_impl; + +namespace impl { + +template +struct async_client; + +template +struct sync_client; + +template +struct client_base { + typedef unsupported_tag type; +}; + +template +struct client_base >::type> { + typedef async_client type; +}; + +template +struct client_base >::type> { + typedef sync_client type; +}; + +} // namespace impl + +template +struct basic_client; + +template +struct basic_client_impl + : impl::client_base::type { + BOOST_STATIC_ASSERT( + (mpl::not_, is_sync > >::value)); + + typedef typename impl::client_base::type + base_type; + typedef typename base_type::string_type string_type; + + basic_client_impl(bool cache_resolved, bool follow_redirect, + bool always_verify_peer, + optional const& certificate_filename, + optional const& verify_path, + optional const& certificate_file, + optional const& private_key_file, + optional const& ciphers, long ssl_options, + boost::shared_ptr service, + int timeout) + : base_type(cache_resolved, follow_redirect, always_verify_peer, timeout, + service, certificate_filename, verify_path, certificate_file, + private_key_file, ciphers, ssl_options) {} + + ~basic_client_impl() {} +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_PIMPL_HPP_20100623 diff --git a/cpp-netlib/boost/network/protocol/http/client/sync_impl.hpp b/cpp-netlib/boost/network/protocol/http/client/sync_impl.hpp new file mode 100644 index 00000000..5051fbd8 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/client/sync_impl.hpp @@ -0,0 +1,99 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_SYNC_IMPL_HPP_20100623 +#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_SYNC_IMPL_HPP_20100623 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Copyright 2013 Google, Inc. +// Copyright 2010 Dean Michael Berris +// 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) + +namespace boost { +namespace network { +namespace http { + +template +struct basic_client_impl; + +namespace impl { +template +struct sync_client + : connection_policy::type { + typedef typename string::type string_type; + typedef typename connection_policy::type + connection_base; + typedef typename resolver::type resolver_type; + typedef function const&, + system::error_code const&)> body_callback_function_type; + typedef function body_generator_function_type; + friend struct basic_client_impl; + + boost::shared_ptr service_ptr; + boost::asio::io_service& service_; + resolver_type resolver_; + optional certificate_filename_; + optional verify_path_; + optional certificate_file_; + optional private_key_file_; + optional ciphers_; + long ssl_options_; + bool always_verify_peer_; + + sync_client( + bool cache_resolved, bool follow_redirect, bool always_verify_peer, + int timeout, boost::shared_ptr service, + optional const& certificate_filename = + optional(), + optional const& verify_path = optional(), + optional const& certificate_file = optional(), + optional const& private_key_file = optional(), + optional const& ciphers = optional(), + long ssl_options = 0) + : connection_base(cache_resolved, follow_redirect, timeout), + service_ptr(service.get() ? service + : make_shared()), + service_(*service_ptr), + resolver_(service_), + certificate_filename_(certificate_filename), + verify_path_(verify_path), + certificate_file_(certificate_file), + private_key_file_(private_key_file), + ciphers_(ciphers), + ssl_options_(ssl_options), + always_verify_peer_(always_verify_peer) {} + + ~sync_client() { + connection_base::cleanup(); + service_ptr.reset(); + } + + void wait_complete() {} + + basic_response request_skeleton(basic_request const& request_, + string_type method, bool get_body, + body_callback_function_type callback, + body_generator_function_type generator) { + typename connection_base::connection_ptr connection_; + connection_ = connection_base::get_connection( + resolver_, request_, always_verify_peer_, certificate_filename_, + verify_path_, certificate_file_, private_key_file_, ciphers_); + return connection_->send_request(method, request_, get_body, callback, + generator); + } +}; + +} // namespace impl +} // namespace http +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_SYNC_IMPL_HPP_20100623 diff --git a/cpp-netlib/boost/network/protocol/http/errors.hpp b/cpp-netlib/boost/network/protocol/http/errors.hpp new file mode 100644 index 00000000..e2348eb9 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/errors.hpp @@ -0,0 +1,31 @@ + +// Copyright Dean Michael Berris 2007, 2008. +// 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 __NETWORK_PROTOCOL_HTTP_ERRORS_20080516_HPP__ +#define __NETWORK_PROTOCOL_HTTP_ERRORS_20080516_HPP__ + +#include +#include + +namespace boost { +namespace network { +namespace http { +namespace errors { + +template +struct connection_timeout_exception : std::runtime_error {}; + +typedef connection_timeout_exception<> connection_timeout; + +} // namespace errors + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_PROTOCOL_HTTP_20080516_HPP__ diff --git a/cpp-netlib/boost/network/protocol/http/impl/message.ipp b/cpp-netlib/boost/network/protocol/http/impl/message.ipp new file mode 100644 index 00000000..5171cdec --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/impl/message.ipp @@ -0,0 +1,299 @@ +// This file is part of the Boost Network library +// Based on the Pion Network Library (r421) +// Copyright Atomic Labs, Inc. 2007-2008 +// See http://cpp-netlib.sourceforge.net for library home page. +// +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_IPP + +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +// static member functions of boost::network::http::message + +template +typename message_impl::string_type const message_impl::url_decode( + typename message_impl::string_type const &str) { + char decode_buf[3]; + typename message_impl::string_type result; + result.reserve(str.size()); + + for (typename message_impl::string_type::size_type pos = 0; + pos < str.size(); ++pos) { + switch (str[pos]) { + case '+': + // convert to space character + result += ' '; + break; + case '%': + // decode hexidecimal value + if (pos + 2 < str.size()) { + decode_buf[0] = str[++pos]; + decode_buf[1] = str[++pos]; + decode_buf[2] = '\0'; + result += static_cast(strtol(decode_buf, 0, 16)); + } else { + // recover from error by not decoding character + result += '%'; + } + break; + default: + // character does not need to be escaped + result += str[pos]; + } + }; + + return result; +} + +template +typename message_impl::string_type const message_impl::url_encode( + typename message_impl::string_type const &str) { + char encode_buf[4]; + typename message_impl::string_type result; + encode_buf[0] = '%'; + result.reserve(str.size()); + + // character selection for this algorithm is based on the following url: + // http://www.blooberry.com/indexdot/html/topics/urlencoding.htm + + for (typename message_impl::string_type::size_type pos = 0; + pos < str.size(); ++pos) { + switch (str[pos]) { + default: + if (str[pos] >= 32 && str[pos] < 127) { + // character does not need to be escaped + result += str[pos]; + break; + } + // else pass through to next case + + case '$': + case '&': + case '+': + case ',': + case '/': + case ':': + case ';': + case '=': + case '?': + case '@': + case '"': + case '<': + case '>': + case '#': + case '%': + case '{': + case '}': + case '|': + case '\\': + case '^': + case '~': + case '[': + case ']': + case '`': + // the character needs to be encoded + sprintf(encode_buf + 1, "%02X", str[pos]); + result += encode_buf; + break; + } + }; + + return result; +} + +template +typename message_impl::string_type const +message_impl::make_query_string( + typename query_container::type const &query_params) { + typename message_impl::string_type query_string; + for (typename query_container::type::const_iterator i = + query_params.begin(); + i != query_params.end(); ++i) { + if (i != query_params.begin()) query_string += '&'; + query_string += url_encode(i->first); + query_string += '='; + query_string += url_encode(i->second); + } + return query_string; +} + +template +typename message_impl::string_type const +message_impl::make_set_cookie_header( + typename message_impl::string_type const &name, + typename message_impl::string_type const &value, + typename message_impl::string_type const &path, bool const has_max_age, + unsigned long const max_age) { + typename message_impl::string_type set_cookie_header(name); + set_cookie_header += "=\""; + set_cookie_header += value; + set_cookie_header += "\"; Version=\"1\""; + if (!path.empty()) { + set_cookie_header += "; Path=\""; + set_cookie_header += path; + set_cookie_header += '\"'; + } + if (has_max_age) { + set_cookie_header += "; Max-Age=\""; + set_cookie_header += + boost::lexical_cast::string_type>(max_age); + set_cookie_header += '\"'; + } + return set_cookie_header; +} + +template +bool message_impl::base64_decode( + const typename message_impl::string_type &input, + typename message_impl::string_type &output) { + static const char nop = -1; + static const char decoding_data[] = { + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 62, nop, + nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, nop, nop, + nop, nop, nop, nop, nop, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, nop, nop, nop, nop, nop, nop, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, + nop}; + + unsigned int input_length = input.size(); + const char *input_ptr = input.data(); + + // allocate space for output string + output.clear(); + output.reserve(((input_length + 2) / 3) * 4); + + // for each 4-bytes sequence from the input, extract 4 6-bits sequences + // by droping first two bits + // and regenerate into 3 8-bits sequence + + for (unsigned int i = 0; i < input_length; i++) { + char base64code0; + char base64code1; + char base64code2 = 0; // initialized to 0 to suppress warnings + char base64code3; + + base64code0 = decoding_data[static_cast(input_ptr[i])]; + if (base64code0 == nop) // non base64 character + return false; + if (!(++i < input_length)) // we need at least two input bytes for + // first byte output + return false; + base64code1 = decoding_data[static_cast(input_ptr[i])]; + if (base64code1 == nop) // non base64 character + return false; + + output += ((base64code0 << 2) | ((base64code1 >> 4) & 0x3)); + + if (++i < input_length) { + char c = input_ptr[i]; + if (c == '=') { // padding , end of input + BOOST_ASSERT((base64code1 & 0x0f) == 0); + return true; + } + base64code2 = decoding_data[static_cast(input_ptr[i])]; + if (base64code2 == nop) // non base64 character + return false; + + output += ((base64code1 << 4) & 0xf0) | ((base64code2 >> 2) & 0x0f); + } + + if (++i < input_length) { + char c = input_ptr[i]; + if (c == '=') { // padding , end of input + BOOST_ASSERT((base64code2 & 0x03) == 0); + return true; + } + base64code3 = decoding_data[static_cast(input_ptr[i])]; + if (base64code3 == nop) // non base64 character + return false; + + output += (((base64code2 << 6) & 0xc0) | base64code3); + } + } + + return true; +} + +template +bool message_impl::base64_encode( + typename message_impl::string_type const &input, + typename message_impl::string_type &output) { + static const char encoding_data[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + unsigned int input_length = input.size(); + const char *input_ptr = input.data(); + + // allocate space for output string + output.clear(); + output.reserve(((input_length + 2) / 3) * 4); + + // for each 3-bytes sequence from the input, extract 4 6-bits sequences + // and encode using + // encoding_data lookup table. + // if input do not contains enough chars to complete 3-byte sequence,use + // pad char '=' + for (unsigned int i = 0; i < input_length; i++) { + int base64code0 = 0; + int base64code1 = 0; + int base64code2 = 0; + int base64code3 = 0; + + base64code0 = (input_ptr[i] >> 2) & 0x3f; // 1-byte 6 bits + output += encoding_data[base64code0]; + base64code1 = (input_ptr[i] << 4) & 0x3f; // 1-byte 2 bits + + + if (++i < input_length) { + base64code1 |= (input_ptr[i] >> 4) & 0x0f; // 2-byte 4 bits + output += encoding_data[base64code1]; + base64code2 = (input_ptr[i] << 2) & 0x3f; // 2-byte 4 bits + + + if (++i < input_length) { + base64code2 |= (input_ptr[i] >> 6) & 0x03; // 3-byte 2 bits + base64code3 = input_ptr[i] & 0x3f; // 3-byte 6 bits + output += encoding_data[base64code2]; + output += encoding_data[base64code3]; + } else { + output += encoding_data[base64code2]; + output += '='; + } + } else { + output += encoding_data[base64code1]; + output += '='; + output += '='; + } + } + + return true; +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HPP diff --git a/cpp-netlib/boost/network/protocol/http/impl/parser.ipp b/cpp-netlib/boost/network/protocol/http/impl/parser.ipp new file mode 100644 index 00000000..9212d0c6 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/impl/parser.ipp @@ -0,0 +1,807 @@ +// This file is part of the Boost Network library +// Based on the Pion Network Library (r421) +// Copyright Atomic Labs, Inc. 2007-2008 +// See http://cpp-netlib.sourceforge.net for library home page. +// +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +// member functions for class basic_parser + +template +boost::tribool basic_parser::parse_http_headers( + basic_message& http_msg) { + // + // note that boost::tribool may have one of THREE states: + // + // false: encountered an error while parsing HTTP headers + // true: finished successfully parsing the HTTP headers + // indeterminate: parsed bytes, but the HTTP headers are not yet + // finished + // + const char* read_start_ptr = m_read_ptr; + m_bytes_last_read = 0; + while (m_read_ptr < m_read_end_ptr) { + + switch (m_headers_parse_state) { + case PARSE_METHOD_START: + // we have not yet started parsing the HTTP method string + if (*m_read_ptr != ' ' && *m_read_ptr != '\r' && + *m_read_ptr != '\n') { // ignore leading whitespace + if (!is_char(*m_read_ptr) || is_control(*m_read_ptr) || + is_special(*m_read_ptr)) + return false; + m_headers_parse_state = PARSE_METHOD; + m_method.erase(); + m_method.push_back(*m_read_ptr); + } + break; + + case PARSE_METHOD: + // we have started parsing the HTTP method string + if (*m_read_ptr == ' ') { + m_resource.erase(); + m_headers_parse_state = PARSE_URI_STEM; + } else if (!is_char(*m_read_ptr) || is_control(*m_read_ptr) || + is_special(*m_read_ptr)) { + return false; + } else if (m_method.size() >= ParserTraits::METHOD_MAX) { + return false; + } else { + m_method.push_back(*m_read_ptr); + } + break; + + case PARSE_URI_STEM: + // we have started parsing the URI stem (or resource name) + if (*m_read_ptr == ' ') { + m_headers_parse_state = PARSE_HTTP_VERSION_H; + } else if (*m_read_ptr == '?') { + m_query_string.erase(); + m_headers_parse_state = PARSE_URI_QUERY; + } else if (is_control(*m_read_ptr)) { + return false; + } else if (m_resource.size() >= ParserTraits::RESOURCE_MAX) { + return false; + } else { + m_resource.push_back(*m_read_ptr); + } + break; + + case PARSE_URI_QUERY: + // we have started parsing the URI query string + if (*m_read_ptr == ' ') { + m_headers_parse_state = PARSE_HTTP_VERSION_H; + } else if (is_control(*m_read_ptr)) { + return false; + } else if (m_query_string.size() >= ParserTraits::QUERY_STRING_MAX) { + return false; + } else { + m_query_string.push_back(*m_read_ptr); + } + break; + + case PARSE_HTTP_VERSION_H: + // parsing "HTTP" + if (*m_read_ptr != 'H') return false; + m_headers_parse_state = PARSE_HTTP_VERSION_T_1; + break; + + case PARSE_HTTP_VERSION_T_1: + // parsing "HTTP" + if (*m_read_ptr != 'T') return false; + m_headers_parse_state = PARSE_HTTP_VERSION_T_2; + break; + + case PARSE_HTTP_VERSION_T_2: + // parsing "HTTP" + if (*m_read_ptr != 'T') return false; + m_headers_parse_state = PARSE_HTTP_VERSION_P; + break; + + case PARSE_HTTP_VERSION_P: + // parsing "HTTP" + if (*m_read_ptr != 'P') return false; + m_headers_parse_state = PARSE_HTTP_VERSION_SLASH; + break; + + case PARSE_HTTP_VERSION_SLASH: + // parsing slash after "HTTP" + if (*m_read_ptr != '/') return false; + m_headers_parse_state = PARSE_HTTP_VERSION_MAJOR_START; + break; + + case PARSE_HTTP_VERSION_MAJOR_START: + // parsing the first digit of the major version number + if (!is_digit(*m_read_ptr)) return false; + http_msg.setVersionMajor(*m_read_ptr - '0'); + m_headers_parse_state = PARSE_HTTP_VERSION_MAJOR; + break; + + case PARSE_HTTP_VERSION_MAJOR: + // parsing the major version number (not first digit) + if (*m_read_ptr == '.') { + m_headers_parse_state = PARSE_HTTP_VERSION_MINOR_START; + } else if (is_digit(*m_read_ptr)) { + http_msg.setVersionMajor((http_msg.getVersionMajor() * 10) + + (*m_read_ptr - '0')); + } else { + return false; + } + break; + + case PARSE_HTTP_VERSION_MINOR_START: + // parsing the first digit of the minor version number + if (!is_digit(*m_read_ptr)) return false; + http_msg.setVersionMinor(*m_read_ptr - '0'); + m_headers_parse_state = PARSE_HTTP_VERSION_MINOR; + break; + + case PARSE_HTTP_VERSION_MINOR: + // parsing the major version number (not first digit) + if (*m_read_ptr == ' ') { + // should only happen for responses + if (m_is_request) return false; + m_headers_parse_state = PARSE_STATUS_CODE_START; + } else if (*m_read_ptr == '\r') { + // should only happen for requests + if (!m_is_request) return false; + m_headers_parse_state = PARSE_EXPECTING_NEWLINE; + } else if (*m_read_ptr == '\n') { + // should only happen for requests + if (!m_is_request) return false; + m_headers_parse_state = PARSE_EXPECTING_CR; + } else if (is_digit(*m_read_ptr)) { + http_msg.setVersionMinor((http_msg.getVersionMinor() * 10) + + (*m_read_ptr - '0')); + } else { + return false; + } + break; + + case PARSE_STATUS_CODE_START: + // parsing the first digit of the response status code + if (!is_digit(*m_read_ptr)) return false; + m_status_code = (*m_read_ptr - '0'); + m_headers_parse_state = PARSE_STATUS_CODE; + break; + + case PARSE_STATUS_CODE: + // parsing the response status code (not first digit) + if (*m_read_ptr == ' ') { + m_status_message.erase(); + m_headers_parse_state = PARSE_STATUS_MESSAGE; + } else if (is_digit(*m_read_ptr)) { + m_status_code = ((m_status_code * 10) + (*m_read_ptr - '0')); + } else { + return false; + } + break; + + case PARSE_STATUS_MESSAGE: + // parsing the response status message + if (*m_read_ptr == '\r') { + m_headers_parse_state = PARSE_EXPECTING_NEWLINE; + } else if (*m_read_ptr == '\n') { + m_headers_parse_state = PARSE_EXPECTING_CR; + } else if (is_control(*m_read_ptr)) { + return false; + } else if (m_status_message.size() >= + ParserTraits::STATUS_MESSAGE_MAX) { + return false; + } else { + m_status_message.push_back(*m_read_ptr); + } + break; + + case PARSE_EXPECTING_NEWLINE: + // we received a CR; expecting a newline to follow + if (*m_read_ptr == '\n') { + m_headers_parse_state = PARSE_HEADER_START; + } else if (*m_read_ptr == '\r') { + // we received two CR's in a row + // assume CR only is (incorrectly) being used for line + // termination + // therefore, the message is finished + ++m_read_ptr; + m_bytes_last_read = (m_read_ptr - read_start_ptr); + m_bytes_total_read += m_bytes_last_read; + return true; + } else if (*m_read_ptr == '\t' || *m_read_ptr == ' ') { + m_headers_parse_state = PARSE_HEADER_WHITESPACE; + } else if (!is_char(*m_read_ptr) || is_control(*m_read_ptr) || + is_special(*m_read_ptr)) { + return false; + } else { + // assume it is the first character for the name of a header + m_header_name.erase(); + m_header_name.push_back(*m_read_ptr); + m_headers_parse_state = PARSE_HEADER_NAME; + } + break; + + case PARSE_EXPECTING_CR: + // we received a newline without a CR + if (*m_read_ptr == '\r') { + m_headers_parse_state = PARSE_HEADER_START; + } else if (*m_read_ptr == '\n') { + // we received two newlines in a row + // assume newline only is (incorrectly) being used for line + // termination + // therefore, the message is finished + ++m_read_ptr; + m_bytes_last_read = (m_read_ptr - read_start_ptr); + m_bytes_total_read += m_bytes_last_read; + return true; + } else if (*m_read_ptr == '\t' || *m_read_ptr == ' ') { + m_headers_parse_state = PARSE_HEADER_WHITESPACE; + } else if (!is_char(*m_read_ptr) || is_control(*m_read_ptr) || + is_special(*m_read_ptr)) { + return false; + } else { + // assume it is the first character for the name of a header + m_header_name.erase(); + m_header_name.push_back(*m_read_ptr); + m_headers_parse_state = PARSE_HEADER_NAME; + } + break; + + case PARSE_HEADER_WHITESPACE: + // parsing whitespace before a header name + if (*m_read_ptr == '\r') { + m_headers_parse_state = PARSE_EXPECTING_NEWLINE; + } else if (*m_read_ptr == '\n') { + m_headers_parse_state = PARSE_EXPECTING_CR; + } else if (*m_read_ptr != '\t' && *m_read_ptr != ' ') { + if (!is_char(*m_read_ptr) || is_control(*m_read_ptr) || + is_special(*m_read_ptr)) + return false; + // assume it is the first character for the name of a header + m_header_name.erase(); + m_header_name.push_back(*m_read_ptr); + m_headers_parse_state = PARSE_HEADER_NAME; + } + break; + + case PARSE_HEADER_START: + // parsing the start of a new header + if (*m_read_ptr == '\r') { + m_headers_parse_state = PARSE_EXPECTING_FINAL_NEWLINE; + } else if (*m_read_ptr == '\n') { + m_headers_parse_state = PARSE_EXPECTING_FINAL_CR; + } else if (*m_read_ptr == '\t' || *m_read_ptr == ' ') { + m_headers_parse_state = PARSE_HEADER_WHITESPACE; + } else if (!is_char(*m_read_ptr) || is_control(*m_read_ptr) || + is_special(*m_read_ptr)) { + return false; + } else { + // first character for the name of a header + m_header_name.erase(); + m_header_name.push_back(*m_read_ptr); + m_headers_parse_state = PARSE_HEADER_NAME; + } + break; + + case PARSE_HEADER_NAME: + // parsing the name of a header + if (*m_read_ptr == ':') { + m_header_value.erase(); + m_headers_parse_state = PARSE_SPACE_BEFORE_HEADER_VALUE; + } else if (!is_char(*m_read_ptr) || is_control(*m_read_ptr) || + is_special(*m_read_ptr)) { + return false; + } else if (m_header_name.size() >= ParserTraits::HEADER_NAME_MAX) { + return false; + } else { + // character (not first) for the name of a header + m_header_name.push_back(*m_read_ptr); + } + break; + + case PARSE_SPACE_BEFORE_HEADER_VALUE: + // parsing space character before a header's value + if (*m_read_ptr == ' ') { + m_headers_parse_state = PARSE_HEADER_VALUE; + } else if (*m_read_ptr == '\r') { + http_msg.addHeader(m_header_name, m_header_value); + m_headers_parse_state = PARSE_EXPECTING_NEWLINE; + } else if (*m_read_ptr == '\n') { + http_msg.addHeader(m_header_name, m_header_value); + m_headers_parse_state = PARSE_EXPECTING_CR; + } else if (!is_char(*m_read_ptr) || is_control(*m_read_ptr) || + is_special(*m_read_ptr)) { + return false; + } else { + // assume it is the first character for the value of a header + m_header_value.push_back(*m_read_ptr); + m_headers_parse_state = PARSE_HEADER_VALUE; + } + break; + + case PARSE_HEADER_VALUE: + // parsing the value of a header + if (*m_read_ptr == '\r') { + http_msg.addHeader(m_header_name, m_header_value); + m_headers_parse_state = PARSE_EXPECTING_NEWLINE; + } else if (*m_read_ptr == '\n') { + http_msg.addHeader(m_header_name, m_header_value); + m_headers_parse_state = PARSE_EXPECTING_CR; + } else if (is_control(*m_read_ptr)) { + return false; + } else if (m_header_value.size() >= ParserTraits::HEADER_VALUE_MAX) { + return false; + } else { + // character (not first) for the value of a header + m_header_value.push_back(*m_read_ptr); + } + break; + + case PARSE_EXPECTING_FINAL_NEWLINE: + if (*m_read_ptr == '\n') ++m_read_ptr; + m_bytes_last_read = (m_read_ptr - read_start_ptr); + m_bytes_total_read += m_bytes_last_read; + return true; + + case PARSE_EXPECTING_FINAL_CR: + if (*m_read_ptr == '\r') ++m_read_ptr; + m_bytes_last_read = (m_read_ptr - read_start_ptr); + m_bytes_total_read += m_bytes_last_read; + return true; + } + + ++m_read_ptr; + } + + m_bytes_last_read = (m_read_ptr - read_start_ptr); + m_bytes_total_read += m_bytes_last_read; + return boost::indeterminate; +} + +template +boost::tribool basic_parser::parse_chunks( + types::chunk_cache_t& chunk_buffers) { + // + // note that boost::tribool may have one of THREE states: + // + // false: encountered an error while parsing message + // true: finished successfully parsing the message + // indeterminate: parsed bytes, but the message is not yet finished + // + const char* read_start_ptr = m_read_ptr; + m_bytes_last_read = 0; + while (m_read_ptr < m_read_end_ptr) { + + switch (m_chunked_content_parse_state) { + case PARSE_CHUNK_SIZE_START: + // we have not yet started parsing the next chunk size + if (is_hex_digit(*m_read_ptr)) { + m_chunk_size_str.erase(); + m_chunk_size_str.push_back(*m_read_ptr); + m_chunked_content_parse_state = PARSE_CHUNK_SIZE; + } else if (*m_read_ptr == ' ' || *m_read_ptr == '\x09' || + *m_read_ptr == '\x0D' || *m_read_ptr == '\x0A') { + // Ignore leading whitespace. Technically, the standard + // probably doesn't allow white space here, + // but we'll be flexible, since there's no ambiguity. + break; + } else { + return false; + } + break; + + case PARSE_CHUNK_SIZE: + if (is_hex_digit(*m_read_ptr)) { + m_chunk_size_str.push_back(*m_read_ptr); + } else if (*m_read_ptr == '\x0D') { + m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE; + } else if (*m_read_ptr == ' ' || *m_read_ptr == '\x09') { + // Ignore trailing tabs or spaces. Technically, the standard + // probably doesn't allow this, + // but we'll be flexible, since there's no ambiguity. + m_chunked_content_parse_state = PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE; + } else { + return false; + } + break; + + case PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE: + if (*m_read_ptr == '\x0D') { + m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE; + } else if (*m_read_ptr == ' ' || *m_read_ptr == '\x09') { + // Ignore trailing tabs or spaces. Technically, the standard + // probably doesn't allow this, + // but we'll be flexible, since there's no ambiguity. + break; + } else { + return false; + } + break; + + case PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE: + // We received a CR; expecting LF to follow. We can't be flexible + // here because + // if we see anything other than LF, we can't be certain where the + // chunk starts. + if (*m_read_ptr == '\x0A') { + m_bytes_read_in_current_chunk = 0; + m_size_of_current_chunk = strtol(m_chunk_size_str.c_str(), 0, 16); + if (m_size_of_current_chunk == 0) { + m_chunked_content_parse_state = + PARSE_EXPECTING_FINAL_CR_AFTER_LAST_CHUNK; + } else { + m_current_chunk.clear(); + m_chunked_content_parse_state = PARSE_CHUNK; + } + } else { + return false; + } + break; + + case PARSE_CHUNK: + if (m_bytes_read_in_current_chunk < m_size_of_current_chunk) { + m_current_chunk.push_back(*m_read_ptr); + m_bytes_read_in_current_chunk++; + } + if (m_bytes_read_in_current_chunk == m_size_of_current_chunk) { + chunk_buffers.push_back(m_current_chunk); + m_current_chunk.clear(); + m_chunked_content_parse_state = PARSE_EXPECTING_CR_AFTER_CHUNK; + } + break; + + case PARSE_EXPECTING_CR_AFTER_CHUNK: + // we've read exactly m_size_of_current_chunk bytes since starting + // the current chunk + if (*m_read_ptr == '\x0D') { + m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK; + } else { + return false; + } + break; + + case PARSE_EXPECTING_LF_AFTER_CHUNK: + // we received a CR; expecting LF to follow + if (*m_read_ptr == '\x0A') { + m_chunked_content_parse_state = PARSE_CHUNK_SIZE_START; + } else { + return false; + } + break; + + case PARSE_EXPECTING_FINAL_CR_AFTER_LAST_CHUNK: + // we've read the final chunk; expecting final CRLF + if (*m_read_ptr == '\x0D') { + m_chunked_content_parse_state = + PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK; + } else { + return false; + } + break; + + case PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK: + // we received the final CR; expecting LF to follow + if (*m_read_ptr == '\x0A') { + ++m_read_ptr; + m_bytes_last_read = (m_read_ptr - read_start_ptr); + m_bytes_total_read += m_bytes_last_read; + return true; + } else { + return false; + } + } + + ++m_read_ptr; + } + + m_bytes_last_read = (m_read_ptr - read_start_ptr); + m_bytes_total_read += m_bytes_last_read; + return boost::indeterminate; +} + +template +std::size_t basic_parser::consume_content( + basic_message& http_msg) { + // get the payload content length from the HTTP headers + http_msg.updateContentLengthUsingHeader(); + + // read the post content + std::size_t content_bytes_to_read = http_msg.getContentLength(); + char* post_buffer = http_msg.createContentBuffer(); + + if (m_read_ptr < m_read_end_ptr) { + // there are extra bytes left from the last read operation + // copy them into the beginning of the content buffer + const std::size_t bytes_left_in_read_buffer = bytes_available(); + + if (bytes_left_in_read_buffer >= http_msg.getContentLength()) { + // the last read operation included all of the payload content + memcpy(post_buffer, m_read_ptr, http_msg.getContentLength()); + content_bytes_to_read = 0; + m_read_ptr += http_msg.getContentLength(); + } else { + // only some of the post content has been read so far + memcpy(post_buffer, m_read_ptr, bytes_left_in_read_buffer); + content_bytes_to_read -= bytes_left_in_read_buffer; + m_read_ptr = m_read_end_ptr; + } + } + + m_bytes_last_read = (http_msg.getContentLength() - content_bytes_to_read); + m_bytes_total_read += m_bytes_last_read; + return m_bytes_last_read; +} + +template +std::size_t basic_parser::consume_content_as_next_chunk( + types::chunk_cache_t& chunk_buffers) { + if (bytes_available() == 0) { + m_bytes_last_read = 0; + } else { + std::vector next_chunk; + while (m_read_ptr < m_read_end_ptr) { + next_chunk.push_back(*m_read_ptr); + ++m_read_ptr; + } + chunk_buffers.push_back(next_chunk); + m_bytes_last_read = next_chunk.size(); + m_bytes_total_read += m_bytes_last_read; + } + return m_bytes_last_read; +} + +template +void basic_parser::finish(basic_request& http_request) { + http_request.setIsValid(true); + http_request.setMethod(m_method); + http_request.setResource(m_resource); + http_request.setQueryString(m_query_string); + + // parse query pairs from the URI query string + if (!m_query_string.empty()) { + if (!parseURLEncoded(http_request.getQueryParams(), m_query_string.c_str(), + m_query_string.size())) + } + + // parse query pairs from post content (x-www-form-urlencoded) + if (http_request.getHeader(types::HEADER_CONTENT_TYPE) == + types::CONTENT_TYPE_URLENCODED) { + if (!parseURLEncoded(http_request.getQueryParams(), + http_request.getContent(), + http_request.getContentLength())) + } + + // parse "Cookie" headers + std::pair + cookie_pair = http_request.getHeaders().equal_range(types::HEADER_COOKIE); + for (types::headers::const_iterator cookie_iterator = cookie_pair.first; + cookie_iterator != http_request.getHeaders().end() && + cookie_iterator != cookie_pair.second; + ++cookie_iterator) { + if (!parseCookieHeader(http_request.getCookieParams(), + cookie_iterator->second)) + } +} + +template +void basic_parser::finish(basic_response& http_response) { + http_response.setIsValid(true); + http_response.setStatusCode(m_status_code); + http_response.setStatusMessage(m_status_message); +} + +template +inline void basic_parser::reset(void) { + m_headers_parse_state = + (m_is_request ? PARSE_METHOD_START : PARSE_HTTP_VERSION_H); + m_chunked_content_parse_state = PARSE_CHUNK_SIZE_START; + m_status_code = 0; + m_status_message.erase(); + m_method.erase(); + m_resource.erase(); + m_query_string.erase(); + m_current_chunk.clear(); + m_bytes_last_read = m_bytes_total_read = 0; +} + +template +static bool basic_parser::parse_url_encoded( + types::query_params& params, const char* ptr, const std::size_t len) { + // used to track whether we are parsing the name or value + enum query_parse_state_t { + QUERY_PARSE_NAME, + QUERY_PARSE_VALUE + } parse_state = QUERY_PARSE_NAME; + + // misc other variables used for parsing + const char* const end = ptr + len; + string_type query_name; + string_type query_value; + + // iterate through each encoded character + while (ptr < end) { + switch (parse_state) { + + case QUERY_PARSE_NAME: + // parsing query name + if (*ptr == '=') { + // end of name found + if (query_name.empty()) return false; + parse_state = QUERY_PARSE_VALUE; + } else if (*ptr == '&') { + // value is empty (OK) + if (query_name.empty()) return false; + params.insert(std::make_pair(query_name, query_value)); + query_name.erase(); + } else if (is_control(*ptr) || + query_name.size() >= ParserTraits::QUERY_NAME_MAX) { + // control character detected, or max sized exceeded + return false; + } else { + // character is part of the name + query_name.push_back(*ptr); + } + break; + + case QUERY_PARSE_VALUE: + // parsing query value + if (*ptr == '&') { + // end of value found (OK if empty) + params.insert(std::make_pair(query_name, query_value)); + query_name.erase(); + query_value.erase(); + parse_state = QUERY_PARSE_NAME; + } else if (is_control(*ptr) || + query_value.size() >= ParserTraits::QUERY_VALUE_MAX) { + // control character detected, or max sized exceeded + return false; + } else { + // character is part of the value + query_value.push_back(*ptr); + } + break; + } + + ++ptr; + } + + // handle last pair in string + if (!query_name.empty()) + params.insert(std::make_pair(query_name, query_value)); + + return true; +} + +template +static bool basic_parser::parse_cookie_header( + types::cookie_params& params, const string_type& cookie_header) { + // BASED ON RFC 2109 + // + // The current implementation ignores cookie attributes which begin with + // '$' + // (i.e. $Path=/, $Domain=, etc.) + + // used to track what we are parsing + enum cookie_parse_state_t { + COOKIE_PARSE_NAME, + COOKIE_PARSE_VALUE, + COOKIE_PARSE_IGNORE + } parse_state = COOKIE_PARSE_NAME; + + // misc other variables used for parsing + string_type cookie_name; + string_type cookie_value; + char value_quote_character = '\0'; + + // iterate through each character + for (string_type::const_iterator string_iterator = cookie_header.begin(); + string_iterator != cookie_header.end(); ++string_iterator) { + switch (parse_state) { + + case COOKIE_PARSE_NAME: + // parsing cookie name + if (*string_iterator == '=') { + // end of name found + if (cookie_name.empty()) return false; + value_quote_character = '\0'; + parse_state = COOKIE_PARSE_VALUE; + } else if (*string_iterator == ';' || *string_iterator == ',') { + // ignore empty cookie names since this may occur naturally + // when quoted values are encountered + if (!cookie_name.empty()) { + // value is empty (OK) + if (cookie_name[0] != '$') + params.insert(std::make_pair(cookie_name, cookie_value)); + cookie_name.erase(); + } + } else if (*string_iterator != ' ') { // ignore whitespace + // check if control character detected, or max sized exceeded + if (is_control(*string_iterator) || + cookie_name.size() >= ParserTraits::COOKIE_NAME_MAX) + return false; + // character is part of the name + // cookie names are case insensitive -> convert to lowercase + cookie_name.push_back(tolower(*string_iterator)); + } + break; + + case COOKIE_PARSE_VALUE: + // parsing cookie value + if (value_quote_character == '\0') { + // value is not (yet) quoted + if (*string_iterator == ';' || *string_iterator == ',') { + // end of value found (OK if empty) + if (cookie_name[0] != '$') + params.insert(std::make_pair(cookie_name, cookie_value)); + cookie_name.erase(); + cookie_value.erase(); + parse_state = COOKIE_PARSE_NAME; + } else if (*string_iterator == '\'' || *string_iterator == '"') { + if (cookie_value.empty()) { + // begin quoted value + value_quote_character = *string_iterator; + } else if (cookie_value.size() >= ParserTraits::COOKIE_VALUE_MAX) { + // max size exceeded + return false; + } else { + // assume character is part of the (unquoted) value + cookie_value.push_back(*string_iterator); + } + } else if (*string_iterator != ' ') { // ignore unquoted whitespace + // check if control character detected, or max sized exceeded + if (is_control(*string_iterator) || + cookie_value.size() >= ParserTraits::COOKIE_VALUE_MAX) + return false; + // character is part of the (unquoted) value + cookie_value.push_back(*string_iterator); + } + } else { + // value is quoted + if (*string_iterator == value_quote_character) { + // end of value found (OK if empty) + if (cookie_name[0] != '$') + params.insert(std::make_pair(cookie_name, cookie_value)); + cookie_name.erase(); + cookie_value.erase(); + parse_state = COOKIE_PARSE_IGNORE; + } else if (cookie_value.size() >= ParserTraits::COOKIE_VALUE_MAX) { + // max size exceeded + return false; + } else { + // character is part of the (quoted) value + cookie_value.push_back(*string_iterator); + } + } + break; + + case COOKIE_PARSE_IGNORE: + // ignore everything until we reach a comma "," or semicolon ";" + if (*string_iterator == ';' || *string_iterator == ',') + parse_state = COOKIE_PARSE_NAME; + break; + } + } + + // handle last cookie in string + if (!cookie_name.empty() && cookie_name[0] != '$') + params.insert(std::make_pair(cookie_name, cookie_value)); + + return true; +} + +}; // namespace http + +}; // namespace network + +}; // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_IPP diff --git a/cpp-netlib/boost/network/protocol/http/impl/request.hpp b/cpp-netlib/boost/network/protocol/http/impl/request.hpp new file mode 100644 index 00000000..29608f8a --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/impl/request.hpp @@ -0,0 +1,231 @@ + +// Copyright Dean Michael Berris 2007,2009,2010. +// Copyright Michael Dickey 2008. +// 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 __NETWORK_PROTOCOL_HTTP_REQUEST_IMPL_20070908_1_HPP__ +#define __NETWORK_PROTOCOL_HTTP_REQUEST_IMPL_20070908_1_HPP__ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +namespace boost { +namespace network { + +/** Specialize the traits for the http_server tag. */ +template <> +struct headers_container< + http::tags::http_server> : vector:: + apply::type> {}; + +template <> +struct headers_container< + http::tags:: + http_async_server> : vector:: + apply::type> {}; + +namespace http { + +/** request.hpp + * + * This file implements the basic request object required + * by the HTTP client implementation. The basic_request + * object encapsulates a URI which is parsed at runtime. + */ + +template +struct basic_request : public basic_message { + + mutable boost::network::uri::uri uri_; + boost::uint16_t source_port_; + typedef basic_message base_type; + + public: + typedef typename sync_only::type tag; + typedef typename string::type string_type; + typedef boost::uint16_t port_type; + + explicit basic_request(string_type const& uri_) : uri_(uri_), source_port_(0) {} + + explicit basic_request(boost::network::uri::uri const& uri_) : uri_(uri_), source_port_(0) {} + + void uri(string_type const& new_uri) { uri_ = new_uri; } + + void uri(boost::network::uri::uri const& new_uri) { uri_ = new_uri; } + + basic_request() : base_type(), source_port_(0) {} + + basic_request(basic_request const& other) + : base_type(other), uri_(other.uri_), source_port_(other.source_port_) {} + + basic_request& operator=(basic_request rhs) { + rhs.swap(*this); + return *this; + } + + void swap(basic_request& other) { + base_type& base_ref(other); + basic_request& this_ref(*this); + base_ref.swap(this_ref); + boost::swap(other.uri_, this->uri_); + boost::swap(other.source_port_, this->source_port_); + } + + string_type const host() const { return uri_.host(); } + + port_type port() const { + boost::optional port = uri::port_us(uri_); + if (!port) { + typedef constants consts; + return boost::iequals(uri_.scheme(), string_type(consts::https())) ? 443 + : 80; + } + return *port; + } + + string_type const path() const { return uri_.path(); } + + string_type const query() const { return uri_.query(); } + + string_type const anchor() const { return uri_.fragment(); } + + string_type const protocol() const { return uri_.scheme(); } + + void uri(string_type const& new_uri) const { uri_ = new_uri; } + + boost::network::uri::uri const& uri() const { return uri_; } + + void source_port(const boost::uint16_t port) { source_port_ = port; } + + boost::uint16_t source_port() const { return source_port_; } +}; + +/** This is the implementation of a POD request type + * that is specificially used by the HTTP server + * implementation. This fully specializes the + * basic_request template above to be + * primarily and be solely a POD for performance + * reasons. + * + * Reality check: This is not a POD because it contains a non-POD + * member, the headers vector. :( + */ +template +struct not_quite_pod_request_base { + typedef Tag tag; + typedef typename string::type string_type; + typedef typename request_header::type header_type; + typedef typename vector::template apply::type vector_type; + typedef vector_type headers_container_type; + typedef boost::uint16_t port_type; + mutable string_type source; + mutable port_type source_port; + mutable string_type method; + mutable string_type destination; + mutable boost::uint8_t http_version_major; + mutable boost::uint8_t http_version_minor; + mutable vector_type headers; + mutable string_type body; + + void swap(not_quite_pod_request_base& r) const { + using std::swap; + swap(method, r.method); + swap(source, r.source); + swap(source_port, r.source_port); + swap(destination, r.destination); + swap(http_version_major, r.http_version_major); + swap(http_version_minor, r.http_version_minor); + swap(headers, r.headers); + swap(body, r.body); + } +}; + +template <> +struct basic_request : not_quite_pod_request_base< + tags::http_async_server> {}; + +template <> +struct basic_request : not_quite_pod_request_base< + tags::http_server> {}; + +template +struct ServerRequest; + +BOOST_CONCEPT_ASSERT((ServerRequest >)); +BOOST_CONCEPT_ASSERT((ServerRequest >)); + +template +inline void swap(basic_request& lhs, basic_request& rhs) { + lhs.swap(rhs); +} + +} // namespace http + +namespace http { +namespace impl { + +template <> +struct request_headers_wrapper { + basic_request const& request_; + request_headers_wrapper(basic_request const& request_) + : request_(request_) {} + typedef headers_container::type headers_container_type; + operator headers_container_type() { return request_.headers; } +}; + +template <> +struct body_wrapper > { + typedef string::type string_type; + basic_request const& request_; + body_wrapper(basic_request const& request_) + : request_(request_) {} + operator string_type() { return request_.body; } +}; + +template <> +struct request_headers_wrapper { + basic_request const& request_; + request_headers_wrapper( + basic_request const& request_) + : request_(request_) {} + typedef headers_container::type + headers_container_type; + operator headers_container_type() { return request_.headers; } +}; + +template <> +struct body_wrapper > { + typedef string::type string_type; + basic_request const& request_; + body_wrapper(basic_request const& request_) + : request_(request_) {} + operator string_type() { return request_.body; } +}; + +} // namespace impl + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // __NETWORK_PROTOCOL_HTTP_REQUEST_IMPL_20070908_1_HPP__ diff --git a/cpp-netlib/boost/network/protocol/http/impl/request_parser.ipp b/cpp-netlib/boost/network/protocol/http/impl/request_parser.ipp new file mode 100644 index 00000000..e9ac43d5 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/impl/request_parser.ipp @@ -0,0 +1,262 @@ +// +// request_parser.ipp +// ~~~~~~~~~~~~~~~~~~ +// +// Implementation file for the header-only version of the request_parser. +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2009 Dean Michael Berris (mikhailberis@gmail.com) +// Copyright (c) 2009 Tarroo, Inc. +// +// 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 BOOST_NETWORK_HTTP_REQUEST_PARSER_IPP +#define BOOST_NETWORK_HTTP_REQUEST_PARSER_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template +boost::tribool basic_request_parser::consume(basic_request& req, + char input) { + switch (state_) { + case method_start: + if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { + return false; + } else { + state_ = method; + req.method.push_back(input); + return boost::indeterminate; + } + case method: + if (input == ' ') { + state_ = uri; + return boost::indeterminate; + } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { + return false; + } else { + req.method.push_back(input); + return boost::indeterminate; + } + case uri_start: + if (is_ctl(input)) { + return false; + } else { + state_ = uri; + req.destination.push_back(input); + return boost::indeterminate; + } + case uri: + if (input == ' ') { + state_ = http_version_h; + return boost::indeterminate; + } else if (is_ctl(input)) { + return false; + } else { + req.destination.push_back(input); + return boost::indeterminate; + } + case http_version_h: + if (input == 'H') { + state_ = http_version_t_1; + return boost::indeterminate; + } else { + return false; + } + case http_version_t_1: + if (input == 'T') { + state_ = http_version_t_2; + return boost::indeterminate; + } else { + return false; + } + case http_version_t_2: + if (input == 'T') { + state_ = http_version_p; + return boost::indeterminate; + } else { + return false; + } + case http_version_p: + if (input == 'P') { + state_ = http_version_slash; + return boost::indeterminate; + } else { + return false; + } + case http_version_slash: + if (input == '/') { + req.http_version_major = 0; + req.http_version_minor = 0; + state_ = http_version_major_start; + return boost::indeterminate; + } else { + return false; + } + case http_version_major_start: + if (is_digit(input)) { + req.http_version_major = req.http_version_major * 10 + input - '0'; + state_ = http_version_major; + return boost::indeterminate; + } else { + return false; + } + case http_version_major: + if (input == '.') { + state_ = http_version_minor_start; + return boost::indeterminate; + } else if (is_digit(input)) { + req.http_version_major = req.http_version_major * 10 + input - '0'; + return boost::indeterminate; + } else { + return false; + } + case http_version_minor_start: + if (is_digit(input)) { + req.http_version_minor = req.http_version_minor * 10 + input - '0'; + state_ = http_version_minor; + return boost::indeterminate; + } else { + return false; + } + case http_version_minor: + if (input == '\r') { + state_ = expecting_newline_1; + return boost::indeterminate; + } else if (is_digit(input)) { + req.http_version_minor = req.http_version_minor * 10 + input - '0'; + return boost::indeterminate; + } else { + return false; + } + case expecting_newline_1: + if (input == '\n') { + state_ = header_line_start; + return boost::indeterminate; + } else { + return false; + } + case header_line_start: + if (input == '\r') { + state_ = expecting_newline_3; + return boost::indeterminate; + } else if (!req.headers.empty() && (input == ' ' || input == '\t')) { + state_ = header_lws; + return boost::indeterminate; + } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { + return false; + } else { + req.headers.push_back(typename request_header::type()); + req.headers.back().name.push_back(input); + state_ = header_name; + return boost::indeterminate; + } + case header_lws: + if (input == '\r') { + state_ = expecting_newline_2; + return boost::indeterminate; + } else if (input == ' ' || input == '\t') { + return boost::indeterminate; + } else if (is_ctl(input)) { + return false; + } else { + state_ = header_value; + req.headers.back().value.push_back(input); + return boost::indeterminate; + } + case header_name: + if (input == ':') { + state_ = space_before_header_value; + return boost::indeterminate; + } else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) { + return false; + } else { + req.headers.back().name.push_back(input); + return boost::indeterminate; + } + case space_before_header_value: + if (input == ' ') { + state_ = header_value; + return boost::indeterminate; + } else { + return false; + } + case header_value: + if (input == '\r') { + state_ = expecting_newline_2; + return boost::indeterminate; + } else if (is_ctl(input)) { + return false; + } else { + req.headers.back().value.push_back(input); + return boost::indeterminate; + } + case expecting_newline_2: + if (input == '\n') { + state_ = header_line_start; + return boost::indeterminate; + } else { + return false; + } + case expecting_newline_3: + return (input == '\n'); + default: + return false; + } +} + +template +bool basic_request_parser::is_char(int c) { + return c >= 0 && c <= 127; +} + +template +bool basic_request_parser::is_ctl(int c) { + return (c >= 0 && c <= 31) || (c == 127); +} + +template +bool basic_request_parser::is_tspecial(int c) { + switch (c) { + case '(': + case ')': + case '<': + case '>': + case '@': + case ',': + case ';': + case ':': + case '\\': + case '"': + case '/': + case '[': + case ']': + case '?': + case '=': + case '{': + case '}': + case ' ': + case '\t': + return true; + default: + return false; + } +} + +template +bool basic_request_parser::is_digit(int c) { + return c >= '0' && c <= '9'; +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_HTTP_REQUEST_PARSER_IPP diff --git a/cpp-netlib/boost/network/protocol/http/impl/response.ipp b/cpp-netlib/boost/network/protocol/http/impl/response.ipp new file mode 100644 index 00000000..f41be41d --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/impl/response.ipp @@ -0,0 +1,522 @@ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2009 Dean Michael Berris (mikhailberis@gmail.com) +// Copyright (c) 2009 Tarroo, Inc. +// Copyright (c) 2014 Jussi Lyytinen (jussi@lyytinen.org) +// +// 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) +// +// Note: This implementation has significantly changed from the original example +// from a plain header file into a header-only implementation using C++ +// templates +// to reduce the dependence on building an external library. +// + +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_IMPL_RESPONSE_RESPONSE_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_IMPL_RESPONSE_RESPONSE_IPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +/// A reply to be sent to a client. +template <> +struct basic_response { + typedef tags::http_server tag; + typedef response_header::type header_type; + + /*! The status of the reply. Represent all the status codes of HTTP v1.1 + * from http://tools.ietf.org/html/rfc2616#page-39 and + * http://tools.ietf.org/html/rfc6585 + */ + enum status_type { + continue_http = 100, + switching_protocols = 101, + ok = 200, + created = 201, + accepted = 202, + non_authoritative_information = 203, + no_content = 204, + reset_content = 205, + partial_content = 206, + multiple_choices = 300, + moved_permanently = 301, + moved_temporarily = 302, ///< \deprecated Not HTTP standard + found = 302, + see_other = 303, + not_modified = 304, + use_proxy = 305, + temporary_redirect = 307, + bad_request = 400, + unauthorized = 401, + payment_required = 402, + forbidden = 403, + not_found = 404, + not_supported = 405, ///< \deprecated Not HTTP standard + method_not_allowed = 405, + not_acceptable = 406, + proxy_authentication_required = 407, + request_timeout = 408, + conflict = 409, + gone = 410, + length_required = 411, + precondition_failed = 412, + request_entity_too_large = 413, + request_uri_too_large = 414, + unsupported_media_type = 415, + unsatisfiable_range = 416, ///< \deprecated Not HTTP standard + requested_range_not_satisfiable = 416, + expectation_failed = 417, + precondition_required = 428, + too_many_requests = 429, + request_header_fields_too_large = 431, + internal_server_error = 500, + not_implemented = 501, + bad_gateway = 502, + service_unavailable = 503, + gateway_timeout = 504, + http_version_not_supported = 505, + space_unavailable = 507, + network_authentication_required = 511 + } status; + + /// The headers to be included in the reply. + typedef vector::apply::type headers_vector; + headers_vector headers; + + /// The content to be sent in the reply. + typedef string::type string_type; + string_type content; + + /// Convert the reply into a vector of buffers. The buffers do not own + /// the + /// underlying memory blocks, therefore the reply object must remain + /// valid and + /// not be changed until the write operation has completed. + std::vector to_buffers() { + using boost::asio::const_buffer; + using boost::asio::buffer; + static const char name_value_separator[] = {':', ' '}; + static const char crlf[] = {'\r', '\n'}; + std::vector buffers; + buffers.push_back(to_buffer(status)); + for (std::size_t i = 0; i < headers.size(); ++i) { + header_type &h = headers[i]; + buffers.push_back(buffer(h.name)); + buffers.push_back(buffer(name_value_separator)); + buffers.push_back(buffer(h.value)); + buffers.push_back(buffer(crlf)); + } + buffers.push_back(buffer(crlf)); + buffers.push_back(buffer(content)); + return buffers; + } + + /// Get a stock reply. + static basic_response stock_reply(status_type status) { + return stock_reply(status, to_string(status)); + } + + /// Get a stock reply with custom plain text data. + static basic_response stock_reply(status_type status, + string_type content) { + using boost::lexical_cast; + basic_response rep; + rep.status = status; + rep.content = content; + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = lexical_cast(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = "text/html"; + return rep; + } + + /// Swap response objects + void swap(basic_response &r) { + using std::swap; + swap(headers, r.headers); + swap(content, r.content); + } + + private: + static string_type to_string(status_type status) { + switch (status) { + // 2xx Success + case basic_response::ok: + return ""; + case basic_response::created: + return + "" + "Created" + "

201 Created

" + ""; + case basic_response::accepted: + return + "" + "Accepted" + "

202 Accepted

" + ""; + case basic_response::non_authoritative_information: + return + "" + "Non-Authoritative Information" + "

203 Non-Authoritative Information

" + ""; + case basic_response::no_content: + return + "" + "No Content" + "

204 Content

" + ""; + case basic_response::reset_content: + return + "" + "Reset Content" + "

205 Reset Content

" + ""; + case basic_response::partial_content: + return + "" + "Partial Content" + "

206 Partial Content

" + ""; + + // 3xx Redirection + case basic_response::multiple_choices: + return + "" + "Multiple Choices" + "

300 Multiple Choices

" + ""; + case basic_response::moved_permanently: + return + "" + "Moved Permanently" + "

301 Moved Permanently

" + ""; + case basic_response::moved_temporarily: + return + "" + "Moved Temporarily" + "

302 Moved Temporarily

" + ""; + case basic_response::see_other: + return + "" + "See Other" + "

303 See Other

" + ""; + case basic_response::not_modified: + return + "" + "Not Modified" + "

304 Not Modified

" + ""; + case basic_response::use_proxy: + return + "" + "Use Proxy" + "

305 Use Proxy

" + ""; + case basic_response::temporary_redirect: + return + "" + "Temporary Redirect" + "

307 Temporary Redirect

" + ""; + + // 4xx Client Error + case basic_response::bad_request: + return + "" + "Bad Request" + "

400 Bad Request

" + ""; + case basic_response::unauthorized: + return + "" + "Unauthorized" + "

401 Unauthorized

" + ""; + case basic_response::forbidden: + return + "" + "Forbidden" + "

403 Forbidden

" + ""; + case basic_response::not_found: + return + "" + "Not Found" + "

404 Not Found

" + ""; + case basic_response::not_supported: + return + "" + "Method Not Supported" + "

405 Method Not Supported

" + ""; + case basic_response::not_acceptable: + return + "" + "Not Acceptable\r\n" + "

406 Not Acceptable

" + ""; + case basic_response::proxy_authentication_required: + return + "" + "Proxy Authentication Required" + "

407 Proxy Authentication Required

" + ""; + case basic_response::request_timeout: + return + "" + "Request Timeout" + "

408 Request Timeout

" + ""; + case basic_response::conflict: + return + "" + "Conflict" + "

409 Conflict

" + ""; + case basic_response::gone: + return + "" + "Gone" + "

410 Gone

" + ""; + case basic_response::length_required: + return + "" + "Length Required" + "

411 Length Required

" + ""; + case basic_response::precondition_failed: + return + "" + "Precondition Failed" + "

412 Precondition Failed

" + ""; + case basic_response::request_entity_too_large: + return + "" + "Request Entity Too Large" + "

413 Request Entity Too Large

" + ""; + case basic_response::request_uri_too_large: + return + "" + "Request-URI Too Large" + "

414 Request-URI Too Large

" + ""; + case basic_response::unsupported_media_type: + return + "" + "Unsupported Media Type" + "

415 Unsupported Media Type

" + ""; + case basic_response::unsatisfiable_range: + return + "" + "Unsatisfiable Range" + "

416 Requested Range Not " + "Satisfiable

" + ""; + case basic_response::expectation_failed: + return + "" + "Expectation Failed" + "

417 Expectation Failed

" + ""; + case basic_response::precondition_required: + return + "" + "Precondition Required" + "

428 Precondition Required

" + ""; + case basic_response::too_many_requests: + return + "" + "Too Many Requests" + "

429 Too Many Requests

" + ""; + case basic_response::request_header_fields_too_large: + return + "" + "Request Header Fields Too Large" + "

431 Request Header Fields Too Large

" + ""; + + // 5xx Server Error + case basic_response::internal_server_error: + return + "" + "Internal Server Error" + "

500 Internal Server Error

" + ""; + case basic_response::not_implemented: + return + "" + "Not Implemented" + "

501 Not Implemented

" + ""; + case basic_response::bad_gateway: + return + "" + "Bad Gateway" + "

502 Bad Gateway

" + ""; + case basic_response::service_unavailable: + return + "" + "Service Unavailable" + "

503 Service Unavailable

" + ""; + case basic_response::gateway_timeout: + return + "" + "Gateway Timeout" + "

504 Gateway Timeout

" + ""; + case basic_response::http_version_not_supported: + return + "" + "HTTP Version Not Supported" + "

505 HTTP Version Not Supported

" + ""; + case basic_response::space_unavailable: + return + "" + "Space Unavailable" + "

507 Insufficient Space to Store " + "Resource

" + ""; + + default: + return + "" + "Internal Server Error" + "

500 Internal Server Error

" + ""; + } + } + + boost::asio::const_buffer trim_null(boost::asio::const_buffer buffer) { + std::size_t size = boost::asio::buffer_size(buffer); + return boost::asio::buffer(buffer, size - 1); + } + + boost::asio::const_buffer to_buffer(status_type status) { + using boost::asio::buffer; + switch (status) { + // 2xx Success + case basic_response::ok: + return trim_null(buffer("HTTP/1.1 200 OK\r\n")); + case basic_response::created: + return trim_null(buffer("HTTP/1.1 201 Created\r\n")); + case basic_response::accepted: + return trim_null(buffer("HTTP/1.1 202 Accepted\r\n")); + case basic_response::non_authoritative_information: + return trim_null(buffer("HTTP/1.1 203 Non-Authoritative Information\r\n")); + case basic_response::no_content: + return trim_null(buffer("HTTP/1.1 204 No Content\r\n")); + case basic_response::reset_content: + return trim_null(buffer("HTTP/1.1 205 Reset Content\r\n")); + case basic_response::partial_content: + return trim_null(buffer("HTTP/1.1 206 Partial Content\r\n")); + + // 3xx Redirection + case basic_response::multiple_choices: + return trim_null(buffer("HTTP/1.1 300 Multiple Choices\r\n")); + case basic_response::moved_permanently: + return trim_null(buffer("HTTP/1.1 301 Moved Permanently\r\n")); + case basic_response::moved_temporarily: + return trim_null(buffer("HTTP/1.1 302 Moved Temporarily\r\n")); + case basic_response::see_other: + return trim_null(buffer("HTTP/1.1 303 See Other\r\n")); + case basic_response::not_modified: + return trim_null(buffer("HTTP/1.1 304 Not Modified\r\n")); + case basic_response::use_proxy: + return trim_null(buffer("HTTP/1.1 305 Use Proxy\r\n")); + case basic_response::temporary_redirect: + return trim_null(buffer("HTTP/1.1 307 Temporary Redirect\r\n")); + + // 4xx Client Error + case basic_response::bad_request: + return trim_null(buffer("HTTP/1.1 400 Bad Request\r\n")); + case basic_response::unauthorized: + return trim_null(buffer("HTTP/1.1 401 Unauthorized\r\n")); + case basic_response::forbidden: + return trim_null(buffer("HTTP/1.1 403 Forbidden\r\n")); + case basic_response::not_found: + return trim_null(buffer("HTTP/1.1 404 Not Found\r\n")); + case basic_response::not_supported: + return trim_null(buffer("HTTP/1.1 405 Method Not Supported\r\n")); + case basic_response::not_acceptable: + return trim_null(buffer("HTTP/1.1 406 Method Not Acceptable\r\n")); + case basic_response::proxy_authentication_required: + return trim_null(buffer("HTTP/1.1 407 Proxy Authentication Required\r\n")); + case basic_response::request_timeout: + return trim_null(buffer("HTTP/1.1 408 Request Timeout\r\n")); + case basic_response::conflict: + return trim_null(buffer("HTTP/1.1 409 Conflict\r\n")); + case basic_response::gone: + return trim_null(buffer("HTTP/1.1 410 Gone\r\n")); + case basic_response::length_required: + return trim_null(buffer("HTTP/1.1 411 Length Required\r\n")); + case basic_response::precondition_failed: + return trim_null(buffer("HTTP/1.1 412 Precondition Failed\r\n")); + case basic_response::request_entity_too_large: + return trim_null(buffer("HTTP/1.1 413 Request Entity Too Large\r\n")); + case basic_response::request_uri_too_large: + return trim_null(buffer("HTTP/1.1 414 Request-URI Too Large\r\n")); + case basic_response::unsupported_media_type: + return trim_null(buffer("HTTP/1.1 415 Unsupported Media Type\r\n")); + case basic_response::unsatisfiable_range: + return trim_null(buffer("HTTP/1.1 416 Requested Range Not Satisfiable\r\n")); + case basic_response::precondition_required: + return trim_null(buffer("HTTP/1.1 428 Precondition Required\r\n")); + case basic_response::too_many_requests: + return trim_null(buffer("HTTP/1.1 429 Too Many Requests\r\n")); + case basic_response::request_header_fields_too_large: + return trim_null(buffer("HTTP/1.1 431 Request Header Fields Too Large\r\n")); + + // 5xx Server Error + case basic_response::internal_server_error: + return trim_null(buffer("HTTP/1.1 500 Internal Server Error\r\n")); + case basic_response::not_implemented: + return trim_null(buffer("HTTP/1.1 501 Not Implemented\r\n")); + case basic_response::bad_gateway: + return trim_null(buffer("HTTP/1.1 502 Bad Gateway\r\n")); + case basic_response::service_unavailable: + return trim_null(buffer("HTTP/1.1 503 Service Unavailable\r\n")); + case basic_response::gateway_timeout: + return trim_null(buffer("HTTP/1.1 504 Gateway Timeout\r\n")); + case basic_response::http_version_not_supported: + return trim_null(buffer("HTTP/1.1 505 HTTP Version Not Supported\r\n")); + case basic_response::space_unavailable: + return trim_null(buffer("HTTP/1.1 507 Insufficient Space to Store Resource\r\n")); + + default: + return trim_null(buffer("HTTP/1.1 500 Internal Server Error\r\n")); + } + } +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_IMPL_RESPONSE_RESPONSE_IPP diff --git a/cpp-netlib/boost/network/protocol/http/message.hpp b/cpp-netlib/boost/network/protocol/http/message.hpp new file mode 100644 index 00000000..fa2d44ce --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message.hpp @@ -0,0 +1,137 @@ +// This file is part of the Boost Network library +// Based on the Pion Network Library (r421) +// Copyright Atomic Labs, Inc. 2007-2008 +// See http://cpp-netlib.sourceforge.net for library home page. +// +// 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) +// +// Some changes Copyright (c) Dean Michael Berris 2008 + +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +/// base class for HTTP messages (requests and responses) +template +struct message_impl : public basic_message { + + typedef typename string::type string_type; + + /// escapes URL-encoded strings (a%20value+with%20spaces) + static string_type const url_decode(string_type const &str); + + /// encodes strings so that they are safe for URLs (with%20spaces) + static string_type const url_encode(string_type const &str); + + /// builds an HTTP query string from a collection of query parameters + static string_type const make_query_string( + typename query_container::type const &query_params); + + /** + * creates a "Set-Cookie" header + * + * @param name the name of the cookie + * @param value the value of the cookie + * @param path the path of the cookie + * @param has_max_age true if the max_age value should be set + * @param max_age the life of the cookie, in seconds (0 = discard) + * + * @return the new "Set-Cookie" header + */ + static string_type const make_set_cookie_header( + string_type const &name, string_type const &value, + string_type const &path, bool const has_max_age = false, + unsigned long const max_age = 0); + + /** decodes base64-encoded strings + * + * @param input base64 encoded string + * @param output decoded string ( may include non-text chars) + * @return true if successful, false if input string contains non-base64 + *symbols + */ + static bool base64_decode(string_type const &input, string_type &output); + + /** encodes strings using base64 + * + * @param input arbitrary string ( may include non-text chars) + * @param output base64 encoded string + * @return true if successful + */ + static bool base64_encode(string_type const &input, string_type &output); + + protected: + mutable string_type version_; + mutable boost::uint16_t status_; + mutable string_type status_message_; + + private: + typedef basic_message base_type; + + public: + message_impl() : base_type(), version_(), status_(0u), status_message_() {} + + message_impl(message_impl const &other) + : base_type(other), + version_(other.version_), + status_(other.status_), + status_message_(other.status_message_) {} + + void version(string_type const &version) const { version_ = version; } + + string_type const version() const { return version_; } + + void status(boost::uint16_t status) const { status_ = status; } + + boost::uint16_t status() const { return status_; } + + void status_message(string_type const &status_message) const { + status_message_ = status_message; + } + + string_type const status_message() const { return status_message_; } + + message_impl &operator=(message_impl rhs) { + rhs.swap(*this); + return *this; + } + + void swap(message_impl &other) { + base_type &base_ref(other), &this_ref(*this); + std::swap(this_ref, base_ref); + std::swap(status_, other.status_); + std::swap(status_message_, other.status_message_); + std::swap(version_, other.version_); + } +}; + +template +inline void swap(message_impl &lhs, message_impl &rhs) { + lhs.swap(rhs); +} + +typedef message_impl message; + +} // namespace http + +} // namespace network + +} // namespace boost + +// import implementation file +#include + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HPP diff --git a/cpp-netlib/boost/network/protocol/http/message/async_message.hpp b/cpp-netlib/boost/network/protocol/http/message/async_message.hpp new file mode 100644 index 00000000..854c7075 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/async_message.hpp @@ -0,0 +1,158 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_ASYNC_MESSAGE_HPP_20100622 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_ASYNC_MESSAGE_HPP_20100622 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 +#include +#include + +// FIXME move this out to a trait +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +namespace impl { + +template +struct ready_wrapper; + +} /* impl */ + +template +struct async_message { + + typedef typename string::type string_type; + typedef typename headers_container::type headers_container_type; + typedef typename headers_container_type::value_type header_type; + + async_message() + : status_message_(), + version_(), + source_(), + destination_(), + status_(), + headers_(), + body_() {} + + async_message(async_message const& other) + : status_message_(other.status_message_), + version_(other.version_), + source_(other.source_), + destination_(other.destination_), + status_(other.status_), + headers_(other.headers_), + body_(other.body_) {} + + string_type const status_message() const { return status_message_.get(); } + + void status_message(boost::shared_future const& future) const { + status_message_ = future; + } + + string_type const version() const { return version_.get(); } + + void version(boost::shared_future const& future) const { + version_ = future; + } + + boost::uint16_t status() const { return status_.get(); } + + void status(boost::shared_future const& future) const { + status_ = future; + } + + string_type const source() const { return source_.get(); } + + void source(boost::shared_future const& future) const { + source_ = future; + } + + string_type const destination() const { return destination_.get(); } + + void destination(boost::shared_future const& future) const { + destination_ = future; + } + + headers_container_type const& headers() const { + if (retrieved_headers_) return *retrieved_headers_; + headers_container_type raw_headers = headers_.get(); + raw_headers.insert(added_headers.begin(), added_headers.end()); + BOOST_FOREACH(string_type const & key, removed_headers) { + raw_headers.erase(key); + } + retrieved_headers_ = raw_headers; + return *retrieved_headers_; + } + + void headers(boost::shared_future const& future) + const { + headers_ = future; + } + + void add_header(typename headers_container_type::value_type const& pair_) + const { + added_headers.insert(added_headers.end(), pair_); + } + + void remove_header(typename headers_container_type::key_type const& key_) + const { + removed_headers.insert(key_); + } + + string_type const body() const { return body_.get(); } + + void body(boost::shared_future const& future) const { + body_ = future; + } + + void swap(async_message& other) { + std::swap(status_message_, other.status_message_); + std::swap(status_, other.status_); + std::swap(version_, other.version_); + std::swap(source_, other.source_); + std::swap(destination_, other.destination_); + std::swap(headers_, other.headers_); + std::swap(body_, other.body_); + } + + async_message& operator=(async_message other) { + other.swap(*this); + return *this; + } + + private: + mutable boost::shared_future status_message_, version_, source_, + destination_; + mutable boost::shared_future status_; + mutable boost::shared_future headers_; + mutable headers_container_type added_headers; + mutable std::set removed_headers; + mutable boost::shared_future body_; + mutable boost::optional retrieved_headers_; + + friend struct boost::network::http::impl::ready_wrapper; +}; + +template +inline void swap(async_message& lhs, async_message& rhs) { + lhs.swap(rhs); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_ASYNC_MESSAGE_HPP_20100622 diff --git a/cpp-netlib/boost/network/protocol/http/message/directives/major_version.hpp b/cpp-netlib/boost/network/protocol/http/message/directives/major_version.hpp new file mode 100644 index 00000000..7828b04f --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/directives/major_version.hpp @@ -0,0 +1,41 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_MAJOR_VERSION_HPP_20101120 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_MAJOR_VERSION_HPP_20101120 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +struct major_version_directive { + boost::uint8_t major_version; + explicit major_version_directive(boost::uint8_t major_version) + : major_version(major_version) {} + template + void operator()(basic_request& request) const { + request.http_version_major = major_version; + } +}; + +inline major_version_directive major_version(boost::uint8_t major_version_) { + return major_version_directive(major_version_); +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_MAJOR_VERSION_HPP_20101120 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/message/directives/method.hpp b/cpp-netlib/boost/network/protocol/http/message/directives/method.hpp new file mode 100644 index 00000000..b9e2c1df --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/directives/method.hpp @@ -0,0 +1,23 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_METHOD_HPP_20101120 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_METHOD_HPP_20101120 + +// Copyright 2010 Dean Michael Berris. +// 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) + +namespace boost { +namespace network { +namespace http { + +BOOST_NETWORK_STRING_DIRECTIVE(method, method_, message.method(method_), + message.method = method_); + +} /* http */ + +} /* network */ + +} /* booet */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_METHOD_HPP_20101120 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/message/directives/minor_version.hpp b/cpp-netlib/boost/network/protocol/http/message/directives/minor_version.hpp new file mode 100644 index 00000000..4c44414c --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/directives/minor_version.hpp @@ -0,0 +1,41 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_MINOR_VERSION_HPP_20101120 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_MINOR_VERSION_HPP_20101120 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +struct minor_version_directive { + boost::uint8_t minor_version; + explicit minor_version_directive(boost::uint8_t minor_version) + : minor_version(minor_version) {} + template + void operator()(basic_request& request) const { + request.http_version_minor = minor_version; + } +}; + +inline minor_version_directive minor_version(boost::uint8_t minor_version_) { + return minor_version_directive(minor_version_); +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_MINOR_VERSION_HPP_20101120 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/message/directives/status.hpp b/cpp-netlib/boost/network/protocol/http/message/directives/status.hpp new file mode 100644 index 00000000..61a41e45 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/directives/status.hpp @@ -0,0 +1,76 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_STATUS_HPP_20100603 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_STATUS_HPP_20100603 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +struct status_directive { + + boost::variant > + status_; + + explicit status_directive(boost::uint16_t status) : status_(status) {} + + explicit status_directive(boost::shared_future const &status) + : status_(status) {} + + status_directive(status_directive const &other) : status_(other.status_) {} + + template + struct value : mpl::if_, boost::shared_future, + boost::uint16_t> {}; + + template + struct status_visitor : boost::static_visitor<> { + basic_response const &response; + status_visitor(basic_response const &response) : response(response) {} + + void operator()(typename value::type const &status_) const { + response.status(status_); + } + + template + void operator()(T const &) const { + // FIXME fail here! + } + }; + + template + basic_response const &operator()(basic_response const &response) + const { + apply_visitor(status_visitor(response), status_); + return response; + } +}; + +template +inline status_directive const status(T const &status_) { + return status_directive(status_); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_STATUS_HPP_20100603 diff --git a/cpp-netlib/boost/network/protocol/http/message/directives/status_message.hpp b/cpp-netlib/boost/network/protocol/http/message/directives/status_message.hpp new file mode 100644 index 00000000..2e437ec1 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/directives/status_message.hpp @@ -0,0 +1,27 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_STATUS_MESSAGE_HPP_20100603 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_STATUS_MESSAGE_HPP_20100603 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +BOOST_NETWORK_STRING_DIRECTIVE(status_message, status_message_, + message.status_message(status_message_), + message.status_message = status_message_); + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_STATUS_MESSAGE_HPP_20100603 diff --git a/cpp-netlib/boost/network/protocol/http/message/directives/uri.hpp b/cpp-netlib/boost/network/protocol/http/message/directives/uri.hpp new file mode 100644 index 00000000..1a411426 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/directives/uri.hpp @@ -0,0 +1,26 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_URI_HPP_20100620 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_URI_HPP_20100620 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +BOOST_NETWORK_STRING_DIRECTIVE(uri, uri_, message.uri(uri_), + message.uri = uri_); + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_URI_HPP_20100620 diff --git a/cpp-netlib/boost/network/protocol/http/message/directives/version.hpp b/cpp-netlib/boost/network/protocol/http/message/directives/version.hpp new file mode 100644 index 00000000..16c3115d --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/directives/version.hpp @@ -0,0 +1,26 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_VERSION_HPP_20100603 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_VERSION_HPP_20100603 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +BOOST_NETWORK_STRING_DIRECTIVE(version, version_, message.version(version_), + message.version = version_); + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DIRECTIVES_VERSION_HPP_20100603 diff --git a/cpp-netlib/boost/network/protocol/http/message/header.hpp b/cpp-netlib/boost/network/protocol/http/message/header.hpp new file mode 100644 index 00000000..5be2ad80 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/header.hpp @@ -0,0 +1,99 @@ +// +// header.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2009,2010 Dean Michael Berris (mikhailberis@gmail.com) +// Copyright (c) 2009 Tarroo, Inc. +// +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_HPP_20101122 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_HPP_20101122 + +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct unsupported_tag; + +struct request_header_narrow { + typedef std::string string_type; + std::string name, value; +}; + +struct request_header_wide { + typedef std::wstring string_type; + std::wstring name, value; +}; + +template +struct request_header + : mpl::if_, request_header_narrow, + typename mpl::if_, request_header_wide, + unsupported_tag >::type> {}; + +inline void swap(request_header_narrow& l, request_header_narrow& r) { + swap(l.name, r.name); + swap(l.value, r.value); +} + +inline void swap(request_header_wide& l, request_header_wide& r) { + swap(l.name, r.name); + swap(l.value, r.value); +} + +struct response_header_narrow { + typedef std::string string_type; + std::string name, value; +}; + +struct response_header_wide { + typedef std::wstring string_type; + std::wstring name, value; +}; + +template +struct response_header + : mpl::if_, response_header_narrow, + typename mpl::if_, response_header_wide, + unsupported_tag >::type> {}; + +inline void swap(response_header_narrow& l, response_header_narrow& r) { + std::swap(l.name, r.name); + std::swap(l.value, r.value); +} + +inline void swap(response_header_wide& l, response_header_wide& r) { + std::swap(l.name, r.name); + std::swap(l.value, r.value); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +BOOST_FUSION_ADAPT_STRUCT(boost::network::http::request_header_narrow, + (std::string, name)(std::string, value)) + +BOOST_FUSION_ADAPT_STRUCT(boost::network::http::request_header_wide, + (std::wstring, name)(std::wstring, value)) + +BOOST_FUSION_ADAPT_STRUCT(boost::network::http::response_header_narrow, + (std::string, name)(std::string, value)) + +BOOST_FUSION_ADAPT_STRUCT(boost::network::http::response_header_wide, + (std::wstring, name)(std::wstring, value)) + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_HPP_20101122 diff --git a/cpp-netlib/boost/network/protocol/http/message/header/name.hpp b/cpp-netlib/boost/network/protocol/http/message/header/name.hpp new file mode 100644 index 00000000..a5f6dee2 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/header/name.hpp @@ -0,0 +1,41 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_NAME_HPP_20101028 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_NAME_HPP_20101028 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +T1 &name(std::pair const &p) { + return p.first; +} + +inline std::string const &name(request_header_narrow const &h) { + return h.name; +} + +inline std::wstring const &name(request_header_wide const &h) { return h.name; } + +inline std::string const &name(response_header_narrow const &h) { + return h.name; +} + +inline std::wstring const &name(response_header_wide const &h) { + return h.name; +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_NAME_HPP_20101028 */ diff --git a/cpp-netlib/boost/network/protocol/http/message/header/value.hpp b/cpp-netlib/boost/network/protocol/http/message/header/value.hpp new file mode 100644 index 00000000..dd581d00 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/header/value.hpp @@ -0,0 +1,51 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_VALUE_HPP_20101028 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_VALUE_HPP_20101028 + +// Copyright 2010 Dean Michael Berris. +// 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 + +namespace boost { +namespace network { +namespace http { + +struct request_header_narrow; +struct request_header_wide; +struct response_header_narrow; +struct response_header_wide; + +template +T1& value(std::pair const& p) { + return p.second; +} + +inline request_header_narrow::string_type const& value( + request_header_narrow const& h) { + return h.value; +} + +inline request_header_wide::string_type const& value( + request_header_wide const& h) { + return h.value; +} + +inline response_header_narrow::string_type const& value( + response_header_narrow const& h) { + return h.value; +} + +inline response_header_wide::string_type const& value( + response_header_wide const& h) { + return h.value; +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_VALUE_HPP_20101028 */ diff --git a/cpp-netlib/boost/network/protocol/http/message/header_concept.hpp b/cpp-netlib/boost/network/protocol/http/message/header_concept.hpp new file mode 100644 index 00000000..f3134e25 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/header_concept.hpp @@ -0,0 +1,38 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_CONCEPT_HPP_20101028 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_CONCEPT_HPP_20101028 + +// Copyright 2010 Dean Michael Berris. +// 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 + +namespace boost { +namespace network { +namespace http { + +template +struct Header : DefaultConstructible, Assignable, CopyConstructible { + + BOOST_CONCEPT_USAGE(Header) { + typedef typename H::string_type string_type; + string_type name_ = name(header); + string_type value_ = value(header); + H h1, h2; + swap(h1, h2); // ADL Swap! + (void)name_; + (void)value_; + } + + private: + H header; +}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HEADER_CONCEPT_HPP_20101028 */ diff --git a/cpp-netlib/boost/network/protocol/http/message/message_base.hpp b/cpp-netlib/boost/network/protocol/http/message/message_base.hpp new file mode 100644 index 00000000..39376531 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/message_base.hpp @@ -0,0 +1,33 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_BASE_HPP_20100603 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_BASE_HPP_20100603 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct async_message; + +template +struct message_impl; + +template +struct message_base + : mpl::if_, async_message, message_impl > {}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_BASE_HPP_20100603 diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/body.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/body.hpp new file mode 100644 index 00000000..dd1c7430 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/body.hpp @@ -0,0 +1,77 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_BODY_HPP_20100624 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_BODY_HPP_20100624 + +// Copyright 2010 (C) Dean Michael Berris +// 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 +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +template +struct basic_request; + +namespace impl { + +template +void body(basic_response &response, T const &value, mpl::false_ const &) { + response << ::boost::network::body(value); +} + +template +void body(basic_response &response, T const &future, mpl::true_ const &) { + response.body(future); +} +} + +template +inline void body(basic_response &response, T const &value) { + impl::body(response, value, is_async()); +} + +template +inline void body_impl(basic_request &request, T const &value, + tags::server) { + request.body = value; +} + +template +inline void body_impl(basic_request &request, T const &value, + tags::client) { + request << ::boost::network::body(value); +} + +template +inline void body(basic_request &request, T const &value) { + body_impl(request, value, typename client_or_server::type()); +} + +} // namespace http + +namespace impl { + +template +inline void body(Message const &message, ValueType const &body_, + http::tags::http_server, Async) { + message.body = body_; +} + +} /* impl */ + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_BODY_HPP_20100624 diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/clear_headers.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/clear_headers.hpp new file mode 100644 index 00000000..b723bb04 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/clear_headers.hpp @@ -0,0 +1,52 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_CLEAR_HEADER_HPP_20101128 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_CLEAR_HEADER_HPP_20101128 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +inline void clear_headers_impl(basic_request& request, tags::pod) { + typedef typename basic_request::headers_container_type headers_container; + headers_container().swap(request.headers); +} + +template +inline void clear_headers_impl(basic_request& request, tags::normal) { + request.headers(typename basic_request::headers_container_type()); +} + +template +inline void clear_headers_impl(basic_request& request, tags::client) { + clear_headers_impl(request, typename pod_or_normal::type()); +} + +template +inline void clear_headers_impl(basic_request& request, tags::server) { + typedef typename basic_request::headers_container_type headers_container; + headers_container().swap(request.headers); +} + +template +inline void clear_headers(basic_request& request) { + clear_headers_impl(request, typename client_or_server::type()); +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_CLEAR_HEADER_HPP_20101128 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/destination.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/destination.hpp new file mode 100644 index 00000000..902d7bd1 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/destination.hpp @@ -0,0 +1,95 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_DESTINATION_HPP_20100624 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_DESTINATION_HPP_20100624 + +// Copyright 2010 (C) Dean Michael Berris +// 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 +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +template +struct basic_request; + +namespace impl { + +template +void destination(basic_response &response, T const &value, + mpl::false_ const &) { + response << ::boost::network::destination(value); +} + +template +void destination(basic_response &response, T const &future, + mpl::true_ const &) { + response.destination(future); +} +} + +template +inline void destination(basic_response &response, T const &value) { + impl::destination(response, value, is_async()); +} + +template +struct ServerRequest; + +template +inline void destination_impl(basic_request &request, T const &value, + tags::server) { + request.destination = value; +} + +template +inline void destination_impl(basic_request &request, T const &value, + tags::pod) { + request.destination = value; +} + +template +inline void destination_impl(basic_request &request, T const &value, + tags::normal) { + request.destination(value); +} + +template +inline void destination_impl(basic_request &request, T const &value, + tags::client) { + destination_impl(request, value, typename pod_or_normal::type()); +} + +template +inline void destination(basic_request &request, T const &value) { + destination_impl(request, value, typename client_or_server::type()); +} + +} // namespace http + +namespace impl { + +template +inline void destination(Message const &message, ValueType const &destination_, + http::tags::http_server, Async) { + message.destination = destination_; +} + +} /* impl */ + +} // namespace network + +} // namespace boost + +#include + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_DESTINATION_HPP_20100624 diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/headers.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/headers.hpp new file mode 100644 index 00000000..90354941 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/headers.hpp @@ -0,0 +1,60 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_HEADERS_HPP_20100624 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_HEADERS_HPP_20100624 + +// Copyright 2010 (C) Dean Michael Berris +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +template +struct basic_request; + +namespace impl { + +template +void headers(basic_response &response, T const &value, + mpl::false_ const &) { + response << headers(value); +} + +template +void headers(basic_response &response, T const &future, + mpl::true_ const &) { + response.headers(future); +} + +template +void headers(basic_request &request, T const &value, + tags::server const &) { + request.headers = value; +} +} + +template +inline void headers(basic_response &response, T const &value) { + impl::headers(response, value, is_async()); +} + +template +inline void headers(basic_request &request, T const &value) { + impl::headers(request, value, Tag()); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_HEADERS_HPP_20100624 diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/major_version.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/major_version.hpp new file mode 100644 index 00000000..fbe60eb6 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/major_version.hpp @@ -0,0 +1,33 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_MAJOR_VERSION_HPP_20101120 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_MAJOR_VERSION_HPP_20101120 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +template +inline typename enable_if, void>::type major_version( + basic_request& request, boost::uint8_t major_version_) { + request.http_version_major = major_version_; +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_MAJOR_VERSION_HPP_20101120 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/method.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/method.hpp new file mode 100644 index 00000000..8aeab4ce --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/method.hpp @@ -0,0 +1,31 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_METHOD_HPP_20101118 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_METHOD_HPP_20101118 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +template +inline typename enable_if, void>::type method( + basic_request& request, typename string::type const& method_) { + request.method = method_; +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_METHOD_HPP_20101118 */ diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/minor_version.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/minor_version.hpp new file mode 100644 index 00000000..0850ba92 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/minor_version.hpp @@ -0,0 +1,33 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_MINOR_VERSION_HPP_20101120 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_MINOR_VERSION_HPP_20101120 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +template +inline typename enable_if, void>::type minor_version( + basic_request& request, boost::uint8_t minor_version_) { + request.http_version_minor = minor_version_; +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_MINOR_VERSION_HPP_20101120 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/source.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/source.hpp new file mode 100644 index 00000000..396b69fa --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/source.hpp @@ -0,0 +1,87 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_SOURCE_HPP_20100624 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_SOURCE_HPP_20100624 + +// Copyright 2010 (C) Dean Michael Berris +// 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 +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +namespace impl { + +template +void source(basic_response &response, T const &value, + mpl::false_ const &) { + response << ::boost::network::source(value); +} + +template +void source(basic_response &response, T const &future, + mpl::true_ const &) { + response.source(future); +} + +template +void source(basic_request &request, T const &value, tags::server const &) { + request.source = value; +} + +template +void source(basic_request &request, T const &value, tags::client const &) { + request << ::boost::network::source(value); +} +} + +template +inline void source(basic_response &response, T const &value) { + impl::source(response, value, is_async()); +} + +template +inline void source_impl(basic_request &request, T const &value, + tags::server) { + impl::source(request, value, Tag()); +} + +template +inline void source_impl(basic_request &request, T const &value, + tags::client) { + impl::source(request, value, Tag()); +} + +template +inline void source(basic_request &request, T const &value) { + source_impl(request, value, typename client_or_server::type()); +} + +} // namespace http + +namespace impl { + +template +inline void source(Message const &message, ValueType const &source_, + http::tags::http_server const &, Async const &) { + message.source = source_; +} + +} /* impl */ + +} // namespace network + +} // namespace boost + +#include +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_SOURCE_HPP_20100624 diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/status.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/status.hpp new file mode 100644 index 00000000..27a774be --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/status.hpp @@ -0,0 +1,47 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_STATUS_HPP_20100608 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_STATUS_HPP_20100608 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +namespace impl { + +template +void status(basic_response &response, T const &value, + mpl::false_ const &) { + response << boost::network::http::status(value); +} + +template +void status(basic_response &response, T const &future, + mpl::true_ const &) { + response.status(future); +} + +} // namespace impl + +template +void status(basic_response &response, T const &value) { + impl::status(response, value, is_async()); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_STATUS_HPP_20100608 diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/status_message.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/status_message.hpp new file mode 100644 index 00000000..75016305 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/status_message.hpp @@ -0,0 +1,47 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_STATUS_MESSAGE_HPP_20100608 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_STATUS_MESSAGE_HPP_20100608 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +namespace impl { + +template +void status_message(basic_response &response, T const &value, + mpl::false_ const &) { + response << boost::network::http::status_message(value); +} + +template +void status_message(basic_response &response, T const &future, + mpl::true_ const &) { + response.status_message(future); +} + +} // namespace impl + +template +void status_message(basic_response &response, T const &value) { + impl::status_message(response, value, is_async()); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_STATUS_MESSAGE_HPP_20100608 diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/uri.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/uri.hpp new file mode 100644 index 00000000..d173a774 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/uri.hpp @@ -0,0 +1,31 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_URI_HPP_20100621 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_URI_HPP_20100621 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +template +void uri(basic_request& request, T const& value) { + request.uri(value); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_URI_HPP_20100621 diff --git a/cpp-netlib/boost/network/protocol/http/message/modifiers/version.hpp b/cpp-netlib/boost/network/protocol/http/message/modifiers/version.hpp new file mode 100644 index 00000000..f237870b --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/modifiers/version.hpp @@ -0,0 +1,49 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_VERSION_HPP_20100608 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_VERSION_HPP_20100608 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +namespace impl { + +template +void version(basic_response &response, T const &value, + mpl::false_ const &) { + response << boost::network::http::version(value); +} + +template +void version(basic_response &response, T const &future, + mpl::true_ const &) { + response.version(future); +} + +} // namespace impl + +template +void version(basic_response &response, T const &value) { + impl::version(response, value, is_async()); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_VERSION_HPP_20100608 diff --git a/cpp-netlib/boost/network/protocol/http/message/traits/status.hpp b/cpp-netlib/boost/network/protocol/http/message/traits/status.hpp new file mode 100644 index 00000000..93b66885 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/traits/status.hpp @@ -0,0 +1,36 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_STATUS_HPP_20100903 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_STATUS_HPP_20100903 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +namespace traits { + +template +struct unsupported_tag; + +template +struct status + : mpl::if_< + is_async, + boost::shared_future, + typename mpl::if_, boost::uint16_t, + unsupported_tag >::type> {}; + +} /* traits */ + +} /* http */ +} /* network */ +} /* boost */ + +#endif diff --git a/cpp-netlib/boost/network/protocol/http/message/traits/status_message.hpp b/cpp-netlib/boost/network/protocol/http/message/traits/status_message.hpp new file mode 100644 index 00000000..92487ae7 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/traits/status_message.hpp @@ -0,0 +1,40 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_STATUS_MESSAGE_HPP_20100903 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_STATUS_MESSAGE_HPP_20100903 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +namespace traits { + +template +struct unsupported_tag; + +template +struct status_message + : mpl::if_< + is_async, + boost::shared_future::type>, + typename mpl::if_< + mpl::or_, + is_same, + is_same >, + typename string::type, + unsupported_tag >::type> {}; + +} /* traits */ + +} /* http */ +} /* network */ +} /* boost */ + +#endif diff --git a/cpp-netlib/boost/network/protocol/http/message/traits/version.hpp b/cpp-netlib/boost/network/protocol/http/message/traits/version.hpp new file mode 100644 index 00000000..d4b99811 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/traits/version.hpp @@ -0,0 +1,52 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_VERSION_HPP_20100903 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_VERSION_HPP_20100903 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +namespace traits { + +template +struct unsupported_tag; + +template +struct version { + typedef unsupported_tag type; +}; + +template +struct version >::type> { + typedef boost::shared_future::type> + type; +}; + +template +struct version< + Message, typename enable_if< + mpl::or_, + is_default_string, + is_default_wstring > >::type> { + typedef typename string::type type; +}; + +} /* traits */ + +} /* http */ +} /* network */ +} /* boost */ + +#endif diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/anchor.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/anchor.hpp new file mode 100644 index 00000000..27c4dd51 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/anchor.hpp @@ -0,0 +1,38 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_ANCHOR_HPP_20100618 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_ANCHOR_HPP_20100618 + +// Copyright 2010 (c) Dean Michael Berris. +// Copyright 2010 (c) Sinefunc, Inc. +// 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) + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +namespace impl { +template +struct anchor_wrapper { + basic_request const& message_; + anchor_wrapper(basic_request const& message) : message_(message) {} + typedef typename basic_request::string_type string_type; + operator string_type() { return message_.anchor(); } +}; +} + +template +inline impl::anchor_wrapper anchor(basic_request const& request) { + return impl::anchor_wrapper(request); +} + +} // namespace http + +} // namespace network + +} // nmaespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_ANCHOR_HPP_20100618 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/body.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/body.hpp new file mode 100644 index 00000000..d4d6e63c --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/body.hpp @@ -0,0 +1,64 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_BODY_HPP_20100622 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_BODY_HPP_20100622 + +// Copyright 2010 (c) Dean Michael Berris +// 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) + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +template +struct basic_request; + +namespace impl { + +template +struct body_wrapper { + typedef typename string::type string_type; + Message const& message_; + explicit body_wrapper(Message const& message) : message_(message) {} + body_wrapper(body_wrapper const& other) : message_(other.message_) {} + + operator string_type() const { return message_.body(); } + + size_t size() const { return message_.body().size(); } + + boost::iterator_range range() const { + return boost::make_iterator_range(message_.body()); + } +}; + +template +inline std::ostream& operator<<(std::ostream& os, + body_wrapper const& body) { + os << static_cast::string_type>(body); + return os; +} + +} // namespace impl + +template +inline typename impl::body_wrapper > body( + basic_response const& message) { + return impl::body_wrapper >(message); +} + +template +inline typename impl::body_wrapper > body( + basic_request const& message) { + return impl::body_wrapper >(message); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_BODY_HPP_20100622 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/destination.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/destination.hpp new file mode 100644 index 00000000..8210ab39 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/destination.hpp @@ -0,0 +1,35 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DESTINATION_HPP_20100624 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DESTINATION_HPP_20100624 + +// Copyright 2010 (c) Dean Michael Berris. +// 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 + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +template +struct basic_request; + +template +struct Request; + +template +struct Response; + +BOOST_NETWORK_DEFINE_HTTP_WRAPPER(destination, destination, destination); + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_DESTINATION_HPP_20100624 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/headers.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/headers.hpp new file mode 100644 index 00000000..a1bcd710 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/headers.hpp @@ -0,0 +1,123 @@ + +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPER_HEADERS_HPP_20100811 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPER_HEADERS_HPP_20100811 + +// Copyright Dean Michael Berris 2010. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct headers_range { + typedef typename headers_container::type + headers_container_type; + typedef typename boost::iterator_range< + typename headers_container_type::const_iterator> type; +}; + +template +struct basic_request; + +template +struct basic_response; + +namespace impl { + +template +struct request_headers_wrapper { + typedef typename string::type string_type; + typedef typename headers_range >::type range_type; + typedef typename headers_container::type headers_container_type; + typedef typename headers_container_type::const_iterator const_iterator; + typedef typename headers_container_type::iterator iterator; + + explicit request_headers_wrapper(basic_request const& message) + : message_(message) {} + + range_type operator[](string_type const& key) const { + return message_.headers().equal_range(key); + } + + typename headers_container_type::size_type count(string_type const& key) + const { + return message_.headers().count(key); + } + + const_iterator begin() const { return message_.headers().begin(); } + + const_iterator end() const { return message_.headers().end(); } + + operator range_type() { + return make_iterator_range(message_.headers().begin(), + message_.headers().end()); + } + + operator headers_container_type() { return message_.headers(); } + + private: + basic_request const& message_; +}; + +template +struct response_headers_wrapper { + typedef typename string::type string_type; + typedef typename headers_range >::type range_type; + typedef typename headers_container::type headers_container_type; + typedef typename headers_container_type::const_iterator const_iterator; + typedef typename headers_container_type::iterator iterator; + + explicit response_headers_wrapper(basic_response const& message) + : message_(message) {} + + range_type operator[](string_type const& key) const { + return message_.headers().equal_range(key); + } + + typename headers_container_type::size_type count(string_type const& key) + const { + return message_.headers().count(key); + } + + const_iterator begin() const { return message_.headers().begin(); } + + const_iterator end() const { return message_.headers().end(); } + + operator range_type() { + return make_iterator_range(message_.headers().begin(), + message_.headers().end()); + } + + operator headers_container_type() { return message_.headers(); } + + private: + basic_response const& message_; +}; + +} // namespace impl + +template +inline impl::request_headers_wrapper headers( + basic_request const& request_) { + return impl::request_headers_wrapper(request_); +} + +template +inline impl::response_headers_wrapper headers( + basic_response const& response_) { + return impl::response_headers_wrapper(response_); +} + +} // namepace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPER_HEADERS_HPP_20100811 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/helper.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/helper.hpp new file mode 100644 index 00000000..2f463414 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/helper.hpp @@ -0,0 +1,58 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_HELPER_20101013 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_HELPER_20101013 + +// Copyright 2010 (c) Dean Michael Berris +// 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 + +#ifndef BOOST_NETWORK_DEFINE_HTTP_WRAPPER +#define BOOST_NETWORK_DEFINE_HTTP_WRAPPER(name, accessor, pod_field) \ + struct name##_pod_accessor { \ + protected: \ + template \ + typename Message::string_type const& get_value(Message const& message) \ + const { \ + return message.pod_field; \ + } \ + }; \ + \ + struct name##_member_accessor { \ + protected: \ + template \ + typename Message::string_type get_value(Message const& message) const { \ + return message.accessor(); \ + } \ + }; \ + \ + template \ + struct name##_wrapper_impl \ + : mpl::if_, name##_pod_accessor, \ + name##_member_accessor> {}; \ + \ + template \ + struct name##_wrapper : name##_wrapper_impl::type { \ + typedef typename string::type string_type; \ + Message const& message_; \ + name##_wrapper(Message const& message) : message_(message) {} \ + name##_wrapper(name##_wrapper const& other) : message_(other.message_) {} \ + operator string_type() const { return this->get_value(message_); } \ + }; \ + \ + template \ + inline name##_wrapper > const name( \ + basic_response const& message) { \ + return name##_wrapper >(message); \ + } \ + \ + template \ + inline name##_wrapper > const name( \ + basic_request const& message) { \ + return name##_wrapper >(message); \ + } + +#endif /* BOOST_NETWORK_DEFINE_HTTP_WRAPPER */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_HELPER_20101013 */ diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/host.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/host.hpp new file mode 100644 index 00000000..9841674d --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/host.hpp @@ -0,0 +1,42 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HOST_HPP_20100618 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HOST_HPP_20100618 + +// Copyright 2010 (c) Dean Michael Berris. +// Copyright 2010 (c) Sinefunc, Inc. +// 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) + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +namespace impl { + +template +struct host_wrapper { + basic_request const& message_; + + host_wrapper(basic_request const& message) : message_(message) {} + + typedef typename basic_request::string_type string_type; + + operator string_type() { return message_.host(); } +}; +} + +template +inline impl::host_wrapper host(basic_request const& request) { + return impl::host_wrapper(request); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HOST_HPP_20100618 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/major_version.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/major_version.hpp new file mode 100644 index 00000000..40ad3d52 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/major_version.hpp @@ -0,0 +1,41 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_MAJOR_VERSION_HPP_20101120 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_MAJOR_VERSION_HPP_20101120 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +template +struct major_version_wrapper { + basic_request const& request; + explicit major_version_wrapper(basic_request const& request) + : request(request) {} + operator boost::uint8_t() { return request.http_version_major; } +}; + +template +inline typename enable_if, major_version_wrapper >::type +major_version(basic_request const& request) { + return major_version_wrapper(request); +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_MAJOR_VERSION_HPP_20101120 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/method.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/method.hpp new file mode 100644 index 00000000..6f194d3f --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/method.hpp @@ -0,0 +1,43 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_METHOD_HPP_20101118 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_METHOD_HPP_20101118 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +template +struct method_wrapper { + explicit method_wrapper(basic_request const& message) + : message_(message) {} + + basic_request const& message_; + + typedef typename basic_request::string_type string_type; + + operator string_type() { return message_.method; } +}; + +template +inline typename enable_if, typename string::type>::type +method(basic_request const& message) { + return method_wrapper(message); +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_METHOD_HPP_20101118 */ diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/minor_version.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/minor_version.hpp new file mode 100644 index 00000000..aad54e38 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/minor_version.hpp @@ -0,0 +1,41 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_MINOR_VERSION_HPP_20101120 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_MINOR_VERSION_HPP_20101120 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +template +struct minor_version_wrapper { + basic_request const& request; + explicit minor_version_wrapper(basic_request const& request) + : request(request) {} + operator boost::uint8_t() { return request.http_version_minor; } +}; + +template +inline typename enable_if, minor_version_wrapper >::type +minor_version(basic_request const& request) { + return minor_version_wrapper(request); +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_MINOR_VERSION_HPP_20101120 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/path.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/path.hpp new file mode 100644 index 00000000..56f67e5c --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/path.hpp @@ -0,0 +1,42 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_PATH_HPP_20100618 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_PATH_HPP_20100618 + +// Copyright 2010 (c) Dean Michael Berris. +// Copyright 2010 (c) Sinefunc, Inc. +// 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) + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +namespace impl { + +template +struct path_wrapper { + basic_request const& message_; + + path_wrapper(basic_request const& message) : message_(message) {} + + typedef typename basic_request::string_type string_type; + + operator string_type() { return message_.path(); } +}; +} + +template +inline impl::path_wrapper path(basic_request const& request) { + return impl::path_wrapper(request); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_PATH_HPP_20100618 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/port.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/port.hpp new file mode 100644 index 00000000..f05d9dc8 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/port.hpp @@ -0,0 +1,62 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_PORT_HPP_20100618 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_PORT_HPP_20100618 + +// Copyright 2010, 2014 Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// Copyright 2014 Google, Inc. +// Copyright 2014 Jussi Lyytinen +// 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 +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +namespace impl { + +template +struct port_wrapper { + basic_request const& message_; + + port_wrapper(basic_request const& message) : message_(message) {} + + typedef typename basic_request::port_type port_type; + + operator port_type() const { return message_.port(); } + +#if (_MSC_VER >= 1600 && BOOST_VERSION > 105500) + // Because of a breaking change in Boost 1.56 to boost::optional, implicit + // conversions no longer work correctly with MSVC. The conversion therefore + // has to be done explicitly with as_optional(). + boost::optional as_optional() const { + return uri::port_us(message_.uri()); + } +#else + operator boost::optional() const { + return uri::port_us(message_.uri()); + } +#endif + +}; + +} // namespace impl + +template +inline impl::port_wrapper port(basic_request const& request) { + return impl::port_wrapper(request); +} + +} // namespace http +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_PORT_HPP_20100618 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/protocol.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/protocol.hpp new file mode 100644 index 00000000..0b18fda8 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/protocol.hpp @@ -0,0 +1,38 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_PROTOCOL_HPP_20100619 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_PROTOCOL_HPP_20100619 + +// Copyright 2010 (c) Dean Michael Berris. +// Copyright 2010 (c) Sinefunc, Inc. +// 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) + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +namespace impl { +template +struct protocol_wrapper { + basic_request const& message_; + protocol_wrapper(basic_request const& message) : message_(message) {} + typedef typename basic_request::string_type string_type; + operator string_type() { return message_.protocol(); } +}; +} + +template +inline impl::protocol_wrapper protocol(basic_request const& request) { + return impl::protocol_wrapper(request); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_PROTOCOL_HPP_20100619 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/query.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/query.hpp new file mode 100644 index 00000000..3d3353c6 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/query.hpp @@ -0,0 +1,43 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_QUERY_HPP_20100618 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_QUERY_HPP_20100618 + +// Copyright 2010 (c) Dean Michael Berris. +// Copyright 2010 (c) Sinefunc, Inc. +// 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) + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +namespace impl { + +template +struct query_wrapper { + basic_request const& message_; + + query_wrapper(basic_request const& message) : message_(message) {} + + typedef typename basic_request::string_type string_type; + + operator string_type() { return message_.query(); } +}; + +} // namespace impl + +template +inline impl::query_wrapper query(basic_request const& request) { + return impl::query_wrapper(request); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_QUERY_HPP_20100618 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/ready.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/ready.hpp new file mode 100644 index 00000000..cb1ab354 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/ready.hpp @@ -0,0 +1,47 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_READY_HPP_20100618 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_READY_HPP_20100618 + +// Copyright 2010 Dean Michael Berris. +// 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 + +namespace boost { +namespace network { +namespace http { + +template +struct async_message; + +namespace impl { +template +struct ready_wrapper + : boost::network::detail::wrapper_base_const > { + typedef boost::network::detail::wrapper_base_const > + wrapper_base; + explicit ready_wrapper(async_message const& message) + : wrapper_base(message) {} + operator bool() { + return wrapper_base::_message.version_.is_ready() && + wrapper_base::_message.status_.is_ready() && + wrapper_base::_message.status_message_.is_ready() && + wrapper_base::_message.headers_.is_ready() && + wrapper_base::_message.body_.is_ready(); + } +}; +} // namespace impl + +template +inline bool ready(async_message const& message) { + return impl::ready_wrapper(message); +} + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_READY_HPP_20100618 */ diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/source.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/source.hpp new file mode 100644 index 00000000..e4dee116 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/source.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_SOURCE_HPP_20100622 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_SOURCE_HPP_20100622 + +// Copyright 2010 (c) Dean Michael Berris +// 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 + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +template +struct basic_request; + +BOOST_NETWORK_DEFINE_HTTP_WRAPPER(source, source, source); + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_SOURCE_HPP_20100622 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/status.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/status.hpp new file mode 100644 index 00000000..06ecc6ec --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/status.hpp @@ -0,0 +1,50 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_STATUS_HPP_20100603 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_STATUS_HPP_20100603 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +namespace impl { + +template +struct status_wrapper { + + basic_response const& response_; + + explicit status_wrapper(basic_response const& response) + : response_(response) {} + + status_wrapper(status_wrapper const& other) : response_(other.response_) {} + + operator boost::uint16_t() { return response_.status(); } +}; + +} // namespace impl + +template +struct Response; + +template +inline impl::status_wrapper status(basic_response const& response) { + return impl::status_wrapper(response); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_STATUS_HPP_20100603 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/status_message.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/status_message.hpp new file mode 100644 index 00000000..ea4c8fc4 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/status_message.hpp @@ -0,0 +1,58 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_STATUS_MESSAGE_HPP_20100603 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_STATUS_MESSAGE_HPP_20100603 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// Copyright 2014 (c) Google, Inc. +// 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 + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +namespace impl { + +template +struct status_message_wrapper { + + typedef typename string::type string_type; + + basic_response const& response_; + + explicit status_message_wrapper(basic_response const& response) + : response_(response) {} + + status_message_wrapper(status_message_wrapper const& other) + : response_(other.response_) {} + + operator string_type() const { return response_.status_message(); } +}; + +template +inline std::ostream& operator<<(std::ostream& os, + const status_message_wrapper& wrapper) { + return os << static_cast::type>(wrapper); +} + +} // namespace impl + +template +inline impl::status_message_wrapper status_message( + basic_response const& response) { + return impl::status_message_wrapper(response); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPER_STATUS_MESSAGE_HPP_20100603 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/uri.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/uri.hpp new file mode 100644 index 00000000..2e80d1c6 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/uri.hpp @@ -0,0 +1,41 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_URI_HPP_20100620 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_URI_HPP_20100620 + +// Copyright 2010 (c) Dean Michael Berris. +// Copyright 2010 (c) Sinefunc, Inc. +// 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 + +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +namespace impl { +template +struct uri_wrapper { + basic_request const& message_; + uri_wrapper(basic_request const& message) : message_(message) {} + typedef typename basic_request::string_type string_type; + operator string_type() { return message_.uri().raw(); } + operator boost::network::uri::uri() { return message_.uri(); } +}; +} + +template +inline impl::uri_wrapper uri(basic_request const& request) { + return impl::uri_wrapper(request); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_URI_HPP_20100620 diff --git a/cpp-netlib/boost/network/protocol/http/message/wrappers/version.hpp b/cpp-netlib/boost/network/protocol/http/message/wrappers/version.hpp new file mode 100644 index 00000000..c0502284 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/message/wrappers/version.hpp @@ -0,0 +1,47 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_VERSION_HPP_20100603 +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_VERSION_HPP_20100603 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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) + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response; + +namespace impl { + +template +struct version_wrapper { + + typedef typename string::type string_type; + + basic_response const& response_; + + explicit version_wrapper(basic_response const& response) + : response_(response) {} + + version_wrapper(version_wrapper const& other) : response_(other.response_) {} + + operator string_type() { return response_.version(); } +}; + +} // namespace impl + +template +inline impl::version_wrapper version(basic_response const& response) { + return impl::version_wrapper(response); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_WRAPPERS_VERSION_HPP_20100603 diff --git a/cpp-netlib/boost/network/protocol/http/parser.hpp b/cpp-netlib/boost/network/protocol/http/parser.hpp new file mode 100644 index 00000000..d0e33e79 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/parser.hpp @@ -0,0 +1,352 @@ +// This file is part of the Boost Network library +// Based on the Pion Network Library (r421) +// Copyright Atomic Labs, Inc. 2007-2008 +// See http://cpp-netlib.sourceforge.net for library home page. +// +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_HPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +// forward declarations used to finish HTTP requests +template +class basic_request; + +// forward declarations used to finish HTTP requests +template +class basic_response; + +/// an incremental HTTP 1.0/1.1 protocol parser +template > +class basic_parser : private boost::noncopyable { + public: + // import types from ParserTraits template + typedef ParserTraits traits_type; + typedef typename string::type string_type; + + // default destructor + virtual ~basic_parser() {} + + /** + * creates a new HTTP protocol parser + * + * @param is_request if true, the message is parsed as an HTTP request; + * if false, the message is parsed as an HTTP response + */ + basic_parser(const bool is_request) + : m_is_request(is_request), + m_read_ptr(NULL), + m_read_end_ptr(NULL), + m_headers_parse_state(is_request ? PARSE_METHOD_START + : PARSE_HTTP_VERSION_H), + m_chunked_content_parse_state(PARSE_CHUNK_SIZE_START), + m_status_code(0), + m_bytes_last_read(0), + m_bytes_total_read(0) {} + + /** + * parses an HTTP message up to the end of the headers using bytes + * available in the read buffer + * + * @param http_msg the HTTP message object to populate from parsing + * + * @return boost::tribool result of parsing: + * false = message has an error, + * true = finished parsing HTTP headers, + * indeterminate = not yet finished parsing HTTP + *headers + */ + boost::tribool parse_http_headers(basic_message& http_msg); + + /** + * parses a chunked HTTP message-body using bytes available in the read + *buffer + * + * @param chunk_buffers buffers to be populated from parsing chunked + *content + * + * @return boost::tribool result of parsing: + * false = message has an error, + * true = finished parsing message, + * indeterminate = message is not yet finished + */ + boost::tribool parse_chunks(types::chunk_cache_t& chunk_buffers); + + /** + * prepares the payload content buffer and consumes any content + *remaining + * in the parser's read buffer + * + * @param http_msg the HTTP message object to consume content for + * @return unsigned long number of content bytes consumed, if any + */ + std::size_t consume_content(basic_message& http_msg); + + /** + * consume the bytes available in the read buffer, converting them into + * the next chunk for the HTTP message + * + * @param chunk_buffers buffers to be populated from parsing chunked + *content + * @return unsigned long number of content bytes consumed, if any + */ + std::size_t consume_content_as_next_chunk( + types::chunk_cache_t& chunk_buffers); + + /** + * finishes parsing an HTTP request message (copies over request-only + *data) + * + * @param http_request the HTTP request object to finish + */ + void finish(basic_request& http_request); + + /** + * finishes an HTTP response message (copies over response-only data) + * + * @param http_request the HTTP response object to finish + */ + void finish(basic_response& http_response); + + /** + * resets the location and size of the read buffer + * + * @param ptr pointer to the first bytes available to be read + * @param len number of bytes available to be read + */ + inline void set_read_buffer(const char* ptr, std::size_t len) { + m_read_ptr = ptr; + m_read_end_ptr = ptr + len; + } + + /** + * saves the current read position bookmark + * + * @param read_ptr points to the next character to be consumed in the + *read_buffer + * @param read_end_ptr points to the end of the read_buffer (last byte + + *1) + */ + inline void save_read_position(const char*& read_ptr, + const char*& read_end_ptr) const { + read_ptr = m_read_ptr; + read_end_ptr = m_read_end_ptr; + } + + /// resets the parser to its initial state + inline void reset(void); + + /// returns true if there are no more bytes available in the read buffer + inline bool eof(void) const { + return m_read_ptr == NULL || m_read_ptr >= m_read_end_ptr; + } + + /// returns the number of bytes read during the last parse operation + inline std::size_t gcount(void) const { return m_bytes_last_read; } + + /// returns the total number of bytes read while parsing the HTTP + /// message + inline std::size_t bytes_read(void) const { return m_bytes_total_read; } + + /// returns the number of bytes available in the read buffer + inline std::size_t bytes_available(void) const { + return (eof() ? 0 : (m_read_end_ptr - m_read_ptr)); + } + + protected: + /** + * parse key-value pairs out of a url-encoded string + * (i.e. this=that&a=value) + * + * @param params container for key-values string pairs + * @param ptr points to the start of the encoded string + * @param len length of the encoded string, in bytes + * + * @return bool true if successful + */ + static bool parse_url_encoded(types::query_params& params, const char* ptr, + const std::size_t len); + + /** + * parse key-value pairs out of a "Cookie" request header + * (i.e. this=that; a=value) + * + * @param params container for key-values string pairs + * @param cookie_header header string to be parsed + * + * @return bool true if successful + */ + static bool parse_cookie_header(types::cookie_params& params, + const string_type& cookie_header); + + /// true if the message is an HTTP request; false if it is an HTTP + /// response + const bool m_is_request; + + /// points to the next character to be consumed in the read_buffer + const char* m_read_ptr; + + /// points to the end of the read_buffer (last byte + 1) + const char* m_read_end_ptr; + + private: + // returns true if the argument is a special character + inline static bool is_special(int c) { + switch (c) { + case '(': + case ')': + case '<': + case '>': + case '@': + case ',': + case ';': + case ':': + case '\\': + case '"': + case '/': + case '[': + case ']': + case '?': + case '=': + case '{': + case '}': + case ' ': + case '\t': + return true; + default: + return false; + } + } + + // returns true if the argument is a character + inline static bool is_char(int c) { return (c >= 0 && c <= 127); } + + // returns true if the argument is a control character + inline static bool is_control(int c) { + return ((c >= 0 && c <= 31) || c == 127); + } + + // returns true if the argument is a digit + inline static bool is_digit(int c) { return (c >= '0' && c <= '9'); } + + // returns true if the argument is a hexadecimal digit + inline static bool is_hex_digit(int c) { + return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F')); + } + + /// state used to keep track of where we are in parsing the HTTP headers + enum headers_parse_state_t { + PARSE_METHOD_START, + PARSE_METHOD, + PARSE_URI_STEM, + PARSE_URI_QUERY, + PARSE_HTTP_VERSION_H, + PARSE_HTTP_VERSION_T_1, + PARSE_HTTP_VERSION_T_2, + PARSE_HTTP_VERSION_P, + PARSE_HTTP_VERSION_SLASH, + PARSE_HTTP_VERSION_MAJOR_START, + PARSE_HTTP_VERSION_MAJOR, + PARSE_HTTP_VERSION_MINOR_START, + PARSE_HTTP_VERSION_MINOR, + PARSE_STATUS_CODE_START, + PARSE_STATUS_CODE, + PARSE_STATUS_MESSAGE, + PARSE_EXPECTING_NEWLINE, + PARSE_EXPECTING_CR, + PARSE_HEADER_WHITESPACE, + PARSE_HEADER_START, + PARSE_HEADER_NAME, + PARSE_SPACE_BEFORE_HEADER_VALUE, + PARSE_HEADER_VALUE, + PARSE_EXPECTING_FINAL_NEWLINE, + PARSE_EXPECTING_FINAL_CR + }; + + /// state used to keep track of where we are in parsing chunked content + enum chunked_content_parse_state_t { + PARSE_CHUNK_SIZE_START, + PARSE_CHUNK_SIZE, + PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE, + PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE, + PARSE_CHUNK, + PARSE_EXPECTING_CR_AFTER_CHUNK, + PARSE_EXPECTING_LF_AFTER_CHUNK, + PARSE_EXPECTING_FINAL_CR_AFTER_LAST_CHUNK, + PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK + }; + + /// the current state of parsing HTTP headers + headers_parse_state_t m_headers_parse_state; + + /// the current state of parsing chunked content + chunked_content_parse_state_t m_chunked_content_parse_state; + + /// Used for parsing the HTTP response status code + boost::uint16_t m_status_code; + + /// Used for parsing the HTTP response status message + string_type m_status_message; + + /// Used for parsing the request method + string_type m_method; + + /// Used for parsing the name of resource requested + string_type m_resource; + + /// Used for parsing the query string portion of a URI + string_type m_query_string; + + /// Used for parsing the name of HTTP headers + string_type m_header_name; + + /// Used for parsing the value of HTTP headers + string_type m_header_value; + + /// Used for parsing the chunk size + string_type m_chunk_size_str; + + /// Used for parsing the current chunk + std::vector m_current_chunk; + + /// number of bytes in the chunk currently being parsed + std::size_t m_size_of_current_chunk; + + /// number of bytes read so far in the chunk currently being parsed + std::size_t m_bytes_read_in_current_chunk; + + /// number of bytes read during last parse operation + std::size_t m_bytes_last_read; + + /// total number of bytes read while parsing the HTTP message + std::size_t m_bytes_total_read; +}; + +/// typedef for the default HTTP protocol parser implementation +typedef basic_parser parser; + +}; // namespace http + +}; // namespace network + +}; // namespace boost + +// import implementation file +#include + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_HPP diff --git a/cpp-netlib/boost/network/protocol/http/parser/incremental.hpp b/cpp-netlib/boost/network/protocol/http/parser/incremental.hpp new file mode 100644 index 00000000..ba7222a3 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/parser/incremental.hpp @@ -0,0 +1,312 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_PARSER_INCREMENTAL_HPP_20100909 +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_INCREMENTAL_HPP_20100909 + +// Copyright Dean Michael Berris 2010. +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct response_parser { + + enum state_t { + http_response_begin, + http_version_h, + http_version_t1, + http_version_t2, + http_version_p, + http_version_slash, + http_version_major, + http_version_dot, + http_version_minor, + http_version_done, + http_status_digit, + http_status_done, + http_status_message_char, + http_status_message_cr, + http_status_message_done, + http_header_name_char, + http_header_colon, + http_header_value_char, + http_header_line_cr, + http_header_line_done, + http_headers_end_cr, + http_headers_done + }; + + explicit response_parser(state_t state = http_response_begin) + : state_(state) {} + + response_parser(response_parser const& other) : state_(other.state_) {} + + ~response_parser() {} + + void swap(response_parser& other) { std::swap(other.state_, this->state_); } + + response_parser& operator=(response_parser rhs) { + rhs.swap(*this); + return *this; + } + + template + fusion::tuple > + parse_until(state_t stop_state, Range& range_) { + logic::tribool parsed_ok(logic::indeterminate); + typename Range::const_iterator start = boost::begin(range_), + current = start, end = boost::end(range_); + boost::iterator_range local_range = + boost::make_iterator_range(start, end); + while (!boost::empty(local_range) && indeterminate(parsed_ok)) { + current = boost::begin(local_range); + if (state_ == stop_state) { + parsed_ok = true; + } else { + switch (state_) { + case http_response_begin: + if (*current == ' ' || *current == '\r' || *current == '\n') { + // skip valid leading whitespace + ++start; + ++current; + } else if (*current == 'H') { + state_ = http_version_h; + start = current; + ++current; + } else { + parsed_ok = false; + } + break; + case http_version_h: + if (*current == 'T') { + state_ = http_version_t1; + ++current; + } else { + parsed_ok = false; + } + break; + case http_version_t1: + if (*current == 'T') { + state_ = http_version_t2; + ++current; + } else { + parsed_ok = false; + } + break; + case http_version_t2: + if (*current == 'P') { + state_ = http_version_p; + ++current; + } else { + parsed_ok = false; + } + break; + case http_version_p: + if (*current == '/') { + state_ = http_version_slash; + ++current; + } else { + parsed_ok = false; + } + break; + case http_version_slash: + if (algorithm::is_digit()(*current)) { + state_ = http_version_major; + ++current; + } else { + parsed_ok = false; + } + break; + case http_version_major: + if (*current == '.') { + state_ = http_version_dot; + ++current; + } else { + parsed_ok = false; + } + break; + case http_version_dot: + if (algorithm::is_digit()(*current)) { + state_ = http_version_minor; + ++current; + } else { + parsed_ok = false; + } + break; + case http_version_minor: + if (*current == ' ') { + state_ = http_version_done; + ++current; + } else { + parsed_ok = false; + } + break; + case http_version_done: + if (algorithm::is_digit()(*current)) { + state_ = http_status_digit; + ++current; + } else { + parsed_ok = false; + } + break; + case http_status_digit: + if (algorithm::is_digit()(*current)) { + ++current; + } else if (*current == ' ') { + state_ = http_status_done; + ++current; + } else if (*current == '\r' || *current == '\n') { + state_ = http_status_done; + } else { + parsed_ok = false; + } + break; + case http_status_done: + if (*current == ' ') { + ++current; + } else if (*current == '\r') { + state_ = http_status_message_cr; + ++current; + } else if (*current == '\n') { + state_ = http_status_message_done; + ++current; + } else { + state_ = http_status_message_char; + ++current; + } + break; + case http_status_message_char: + if (*current == '\r') { + state_ = http_status_message_cr; + ++current; + } else if (*current == '\n') { + state_ = http_status_message_done; + ++current; + } else { + ++current; + } + break; + case http_status_message_cr: + if (*current == '\n') { + state_ = http_status_message_done; + ++current; + } else { + parsed_ok = false; + } + break; + case http_status_message_done: + case http_header_line_done: + if (*current == ' ') { + ++current; + } else if (algorithm::is_alnum()(*current) || + algorithm::is_punct()(*current)) { + state_ = http_header_name_char; + ++current; + } else if (*current == '\r') { + state_ = http_headers_end_cr; + ++current; + } else if (*current == '\n') { + state_ = http_headers_done; + ++current; + } else { + parsed_ok = false; + } + break; + case http_header_name_char: + if (*current == ':') { + state_ = http_header_colon; + ++current; + } else if (*current == '\r') { + state_ = http_header_line_cr; + ++current; + } else if (*current == '\n') { + state_ = http_header_line_done; + ++current; + } else if (algorithm::is_alnum()(*current) || + algorithm::is_space()(*current) || + algorithm::is_punct()(*current)) { + ++current; + } else { + parsed_ok = false; + } + break; + case http_header_colon: + if (*current == '\r') { + state_ = http_header_line_cr; + ++current; + } else if (*current == '\n') { + state_ = http_header_line_done; + ++current; + } else if (algorithm::is_space()(*current)) { + ++current; + } else { + state_ = http_header_value_char; + ++current; + } + break; + case http_header_value_char: + if (*current == '\r') { + state_ = http_header_line_cr; + ++current; + } else if (*current == '\n') { + state_ = http_header_line_done; + ++current; + } else { + ++current; + } + break; + case http_header_line_cr: + if (*current == '\n') { + state_ = http_header_line_done; + ++current; + } else { + parsed_ok = false; + } + break; + case http_headers_end_cr: + if (*current == '\n') { + state_ = http_headers_done; + ++current; + } else { + parsed_ok = false; + } + break; + default: + parsed_ok = false; + } + } + + local_range = boost::make_iterator_range(current, end); + } + if (state_ == stop_state) parsed_ok = true; + return fusion::make_tuple(parsed_ok, + boost::make_iterator_range(start, current)); + } + + state_t state() { return state_; } + + void reset(state_t new_state = http_response_begin) { state_ = new_state; } + + private: + state_t state_; +}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif diff --git a/cpp-netlib/boost/network/protocol/http/policies/async_connection.hpp b/cpp-netlib/boost/network/protocol/http/policies/async_connection.hpp new file mode 100644 index 00000000..667712b3 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/policies/async_connection.hpp @@ -0,0 +1,111 @@ +#ifndef BOOST_NETWORK_POLICY_ASYNC_CONNECTION_HPP_20100529 +#define BOOST_NETWORK_POLICY_ASYNC_CONNECTION_HPP_20100529 + +// Copyright 2010 (C) Dean Michael Berris +// Copyright 2010 (C) Sinefunc, Inc. +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct async_connection_policy : resolver_policy::type { + protected: + typedef typename string::type string_type; + typedef typename resolver_policy::type resolver_base; + typedef typename resolver_base::resolver_type resolver_type; + typedef typename resolver_base::resolve_function resolve_function; + typedef function const&, + system::error_code const&)> body_callback_function_type; + typedef function body_generator_function_type; + + struct connection_impl { + connection_impl(bool follow_redirect, bool always_verify_peer, + resolve_function resolve, resolver_type& resolver, + bool https, int timeout, + optional const& certificate_filename, + optional const& verify_path, + optional const& certificate_file, + optional const& private_key_file, + optional const& ciphers, long ssl_options) { + pimpl = impl::async_connection_base< + Tag, version_major, + version_minor>::new_connection(resolve, resolver, follow_redirect, + always_verify_peer, https, timeout, + certificate_filename, verify_path, + certificate_file, private_key_file, + ciphers, ssl_options); + } + + basic_response send_request(string_type const& method, + basic_request const& request_, + bool get_body, + body_callback_function_type callback, + body_generator_function_type generator) { + return pimpl->start(request_, method, get_body, callback, generator); + } + + private: + shared_ptr > pimpl; + }; + + typedef boost::shared_ptr connection_ptr; + connection_ptr get_connection( + resolver_type& resolver, basic_request const& request_, + bool always_verify_peer, + optional const& certificate_filename = + optional(), + optional const& verify_path = optional(), + optional const& certificate_file = optional(), + optional const& private_key_file = optional(), + optional const& ciphers = optional(), + long ssl_options = 0) { + string_type protocol_ = protocol(request_); + connection_ptr connection_(new connection_impl( + follow_redirect_, always_verify_peer, + boost::bind(&async_connection_policy::resolve, + this, boost::arg<1>(), boost::arg<2>(), boost::arg<3>(), + boost::arg<4>()), + resolver, boost::iequals(protocol_, string_type("https")), timeout_, + certificate_filename, verify_path, certificate_file, private_key_file, + ciphers, ssl_options)); + return connection_; + } + + void cleanup() {} + + async_connection_policy(bool cache_resolved, bool follow_redirect, + int timeout) + : resolver_base(cache_resolved), + follow_redirect_(follow_redirect), + timeout_(timeout) {} + + bool follow_redirect_; + int timeout_; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_POLICY_ASYNC_CONNECTION_HPP_ diff --git a/cpp-netlib/boost/network/protocol/http/policies/async_resolver.hpp b/cpp-netlib/boost/network/protocol/http/policies/async_resolver.hpp new file mode 100644 index 00000000..61a71014 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/policies/async_resolver.hpp @@ -0,0 +1,91 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_ASYNC_RESOLVER_20100622 +#define BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_ASYNC_RESOLVER_20100622 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { +namespace policies { + +template +struct async_resolver : boost::enable_shared_from_this > { + typedef typename resolver::type resolver_type; + typedef typename resolver_type::iterator resolver_iterator; + typedef typename resolver_type::query resolver_query; + typedef std::pair + resolver_iterator_pair; + typedef typename string::type string_type; + typedef boost::unordered_map + endpoint_cache; + typedef boost::function< + void(boost::system::error_code const &, resolver_iterator_pair)> + resolve_completion_function; + typedef boost::function resolve_function; + + protected: + bool cache_resolved_; + endpoint_cache endpoint_cache_; + boost::shared_ptr service_; + boost::shared_ptr resolver_strand_; + + explicit async_resolver(bool cache_resolved) + : cache_resolved_(cache_resolved), endpoint_cache_() {} + + void resolve(resolver_type &resolver_, string_type const &host, + boost::uint16_t port, + resolve_completion_function once_resolved) { + if (cache_resolved_) { + typename endpoint_cache::iterator iter = + endpoint_cache_.find(boost::to_lower_copy(host)); + if (iter != endpoint_cache_.end()) { + boost::system::error_code ignored; + once_resolved(ignored, iter->second); + return; + } + } + + typename resolver_type::query q(host, + lexical_cast(port)); + resolver_.async_resolve(q, resolver_strand_->wrap(boost::bind( + &async_resolver::handle_resolve, + async_resolver::shared_from_this(), + boost::to_lower_copy(host), once_resolved, + boost::asio::placeholders::error, + boost::asio::placeholders::iterator))); + } + + void handle_resolve(string_type const &host, + resolve_completion_function once_resolved, + boost::system::error_code const &ec, + resolver_iterator endpoint_iterator) { + typename endpoint_cache::iterator iter; + bool inserted = false; + if (!ec && cache_resolved_) { + boost::fusion::tie(iter, inserted) = + endpoint_cache_.insert(std::make_pair( + host, std::make_pair(endpoint_iterator, resolver_iterator()))); + once_resolved(ec, iter->second); + } else { + once_resolved(ec, std::make_pair(endpoint_iterator, resolver_iterator())); + } + } +}; + +} // namespace policies + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_ASYNC_RESOLVER_20100622 diff --git a/cpp-netlib/boost/network/protocol/http/policies/pooled_connection.hpp b/cpp-netlib/boost/network/protocol/http/policies/pooled_connection.hpp new file mode 100644 index 00000000..2ac32845 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/policies/pooled_connection.hpp @@ -0,0 +1,236 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_POOLED_CONNECTION_POLICY_20091214 +#define BOOST_NETWORK_PROTOCOL_HTTP_POOLED_CONNECTION_POLICY_20091214 + +// Copyright 2013 Google, Inc. +// Copyright 2009 Dean Michael Berris +// 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 + +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_NETWORK_HTTP_MAXIMUM_REDIRECT_COUNT +#define BOOST_NETWORK_HTTP_MAXIMUM_REDIRECT_COUNT 5 +#endif // BOOST_NETWORK_HTTP_MAXIMUM_REDIRECT_COUNT + +namespace boost { +namespace network { +namespace http { + +template +struct pooled_connection_policy : resolver_policy::type { + protected: + typedef typename string::type string_type; + typedef typename resolver_policy::type resolver_base; + typedef typename resolver_base::resolver_type resolver_type; + typedef function + resolver_function_type; + typedef function const&, + system::error_code const&)> body_callback_function_type; + typedef function body_generator_function_type; + + void cleanup() { host_connection_map().swap(host_connections); } + + struct connection_impl { + typedef function( + resolver_type&, basic_request const&, optional const&, + optional const&, optional const&, + optional const&, optional const&)> + get_connection_function; + + connection_impl( + resolver_type& resolver, bool follow_redirect, string_type const& host, + string_type const& port, resolver_function_type resolve, + get_connection_function get_connection, bool https, + bool always_verify_peer, int timeout, + optional const& certificate_filename = + optional(), + optional const& verify_path = optional(), + optional const& certificate_file = optional(), + optional const& private_key_file = optional(), + optional const& ciphers = optional(), + long ssl_options = 0) + : pimpl(impl::sync_connection_base:: + new_connection(resolver, resolve, https, always_verify_peer, + timeout, certificate_filename, verify_path, + certificate_file, private_key_file, ciphers, + ssl_options)), + resolver_(resolver), + connection_follow_redirect_(follow_redirect), + get_connection_(get_connection), + certificate_filename_(certificate_filename), + verify_path_(verify_path), + certificate_file_(certificate_file), + private_key_file_(private_key_file), + ciphers_(ciphers), + ssl_options_(ssl_options) { + // TODO(dberris): review parameter necessity. + (void)host; + (void)port; + } + + basic_response send_request(string_type const& method, + basic_request request_, bool get_body, + body_callback_function_type callback, + body_generator_function_type generator) { + return send_request_impl(method, request_, get_body, callback, generator); + } + + private: + basic_response send_request_impl( + string_type const& method, basic_request request_, bool get_body, + body_callback_function_type callback, + body_generator_function_type generator) { + // TODO(dberris): review parameter necessity. + (void)callback; + + boost::uint8_t count = 0; + bool retry = false; + do { + if (count >= BOOST_NETWORK_HTTP_MAXIMUM_REDIRECT_COUNT) + boost::throw_exception(std::runtime_error( + "Redirection exceeds maximum redirect count.")); + + basic_response response_; + // check if the socket is open first + if (!pimpl->is_open()) { + pimpl->init_socket(request_.host(), + lexical_cast(request_.port())); + } + response_ = basic_response(); + response_ << ::boost::network::source(request_.host()); + + pimpl->send_request_impl(method, request_, generator); + boost::asio::streambuf response_buffer; + + try { + pimpl->read_status(response_, response_buffer); + } + catch (boost::system::system_error& e) { + if (!retry && e.code() == boost::asio::error::eof) { + retry = true; + pimpl->init_socket(request_.host(), + lexical_cast(request_.port())); + continue; + } + throw; // it's a retry, and there's something wrong. + } + + pimpl->read_headers(response_, response_buffer); + + if (get_body && response_.status() != 304 && + (response_.status() != 204) && + !(response_.status() >= 100 && response_.status() <= 199)) { + pimpl->read_body(response_, response_buffer); + } + + typename headers_range >::type connection_range = + headers(response_)["Connection"]; + if (version_major == 1 && version_minor == 1 && + !boost::empty(connection_range) && + boost::begin(connection_range)->second == string_type("close")) { + pimpl->close_socket(); + } else if (version_major == 1 && version_minor == 0) { + pimpl->close_socket(); + } + + if (connection_follow_redirect_) { + boost::uint16_t status = response_.status(); + if (status >= 300 && status <= 307) { + typename headers_range >::type location_range = + headers(response_)["Location"]; + typename range_iterator< + typename headers_range >::type>::type + location_header = boost::begin(location_range); + if (location_header != boost::end(location_range)) { + request_.uri(location_header->second); + connection_ptr connection_; + connection_ = get_connection_( + resolver_, request_, certificate_filename_, verify_path_, + certificate_file_, private_key_file_, ciphers_); + ++count; + continue; + } else + boost::throw_exception(std::runtime_error( + "Location header not defined in redirect response.")); + } + } + return response_; + } while (true); + } + + shared_ptr > pimpl; + resolver_type& resolver_; + bool connection_follow_redirect_; + get_connection_function get_connection_; + optional certificate_filename_; + optional verify_path_; + optional certificate_file_; + optional private_key_file_; + optional ciphers_; + long ssl_options_; + }; + + typedef shared_ptr connection_ptr; + + typedef unordered_map host_connection_map; + host_connection_map host_connections; + bool follow_redirect_; + int timeout_; + + connection_ptr get_connection( + resolver_type& resolver, basic_request const& request_, + bool always_verify_peer, + optional const& certificate_filename = + optional(), + optional const& verify_path = optional(), + optional const& certificate_file = optional(), + optional const& private_key_file = optional(), + optional const& ciphers = optional()) { + string_type index = + (request_.host() + ':') + lexical_cast(request_.port()); + connection_ptr connection_; + typename host_connection_map::iterator it = host_connections.find(index); + if (it == host_connections.end()) { + connection_.reset(new connection_impl( + resolver, follow_redirect_, request_.host(), + lexical_cast(request_.port()), + boost::bind(&pooled_connection_policy::resolve, + this, boost::arg<1>(), boost::arg<2>(), boost::arg<3>()), + boost::bind(&pooled_connection_policy::get_connection, + this, boost::arg<1>(), boost::arg<2>(), + always_verify_peer, boost::arg<3>(), boost::arg<4>(), + boost::arg<5>(), boost::arg<6>(), boost::arg<7>()), + boost::iequals(request_.protocol(), string_type("https")), + always_verify_peer, timeout_, certificate_filename, verify_path, + certificate_file, private_key_file, ciphers, 0)); + host_connections.insert(std::make_pair(index, connection_)); + return connection_; + } + return it->second; + } + + pooled_connection_policy(bool cache_resolved, bool follow_redirect, + int timeout) + : resolver_base(cache_resolved), + host_connections(), + follow_redirect_(follow_redirect), + timeout_(timeout) {} +}; + +} // namespace http +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_POOLED_CONNECTION_POLICY_20091214 diff --git a/cpp-netlib/boost/network/protocol/http/policies/simple_connection.hpp b/cpp-netlib/boost/network/protocol/http/policies/simple_connection.hpp new file mode 100644 index 00000000..4e9677ab --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/policies/simple_connection.hpp @@ -0,0 +1,156 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_SIMPLE_CONNECTION_20091214 +#define BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_SIMPLE_CONNECTION_20091214 + +// Copyright 2013 Google, Inc. +// Copyright 2009 Dean Michael Berris +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct simple_connection_policy : resolver_policy::type { + protected: + typedef typename string::type string_type; + typedef typename resolver_policy::type resolver_base; + typedef typename resolver_base::resolver_type resolver_type; + typedef function + resolver_function_type; + typedef function const&, + system::error_code const&)> body_callback_function_type; + typedef function body_generator_function_type; + + struct connection_impl { + connection_impl( + resolver_type& resolver, bool follow_redirect, bool always_verify_peer, + string_type const& hostname, string_type const& port, + resolver_function_type resolve, bool https, int timeout, + optional const& certificate_filename = + optional(), + optional const& verify_path = optional(), + optional const& certificate_file = optional(), + optional const& private_key_file = optional(), + optional const& ciphers = optional(), + long ssl_options = 0) + : pimpl(), follow_redirect_(follow_redirect) { + // TODO(dberris): review parameter necessity. + (void)hostname; + (void)port; + + pimpl.reset(impl::sync_connection_base< + Tag, version_major, + version_minor>::new_connection(resolver, resolve, https, + always_verify_peer, timeout, + certificate_filename, verify_path, + certificate_file, private_key_file, + ciphers, ssl_options)); + } + + basic_response send_request(string_type const& method, + basic_request request_, bool get_body, + body_callback_function_type callback, + body_generator_function_type generator) { + // TODO(dberris): review parameter necessity. + (void)callback; + + basic_response response_; + do { + pimpl->init_socket(request_.host(), + lexical_cast(request_.port())); + pimpl->send_request_impl(method, request_, generator); + + response_ = basic_response(); + response_ << network::source(request_.host()); + + boost::asio::streambuf response_buffer; + pimpl->read_status(response_, response_buffer); + pimpl->read_headers(response_, response_buffer); + if (get_body) pimpl->read_body(response_, response_buffer); + + if (follow_redirect_) { + boost::uint16_t status = response_.status(); + if (status >= 300 && status <= 307) { + typename headers_range >::type + location_range = headers(response_)["Location"]; + typename range_iterator< + typename headers_range >::type>::type + location_header = boost::begin(location_range); + if (location_header != boost::end(location_range)) { + request_.uri(location_header->second); + } else + throw std::runtime_error( + "Location header not defined in redirect response."); + } else + break; + } else + break; + } while (true); + return response_; + } + + private: + shared_ptr > pimpl; + bool follow_redirect_; + }; + + typedef boost::shared_ptr connection_ptr; + connection_ptr get_connection( + resolver_type& resolver, basic_request const& request_, + bool always_verify_peer, + optional const& certificate_filename = + optional(), + optional const& verify_path = optional(), + optional const& certificate_file = optional(), + optional const& private_key_file = optional(), + optional const& ciphers = optional(), + long ssl_options = 0) { + connection_ptr connection_(new connection_impl( + resolver, follow_redirect_, always_verify_peer, request_.host(), + lexical_cast(request_.port()), + boost::bind(&simple_connection_policy::resolve, + this, boost::arg<1>(), boost::arg<2>(), boost::arg<3>()), + boost::iequals(request_.protocol(), string_type("https")), timeout_, + certificate_filename, verify_path, certificate_file, private_key_file, + ciphers, ssl_options)); + return connection_; + } + + void cleanup() {} + + simple_connection_policy(bool cache_resolved, bool follow_redirect, + int timeout) + : resolver_base(cache_resolved), + follow_redirect_(follow_redirect), + timeout_(timeout) {} + + // member variables + bool follow_redirect_; + int timeout_; +}; + +} // namespace http +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_SIMPLE_CONNECTION_20091214 diff --git a/cpp-netlib/boost/network/protocol/http/policies/sync_resolver.hpp b/cpp-netlib/boost/network/protocol/http/policies/sync_resolver.hpp new file mode 100644 index 00000000..9f93b985 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/policies/sync_resolver.hpp @@ -0,0 +1,73 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_SYNC_RESOLVER_20091214 +#define BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_SYNC_RESOLVER_20091214 + +// Copyright Dean Michael Berris 2009. +// 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 +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { +namespace policies { + +template +struct sync_resolver { + + typedef typename resolver::type resolver_type; + typedef typename resolver_type::iterator resolver_iterator; + typedef typename resolver_type::query resolver_query; + typedef std::pair + resolver_iterator_pair; + + protected: + typedef typename string::type string_type; + typedef boost::unordered_map + resolved_cache; + resolved_cache endpoint_cache_; + bool cache_resolved_; + + sync_resolver(bool cache_resolved) : cache_resolved_(cache_resolved) {} + + resolver_iterator_pair resolve(resolver_type& resolver_, + string_type const& hostname, + string_type const& port) { + if (cache_resolved_) { + typename resolved_cache::iterator cached_iterator = + endpoint_cache_.find(hostname); + if (cached_iterator == endpoint_cache_.end()) { + bool inserted = false; + boost::fusion::tie(cached_iterator, inserted) = + endpoint_cache_.insert(std::make_pair( + boost::to_lower_copy(hostname), + std::make_pair( + resolver_.resolve(resolver_query( + hostname, port, resolver_query::numeric_service)), + resolver_iterator()))); + }; + return cached_iterator->second; + }; + + return std::make_pair(resolver_.resolve(resolver_query( + hostname, port, resolver_query::numeric_service)), + resolver_iterator()); + }; +}; + +} // namespace policies + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_SYNC_RESOLVER_20091214 diff --git a/cpp-netlib/boost/network/protocol/http/request.hpp b/cpp-netlib/boost/network/protocol/http/request.hpp new file mode 100644 index 00000000..8c688118 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/request.hpp @@ -0,0 +1,84 @@ + +// Copyright Dean Michael Berris 2007. +// 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 __NETWORK_PROTOCOL_HTTP_REQUEST_20070908_1_HPP__ +#define __NETWORK_PROTOCOL_HTTP_REQUEST_20070908_1_HPP__ + +// Implement the HTTP Request Object + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// forward declarations +namespace boost { +namespace network { +namespace http { + +template +struct basic_request; + +} // namespace http + +} // namespace network + +} // namespace boost + +#include + +namespace boost { +namespace network { +namespace http { + +template +basic_request& operator<<(basic_request& message, + Directive const& directive) { + directive(message); + return message; +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#include + +#endif // __NETWORK_PROTOCOL_HTTP_REQUEST_20070908-1_HPP__ diff --git a/cpp-netlib/boost/network/protocol/http/request_concept.hpp b/cpp-netlib/boost/network/protocol/http/request_concept.hpp new file mode 100644 index 00000000..4d843cbb --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/request_concept.hpp @@ -0,0 +1,115 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_REQUEST_CONCEPT_HPP_20100603 +#define BOOST_NETWORK_PROTOCOL_HTTP_REQUEST_CONCEPT_HPP_20100603 + +// Copyright 2010 (c) Dean Michael Berris. +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct ServerRequest { + typedef typename R::string_type string_type; + typedef typename R::tag tag; + typedef typename R::headers_container_type headers_container_type; + + BOOST_CONCEPT_USAGE(ServerRequest) { + string_type source_, method_, destination_; + boost::uint8_t major_version_, minor_version_; + headers_container_type headers_; + string_type body_; + + source_ = source(request); + method_ = method(request); + destination_ = destination(request); + major_version_ = major_version(request); + minor_version_ = minor_version(request); + headers_ = headers(request); + body_ = body(request); + + source(request, source_); + method(request, method_); + destination(request, destination_); + major_version(request, major_version_); + minor_version(request, minor_version_); + headers(request, headers_); + add_header(request, string_type(), string_type()); + remove_header(request, string_type()); + clear_headers(request); + body(request, body_); + + string_type name, value; + + request << ::boost::network::source(source_) + << ::boost::network::destination(destination_) + << ::boost::network::http::method(method_) + << ::boost::network::http::major_version(major_version_) + << ::boost::network::http::minor_version(minor_version_) + << ::boost::network::header(name, value) + << ::boost::network::body(body_); + + (void)source_; + (void)method_; + (void)destination_; + (void)major_version_; + (void)minor_version_; + (void)headers_; + (void)body_; + (void)name; + (void)value; + } + + private: + R request; +}; + +template +struct ClientRequest : boost::network::Message { + typedef typename R::string_type string_type; + typedef typename R::port_type port_type; + + BOOST_CONCEPT_USAGE(ClientRequest) { + string_type tmp; + R request_(tmp); + swap(request, request_); // swappable via ADL + + string_type host_ = host(request); + port_type port_ = port(request); + string_type path_ = path(request); + string_type query_ = query(request); + string_type anchor_ = anchor(request); + string_type protocol_ = protocol(request); + + request << uri(string_type()); + + boost::network::http::uri(request, string_type()); + + (void)host_; + (void)port_; + (void)path_; + (void)query_; + (void)anchor_; + (void)protocol_; + } + + private: + R request; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_REQUEST_CONCEPT_HPP_20100603 diff --git a/cpp-netlib/boost/network/protocol/http/request_parser.hpp b/cpp-netlib/boost/network/protocol/http/request_parser.hpp new file mode 100644 index 00000000..d68f6fbf --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/request_parser.hpp @@ -0,0 +1,108 @@ +// +// request_parser.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2009 Dean Michael Berris (mikhailberis at gmail dot com) +// Copyright (c) 2009 Tarro, Inc. +// +// 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) +// +// Modifications by Dean Michael Berris +// + +#ifndef HTTP_SERVER3_REQUEST_PARSER_HPP +#define HTTP_SERVER3_REQUEST_PARSER_HPP + +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +namespace tag { +struct default_; +} + +/// Parser for incoming requests. +template +class basic_request_parser { + public: + /// Construct ready to parse the request method. + basic_request_parser() : state_(method_start) {} + + /// Reset to initial parser state. + void reset() { state_ = method_start; } + + /// Parse some data. The tribool return value is true when a complete + /// request + /// has been parsed, false if the data is invalid, indeterminate when + /// more + /// data is required. The InputIterator return value indicates how much + /// of the + /// input has been consumed. + template + boost::tuple parse_headers( + basic_request& req, InputIterator begin, InputIterator end) { + while (begin != end) { + boost::tribool result = consume(req, *begin++); + if (result || !result) return boost::make_tuple(result, begin); + } + boost::tribool result = boost::indeterminate; + return boost::make_tuple(result, begin); + } + + private: + /// Handle the next character of input. + boost::tribool consume(basic_request& req, char input); + + /// Check if a byte is an HTTP character. + static bool is_char(int c); + + /// Check if a byte is an HTTP control character. + static bool is_ctl(int c); + + /// Check if a byte is defined as an HTTP tspecial character. + static bool is_tspecial(int c); + + /// Check if a byte is a digit. + static bool is_digit(int c); + + /// The current state of the parser. + enum state { + method_start, + method, + uri_start, + uri, + http_version_h, + http_version_t_1, + http_version_t_2, + http_version_p, + http_version_slash, + http_version_major_start, + http_version_major, + http_version_minor_start, + http_version_minor, + expecting_newline_1, + header_line_start, + header_lws, + header_name, + space_before_header_value, + header_value, + expecting_newline_2, + expecting_newline_3 + } state_; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#include + +#endif // HTTP_SERVER3_REQUEST_PARSER_HPP diff --git a/cpp-netlib/boost/network/protocol/http/response.hpp b/cpp-netlib/boost/network/protocol/http/response.hpp new file mode 100644 index 00000000..dea1f46e --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/response.hpp @@ -0,0 +1,100 @@ +// Copyright Dean Michael Berris 2007. +// Copyright Michael Dickey 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_RESPONSE_HPP +#define BOOST_NETWORK_PROTOCOL_HTTP_RESPONSE_HPP + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct basic_response : public message_base::type { + + typedef typename string::type string_type; + + private: + typedef typename message_base::type base_type; + + public: + typedef Tag tag; + + basic_response() : base_type() {} + + basic_response(basic_response const& other) : base_type(other) {} + + basic_response& operator=(basic_response rhs) { + rhs.swap(*this); + return *this; + }; + + void swap(basic_response& other) { + base_type& base_ref(other), &this_ref(*this); + std::swap(this_ref, base_ref); + }; +}; + +template +inline void swap(basic_response& lhs, basic_response& rhs) { + lhs.swap(rhs); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#include + +namespace boost { +namespace network { +namespace http { + +template +basic_response& operator<<(basic_response& message, + Directive const& directive) { + directive(message); + return message; +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_RESPONSE_HPP diff --git a/cpp-netlib/boost/network/protocol/http/response_concept.hpp b/cpp-netlib/boost/network/protocol/http/response_concept.hpp new file mode 100644 index 00000000..63128296 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/response_concept.hpp @@ -0,0 +1,62 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_RESPONSE_CONCEPT_HPP_20100603 +#define BOOST_NETWORK_PROTOCOL_HTTP_RESPONSE_CONCEPT_HPP_20100603 + +// Copyright 2010 (c) Dean Michael Berris. +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct Response : boost::network::Message { + typedef typename R::string_type string_type; + + BOOST_CONCEPT_USAGE(Response) { + R response_; + swap(response, response_); // swappable via ADL + + typedef typename traits::version::type version_type; + typedef typename traits::status::type status_type; + typedef typename traits::status_message::type status_message_type; + + response << version(version_type()) // version directive + << status(status_type()) // status directive + << status_message( + status_message_type()) // status_message directive + ; + + version(response, version_type()); + status(response, status_type()); + status_message(response, status_message_type()); + + string_type version_ = version(response); + boost::uint16_t status_ = status(response); + string_type status_message_ = status_message(response); + + (void)version_; + (void)status_; + (void)status_message_; + } + + private: + R response; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_RESPONSE_CONCEPT_HPP_20100603 diff --git a/cpp-netlib/boost/network/protocol/http/server.hpp b/cpp-netlib/boost/network/protocol/http/server.hpp new file mode 100644 index 00000000..d7c127ee --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server.hpp @@ -0,0 +1,62 @@ +// Copyright 2009 (c) Tarro, Inc. +// Copyright 2009 (c) Dean Michael Berris +// Copyright 2010 (c) Glyn Matthews +// Copyright 2003-2008 (c) Chris Kholhoff +// 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 BOOST_NETWORK_HTTP_SERVER_HPP_ +#define BOOST_NETWORK_HTTP_SERVER_HPP_ + +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct server_base { + typedef unsupported_tag type; +}; + +template +struct server_base >::type> { + typedef async_server_base type; +}; + +template +struct server_base >::type> { + typedef sync_server_base type; +}; + +template +struct basic_server : server_base::type {}; + +template +struct server : server_base::type { + typedef typename server_base::type server_base; + typedef server_options options; + + explicit server(options const &options) : server_base(options) {} +}; + +template +struct async_server : server_base::type { + typedef typename server_base::type + server_base; + typedef server_options options; + + explicit async_server(options const &options) : server_base(options) {} +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_HTTP_SERVER_HPP_ diff --git a/cpp-netlib/boost/network/protocol/http/server/async_connection.hpp b/cpp-netlib/boost/network/protocol/http/server/async_connection.hpp new file mode 100644 index 00000000..0f84eea9 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server/async_connection.hpp @@ -0,0 +1,674 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_SERVER_CONNECTION_HPP_20101027 +#define BOOST_NETWORK_PROTOCOL_HTTP_SERVER_CONNECTION_HPP_20101027 + +// Copyright 2010 Dean Michael Berris. +// Copyright 2014 Jelle Van den Driessche. +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef BOOST_NETWORK_NO_LIB +#include +#endif + +#ifndef BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE +/** Here we define a page's worth of header connection buffer data. + * This can be tuned to reduce the memory cost of connections, but this + * default size is set to be friendly to typical service applications. + * This is the maximum size though and Boost.Asio's internal representation + * of a streambuf would make appropriate decisions on how big a buffer + * is to begin with. + * + * This kinda assumes that a page is by default 4096. Since we're using + * the default allocator with the static buffers, it's not guaranteed that + * the static buffers will be page-aligned when they are allocated. + */ +#define BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE 4096 +#endif /* BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE */ + +namespace boost { +namespace network { +namespace http { + +#ifndef BOOST_NETWORK_NO_LIB +extern void parse_version(std::string const& partial_parsed, + fusion::tuple& version_pair); +extern void parse_headers(std::string const& input, + std::vector& container); +#endif + +template +struct async_connection + : boost::enable_shared_from_this > { + + enum status_t { + ok = 200, + created = 201, + accepted = 202, + no_content = 204, + partial_content = 206, + multiple_choices = 300, + moved_permanently = 301, + moved_temporarily = 302, + not_modified = 304, + bad_request = 400, + unauthorized = 401, + forbidden = 403, + not_found = 404, + not_supported = 405, + not_acceptable = 406, + request_timeout = 408, + precondition_failed = 412, + unsatisfiable_range = 416, + internal_server_error = 500, + not_implemented = 501, + bad_gateway = 502, + service_unavailable = 503, + space_unavailable = 507 + }; + + typedef typename string::type string_type; + typedef basic_request request; + typedef shared_ptr connection_ptr; + + private: + static char const* status_message(status_t status) { + static char const ok_[] = "OK", created_[] = "Created", + accepted_[] = "Accepted", no_content_[] = "No Content", + multiple_choices_[] = "Multiple Choices", + moved_permanently_[] = "Moved Permanently", + moved_temporarily_[] = "Moved Temporarily", + not_modified_[] = "Not Modified", + bad_request_[] = "Bad Request", + unauthorized_[] = "Unauthorized", + forbidden_[] = "Fobidden", not_found_[] = "Not Found", + not_supported_[] = "Not Supported", + not_acceptable_[] = "Not Acceptable", + internal_server_error_[] = "Internal Server Error", + not_implemented_[] = "Not Implemented", + bad_gateway_[] = "Bad Gateway", + service_unavailable_[] = "Service Unavailable", + unknown_[] = "Unknown", + partial_content_[] = "Partial Content", + request_timeout_[] = "Request Timeout", + precondition_failed_[] = "Precondition Failed", + unsatisfiable_range_[] = + "Requested Range Not Satisfiable", + space_unavailable_[] = + "Insufficient Space to Store Resource"; + switch (status) { + case ok: + return ok_; + case created: + return created_; + case accepted: + return accepted_; + case no_content: + return no_content_; + case multiple_choices: + return multiple_choices_; + case moved_permanently: + return moved_permanently_; + case moved_temporarily: + return moved_temporarily_; + case not_modified: + return not_modified_; + case bad_request: + return bad_request_; + case unauthorized: + return unauthorized_; + case forbidden: + return forbidden_; + case not_found: + return not_found_; + case not_supported: + return not_supported_; + case not_acceptable: + return not_acceptable_; + case internal_server_error: + return internal_server_error_; + case not_implemented: + return not_implemented_; + case bad_gateway: + return bad_gateway_; + case service_unavailable: + return service_unavailable_; + case partial_content: + return partial_content_; + case request_timeout: + return request_timeout_; + case precondition_failed: + return precondition_failed_; + case unsatisfiable_range: + return unsatisfiable_range_; + case space_unavailable: + return space_unavailable_; + default: + return unknown_; + } + } + + public: + async_connection(asio::io_service& io_service, Handler& handler, + utils::thread_pool& thread_pool, + boost::shared_ptr ctx = + boost::shared_ptr()) + : strand(io_service), + handler(handler), + thread_pool_(thread_pool), + headers_buffer( + BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE), +#ifdef BOOST_NETWORK_ENABLE_HTTPS + socket_(io_service, ctx), +#else + socket_(io_service), +#endif + handshake_done(false), + headers_already_sent(false), + headers_in_progress(false) { + new_start = read_buffer_.begin(); + } + + ~async_connection() throw() { + boost::system::error_code ignored; + socket_.shutdown(asio::ip::tcp::socket::shutdown_receive, ignored); + } + + /** Function: template set_headers(Range headers) + * Precondition: headers have not been sent yet + * Postcondition: headers have been linearized to a buffer, + * and assumed to have been sent already when the + *function exits + * Throws: std::logic_error in case the headers have already been sent. + * + * A call to set_headers takes a Range where each element models the + * Header concept. This Range will be linearized onto a buffer, which + *is + * then sent as soon as the first call to `write` or `flush` commences. + */ + template + void set_headers(Range headers) { + lock_guard lock(headers_mutex); + if (headers_in_progress || headers_already_sent) + boost::throw_exception( + std::logic_error("Headers have already been sent.")); + + if (error_encountered) + boost::throw_exception(boost::system::system_error(*error_encountered)); + + typedef constants consts; + { + std::ostream stream(&headers_buffer); + stream << consts::http_slash() << 1 << consts::dot() << 1 + << consts::space() << status << consts::space() + << status_message(status) << consts::crlf(); + if (!boost::empty(headers)) { + typedef typename string::type string_type; + boost::transform(headers, std::ostream_iterator(stream), + linearize_header()); + } else { + stream << consts::crlf(); + } + stream << consts::crlf(); + } + + write_headers_only( + boost::bind(&async_connection::do_nothing, + async_connection::shared_from_this())); + } + + void set_status(status_t new_status) { + lock_guard lock(headers_mutex); + if (headers_already_sent) + boost::throw_exception(std::logic_error( + "Headers have already been sent, cannot reset status.")); + if (error_encountered) + boost::throw_exception(boost::system::system_error(*error_encountered)); + + status = new_status; + } + + template + void write(Range const& range) { + lock_guard lock(headers_mutex); + if (error_encountered) + boost::throw_exception(boost::system::system_error(*error_encountered)); + + boost::function f = boost::bind( + &async_connection::default_error, + async_connection::shared_from_this(), boost::arg<1>()); + + write_impl(boost::make_iterator_range(range), f); + } + + template + typename disable_if< + is_base_of, void>::type + write(Range const& range, Callback const& callback) { + lock_guard lock(headers_mutex); + if (error_encountered) + boost::throw_exception(boost::system::system_error(*error_encountered)); + write_impl(boost::make_iterator_range(range), callback); + } + + template + typename enable_if< + is_base_of, + void>::type + write(ConstBufferSeq const& seq, Callback const& callback) { + write_vec_impl(seq, callback, shared_array_list(), shared_buffers()); + } + + private: + typedef boost::array + buffer_type; + + public: + typedef iterator_range input_range; + typedef boost::function< + void(input_range, boost::system::error_code, std::size_t, connection_ptr)> + read_callback_function; + + void read(read_callback_function callback) { + if (error_encountered) + boost::throw_exception(boost::system::system_error(*error_encountered)); + if (new_start != read_buffer_.begin()) { + input_range input = + boost::make_iterator_range(new_start, read_buffer_.end()); + buffer_type::iterator start_tmp = new_start; + new_start = read_buffer_.begin(); + thread_pool().post( + boost::bind(callback, input, boost::system::error_code(), + std::distance(start_tmp, data_end), + async_connection::shared_from_this())); + return; + } + + socket().async_read_some( + asio::buffer(read_buffer_), + strand.wrap(boost::bind( + &async_connection::wrap_read_handler, + async_connection::shared_from_this(), callback, + asio::placeholders::error, asio::placeholders::bytes_transferred))); + } + + boost::network::stream_handler& socket() { return socket_; } + utils::thread_pool& thread_pool() { return thread_pool_; } + bool has_error() { return (!!error_encountered); } + optional error() { return error_encountered; } + + private: + void wrap_read_handler(read_callback_function callback, + boost::system::error_code const& ec, + std::size_t bytes_transferred) { + if (ec) error_encountered = in_place(ec); + buffer_type::const_iterator data_start = read_buffer_.begin(), + data_end = read_buffer_.begin(); + std::advance(data_end, bytes_transferred); + thread_pool().post(boost::bind( + callback, boost::make_iterator_range(data_start, data_end), ec, + bytes_transferred, async_connection::shared_from_this())); + } + + void default_error(boost::system::error_code const& ec) { + error_encountered = in_place(ec); + } + + typedef boost::array + array; + typedef std::list > array_list; + typedef boost::shared_ptr shared_array_list; + typedef boost::shared_ptr > shared_buffers; + typedef request_parser request_parser_type; + typedef boost::lock_guard lock_guard; + typedef std::list > pending_actions_list; + + asio::io_service::strand strand; + Handler& handler; + utils::thread_pool& thread_pool_; + asio::streambuf headers_buffer; + boost::network::stream_handler socket_; + bool handshake_done; + volatile bool headers_already_sent, headers_in_progress; + + boost::recursive_mutex headers_mutex; + buffer_type read_buffer_; + status_t status; + request_parser_type parser; + request request_; + buffer_type::iterator new_start, data_end; + string_type partial_parsed; + optional error_encountered; + pending_actions_list pending_actions; + + template + friend struct async_server_base; + + enum state_t { + method, + uri, + version, + headers + }; + + void start() { + typename ostringstream::type ip_stream; + ip_stream << socket_.remote_endpoint().address().to_string() << ':' + << socket_.remote_endpoint().port(); + request_.source = ip_stream.str(); + read_more(method); + } + + void read_more(state_t state) { +#ifdef BOOST_NETWORK_ENABLE_HTTPS + if (socket_.is_ssl_enabled() && !handshake_done) { + socket_.async_handshake( + boost::asio::ssl::stream_base::server, + boost::bind(&async_connection::handle_handshake, + async_connection::shared_from_this(), + boost::asio::placeholders::error, state)); + } else { +#endif + socket_.async_read_some( + asio::buffer(read_buffer_), + strand.wrap( + boost::bind(&async_connection::handle_read_data, + async_connection::shared_from_this(), + state, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); +#ifdef BOOST_NETWORK_ENABLE_HTTPS + } +#endif + } + + void handle_read_data(state_t state, boost::system::error_code const& ec, + std::size_t bytes_transferred) { + if (!ec) { + logic::tribool parsed_ok; + iterator_range result_range, input_range; + data_end = read_buffer_.begin(); + std::advance(data_end, bytes_transferred); + switch (state) { + case method: + input_range = boost::make_iterator_range(new_start, data_end); + fusion::tie(parsed_ok, result_range) = + parser.parse_until(request_parser_type::method_done, input_range); + if (!parsed_ok) { + client_error(); + break; + } else if (parsed_ok == true) { + swap(partial_parsed, request_.method); + request_.method.append(boost::begin(result_range), + boost::end(result_range)); + trim(request_.method); + new_start = boost::end(result_range); + } else { + partial_parsed.append(boost::begin(result_range), + boost::end(result_range)); + new_start = read_buffer_.begin(); + read_more(method); + break; + } + case uri: + input_range = boost::make_iterator_range(new_start, data_end); + fusion::tie(parsed_ok, result_range) = + parser.parse_until(request_parser_type::uri_done, input_range); + if (!parsed_ok) { + client_error(); + break; + } else if (parsed_ok == true) { + swap(partial_parsed, request_.destination); + request_.destination.append(boost::begin(result_range), + boost::end(result_range)); + trim(request_.destination); + new_start = boost::end(result_range); + } else { + partial_parsed.append(boost::begin(result_range), + boost::end(result_range)); + new_start = read_buffer_.begin(); + read_more(uri); + break; + } + case version: + input_range = boost::make_iterator_range(new_start, data_end); + fusion::tie(parsed_ok, result_range) = parser.parse_until( + request_parser_type::version_done, input_range); + if (!parsed_ok) { + client_error(); + break; + } else if (parsed_ok == true) { + fusion::tuple version_pair; + partial_parsed.append(boost::begin(result_range), + boost::end(result_range)); + parse_version(partial_parsed, version_pair); + request_.http_version_major = fusion::get<0>(version_pair); + request_.http_version_minor = fusion::get<1>(version_pair); + new_start = boost::end(result_range); + partial_parsed.clear(); + } else { + partial_parsed.append(boost::begin(result_range), + boost::end(result_range)); + new_start = read_buffer_.begin(); + read_more(version); + break; + } + case headers: + input_range = boost::make_iterator_range(new_start, data_end); + fusion::tie(parsed_ok, result_range) = parser.parse_until( + request_parser_type::headers_done, input_range); + if (!parsed_ok) { + client_error(); + break; + } else if (parsed_ok == true) { + partial_parsed.append(boost::begin(result_range), + boost::end(result_range)); + try { + parse_headers(partial_parsed, request_.headers); + } catch (...) { + client_error(); + break; + } + new_start = boost::end(result_range); + thread_pool().post(boost::bind( + &Handler::operator(), &handler, cref(request_), + async_connection::shared_from_this())); + return; + } else { + partial_parsed.append(boost::begin(result_range), + boost::end(result_range)); + new_start = read_buffer_.begin(); + read_more(headers); + break; + } + default: + BOOST_ASSERT(false && + "This is a bug, report to the cpp-netlib devel " + "mailing list!"); + std::abort(); + } + } else { + error_encountered = in_place(ec); + } + } + + void client_error() { + static char const* bad_request = + "HTTP/1.0 400 Bad Request\r\nConnection: close\r\nContent-Type: " + "text/plain\r\nContent-Length: 12\r\n\r\nBad Request."; + + asio::async_write( + socket(), asio::buffer(bad_request, strlen(bad_request)), + strand.wrap(boost::bind( + &async_connection::client_error_sent, + async_connection::shared_from_this(), + asio::placeholders::error, asio::placeholders::bytes_transferred))); + } + + void client_error_sent(boost::system::error_code const& ec, + std::size_t bytes_transferred) { + if (!ec) { + boost::system::error_code ignored; + socket().shutdown(asio::ip::tcp::socket::shutdown_both, ignored); + socket().close(ignored); + } else { + error_encountered = in_place(ec); + } + } + + void do_nothing() {} + + void write_headers_only(boost::function callback) { + if (headers_in_progress) return; + headers_in_progress = true; + asio::async_write( + socket(), headers_buffer, + strand.wrap(boost::bind( + &async_connection::handle_write_headers, + async_connection::shared_from_this(), callback, + asio::placeholders::error, asio::placeholders::bytes_transferred))); + } + + void handle_write_headers(boost::function callback, + boost::system::error_code const& ec, + std::size_t bytes_transferred) { + lock_guard lock(headers_mutex); + if (!ec) { + headers_buffer.consume(headers_buffer.size()); + headers_already_sent = true; + thread_pool().post(callback); + pending_actions_list::iterator start = pending_actions.begin(), + end = pending_actions.end(); + while (start != end) { + thread_pool().post(*start++); + } + pending_actions_list().swap(pending_actions); + } else { + error_encountered = in_place(ec); + } + } + + void handle_write( + boost::function callback, + shared_array_list temporaries, shared_buffers buffers, + boost::system::error_code const& ec, std::size_t bytes_transferred) { + // we want to forget the temporaries and buffers + thread_pool().post(boost::bind(callback, ec)); + } + + template + void write_impl(Range range, + boost::function callback) { + // linearize the whole range into a vector + // of fixed-sized buffers, then schedule an asynchronous + // write of these buffers -- make sure they are live + // by making these linearized buffers shared and made + // part of the completion handler. + // + // once the range has been linearized and sent, schedule + // a wrapper to be called in the io_service's thread, that + // will re-schedule the given callback into the thread pool + // referred to here so that the io_service's thread can concentrate + // on doing I/O. + // + + static std::size_t const connection_buffer_size = + BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE; + shared_array_list temporaries = boost::make_shared(); + shared_buffers buffers = + boost::make_shared >(0); + + std::size_t range_size = boost::distance(range); + buffers->reserve((range_size / connection_buffer_size) + + ((range_size % connection_buffer_size) ? 1 : 0)); + std::size_t slice_size = std::min(range_size, connection_buffer_size); + typename boost::range_iterator::type start = boost::begin(range), + end = boost::end(range); + while (slice_size != 0) { + using boost::adaptors::sliced; + shared_ptr new_array = make_shared(); + boost::copy(range | sliced(0, slice_size), new_array->begin()); + temporaries->push_back(new_array); + buffers->push_back(asio::buffer(new_array->data(), slice_size)); + std::advance(start, slice_size); + range = boost::make_iterator_range(start, end); + range_size = boost::distance(range); + slice_size = std::min(range_size, connection_buffer_size); + } + + if (!buffers->empty()) { + write_vec_impl(*buffers, callback, temporaries, buffers); + } + } + + template + void write_vec_impl(ConstBufferSeq const& seq, Callback const& callback, + shared_array_list temporaries, shared_buffers buffers) { + lock_guard lock(headers_mutex); + if (error_encountered) + boost::throw_exception(boost::system::system_error(*error_encountered)); + + boost::function callback_function = + callback; + + boost::function continuation = boost::bind( + &async_connection::template write_vec_impl< + ConstBufferSeq, boost::function >, + async_connection::shared_from_this(), seq, + callback_function, temporaries, buffers); + + if (!headers_already_sent && !headers_in_progress) { + write_headers_only(continuation); + return; + } else if (headers_in_progress && !headers_already_sent) { + pending_actions.push_back(continuation); + return; + } + + asio::async_write( + socket_, seq, + boost::bind(&async_connection::handle_write, + async_connection::shared_from_this(), + callback_function, temporaries, buffers, + asio::placeholders::error, + asio::placeholders::bytes_transferred)); + } + void handle_handshake(const boost::system::error_code& ec, state_t state) { + if (!ec) { + handshake_done = true; + read_more(state); + } else { + error_encountered = in_place(ec); + } + } +}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SERVER_CONNECTION_HPP_20101027 */ diff --git a/cpp-netlib/boost/network/protocol/http/server/async_server.hpp b/cpp-netlib/boost/network/protocol/http/server/async_server.hpp new file mode 100644 index 00000000..b3cdde50 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server/async_server.hpp @@ -0,0 +1,188 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_SERVER_ASYNC_SERVER_HPP_20101025 +#define BOOST_NETWORK_PROTOCOL_HTTP_SERVER_ASYNC_SERVER_HPP_20101025 + +// Copyright 2010 Dean Michael Berris. +// Copyright 2014 Jelle Van den Driessche. +// 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 +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct async_server_base : server_storage_base, socket_options_base { + typedef basic_request request; + typedef basic_response response; + typedef typename string::type string_type; + typedef typename boost::network::http::response_header::type + response_header; + typedef async_connection connection; + typedef shared_ptr connection_ptr; + typedef boost::unique_lock scoped_mutex_lock; + + explicit async_server_base(server_options const &options) + : server_storage_base(options), + socket_options_base(options), + handler(options.handler()), + address_(options.address()), + port_(options.port()), + thread_pool(options.thread_pool() + ? options.thread_pool() + : boost::make_shared()), + acceptor(server_storage_base::service_), + stopping(false), + new_connection(), + listening_mutex_(), + stopping_mutex_(), + listening(false), + ctx_(options.context()) {} + + void run() { + listen(); + service_.run(); + }; + + void stop() { + // stop accepting new requests and let all the existing + // handlers finish. + scoped_mutex_lock listening_lock(listening_mutex_); + if (listening) { // we dont bother stopping if we arent currently + // listening + scoped_mutex_lock stopping_lock(stopping_mutex_); + stopping = true; + system::error_code ignored; + acceptor.close(ignored); + listening = false; + service_.post(boost::bind(&async_server_base::handle_stop, this)); + } + } + + void listen() { + scoped_mutex_lock listening_lock(listening_mutex_); + BOOST_NETWORK_MESSAGE("Listening on " << address_ << ':' << port_); + if (!listening) + start_listening(); // we only initialize our acceptor/sockets if we + // arent already listening + if (!listening) { + BOOST_NETWORK_MESSAGE("Error listening on " << address_ << ':' << port_); + boost::throw_exception( + std::runtime_error("Error listening on provided port.")); + } + } + + private: + Handler &handler; + string_type address_, port_; + boost::shared_ptr thread_pool; + asio::ip::tcp::acceptor acceptor; + bool stopping; + connection_ptr new_connection; + boost::mutex listening_mutex_; + boost::mutex stopping_mutex_; + bool listening; + boost::shared_ptr ctx_; + + void handle_stop() { + scoped_mutex_lock stopping_lock(stopping_mutex_); + if (stopping) + service_.stop(); // a user may have started listening again before + // the stop command is reached + } + + void handle_accept(boost::system::error_code const &ec) { + { + scoped_mutex_lock stopping_lock(stopping_mutex_); + if (stopping) + return; // we dont want to add another handler instance, and we + // dont want to know about errors for a socket we dont + // need anymore + } + + if (ec) { + BOOST_NETWORK_MESSAGE("Error accepting connection, reason: " << ec); + } + +#ifdef BOOST_NETWORK_ENABLE_HTTPS + socket_options_base::socket_options(new_connection->socket().next_layer()); +#else + socket_options_base::socket_options(new_connection->socket()); +#endif + + new_connection->start(); + new_connection.reset(new connection(service_, handler, *thread_pool, ctx_)); + acceptor.async_accept( +#ifdef BOOST_NETWORK_ENABLE_HTTPS + new_connection->socket().next_layer(), +#else + new_connection->socket(), +#endif + boost::bind(&async_server_base::handle_accept, this, + boost::asio::placeholders::error)); + } + + void start_listening() { + using boost::asio::ip::tcp; + system::error_code error; + service_.reset(); // this allows repeated cycles of run -> stop -> + // run + tcp::resolver resolver(service_); + tcp::resolver::query query(address_, port_); + tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, error); + if (error) { + BOOST_NETWORK_MESSAGE("Error resolving '" << address_ << ':' << port_); + return; + } + tcp::endpoint endpoint = *endpoint_iterator; + acceptor.open(endpoint.protocol(), error); + if (error) { + BOOST_NETWORK_MESSAGE("Error opening socket: " << address_ << ":" + << port_); + return; + } + socket_options_base::acceptor_options(acceptor); + acceptor.bind(endpoint, error); + if (error) { + BOOST_NETWORK_MESSAGE("Error binding socket: " << address_ << ":" + << port_); + return; + } + acceptor.listen(asio::socket_base::max_connections, error); + if (error) { + BOOST_NETWORK_MESSAGE("Error listening on socket: '" + << error << "' on " << address_ << ":" << port_); + return; + } + new_connection.reset(new connection(service_, handler, *thread_pool, ctx_)); + acceptor.async_accept( +#ifdef BOOST_NETWORK_ENABLE_HTTPS + new_connection->socket().next_layer(), +#else + new_connection->socket(), +#endif + boost::bind(&async_server_base::handle_accept, this, + boost::asio::placeholders::error)); + listening = true; + scoped_mutex_lock stopping_lock(stopping_mutex_); + stopping = false; // if we were in the process of stopping, we revoke + // that command and continue listening + BOOST_NETWORK_MESSAGE("Now listening on socket: '" << address_ << ":" + << port_ << "'"); + } +}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SERVER_ASYNC_SERVER_HPP_20101025 */ diff --git a/cpp-netlib/boost/network/protocol/http/server/impl/parsers.ipp b/cpp-netlib/boost/network/protocol/http/server/impl/parsers.ipp new file mode 100644 index 00000000..4d7fb1a9 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server/impl/parsers.ipp @@ -0,0 +1,74 @@ +#ifndef SERVER_REQUEST_PARSERS_IMPL_UW3PM6V6 +#define SERVER_REQUEST_PARSERS_IMPL_UW3PM6V6 + +#define BOOST_SPIRIT_UNICODE +#include + +// Copyright 2013 Google, Inc. +// Copyright 2010 Dean Michael Berris. +// 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 +#include + +#ifdef BOOST_NETWORK_NO_LIB +#ifndef BOOST_NETWORK_INLINE +#define BOOST_NETWORK_INLINE inline +#endif +#else +#define BOOST_NETWORK_INLINE +#endif +#include + +namespace boost { +namespace spirit { +namespace traits { + +typedef std::basic_string u32_string; + +template <> // +struct assign_to_container_from_value { + static void call(u32_string const& val, std::string& attr) { + u32_to_u8_iterator begin = val.begin(), + end = val.end(); + for (; begin != end; ++begin) attr += *begin; + } +}; + +} // namespace traits +} // namespace spirit +} // namespace boost + +namespace boost { +namespace network { +namespace http { + +BOOST_NETWORK_INLINE void parse_version( + std::string const& partial_parsed, + fusion::tuple& version_pair) { + using namespace boost::spirit::qi; + parse(partial_parsed.begin(), partial_parsed.end(), + (lit("HTTP/") >> ushort_ >> '.' >> ushort_), version_pair); +} + +BOOST_NETWORK_INLINE void parse_headers( + std::string const& input, std::vector& container) { + using namespace boost::spirit::qi; + u8_to_u32_iterator begin = input.begin(), + end = input.end(); + typedef as as_u32_string; + parse(begin, end, + *(+((alnum | punct) - ':') >> lit(": ") >> + as_u32_string()[+((alnum | space | punct) - '\r' - '\n')] >> + lit("\r\n")) >> + lit("\r\n"), + container); +} + +} // namespace http +} // namespace network +} // namespace boost + +#endif /* SERVER_REQUEST_PARSERS_IMPL_UW3PM6V6 */ diff --git a/cpp-netlib/boost/network/protocol/http/server/options.hpp b/cpp-netlib/boost/network/protocol/http/server/options.hpp new file mode 100644 index 00000000..c64532e4 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server/options.hpp @@ -0,0 +1,210 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_SERVER_OPTIONS_20130128 +#define BOOST_NETWORK_PROTOCOL_HTTP_SERVER_OPTIONS_20130128 + +// Copyright 2013 Google, Inc. +// Copyright 2013 Dean Michael Berris +// Copyright 2014 Jelle Van den Driessche +// 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 +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct server_options { + typedef typename string::type string_type; + + explicit server_options(Handler &handler) + : io_service_(), + handler_(handler), + address_("localhost"), + port_("80"), + reuse_address_(false), + report_aborted_(false), + non_blocking_io_(true), + linger_(true), + linger_timeout_(0), + receive_buffer_size_(), + send_buffer_size_(), + receive_low_watermark_(), + send_low_watermark_(), + thread_pool_(), + context_() {} + + server_options(const server_options &other) + : io_service_(other.io_service()), + handler_(other.handler_), + address_(other.address_), + port_(other.port_), + reuse_address_(other.reuse_address_), + report_aborted_(other.report_aborted_), + non_blocking_io_(other.non_blocking_io_), + linger_(other.linger_), + linger_timeout_(0), + receive_buffer_size_(other.receive_buffer_size_), + send_buffer_size_(other.send_buffer_size_), + receive_low_watermark_(other.receive_low_watermark_), + send_low_watermark_(other.send_low_watermark_), + thread_pool_(other.thread_pool_), + context_(other.context_) {} + + server_options &operator=(server_options other) { + other.swap(*this); + return *this; + } + + void swap(server_options &other) { + using std::swap; + swap(io_service_, other.io_service_); + swap(address_, other.address_); + swap(port_, other.port_); + swap(reuse_address_, other.reuse_address_); + swap(report_aborted_, other.report_aborted_); + swap(non_blocking_io_, other.non_blocking_io_); + swap(linger_, other.linger_); + swap(linger_timeout_, other.linger_timeout_); + swap(receive_buffer_size_, other.receive_buffer_size_); + swap(send_buffer_size_, other.send_buffer_size_); + swap(receive_low_watermark_, other.receive_low_watermark_); + swap(send_low_watermark_, other.send_low_watermark_); + swap(thread_pool_, other.thread_pool_); + swap(context_, other.context_); + } + + server_options &context(boost::shared_ptr v) { + context_ = v; + return *this; + } + server_options &io_service(boost::shared_ptr v) { + io_service_ = v; + return *this; + } + server_options &address(string_type const &v) { + address_ = v; + return *this; + } + server_options &port(string_type const &v) { + port_ = v; + return *this; + } + server_options &reuse_address(bool v) { + reuse_address_ = v; + return *this; + } + server_options &report_aborted(bool v) { + report_aborted_ = v; + return *this; + } + server_options &non_blocking_io(bool v) { + non_blocking_io_ = v; + return *this; + } + server_options &linger(bool v) { + linger_ = v; + return *this; + } + server_options &linger_timeout(size_t v) { + linger_timeout_ = v; + return *this; + } + server_options &receive_buffer_size( + boost::asio::socket_base::receive_buffer_size v) { + receive_buffer_size_ = v; + return *this; + } + server_options &send_buffer_size( + boost::asio::socket_base::send_buffer_size v) { + send_buffer_size_ = v; + return *this; + } + server_options &receive_low_watermark( + boost::asio::socket_base::receive_low_watermark v) { + receive_low_watermark_ = v; + return *this; + } + server_options &send_low_watermark( + boost::asio::socket_base::send_low_watermark v) { + send_low_watermark_ = v; + return *this; + } + server_options &thread_pool(boost::shared_ptr v) { + thread_pool_ = v; + return *this; + } + + boost::shared_ptr io_service() const { + return io_service_; + } + string_type address() const { return address_; } + string_type port() const { return port_; } + Handler &handler() const { return handler_; } + bool reuse_address() const { return reuse_address_; } + bool report_aborted() const { return report_aborted_; } + bool non_blocking_io() const { return non_blocking_io_; } + bool linger() const { return linger_; } + size_t linger_timeout() const { return linger_timeout_; } + boost::optional + receive_buffer_size() const { + return receive_buffer_size_; + } + boost::optional send_buffer_size() + const { + return send_buffer_size_; + } + boost::optional + receive_low_watermark() const { + return receive_low_watermark_; + } + boost::optional + send_low_watermark() const { + return send_low_watermark_; + } + boost::shared_ptr thread_pool() const { + return thread_pool_; + } + boost::shared_ptr context() const { + return context_; + } + + private: + boost::shared_ptr io_service_; + Handler &handler_; + string_type address_; + string_type port_; + bool reuse_address_; + bool report_aborted_; + bool non_blocking_io_; + bool linger_; + size_t linger_timeout_; + boost::optional + receive_buffer_size_; + boost::optional send_buffer_size_; + boost::optional + receive_low_watermark_; + boost::optional + send_low_watermark_; + boost::shared_ptr thread_pool_; + boost::shared_ptr context_; +}; + +template +inline void swap(server_options &a, + server_options &b) { + a.swap(b); +} + +} /* http */ +} /* network */ +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SERVER_OPTIONS_20130128 */ diff --git a/cpp-netlib/boost/network/protocol/http/server/request.hpp b/cpp-netlib/boost/network/protocol/http/server/request.hpp new file mode 100644 index 00000000..f559ebf2 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server/request.hpp @@ -0,0 +1,51 @@ +// +// request.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2009 Dean Michael Berris (mikhailberis@gmail.com) +// Copyright (c) 2009 Tarro, Inc. +// +// 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 BOOST_NETWORK_HTTP_REQUEST_HPP +#define BOOST_NETWORK_HTTP_REQUEST_HPP + +#include +#include +#include +#include "header.hpp" + +namespace boost { +namespace network { +namespace http { + +/// A request received from a client. +struct request { + std::string method; + std::string uri; + int http_version_major; + int http_version_minor; + std::vector
headers; + std::string body; +}; + +inline void swap(request& l, request& r) { + using std::swap; + swap(l.method, r.method); + swap(l.uri, r.uri); + swap(l.http_version_major, r.http_version_major); + swap(l.http_version_minor, r.http_version_minor); + swap(l.headers, r.headers); + swap(l.body, r.body); +} + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_HTTP_REQUEST_HPP diff --git a/cpp-netlib/boost/network/protocol/http/server/request_parser.hpp b/cpp-netlib/boost/network/protocol/http/server/request_parser.hpp new file mode 100644 index 00000000..86587d95 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server/request_parser.hpp @@ -0,0 +1,229 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_SERVER_REQUEST_PARSER_HPP_20101005 +#define BOOST_NETWORK_PROTOCOL_HTTP_SERVER_REQUEST_PARSER_HPP_20101005 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct request_parser { + + enum state_t { + method_start, + method_char, + method_done, + uri_char, + uri_done, + version_h, + version_t1, + version_t2, + version_p, + version_slash, + version_d1, + version_dot, + version_d2, + version_cr, + version_done, + header_name, + header_colon, + header_value, + header_cr, + header_line_done, + headers_cr, + headers_done + }; + + explicit request_parser(state_t start_state = method_start) + : internal_state(start_state) {} + + void reset(state_t start_state = method_start) { + internal_state = method_start; + } + + state_t state() const { return internal_state; } + + template + fusion::tuple > + parse_until(state_t stop_state, Range& range) { + logic::tribool parsed_ok = logic::indeterminate; + typedef typename range_iterator::type iterator; + iterator start = boost::begin(range), end = boost::end(range), + current_iterator = start; + iterator_range local_range = + boost::make_iterator_range(start, end); + while (!boost::empty(local_range) && stop_state != internal_state && + indeterminate(parsed_ok)) { + current_iterator = boost::begin(local_range); + switch (internal_state) { + case method_start: + if (algorithm::is_upper()(*current_iterator)) + internal_state = method_char; + else + parsed_ok = false; + break; + case method_char: + if (algorithm::is_upper()(*current_iterator)) + break; + else if (algorithm::is_space()(*current_iterator)) + internal_state = method_done; + else + parsed_ok = false; + break; + case method_done: + if (algorithm::is_cntrl()(*current_iterator)) + parsed_ok = false; + else if (algorithm::is_space()(*current_iterator)) + parsed_ok = false; + else + internal_state = uri_char; + break; + case uri_char: + if (algorithm::is_cntrl()(*current_iterator)) + parsed_ok = false; + else if (algorithm::is_space()(*current_iterator)) + internal_state = uri_done; + break; + case uri_done: + if (*current_iterator == 'H') + internal_state = version_h; + else + parsed_ok = false; + break; + case version_h: + if (*current_iterator == 'T') + internal_state = version_t1; + else + parsed_ok = false; + break; + case version_t1: + if (*current_iterator == 'T') + internal_state = version_t2; + else + parsed_ok = false; + break; + case version_t2: + if (*current_iterator == 'P') + internal_state = version_p; + else + parsed_ok = false; + break; + case version_p: + if (*current_iterator == '/') + internal_state = version_slash; + else + parsed_ok = false; + break; + case version_slash: + if (algorithm::is_digit()(*current_iterator)) + internal_state = version_d1; + else + parsed_ok = false; + break; + case version_d1: + if (*current_iterator == '.') + internal_state = version_dot; + else + parsed_ok = false; + break; + case version_dot: + if (algorithm::is_digit()(*current_iterator)) + internal_state = version_d2; + else + parsed_ok = false; + break; + case version_d2: + if (*current_iterator == '\r') + internal_state = version_cr; + else + parsed_ok = false; + break; + case version_cr: + if (*current_iterator == '\n') + internal_state = version_done; + else + parsed_ok = false; + break; + case version_done: + if (algorithm::is_alnum()(*current_iterator)) + internal_state = header_name; + else if (*current_iterator == '\r') + internal_state = headers_cr; + else + parsed_ok = false; + break; + case header_name: + if (*current_iterator == ':') + internal_state = header_colon; + else if (algorithm::is_alnum()(*current_iterator) || + algorithm::is_punct()(*current_iterator)) + break; + else + parsed_ok = false; + break; + case header_colon: + if (*current_iterator == ' ') + internal_state = header_value; + else + parsed_ok = false; + break; + case header_value: + if (*current_iterator == '\r') + internal_state = header_cr; + else if (algorithm::is_cntrl()(*current_iterator)) + parsed_ok = false; + break; + case header_cr: + if (*current_iterator == '\n') + internal_state = header_line_done; + else + parsed_ok = false; + break; + case header_line_done: + if (*current_iterator == '\r') + internal_state = headers_cr; + else if (algorithm::is_alnum()(*current_iterator)) + internal_state = header_name; + else + parsed_ok = false; + break; + case headers_cr: + if (*current_iterator == '\n') + internal_state = headers_done; + else + parsed_ok = false; + break; + case headers_done: + // anything that follows after headers_done is allowed. + break; + default: + parsed_ok = false; + }; + if (internal_state == stop_state) parsed_ok = true; + local_range = boost::make_iterator_range(++current_iterator, end); + } + return fusion::make_tuple( + parsed_ok, boost::make_iterator_range(start, current_iterator)); + } + + private: + state_t internal_state; +}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SERVER_REQUEST_PARSER_HPP_20101005 */ diff --git a/cpp-netlib/boost/network/protocol/http/server/socket_options_base.hpp b/cpp-netlib/boost/network/protocol/http/server/socket_options_base.hpp new file mode 100644 index 00000000..9cc2ee15 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server/socket_options_base.hpp @@ -0,0 +1,62 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_SERVER_SOCKET_OPTIONS_BASE_HPP_20101210 +#define BOOST_NETWORK_PROTOCOL_HTTP_SERVER_SOCKET_OPTIONS_BASE_HPP_20101210 + +// Copyright 2010 Dean Michael Berris. +// 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 + +namespace boost { +namespace network { +namespace http { + +struct socket_options_base { + protected: + asio::socket_base::reuse_address acceptor_reuse_address; + asio::socket_base::enable_connection_aborted acceptor_report_aborted; + boost::optional receive_buffer_size; + boost::optional send_buffer_size; + boost::optional + receive_low_watermark; + boost::optional send_low_watermark; + asio::socket_base::non_blocking_io non_blocking_io; + asio::socket_base::linger linger; + + template + explicit socket_options_base(server_options const &options) + : acceptor_reuse_address(options.reuse_address()), + acceptor_report_aborted(options.report_aborted()), + receive_buffer_size(options.receive_buffer_size()), + send_buffer_size(options.send_buffer_size()), + receive_low_watermark(options.receive_low_watermark()), + send_low_watermark(options.send_low_watermark()), + non_blocking_io(options.non_blocking_io()), + linger(options.linger(), options.linger_timeout()) {} + + void acceptor_options(boost::asio::ip::tcp::acceptor &acceptor) { + acceptor.set_option(acceptor_reuse_address); + acceptor.set_option(acceptor_report_aborted); + } + + void socket_options(boost::asio::ip::tcp::socket &socket) { + boost::system::error_code ignored; + socket.io_control(non_blocking_io, ignored); + socket.set_option(linger, ignored); + if (receive_buffer_size) socket.set_option(*receive_buffer_size, ignored); + if (receive_low_watermark) + socket.set_option(*receive_low_watermark, ignored); + if (send_buffer_size) socket.set_option(*send_buffer_size, ignored); + if (send_low_watermark) socket.set_option(*send_low_watermark, ignored); + } +}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SERVER_SOCKET_OPTIONS_BASE_HPP_20101210 \ + */ diff --git a/cpp-netlib/boost/network/protocol/http/server/storage_base.hpp b/cpp-netlib/boost/network/protocol/http/server/storage_base.hpp new file mode 100644 index 00000000..ce0073c7 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server/storage_base.hpp @@ -0,0 +1,39 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_SERVER_STORAGE_BASE_HPP_20101210 +#define BOOST_NETWORK_PROTOCOL_HTTP_SERVER_STORAGE_BASE_HPP_20101210 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +struct server_storage_base { + struct no_io_service {}; + struct has_io_service {}; + + protected: + template + explicit server_storage_base(server_options const& options) + : self_service_(options.io_service() + ? options.io_service() + : boost::make_shared()), + service_(*self_service_) {} + + boost::shared_ptr self_service_; + asio::io_service& service_; +}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SERVER_STORAGE_BASE_HPP_20101210 */ diff --git a/cpp-netlib/boost/network/protocol/http/server/sync_connection.hpp b/cpp-netlib/boost/network/protocol/http/server/sync_connection.hpp new file mode 100644 index 00000000..bfe74969 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server/sync_connection.hpp @@ -0,0 +1,233 @@ +// Copyright 2009 (c) Dean Michael Berris +// Copyright 2009 (c) Tarroo, Inc. +// Adapted from Christopher Kholhoff's Boost.Asio Example, released under +// the Boost Software License, Version 1.0. (See acccompanying file +// LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_NETWORK_HTTP_SERVER_SYNC_CONNECTION_HPP_ +#define BOOST_NETWORK_HTTP_SERVER_SYNC_CONNECTION_HPP_ + +#ifndef BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE +#define BOOST_NETWORK_HTTP_SERVER_CONNECTION_BUFFER_SIZE 1024uL +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct sync_connection + : boost::enable_shared_from_this > { + + sync_connection(boost::asio::io_service &service, Handler &handler) + : service_(service), + handler_(handler), + socket_(service_), + wrapper_(service_) {} + + boost::asio::ip::tcp::socket &socket() { return socket_; } + + void start() { + // This is HTTP so we really want to just + // read and parse a request that's incoming + // and then pass that request object to the + // handler_ instance. + // + using boost::asio::ip::tcp; + boost::system::error_code option_error; + socket_.set_option(tcp::no_delay(true), option_error); + if (option_error) + handler_.log(boost::system::system_error(option_error).what()); + socket_.async_read_some( + boost::asio::buffer(buffer_), + wrapper_.wrap( + boost::bind(&sync_connection::handle_read_headers, + sync_connection::shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + } + + private: + struct is_content_length { + template + bool operator()(Header const &header) { + return boost::to_lower_copy(header.name) == "content-length"; + } + }; + + void handle_read_headers(boost::system::error_code const &ec, + size_t bytes_transferred) { + if (!ec) { + request_.source = socket_.remote_endpoint().address().to_string(); + request_.source_port = socket_.remote_endpoint().port(); + boost::tribool done; + buffer_type::iterator new_start; + tie(done, new_start) = parser_.parse_headers( + request_, buffer_.data(), buffer_.data() + bytes_transferred); + if (done) { + if (request_.method[0] == 'P') { + // look for the content-length header + typename std::vector::type>::iterator + it = std::find_if(request_.headers.begin(), + request_.headers.end(), is_content_length()); + if (it == request_.headers.end()) { + response_ = basic_response::stock_reply( + basic_response::bad_request); + boost::asio::async_write( + socket_, response_.to_buffers(), + wrapper_.wrap(boost::bind( + &sync_connection::handle_write, + sync_connection::shared_from_this(), + boost::asio::placeholders::error))); + return; + } + + size_t content_length = 0; + + try { + content_length = boost::lexical_cast(it->value); + } + catch (...) { + response_ = basic_response::stock_reply( + basic_response::bad_request); + boost::asio::async_write( + socket_, response_.to_buffers(), + wrapper_.wrap(boost::bind( + &sync_connection::handle_write, + sync_connection::shared_from_this(), + boost::asio::placeholders::error))); + return; + } + + if (content_length != 0) { + if (new_start != (buffer_.begin() + bytes_transferred)) { + request_.body.append(new_start, + buffer_.begin() + bytes_transferred); + content_length -= + std::distance(new_start, buffer_.begin() + bytes_transferred); + } + if (content_length > 0) { + socket_.async_read_some( + boost::asio::buffer(buffer_), + wrapper_.wrap(boost::bind( + &sync_connection::handle_read_body_contents, + sync_connection::shared_from_this(), + boost::asio::placeholders::error, content_length, + boost::asio::placeholders::bytes_transferred))); + return; + } + } + + handler_(request_, response_); + boost::asio::async_write( + socket_, response_.to_buffers(), + wrapper_.wrap( + boost::bind(&sync_connection::handle_write, + sync_connection::shared_from_this(), + boost::asio::placeholders::error))); + } else { + handler_(request_, response_); + boost::asio::async_write( + socket_, response_.to_buffers(), + wrapper_.wrap( + boost::bind(&sync_connection::handle_write, + sync_connection::shared_from_this(), + boost::asio::placeholders::error))); + } + } else if (!done) { + response_ = + basic_response::stock_reply(basic_response::bad_request); + boost::asio::async_write( + socket_, response_.to_buffers(), + wrapper_.wrap( + boost::bind(&sync_connection::handle_write, + sync_connection::shared_from_this(), + boost::asio::placeholders::error))); + } else { + socket_.async_read_some( + boost::asio::buffer(buffer_), + wrapper_.wrap( + boost::bind(&sync_connection::handle_read_headers, + sync_connection::shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + } + } + // TODO Log the error? + } + + void handle_read_body_contents(boost::system::error_code const &ec, + size_t bytes_to_read, + size_t bytes_transferred) { + if (!ec) { + size_t difference = bytes_to_read - bytes_transferred; + buffer_type::iterator start = buffer_.begin(), past_end = start; + std::advance(past_end, (std::min)(bytes_to_read, bytes_transferred)); + request_.body.append(buffer_.begin(), past_end); + if (difference == 0) { + handler_(request_, response_); + boost::asio::async_write( + socket_, response_.to_buffers(), + wrapper_.wrap( + boost::bind(&sync_connection::handle_write, + sync_connection::shared_from_this(), + boost::asio::placeholders::error))); + } else { + socket_.async_read_some( + boost::asio::buffer(buffer_), + wrapper_.wrap(boost::bind( + &sync_connection::handle_read_body_contents, + sync_connection::shared_from_this(), + boost::asio::placeholders::error, difference, + boost::asio::placeholders::bytes_transferred))); + } + } + // TODO Log the error? + } + + void handle_write(boost::system::error_code const &ec) { + if (!ec) { + using boost::asio::ip::tcp; + boost::system::error_code ignored_ec; + socket_.shutdown(tcp::socket::shutdown_receive, ignored_ec); + } + } + + boost::asio::io_service &service_; + Handler &handler_; + boost::asio::ip::tcp::socket socket_; + boost::asio::io_service::strand wrapper_; + + typedef boost::array + buffer_type; + buffer_type buffer_; + typedef basic_request_parser request_parser; + request_parser parser_; + basic_request request_; + basic_response response_; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_HTTP_SERVER_SYNC_CONNECTION_HPP_ diff --git a/cpp-netlib/boost/network/protocol/http/server/sync_server.hpp b/cpp-netlib/boost/network/protocol/http/server/sync_server.hpp new file mode 100644 index 00000000..7c5c42fa --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/server/sync_server.hpp @@ -0,0 +1,134 @@ + +// Copyright 2010 Dean Michael Berris. +// Copyright 2010 Glyn Matthews. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_SERVER_SYNC_SERVER_HPP_20101025 +#define BOOST_NETWORK_PROTOCOL_HTTP_SERVER_SYNC_SERVER_HPP_20101025 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct sync_server_base : server_storage_base, socket_options_base { + typedef typename string::type string_type; + typedef basic_request request; + typedef basic_response response; + typedef typename boost::network::http::response_header::type + response_header; + + sync_server_base(server_options const& options) + : server_storage_base(options), + socket_options_base(options), + handler_(options.handler()), + address_(options.address()), + port_(options.port()), + acceptor_(server_storage_base::service_), + new_connection(), + listening_mutex_(), + listening_(false) {} + + void run() { + listen(); + service_.run(); + } + + void stop() { + // stop accepting new connections and let all the existing handlers + // finish. + system::error_code ignored; + acceptor_.close(ignored); + service_.stop(); + } + + void listen() { + boost::unique_lock listening_lock(listening_mutex_); + if (!listening_) start_listening(); + } + + private: + Handler& handler_; + string_type address_, port_; + boost::asio::ip::tcp::acceptor acceptor_; + boost::shared_ptr > new_connection; + boost::mutex listening_mutex_; + bool listening_; + + void handle_accept(boost::system::error_code const& ec) { + if (ec) { + } + socket_options_base::socket_options(new_connection->socket()); + new_connection->start(); + new_connection.reset(new sync_connection(service_, handler_)); + acceptor_.async_accept( + new_connection->socket(), + boost::bind(&sync_server_base::handle_accept, this, + boost::asio::placeholders::error)); + } + + void start_listening() { + using boost::asio::ip::tcp; + system::error_code error; + tcp::resolver resolver(service_); + tcp::resolver::query query(address_, port_); + tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, error); + if (error) { + BOOST_NETWORK_MESSAGE("Error resolving address: " << address_ << ':' + << port_); + boost::throw_exception(std::runtime_error("Error resolving address.")); + } + tcp::endpoint endpoint = *endpoint_iterator; + acceptor_.open(endpoint.protocol(), error); + if (error) { + BOOST_NETWORK_MESSAGE("Error opening socket: " << address_ << ':' << port_ + << " -- reason: '" << error + << '\''); + boost::throw_exception(std::runtime_error("Error opening socket.")); + } + socket_options_base::acceptor_options(acceptor_); + acceptor_.bind(endpoint, error); + if (error) { + BOOST_NETWORK_MESSAGE("Error binding to socket: " + << address_ << ':' << port_ << " -- reason: '" + << error << '\''); + boost::throw_exception(std::runtime_error("Error binding to socket.")); + } + acceptor_.listen(tcp::socket::max_connections, error); + if (error) { + BOOST_NETWORK_MESSAGE("Error listening on socket: " + << address_ << ':' << port_ << " -- reason: '" + << error << '\''); + boost::throw_exception(std::runtime_error("Error listening on socket.")); + } + new_connection.reset(new sync_connection(service_, handler_)); + acceptor_.async_accept( + new_connection->socket(), + boost::bind(&sync_server_base::handle_accept, this, + boost::asio::placeholders::error)); + listening_ = true; + } +}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SERVER_SYNC_SERVER_HPP_20101025 */ diff --git a/cpp-netlib/boost/network/protocol/http/support/client_or_server.hpp b/cpp-netlib/boost/network/protocol/http/support/client_or_server.hpp new file mode 100644 index 00000000..434d6f35 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/support/client_or_server.hpp @@ -0,0 +1,41 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_SUPPORT_CLIENT_OR_SERVER_HPP_20101127 +#define BOOST_NETWORK_PROTOCOL_HTTP_SUPPORT_CLIENT_OR_SERVER_HPP_20101127 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct unsupported_tag; + +template +struct client_or_server { + typedef unsupported_tag type; +}; + +template +struct client_or_server >::type> { + typedef tags::server type; +}; + +template +struct client_or_server >::type> { + typedef tags::client type; +}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SUPPORT_CLIENT_OR_SERVER_HPP_20101127 */ diff --git a/cpp-netlib/boost/network/protocol/http/support/is_client.hpp b/cpp-netlib/boost/network/protocol/http/support/is_client.hpp new file mode 100644 index 00000000..c4201c1c --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/support/is_client.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_NETWORK_PROTOCOL_SUPPORT_IS_CLIENT_HPP_20101118 +#define BOOST_NETWORK_PROTOCOL_SUPPORT_IS_CLIENT_HPP_20101118 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct is_client : mpl::false_ {}; + +template +struct is_client< + Tag, typename enable_if::type> : mpl::true_ {}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_SUPPORT_IS_CLIENT_HPP_20101118 */ diff --git a/cpp-netlib/boost/network/protocol/http/support/is_http.hpp b/cpp-netlib/boost/network/protocol/http/support/is_http.hpp new file mode 100644 index 00000000..d170819c --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/support/is_http.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_HTTP_HPP_20100622 +#define BOOST_NETWORK_SUPPORT_IS_HTTP_HPP_20100622 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct is_http : mpl::false_ {}; + +template +struct is_http::type> : mpl::true_ {}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_SUPPORT_IS_HTTP_HPP_20100622 diff --git a/cpp-netlib/boost/network/protocol/http/support/is_keepalive.hpp b/cpp-netlib/boost/network/protocol/http/support/is_keepalive.hpp new file mode 100644 index 00000000..a063167f --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/support/is_keepalive.hpp @@ -0,0 +1,32 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_KEEPALIVE_HPP_20100927 +#define BOOST_NETWORK_SUPPORT_IS_KEEPALIVE_HPP_20100927 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct unsupported_tag; + +template +struct is_keepalive : mpl::false_ {}; + +template +struct is_keepalive< + Tag, typename enable_if::type> : mpl::true_ {}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_SUPPORT_IS_KEEPALIVE_HPP_20100927 */ diff --git a/cpp-netlib/boost/network/protocol/http/support/is_server.hpp b/cpp-netlib/boost/network/protocol/http/support/is_server.hpp new file mode 100644 index 00000000..365ad6e3 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/support/is_server.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_NETWORK_PROTOCOL_SUPPORT_IS_SERVER_HPP_20101118 +#define BOOST_NETWORK_PROTOCOL_SUPPORT_IS_SERVER_HPP_20101118 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct is_server : mpl::false_ {}; + +template +struct is_server< + Tag, typename enable_if::type> : mpl::true_ {}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_SUPPORT_IS_SERVER_HPP_20101118 */ diff --git a/cpp-netlib/boost/network/protocol/http/support/is_simple.hpp b/cpp-netlib/boost/network/protocol/http/support/is_simple.hpp new file mode 100644 index 00000000..c329df8f --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/support/is_simple.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_SIMPLE_HPP_20100927 +#define BOOST_NETWORK_SUPPORT_IS_SIMPLE_HPP_20100927 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct is_simple : mpl::false_ {}; + +template +struct is_simple< + Tag, typename enable_if::type> : mpl::true_ {}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_SUPPORT_IS_SIMPLE_HPP_20100927 */ diff --git a/cpp-netlib/boost/network/protocol/http/support/sync_only.hpp b/cpp-netlib/boost/network/protocol/http/support/sync_only.hpp new file mode 100644 index 00000000..6a3eb3fe --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/support/sync_only.hpp @@ -0,0 +1,30 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_SUPPORT_SYNC_ONLY_HPP_20100927 +#define BOOST_NETWORK_PROTOCOL_HTTP_SUPPORT_SYNC_ONLY_HPP_20100927 + +// Copyright Dean Michael Berris 2010. +// 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 +#include + +namespace boost { +namespace network { +namespace http { + +template +struct sync_only + : mpl::inherit_linearly< + typename mpl::replace_if::type, + is_same, + tags::sync>::type, + mpl::inherit > {}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SUPPORT_SYNC_ONLY_HPP_20100927 */ diff --git a/cpp-netlib/boost/network/protocol/http/tags.hpp b/cpp-netlib/boost/network/protocol/http/tags.hpp new file mode 100644 index 00000000..bdf8b443 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/tags.hpp @@ -0,0 +1,71 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_TAGS_HPP_20101019 +#define BOOST_NETWORK_PROTOCOL_HTTP_TAGS_HPP_20101019 + +// Copyright Dean Michael Berris 2010. +// 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 + +namespace boost { +namespace network { +namespace http { +namespace tags { + +struct http { + typedef mpl::true_::type is_http; +}; +struct keepalive { + typedef mpl::true_::type is_keepalive; +}; +struct simple { + typedef mpl::true_::type is_simple; +}; +struct server { + typedef mpl::true_::type is_server; +}; +struct client { + typedef mpl::true_::type is_client; +}; + +using namespace boost::network::tags; + +template +struct components; + +typedef mpl::vector + http_default_8bit_tcp_resolve_tags; +typedef mpl::vector + http_default_8bit_udp_resolve_tags; +typedef mpl::vector + http_keepalive_8bit_tcp_resolve_tags; +typedef mpl::vector + http_keepalive_8bit_udp_resolve_tags; +typedef mpl::vector + http_async_8bit_udp_resolve_tags; +typedef mpl::vector + http_async_8bit_tcp_resolve_tags; +typedef mpl::vector + http_server_tags; +typedef mpl::vector + http_async_server_tags; + +BOOST_NETWORK_DEFINE_TAG(http_default_8bit_tcp_resolve); +BOOST_NETWORK_DEFINE_TAG(http_default_8bit_udp_resolve); +BOOST_NETWORK_DEFINE_TAG(http_keepalive_8bit_tcp_resolve); +BOOST_NETWORK_DEFINE_TAG(http_keepalive_8bit_udp_resolve); +BOOST_NETWORK_DEFINE_TAG(http_async_8bit_udp_resolve); +BOOST_NETWORK_DEFINE_TAG(http_async_8bit_tcp_resolve); +BOOST_NETWORK_DEFINE_TAG(http_server); +BOOST_NETWORK_DEFINE_TAG(http_async_server); + +} /* tags */ + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_TAGS_HPP_20101019 */ diff --git a/cpp-netlib/boost/network/protocol/http/traits.hpp b/cpp-netlib/boost/network/protocol/http/traits.hpp new file mode 100644 index 00000000..afa4ea0c --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits.hpp @@ -0,0 +1,18 @@ +// This file is part of the Boost Network library +// Based on the Pion Network Library (r421) +// Copyright Atomic Labs, Inc. 2007-2008 +// See http://cpp-netlib.sourceforge.net for library home page. +// +// 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 BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_HPP +#define BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_HPP + +// Convenience header for including different traits implementations. +#include +//#include +#include + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_HPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/connection_keepalive.hpp b/cpp-netlib/boost/network/protocol/http/traits/connection_keepalive.hpp new file mode 100644 index 00000000..0069b3a3 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/connection_keepalive.hpp @@ -0,0 +1,25 @@ +// Copyright (c) Dean Michael Berris 2010. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_CONECTION_KEEPALIVE_20091218 +#define BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_CONECTION_KEEPALIVE_20091218 + +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct connection_keepalive : is_keepalive {}; + +} /* http */ + +} /* network */ + +} /* boost */ + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_CONECTION_KEEPALIVE_20091218 diff --git a/cpp-netlib/boost/network/protocol/http/traits/connection_policy.hpp b/cpp-netlib/boost/network/protocol/http/traits/connection_policy.hpp new file mode 100644 index 00000000..4ee96eee --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/connection_policy.hpp @@ -0,0 +1,61 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CONNECTION_POLICY_20091214 +#define BOOST_NETWORK_PROTOCOL_HTTP_CONNECTION_POLICY_20091214 + +// Copyright 2013 Google, Inc. +// Copyright Dean Michael Berris 2009. +// 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 +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct unsupported_tag; + +template +struct connection_policy { + typedef unsupported_tag type; +}; + +template +struct connection_policy >::type> { + typedef async_connection_policy type; +}; + +template +struct connection_policy< + Tag, version_major, version_minor, + typename enable_if< + mpl::and_, mpl::not_ > > >::type> { + typedef simple_connection_policy type; +}; + +template +struct connection_policy< + Tag, version_major, version_minor, + typename enable_if< + mpl::and_, mpl::not_ > > >::type> { + typedef pooled_connection_policy type; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_CONNECTION_POLICY_20091214 diff --git a/cpp-netlib/boost/network/protocol/http/traits/delegate_factory.hpp b/cpp-netlib/boost/network/protocol/http/traits/delegate_factory.hpp new file mode 100644 index 00000000..cec92c26 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/delegate_factory.hpp @@ -0,0 +1,40 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_DELEGATE_FACTORY_HPP_20110819 +#define BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_DELEGATE_FACTORY_HPP_20110819 + +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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 + +namespace boost { +namespace network { +namespace http { + +namespace impl { + +template +struct connection_delegate_factory; + +} /* impl */ + +template +struct unsupported_tag; + +template +struct delegate_factory { + typedef unsupported_tag type; +}; + +template +struct delegate_factory >::type> { + typedef impl::connection_delegate_factory type; +}; + +} /* http */ +} /* network */ +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_DELEGATE_FACTORY_HPP_20110819 */ diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/chunk_cache.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/chunk_cache.ipp new file mode 100644 index 00000000..c7ac9c88 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/chunk_cache.ipp @@ -0,0 +1,32 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_CHUNK_CACHE_CONTAINER_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_CHUNK_CACHE_CONTAINER_IPP + +#include +#include + +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct chunk_cache { + // TODO define the allocator using an allocator_traits? + typedef std::list::type> > type; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_CHUNK_CACHE_CONTAINER_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/content.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/content.ipp new file mode 100644 index 00000000..81e96d37 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/content.ipp @@ -0,0 +1,46 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_CONTENT_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_CONTENT_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct content { + static char const* type_html() { + static char const* const TYPE_HTML = "text/html"; + return TYPE_HTML; + }; + + static char const* type_text() { + static char const* const TYPE_TEXT = "text/plain"; + return TYPE_TEXT; + }; + + static char const* type_xml() { + static char const* const TYPE_XML = "text/xml"; + return TYPE_XML; + }; + + static char const* type_urlencoded() { + static char const* const TYPE_URLENCODED = + "application/x-www-form-urlencoded"; + return TYPE_URLENCODED; + }; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_CONTENT_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/cookie_name.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/cookie_name.ipp new file mode 100644 index 00000000..af8cf6c5 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/cookie_name.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_COOKIE_NAME_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_COOKIE_NAME_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct cookie_name { + static boost::uint32_t const MAX = 1024u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_COOKIE_NAME_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/cookie_value.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/cookie_value.ipp new file mode 100644 index 00000000..32b7ef38 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/cookie_value.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_COOKIE_VALUE_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_COOKIE_VALUE_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct cookie_value { + static boost::uint32_t const MAX = 1024u * 1024u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_COOKIE_VALUE_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/cookies_container.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/cookies_container.ipp new file mode 100644 index 00000000..ef4db91c --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/cookies_container.ipp @@ -0,0 +1,30 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_COOKIES_CONTAINER_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_COOKIES_CONTAINER_IPP + +#include + +#include + +namespace boost { +namespace network { +namespace http { + +template +struct cookies_container { + typedef std::multimap::type, typename string::type> + type; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_COOKIES_CONTAINER_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/delimiters.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/delimiters.ipp new file mode 100644 index 00000000..b916b670 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/delimiters.ipp @@ -0,0 +1,41 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_DELIMITERS_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_DELIMITERS_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +// specialize on the tags::http_default_8bit_tcp_resolve type +template <> +struct delimiters { + static char const* string_crlf() { + static char const* const CRLF = "\x0D\x0A"; + return CRLF; + }; + + static char const* string_http_version() { + static char const* const HTTP_VERSION = "HTTP/1.1"; + return HTTP_VERSION; + }; + + static char const* header_name_value_delimiter() { + static char const* const HEADER_NAME_VALUE_DELIMITER = ": "; + return HEADER_NAME_VALUE_DELIMITER; + }; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_DELIMITERS_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/header_name.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/header_name.ipp new file mode 100644 index 00000000..dcab0f3f --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/header_name.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_HEADER_NAME_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_HEADER_NAME_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct header_name { + static boost::uint32_t const MAX = 1024u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_HEADER_NAME_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/header_value.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/header_value.ipp new file mode 100644 index 00000000..8f09d718 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/header_value.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_HEADER_VALUE_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_HEADER_VALUE_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct header_value { + static boost::uint32_t const MAX = 1024u * 1024u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_HEADER_VALUE_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/headers.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/headers.ipp new file mode 100644 index 00000000..24fac86b --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/headers.ipp @@ -0,0 +1,85 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_HEADERS_HPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_HEADERS_HPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct headers_ { + static char const* host() { + static char const* const HOST = "Host"; + return HOST; + }; + + static char const* cookie() { + static char const* const COOKIE = "Cookie"; + return COOKIE; + }; + + static char const* set_cookie() { + static char const* const SET_COOKIE = "Set-Cookie"; + return SET_COOKIE; + }; + + static char const* connection() { + static char const* const CONNECTION = "Connection"; + return CONNECTION; + }; + + static char const* content_type() { + static char const* const CONTENT_TYPE = "Content-Type"; + return CONTENT_TYPE; + }; + + static char const* content_length() { + static char const* const CONTENT_LENGTH = "Content-Length"; + return CONTENT_LENGTH; + }; + + static char const* content_location() { + static char const* const CONTENT_LOCATION = "Content-Location"; + return CONTENT_LOCATION; + }; + + static char const* last_modified() { + static char const* const LAST_MODIFIED = "Last-Modified"; + return LAST_MODIFIED; + }; + + static char const* if_modified_since() { + static char const* const IF_MODIFIED_SINCE = "If-Modified-Since"; + return IF_MODIFIED_SINCE; + }; + + static char const* transfer_encoding() { + static char const* const TRANSFER_ENCODING = "Transfer-Encoding"; + return TRANSFER_ENCODING; + }; + + static char const* location() { + static char const* const LOCATION = "Location"; + return LOCATION; + }; + + static char const* authorization() { + static char const* const AUTHORIZATION = "Authorization"; + return AUTHORIZATION; + }; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_HEADERS_HPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/headers_container.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/headers_container.ipp new file mode 100644 index 00000000..d06585ef --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/headers_container.ipp @@ -0,0 +1,51 @@ + +// Copyright 2013 Google, Inc. +// Copyright 2008 Dean Michael Berris +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_HEADERS_CONTAINER_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_HEADERS_CONTAINER_IPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace impl { + +// Moving implementation from original +// message_traits implementation by +// Atomic Labs, Inc. +// -- +// returns true if str1 < str2 (ignoring case) +struct is_less_ignore_case_impl { + inline bool operator()( + string::type const& str1, + string::type const& str2) + const { + return to_lower_copy(str1) < to_lower_copy(str2); + }; +}; + +template +struct headers_container_impl< + Tag, typename enable_if::type> { + + typedef is_less_ignore_case_impl is_less_ignore_case; + + typedef std::multimap::type, + string::type, + is_less_ignore_case> type; +}; + +} // namespace impl +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_HEADERS_CONTAINER_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/method.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/method.ipp new file mode 100644 index 00000000..17c26111 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/method.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_METHOD_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_METHOD_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct method { + static boost::uint32_t const MAX = 1024u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_METHOD_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/post_content.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/post_content.ipp new file mode 100644 index 00000000..6db2b2db --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/post_content.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_POST_CONTENT_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_POST_CONTENT_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct post_content { + static boost::uint32_t const MAX = 1024u * 1024u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_POST_CONTENT_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/query_container.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/query_container.ipp new file mode 100644 index 00000000..b672c3b0 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/query_container.ipp @@ -0,0 +1,30 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_QUERY_CONTAINER_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_QUERY_CONTAINER_IPP + +#include + +#include + +namespace boost { +namespace network { +namespace http { + +template +struct query_container { + typedef std::multimap::type, typename string::type> + type; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_QUERY_CONTAINER_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/query_name.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/query_name.ipp new file mode 100644 index 00000000..f748172b --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/query_name.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_QUERY_NAME_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_QUERY_NAME_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct query_name { + static boost::uint32_t const MAX = 1024u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_QUERY_NAME_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/query_string.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/query_string.ipp new file mode 100644 index 00000000..4876e2c9 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/query_string.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_QUERY_STRING_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_QUERY_STRING_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct query_string { + static boost::uint32_t const MAX = 1024u * 1024u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_QUERY_STRING_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/query_value.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/query_value.ipp new file mode 100644 index 00000000..7a692a06 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/query_value.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_QUERY_VALUE_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_QUERY_VALUE_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct query_value { + static boost::uint32_t const MAX = 1024u * 1024u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_QUERY_VALUE_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/request_methods.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/request_methods.ipp new file mode 100644 index 00000000..140beeff --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/request_methods.ipp @@ -0,0 +1,50 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_REQUEST_METHODS_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_REQUEST_METHODS_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct request_methods { + static char const* head() { + static char const* const HEAD = "HEAD"; + return HEAD; + }; + + static char const* get() { + static char const* const GET = "GET"; + return GET; + }; + + static char const* put() { + static char const* const PUT = "PUT"; + return PUT; + }; + + static char const* post() { + static char const* const POST = "POST"; + return POST; + }; + + static char const* delete_() { + static char const* const DELETE_ = "DELETE"; + return DELETE_; + }; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_REQUEST_METHODS_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/resource.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/resource.ipp new file mode 100644 index 00000000..5551d16f --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/resource.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_RESOURCE_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_RESOURCE_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct resource { + static boost::uint32_t const MAX = 1024u * 256u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_RESOURCE_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/response_code.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/response_code.ipp new file mode 100644 index 00000000..db32bcf9 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/response_code.ipp @@ -0,0 +1,45 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_RESPONSE_CODE_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_RESPONSE_CODE_IPP + +#include +#include + +namespace boost { +namespace network { +namespace http { + +/* This glob doesn't have a specialization on the + * tags::http_default_8bit_tcp_resolve + * yet because it doesn't need to define different behaviour/types + * on different message tags -- for example, it doesn't need to + * determine the type or change the values of the data no matter + * what the tag type is provided. + */ +template +struct response_code { + static boost::uint16_t const RC_OK = 200u; + static boost::uint16_t const RC_CREATED = 201u; + static boost::uint16_t const RC_NO_CONTENT = 204u; + static boost::uint16_t const RC_UNAUTHORIZED = 401u; + static boost::uint16_t const RC_FORBIDDEN = 403u; + static boost::uint16_t const RC_NOT_FOUND = 404u; + static boost::uint16_t const RC_METHOD_NOT_ALLOWED = 405u; + static boost::uint16_t const RC_NOT_MODIFIED = 304u; + static boost::uint16_t const RC_BAD_REQUEST = 400u; + static boost::uint16_t const RC_SERVER_ERROR = 500u; + static boost::uint16_t const RC_NOT_IMPLEMENTED = 501u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_RESPONSE_CODE_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/response_message.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/response_message.ipp new file mode 100644 index 00000000..2f81b2d8 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/response_message.ipp @@ -0,0 +1,80 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_RESPONSE_MESSAGE_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_RESPONSE_MESSAGE_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct response_message { + static char const* ok() { + static char const* const RC_OK = "OK"; + return RC_OK; + }; + + static char const* created() { + static char const* const RC_CREATED = "Created"; + return RC_CREATED; + }; + + static char const* no_content() { + static char const* const RC_NO_CONTENT = "NO Content"; + return RC_NO_CONTENT; + }; + + static char const* unauthorized() { + static char const* const RC_UNAUTHORIZED = "Unauthorized"; + return RC_UNAUTHORIZED; + }; + + static char const* forbidden() { + static char const* const RC_FORBIDDEN = "Fobidden"; + return RC_FORBIDDEN; + }; + + static char const* not_found() { + static char const* const RC_NOT_FOUND = "Not Found"; + return RC_NOT_FOUND; + }; + + static char const* method_not_allowed() { + static char const* const RC_METHOD_NOT_ALLOWED = "Method Not Allowed"; + return RC_METHOD_NOT_ALLOWED; + }; + + static char const* not_modified() { + static char const* const RC_NOT_MODIFIED = "Not Modified"; + return RC_NOT_MODIFIED; + }; + + static char const* bad_request() { + static char const* const RC_BAD_REQUEST = "Bad Request"; + return RC_BAD_REQUEST; + }; + + static char const* server_error() { + static char const* const RC_SERVER_ERROR = "Server Error"; + return RC_SERVER_ERROR; + }; + + static char const* not_implemented() { + static char const* const RC_NOT_IMPLEMENTED = "Not Implemented"; + return RC_NOT_IMPLEMENTED; + }; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_RESPONSE_MESSAGE_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/impl/status_message.ipp b/cpp-netlib/boost/network/protocol/http/traits/impl/status_message.ipp new file mode 100644 index 00000000..78d8a9a4 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/impl/status_message.ipp @@ -0,0 +1,27 @@ + +// Copyright Dean Michael Berris 2008. +// 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 BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_STATUS_MESSAGE_IPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_STATUS_MESSAGE_IPP + +#include + +namespace boost { +namespace network { +namespace http { + +template <> +struct status_message_text { + static boost::uint32_t const MAX = 1024u; +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_STATUS_MESSAGE_IPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/message_traits.hpp b/cpp-netlib/boost/network/protocol/http/traits/message_traits.hpp new file mode 100644 index 00000000..8c2f65a6 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/message_traits.hpp @@ -0,0 +1,65 @@ + +// This file is part of the Boost Network library +// Based on the Pion Network Library (r421) +// Copyright Atomic Labs, Inc. 2007-2008 +// See http://cpp-netlib.sourceforge.net for library home page. +// +// 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) +// +// Some changes Copyright (c) Dean Michael Berris 2008 + +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_HPP +#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_TRAITS_HPP + +namespace boost { +namespace network { +namespace http { + +template +struct delimiters; + +template +struct headers_; + +template +struct content; + +template +struct request_methods; + +template +struct response_message; + +template +struct response_code; + +template +struct query_container; + +template +struct cookies_container; + +template +struct chunk_cache; + +} // namespace http + +} // namespace network + +} // namespace boost + +// Defer definition in implementation files +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_HPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/parser_traits.hpp b/cpp-netlib/boost/network/protocol/http/traits/parser_traits.hpp new file mode 100644 index 00000000..82c3bc38 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/parser_traits.hpp @@ -0,0 +1,71 @@ +// This file is part of the Boost Network library +// Based on the Pion Network Library (r421) +// Copyright Atomic Labs, Inc. 2007-2008 +// See http://cpp-netlib.sourceforge.net for library home page. +// +// 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) +// +// Some changes Copyright 2008 (c) Dean Michael Berris + +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_HPP +#define BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_HPP + +namespace boost { +namespace network { +namespace http { + +template +struct status_message_text; + +template +struct method; + +template +struct resource; + +template +struct query_string; + +template +struct header_name; + +template +struct header_value; + +template +struct query_name; + +template +struct query_value; + +template +struct cookie_name; + +template +struct cookie_value; + +template +struct post_content; + +} // namespace http + +} // namespace network + +} // namespace boost + +// Include implementation files +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_PARSER_TRAITS_HPP diff --git a/cpp-netlib/boost/network/protocol/http/traits/resolver.hpp b/cpp-netlib/boost/network/protocol/http/traits/resolver.hpp new file mode 100644 index 00000000..45048fd8 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/resolver.hpp @@ -0,0 +1,44 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_RESOLVER_20091214 +#define BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_RESOLVER_20091214 + +// Copyright Dean Michael Berris 2009. +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct unsupported_tag; + +template +struct resolver + : mpl::if_, is_http >, + boost::asio::ip::tcp::resolver, + typename mpl::if_, is_http >, + boost::asio::ip::udp::resolver, + unsupported_tag >::type> { + BOOST_STATIC_ASSERT( + (mpl::not_, is_tcp > >::value)); +}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_RESOLVER_20091214 diff --git a/cpp-netlib/boost/network/protocol/http/traits/resolver_policy.hpp b/cpp-netlib/boost/network/protocol/http/traits/resolver_policy.hpp new file mode 100644 index 00000000..5c279dd3 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/resolver_policy.hpp @@ -0,0 +1,37 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_RESOLVER_POLICY_20091214 +#define BOOST_NETWORK_PROTOCOL_HTTP_RESOLVER_POLICY_20091214 + +// Copyright Dean Michael Berris 2009. +// 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 +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace http { + +template +struct unsupported_tag; + +template +struct resolver_policy + : mpl::if_, is_http >, + policies::async_resolver, + typename mpl::if_, policies::sync_resolver, + unsupported_tag >::type> {}; + +} // namespace http + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_PROTOCOL_HTTP_RESOLVER_POLICY_20091214 diff --git a/cpp-netlib/boost/network/protocol/http/traits/vector.hpp b/cpp-netlib/boost/network/protocol/http/traits/vector.hpp new file mode 100644 index 00000000..bc343de7 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/http/traits/vector.hpp @@ -0,0 +1,37 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_VECTOR_HPP_20101019 +#define BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_VECTOR_HPP_20101019 + +// Copyright (c) Dean Michael Berris 2010. +// 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 +#include + +namespace boost { +namespace network { + +template <> +struct vector { + + template + struct apply { + typedef std::vector type; + }; +}; + +template <> +struct vector { + + template + struct apply { + typedef std::vector type; + }; +}; + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_TRAITS_VECTOR_HPP_20101019 */ diff --git a/cpp-netlib/boost/network/protocol/stream_handler.hpp b/cpp-netlib/boost/network/protocol/stream_handler.hpp new file mode 100644 index 00000000..615d8548 --- /dev/null +++ b/cpp-netlib/boost/network/protocol/stream_handler.hpp @@ -0,0 +1,188 @@ +#ifndef NETLIB_IO_STREAM_HANDLER_HPP +#define NETLIB_IO_STREAM_HANDLER_HPP + +// Copyright 2014 Jelle Van den Driessche. +// 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) + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +#pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#ifdef BOOST_NETWORK_ENABLE_HTTPS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { + +typedef boost::asio::ip::tcp::socket tcp_socket; + +#ifndef BOOST_NETWORK_ENABLE_HTTPS +typedef tcp_socket stream_handler; +typedef void ssl_context; +#else + +typedef boost::asio::ssl::stream ssl_socket; +typedef boost::asio::ssl::context ssl_context; + +struct stream_handler { + public: + stream_handler(boost::shared_ptr socket) + : tcp_sock_(socket), ssl_enabled(false) {} + + ~stream_handler() {} + + stream_handler(boost::shared_ptr socket) + : ssl_sock_(socket), ssl_enabled(true) {} + + stream_handler(boost::asio::io_service& io, + boost::shared_ptr ctx = + boost::shared_ptr()) { + tcp_sock_ = boost::make_shared(boost::ref(io)); + ssl_enabled = false; + if (ctx) { + /// SSL is enabled + ssl_sock_ = + boost::make_shared(boost::ref(io), boost::ref(*ctx)); + ssl_enabled = true; + } + } + + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void(boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { + try { + if (ssl_enabled) { + ssl_sock_->async_write_some(buffers, handler); + } else { + tcp_sock_->async_write_some(buffers, handler); + } + } + catch (const boost::system::error_code& e) { + std::cerr << e.message() << std::endl; + } + catch (const boost::system::system_error& e) { + std::cerr << e.code() << ": " << e.what() << std::endl; + } + } + + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void(boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { + try { + if (ssl_enabled) { + ssl_sock_->async_read_some(buffers, handler); + } else { + tcp_sock_->async_read_some(buffers, handler); + } + } + catch (const boost::system::error_code& e) { + std::cerr << e.message() << std::endl; + } + catch (const boost::system::system_error& e) { + std::cerr << e.code() << ": " << e.what() << std::endl; + } + } + + void close(boost::system::error_code& e) { + if (ssl_enabled) { + ssl_sock_->next_layer().close(); + } else { + tcp_sock_->close(); + } + } + + tcp_socket::endpoint_type remote_endpoint() const { + if (ssl_enabled) { + return ssl_sock_->next_layer().remote_endpoint(); + } else { + return tcp_sock_->remote_endpoint(); + } + } + + void shutdown(boost::asio::socket_base::shutdown_type st, + boost::system::error_code& e) { + try { + if (ssl_enabled) { + ssl_sock_->shutdown(e); + } else { + tcp_sock_->shutdown(boost::asio::ip::tcp::socket::shutdown_send, e); + } + } + catch (const boost::system::error_code& e) { + std::cerr << e.message() << std::endl; + } + catch (const boost::system::system_error& e) { + std::cerr << e.code() << ": " << e.what() << std::endl; + } + } + + ssl_socket::next_layer_type& next_layer() const { + if (ssl_enabled) { + return ssl_sock_->next_layer(); + } else { + return *tcp_sock_; + } + } + + ssl_socket::lowest_layer_type& lowest_layer() const { + if (ssl_enabled) { + return ssl_sock_->lowest_layer(); + } else { + return tcp_sock_->lowest_layer(); + } + } + + template + BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, + void(boost::system::error_code)) + async_handshake(ssl_socket::handshake_type type, + BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler) { + try { + if (ssl_enabled) { + return ssl_sock_->async_handshake(type, handler); + } else { + // NOOP + } + } + catch (const boost::system::error_code& e) { + std::cerr << e.message() << std::endl; + } + catch (const boost::system::system_error& e) { + std::cerr << e.code() << ": " << e.what() << std::endl; + } + } + boost::shared_ptr get_tcp_socket() { return tcp_sock_; } + boost::shared_ptr get_ssl_socket() { return ssl_sock_; } + + bool is_ssl_enabled() { return ssl_enabled; } + + private: + boost::shared_ptr tcp_sock_; + boost::shared_ptr ssl_sock_; + bool ssl_enabled; +}; +#endif +} +} + +#endif diff --git a/cpp-netlib/boost/network/support/is_async.hpp b/cpp-netlib/boost/network/support/is_async.hpp new file mode 100644 index 00000000..74fbab3b --- /dev/null +++ b/cpp-netlib/boost/network/support/is_async.hpp @@ -0,0 +1,27 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_ASYNC_HPP_20100608 +#define BOOST_NETWORK_SUPPORT_IS_ASYNC_HPP_20100608 + +// Copyright 2010 (c) Dean Michael Berris +// Copyright 2010 (c) Sinefunc, Inc. +// 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 +#include + +namespace boost { +namespace network { + +template +struct is_async : mpl::false_ {}; + +template +struct is_async< + Tag, typename enable_if::type> : mpl::true_ {}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_SUPPORT_IS_ASYNC_HPP_2010608 diff --git a/cpp-netlib/boost/network/support/is_default_string.hpp b/cpp-netlib/boost/network/support/is_default_string.hpp new file mode 100644 index 00000000..78e2a16f --- /dev/null +++ b/cpp-netlib/boost/network/support/is_default_string.hpp @@ -0,0 +1,27 @@ +// Copyright Dean Michael Berris 2010 +// 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 BOOST_NETWORK_SUPPORT_STRING_CHECK_20100808 +#define BOOST_NETWORK_SUPPORT_STRING_CHECK_20100808 + +#include +#include + +namespace boost { +namespace network { + +template +struct is_default_string : mpl::false_ {}; + +template +struct is_default_string< + Tag, + typename enable_if::type> : mpl::true_ {}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_SUPPORT_STRING_CHECK_20100808 diff --git a/cpp-netlib/boost/network/support/is_default_wstring.hpp b/cpp-netlib/boost/network/support/is_default_wstring.hpp new file mode 100644 index 00000000..02f4db87 --- /dev/null +++ b/cpp-netlib/boost/network/support/is_default_wstring.hpp @@ -0,0 +1,27 @@ +// Copyright Dean Michael Berris 2010 +// 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 BOOST_NETWORK_SUPPORT_WSTRING_CHECK_20100808 +#define BOOST_NETWORK_SUPPORT_WSTRING_CHECK_20100808 + +#include +#include + +namespace boost { +namespace network { + +template +struct is_default_wstring : mpl::false_ {}; + +template +struct is_default_wstring< + Tag, + typename enable_if::type> : mpl::true_ {}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_SUPPORT_STRING_CHECK_20100808 diff --git a/cpp-netlib/boost/network/support/is_http.hpp b/cpp-netlib/boost/network/support/is_http.hpp new file mode 100644 index 00000000..37ab06a4 --- /dev/null +++ b/cpp-netlib/boost/network/support/is_http.hpp @@ -0,0 +1,26 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_HTTP_HPP_20100622 +#define BOOST_NETWORK_SUPPORT_IS_HTTP_HPP_20100622 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include + +namespace boost { +namespace network { + +template +struct is_http : mpl::false_ {}; + +template +struct is_http::type> : mpl::true_ {}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_SUPPORT_IS_HTTP_HPP_20100622 diff --git a/cpp-netlib/boost/network/support/is_keepalive.hpp b/cpp-netlib/boost/network/support/is_keepalive.hpp new file mode 100644 index 00000000..4e454da9 --- /dev/null +++ b/cpp-netlib/boost/network/support/is_keepalive.hpp @@ -0,0 +1,26 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_KEEPALIVE_HPP_20100927 +#define BOOST_NETWORK_SUPPORT_IS_KEEPALIVE_HPP_20100927 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include + +namespace boost { +namespace network { + +template +struct is_keepalive : mpl::false_ {}; + +template +struct is_keepalive< + Tag, typename enable_if::type> : mpl::true_ {}; + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_SUPPORT_IS_KEEPALIVE_HPP_20100927 */ diff --git a/cpp-netlib/boost/network/support/is_pod.hpp b/cpp-netlib/boost/network/support/is_pod.hpp new file mode 100644 index 00000000..1778f112 --- /dev/null +++ b/cpp-netlib/boost/network/support/is_pod.hpp @@ -0,0 +1,26 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_POD_HPP_20101120 +#define BOOST_NETWORK_SUPPORT_IS_POD_HPP_20101120 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include + +namespace boost { +namespace network { + +template +struct is_pod : mpl::false_ {}; + +template +struct is_pod::type> : mpl::true_ {}; + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_SUPPORT_IS_POD_HPP_20101120 */ diff --git a/cpp-netlib/boost/network/support/is_simple.hpp b/cpp-netlib/boost/network/support/is_simple.hpp new file mode 100644 index 00000000..64335317 --- /dev/null +++ b/cpp-netlib/boost/network/support/is_simple.hpp @@ -0,0 +1,26 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_SIMPLE_HPP_20100927 +#define BOOST_NETWORK_SUPPORT_IS_SIMPLE_HPP_20100927 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include + +namespace boost { +namespace network { + +template +struct is_simple : mpl::false_ {}; + +template +struct is_simple< + Tag, typename enable_if::type> : mpl::true_ {}; + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_SUPPORT_IS_SIMPLE_HPP_20100927 */ diff --git a/cpp-netlib/boost/network/support/is_sync.hpp b/cpp-netlib/boost/network/support/is_sync.hpp new file mode 100644 index 00000000..d68d0cc5 --- /dev/null +++ b/cpp-netlib/boost/network/support/is_sync.hpp @@ -0,0 +1,26 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_SYNC_HPP_20100623 +#define BOOST_NETWORK_SUPPORT_IS_SYNC_HPP_20100623 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include + +namespace boost { +namespace network { + +template +struct is_sync : mpl::false_ {}; + +template +struct is_sync::type> : mpl::true_ {}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_SUPPORT_IS_SYNC_HPP_20100623 diff --git a/cpp-netlib/boost/network/support/is_tcp.hpp b/cpp-netlib/boost/network/support/is_tcp.hpp new file mode 100644 index 00000000..3bbc672e --- /dev/null +++ b/cpp-netlib/boost/network/support/is_tcp.hpp @@ -0,0 +1,28 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_TCP_HPP_20100622 +#define BOOST_NETWORK_SUPPORT_IS_TCP_HPP_20100622 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include +#include +#include + +namespace boost { +namespace network { + +template +struct is_tcp : mpl::false_ {}; + +template +struct is_tcp::type> : mpl::true_ {}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_SUPPORT_IS_TCP_HPP_20100622 \ No newline at end of file diff --git a/cpp-netlib/boost/network/support/is_udp.hpp b/cpp-netlib/boost/network/support/is_udp.hpp new file mode 100644 index 00000000..555b9bf8 --- /dev/null +++ b/cpp-netlib/boost/network/support/is_udp.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_NETWORK_SUPPORT_IS_UDP_HPP_20100622 +#define BOOST_NETWORK_SUPPORT_IS_UDP_HPP_20100622 + +// Copyright 2010 (c) Dean Michael Berris +// 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 +#include +#include +#include +#include + +namespace boost { +namespace network { + +template +struct is_udp : mpl::false_ {}; + +template +struct is_udp::type> : mpl::true_ {}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_SUPPORT_IS_UDP_HPP_20100622 diff --git a/cpp-netlib/boost/network/support/pod_or_normal.hpp b/cpp-netlib/boost/network/support/pod_or_normal.hpp new file mode 100644 index 00000000..2d54bbd0 --- /dev/null +++ b/cpp-netlib/boost/network/support/pod_or_normal.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_NETWORK_PROTOCOL_HTTP_SUPPORT_POD_OR_NORMAL_HPP_20101128 +#define BOOST_NETWORK_PROTOCOL_HTTP_SUPPORT_POD_OR_NORMAL_HPP_20101128 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include + +namespace boost { +namespace network { + +template +struct pod_or_normal { + typedef tags::normal type; +}; + +template +struct pod_or_normal< + Tag, typename enable_if::type> : tags::pod {}; + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_PROTOCOL_HTTP_SUPPORT_POD_OR_NORMAL_HPP_20101128 */ diff --git a/cpp-netlib/boost/network/support/sync_only.hpp b/cpp-netlib/boost/network/support/sync_only.hpp new file mode 100644 index 00000000..719737e4 --- /dev/null +++ b/cpp-netlib/boost/network/support/sync_only.hpp @@ -0,0 +1,30 @@ +#ifndef BOOST_NETWORK_SUPPORT_SYNC_ONLY_HPP_20100927 +#define BOOST_NETWORK_SUPPORT_SYNC_ONLY_HPP_20100927 + +// Copyright Dean Michael Berris 2010. +// 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 +#include +#include +#include +#include + +namespace boost { +namespace network { + +template +struct sync_only + : mpl::inherit_linearly< + typename mpl::replace_if::type, + is_same, + tags::sync>::type, + mpl::inherit > {}; + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_SUPPORT_SYNC_ONLY_HPP_20100927 */ diff --git a/cpp-netlib/boost/network/tags.hpp b/cpp-netlib/boost/network/tags.hpp new file mode 100644 index 00000000..a220fd43 --- /dev/null +++ b/cpp-netlib/boost/network/tags.hpp @@ -0,0 +1,68 @@ +// Copyright Dean Michael Berris 2008, 2009. +// Glyn Matthews 2009 +// 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 BOOST_NETWORK_TAG_INCLUDED_20100808 +#define BOOST_NETWORK_TAG_INCLUDED_20100808 + +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace tags { + +struct pod { + typedef mpl::true_::type is_pod; +}; +struct normal { + typedef mpl::true_::type is_normal; +}; +struct async { + typedef mpl::true_::type is_async; +}; +struct tcp { + typedef mpl::true_::type is_tcp; +}; +struct udp { + typedef mpl::true_::type is_udp; +}; +struct sync { + typedef mpl::true_::type is_sync; +}; +struct default_string { + typedef mpl::true_::type is_default_string; +}; +struct default_wstring { + typedef mpl::true_::type is_default_wstring; +}; + +template +struct components; + +// Tag Definition Macro Helper +#ifndef BOOST_NETWORK_DEFINE_TAG +#define BOOST_NETWORK_DEFINE_TAG(name) \ + struct name \ + : mpl::inherit_linearly >::type {}; \ + template <> \ + struct components { \ + typedef name##_tags type; \ + }; +#endif // BOOST_NETWORK_DEFINE_TAG + +typedef default_string default_; + +} // namespace tags + +} // namespace network + +} // namespace boost + +#endif // __BOOST_NETWORK_TAGS_INC__ diff --git a/cpp-netlib/boost/network/traits/char.hpp b/cpp-netlib/boost/network/traits/char.hpp new file mode 100644 index 00000000..70341897 --- /dev/null +++ b/cpp-netlib/boost/network/traits/char.hpp @@ -0,0 +1,37 @@ +// Copyright (c) Dean Michael Berris 2008, 2009. +// 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 BOOST_NETWORK_TRAITS_CHAR_HPP +#define BOOST_NETWORK_TRAITS_CHAR_HPP + +#include +#include + +namespace boost { +namespace network { + +template +struct unsupported_tag; + +template +struct char_ { + typedef unsupported_tag type; +}; + +template +struct char_ >::type> { + typedef char type; +}; + +template +struct char_ >::type> { + typedef wchar_t type; +}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_TRAITS_CHAR_HPP diff --git a/cpp-netlib/boost/network/traits/headers_container.hpp b/cpp-netlib/boost/network/traits/headers_container.hpp new file mode 100644 index 00000000..46f63327 --- /dev/null +++ b/cpp-netlib/boost/network/traits/headers_container.hpp @@ -0,0 +1,33 @@ +// Copyright (c) Glyn Matthews 2009. +// Copyright 2013 Google, Inc. +// Copyright 2013 Dean Michael Berris +// 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 BOOST_NETWORK_TRAITS_HEADERS_CONTAINER_INC +#define BOOST_NETWORK_TRAITS_HEADERS_CONTAINER_INC + +#include +#include +#include + +namespace boost { +namespace network { +namespace impl { + +template +struct headers_container_impl { + typedef std::multimap::type, typename string::type> + type; +}; + +} // namespace impl + +template +struct headers_container : impl::headers_container_impl {}; + +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_TRAITS_HEADERS_CONTAINER_INC__ diff --git a/cpp-netlib/boost/network/traits/istream.hpp b/cpp-netlib/boost/network/traits/istream.hpp new file mode 100644 index 00000000..4a8a0a86 --- /dev/null +++ b/cpp-netlib/boost/network/traits/istream.hpp @@ -0,0 +1,40 @@ + +#ifndef BOOST_NETWORK_TRAITS_ISTREAM_HPP_20100924 +#define BOOST_NETWORK_TRAITS_ISTREAM_HPP_20100924 + +// Copyright 2010 (C) Dean Michael Berris +// 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 +#include +#include +#include + +namespace boost { +namespace network { + +template +struct unsupported_tag; + +template +struct istream { + typedef unsupported_tag type; +}; + +template +struct istream >::type> { + typedef std::istream type; +}; + +template +struct istream >::type> { + typedef std::wistream type; +}; + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_TRAITS_ISTREAM_HPP_20100924 */ diff --git a/cpp-netlib/boost/network/traits/istringstream.hpp b/cpp-netlib/boost/network/traits/istringstream.hpp new file mode 100644 index 00000000..0f5273a3 --- /dev/null +++ b/cpp-netlib/boost/network/traits/istringstream.hpp @@ -0,0 +1,40 @@ +// Copyright (c) Glyn Matthews 2009. +// Copyright (c) Dean Michael Berris 2009. +// 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 BOOST_NETWORK_TRAITS_ISTRINGSTREAM_INC +#define BOOST_NETWORK_TRAITS_ISTRINGSTREAM_INC + +#include +#include +#include +#include + +namespace boost { +namespace network { + +template +struct unsupported_tag; + +template +struct istringstream { + typedef unsupported_tag type; +}; + +template +struct istringstream >::type> { + typedef std::istringstream type; +}; + +template +struct istringstream >::type> { + typedef std::basic_istringstream type; +}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_TRAITS_ISTRINGSTREAM_INC diff --git a/cpp-netlib/boost/network/traits/ostream_iterator.hpp b/cpp-netlib/boost/network/traits/ostream_iterator.hpp new file mode 100644 index 00000000..9099247d --- /dev/null +++ b/cpp-netlib/boost/network/traits/ostream_iterator.hpp @@ -0,0 +1,34 @@ +#ifndef BOOST_NETWORK_TRAITS_OSTREAM_ITERATOR_HPP_20100815 +#define BOOST_NETWORK_TRAITS_OSTREAM_ITERATOR_HPP_20100815 + +// Copyright 2010 (C) Dean Michael Berris +// 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 +#include +#include +#include + +namespace boost { +namespace network { + +template +struct unsupported_tag; + +template +struct ostream_iterator; + +template +struct ostream_iterator + : mpl::if_, std::ostream_iterator, + typename mpl::if_, + std::ostream_iterator, + unsupported_tag >::type> {}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_TRAITS_OSTREAM_ITERATOR_HPP_20100815 diff --git a/cpp-netlib/boost/network/traits/ostringstream.hpp b/cpp-netlib/boost/network/traits/ostringstream.hpp new file mode 100644 index 00000000..f6925b2a --- /dev/null +++ b/cpp-netlib/boost/network/traits/ostringstream.hpp @@ -0,0 +1,41 @@ +// Copyright (c) Glyn Matthews 2009. +// Copyright (c) Dean Michael Berris 2009, 2010. +// 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 BOOST_NETWORK_TRAITS_OSTRINGSTREAM_INC +#define BOOST_NETWORK_TRAITS_OSTRINGSTREAM_INC + +#include +#include +#include +#include +#include + +namespace boost { +namespace network { + +template +struct unsupported_tag; + +template +struct ostringstream { + typedef unsupported_tag type; +}; + +template +struct ostringstream >::type> { + typedef std::ostringstream type; +}; + +template +struct ostringstream >::type> { + typedef std::wostringstream type; +}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_TRAITS_OSTRINGSTREAM_INC diff --git a/cpp-netlib/boost/network/traits/string.hpp b/cpp-netlib/boost/network/traits/string.hpp new file mode 100644 index 00000000..6d9a1a03 --- /dev/null +++ b/cpp-netlib/boost/network/traits/string.hpp @@ -0,0 +1,48 @@ +// Copyright (c) Dean Michael Berris 2008, 2009. +// Glyn Matthews 2009. +// 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 BOOST_NETWORK_TRAITS_STRING_INC +#define BOOST_NETWORK_TRAITS_STRING_INC + +#include +#include +#include +#include + +#ifndef BOOST_NETWORK_DEFAULT_STRING +#define BOOST_NETWORK_DEFAULT_STRING std::string +#endif + +#ifndef BOOST_NETWORK_DEFAULT_WSTRING +#define BOOST_NETWORK_DEFAULT_WSTRING std::wstring +#endif + +namespace boost { +namespace network { + +template +struct unsupported_tag; + +template +struct string { + typedef unsupported_tag type; +}; + +template +struct string >::type> { + typedef BOOST_NETWORK_DEFAULT_STRING type; +}; + +template +struct string >::type> { + typedef BOOST_NETWORK_DEFAULT_WSTRING type; +}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_TRAITS_STRING_INC diff --git a/cpp-netlib/boost/network/traits/vector.hpp b/cpp-netlib/boost/network/traits/vector.hpp new file mode 100644 index 00000000..580a5e14 --- /dev/null +++ b/cpp-netlib/boost/network/traits/vector.hpp @@ -0,0 +1,30 @@ +// Copyright (c) Dean Michael Berris 2008, 2009. +// 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 BOOST_NETWORK_TRAITS_VECTOR_HPP +#define BOOST_NETWORK_TRAITS_VECTOR_HPP + +#include +#include + +namespace boost { +namespace network { + +template +struct unsupported_tag; + +template +struct vector { + + template + struct apply : mpl::if_, std::vector, + unsupported_tag > {}; +}; + +} // namespace network + +} // namespace boost + +#endif // BOOST_NETWORK_TRAITS_VECTOR_HPP diff --git a/cpp-netlib/boost/network/uri.hpp b/cpp-netlib/boost/network/uri.hpp new file mode 100644 index 00000000..7d36bec1 --- /dev/null +++ b/cpp-netlib/boost/network/uri.hpp @@ -0,0 +1,11 @@ +#ifndef BOOST_NETWORK_URL_HPP_ +#define BOOST_NETWORK_URL_HPP_ + +// Copyright 2009 Dean Michael Berris. +// 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 + +#endif diff --git a/cpp-netlib/boost/network/uri/accessors.hpp b/cpp-netlib/boost/network/uri/accessors.hpp new file mode 100644 index 00000000..5248b34d --- /dev/null +++ b/cpp-netlib/boost/network/uri/accessors.hpp @@ -0,0 +1,95 @@ +// Copyright (c) Glyn Matthews 2011. +// 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 __BOOST_NETWORK_URI_URI_ACCESSORS_INC__ +#define __BOOST_NETWORK_URI_URI_ACCESSORS_INC__ + +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace uri { +namespace details { +template +struct key_value_sequence : spirit::qi::grammar { + typedef typename Map::key_type key_type; + typedef typename Map::mapped_type mapped_type; + typedef std::pair pair_type; + + key_value_sequence() : key_value_sequence::base_type(query) { + query = pair >> *((spirit::qi::lit(';') | '&') >> pair); + pair = key >> -('=' >> value); + key = + spirit::qi::char_("a-zA-Z_") >> *spirit::qi::char_("-+.~a-zA-Z_0-9/%"); + value = *spirit::qi::char_("-+.~a-zA-Z_0-9/%"); + } + + spirit::qi::rule query; + spirit::qi::rule pair; + spirit::qi::rule key; + spirit::qi::rule value; +}; +} // namespace details + +template +inline Map &query_map(const uri &uri_, Map &map) { + const uri::string_type range = uri_.query(); + details::key_value_sequence parser; + spirit::qi::parse(boost::begin(range), boost::end(range), parser, map); + return map; +} + +inline uri::string_type username(const uri &uri_) { + const uri::string_type user_info = uri_.user_info(); + uri::const_iterator it(boost::begin(user_info)), end(boost::end(user_info)); + for (; it != end; ++it) { + if (*it == ':') { + break; + } + } + return uri::string_type(boost::begin(user_info), it); +} + +inline uri::string_type password(const uri &uri_) { + const uri::string_type user_info = uri_.user_info(); + uri::const_iterator it(boost::begin(user_info)), end(boost::end(user_info)); + for (; it != end; ++it) { + if (*it == ':') { + ++it; + break; + } + } + return uri::string_type(it, boost::end(user_info)); +} + +inline uri::string_type decoded_path(const uri &uri_) { + const uri::string_type path = uri_.path(); + uri::string_type decoded_path; + decode(path, std::back_inserter(decoded_path)); + return decoded_path; +} + +inline uri::string_type decoded_query(const uri &uri_) { + const uri::string_type query = uri_.query(); + uri::string_type decoded_query; + decode(query, std::back_inserter(decoded_query)); + return decoded_query; +} + +inline uri::string_type decoded_fragment(const uri &uri_) { + const uri::string_type fragment = uri_.fragment(); + uri::string_type decoded_fragment; + decode(fragment, std::back_inserter(decoded_fragment)); + return decoded_fragment; +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_URI_ACCESSORS_INC__ diff --git a/cpp-netlib/boost/network/uri/builder.hpp b/cpp-netlib/boost/network/uri/builder.hpp new file mode 100644 index 00000000..878a3c56 --- /dev/null +++ b/cpp-netlib/boost/network/uri/builder.hpp @@ -0,0 +1,151 @@ +// Copyright (c) Glyn Matthews 2012. +// 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 __BOOST_NETWORK_URI_BUILDER_INC__ +#define __BOOST_NETWORK_URI_BUILDER_INC__ + +#include +#include + +namespace boost { +namespace network { +namespace uri { +class builder { + + typedef uri::string_type string_type; + + public: + builder(uri &uri_) : uri_(uri_) {} + + builder &set_scheme(const string_type &scheme) { + uri_.uri_.append(scheme); + if (opaque_schemes::exists(scheme)) { + uri_.uri_.append(":"); + } else { + uri_.uri_.append("://"); + } + uri_.parse(); + return *this; + } + + builder &scheme(const string_type &scheme) { return set_scheme(scheme); } + + builder &set_user_info(const string_type &user_info) { + uri_.uri_.append(user_info); + uri_.uri_.append("@"); + uri_.parse(); + return *this; + } + + builder &user_info(const string_type &user_info) { + return set_user_info(user_info); + } + + builder &set_host(const string_type &host) { + uri_.uri_.append(host); + uri_.parse(); + return *this; + } + + builder &host(const string_type &host) { return set_host(host); } + + builder &set_host(const asio::ip::address &address) { + uri_.uri_.append(address.to_string()); + uri_.parse(); + return *this; + } + + builder &host(const asio::ip::address &host) { return set_host(host); } + + builder &set_host(const asio::ip::address_v4 &address) { + uri_.uri_.append(address.to_string()); + uri_.parse(); + return *this; + } + + builder &host(const asio::ip::address_v4 &host) { return set_host(host); } + + builder &set_host(const asio::ip::address_v6 &address) { + uri_.uri_.append("["); + uri_.uri_.append(address.to_string()); + uri_.uri_.append("]"); + uri_.parse(); + return *this; + } + + builder &host(const asio::ip::address_v6 &host) { return set_host(host); } + + builder &set_port(const string_type &port) { + uri_.uri_.append(":"); + uri_.uri_.append(port); + uri_.parse(); + return *this; + } + + builder &port(const string_type &port) { return set_port(port); } + + builder &port(uint16_t port) { + return set_port(boost::lexical_cast(port)); + } + + builder &set_path(const string_type &path) { + uri_.uri_.append(path); + uri_.parse(); + return *this; + } + + builder &path(const string_type &path) { return set_path(path); } + + builder &encoded_path(const string_type &path) { + string_type encoded_path; + encode(path, std::back_inserter(encoded_path)); + return set_path(encoded_path); + } + + builder &set_query(const string_type &query) { + uri_.uri_.append("?"); + uri_.uri_.append(query); + uri_.parse(); + return *this; + } + + builder &set_query(const string_type &key, const string_type &value) { + if (!uri_.query_range()) { + uri_.uri_.append("?"); + } else { + uri_.uri_.append("&"); + } + uri_.uri_.append(key); + uri_.uri_.append("="); + uri_.uri_.append(value); + uri_.parse(); + return *this; + } + + builder &query(const string_type &query) { return set_query(query); } + + builder &query(const string_type &key, const string_type &value) { + return set_query(key, value); + } + + builder &set_fragment(const string_type &fragment) { + uri_.uri_.append("#"); + uri_.uri_.append(fragment); + uri_.parse(); + return *this; + } + + builder &fragment(const string_type &fragment) { + return set_fragment(fragment); + } + + private: + uri &uri_; +}; +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_BUILDER_INC__ diff --git a/cpp-netlib/boost/network/uri/config.hpp b/cpp-netlib/boost/network/uri/config.hpp new file mode 100644 index 00000000..de6ae447 --- /dev/null +++ b/cpp-netlib/boost/network/uri/config.hpp @@ -0,0 +1,18 @@ +// Copyright (c) Glyn Matthews 2012. +// 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 __BOOST_NETWORK_URI_CONFIG_INC__ +#define __BOOST_NETWORK_URI_CONFIG_INC__ + +#include +#include + +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_URI_DYN_LINK) +#define BOOST_URI_DECL +#else +#define BOOST_URI_DECL +#endif // defined(BOOST_ALL_DYN_LINK) || defined(BOOST_URI_DYN_LINK) + +#endif // __BOOST_NETWORK_URI_CONFIG_INC__ diff --git a/cpp-netlib/boost/network/uri/decode.hpp b/cpp-netlib/boost/network/uri/decode.hpp new file mode 100644 index 00000000..e9e80e98 --- /dev/null +++ b/cpp-netlib/boost/network/uri/decode.hpp @@ -0,0 +1,92 @@ +// Copyright (c) Glyn Matthews 2011. +// 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 __BOOST_NETWORK_URI_DECODE_INC__ +#define __BOOST_NETWORK_URI_DECODE_INC__ + +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace uri { +namespace detail { +template +CharT letter_to_hex(CharT in) { + switch (in) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return in - '0'; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return in + 10 - 'a'; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + return in + 10 - 'A'; + } + return CharT(); +} +} // namespace detail + +template +OutputIterator decode(const InputIterator &in_begin, + const InputIterator &in_end, + const OutputIterator &out_begin) { + typedef typename boost::iterator_value::type value_type; + + InputIterator it = in_begin; + OutputIterator out = out_begin; + while (it != in_end) { + if (*it == '%') { + ++it; + value_type v0 = detail::letter_to_hex(*it); + ++it; + value_type v1 = detail::letter_to_hex(*it); + ++it; + *out++ = 0x10 * v0 + v1; + } else if (*it == '+') { + *out++ = ' '; + ++it; + } else { + *out++ = *it++; + } + } + return out; +} + +template +inline OutputIterator decode(const SinglePassRange &range, + const OutputIterator &out) { + return decode(boost::begin(range), boost::end(range), out); +} + +inline std::string decoded(const std::string &input) { + std::string decoded; + decode(input, std::back_inserter(decoded)); + return decoded; +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_DECODE_INC__ diff --git a/cpp-netlib/boost/network/uri/detail/uri_parts.hpp b/cpp-netlib/boost/network/uri/detail/uri_parts.hpp new file mode 100644 index 00000000..2564f43a --- /dev/null +++ b/cpp-netlib/boost/network/uri/detail/uri_parts.hpp @@ -0,0 +1,87 @@ +// Copyright 2009, 2010, 2011, 2012 Dean Michael Berris, Jeroen Habraken, Glyn +// Matthews. +// 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 BOOST_NETWORK_URL_DETAIL_URL_PARTS_HPP_ +#define BOOST_NETWORK_URL_DETAIL_URL_PARTS_HPP_ + +#include +#include + +namespace boost { +namespace network { +namespace uri { +namespace detail { +template +struct hierarchical_part { + optional > user_info; + optional > host; + optional > port; + optional > path; + + FwdIter begin() const { return boost::begin(user_info); } + + FwdIter end() const { return boost::end(path); } + + void update() { + if (!user_info) { + if (host) { + user_info = iterator_range(boost::begin(host.get()), + boost::begin(host.get())); + } else if (path) { + user_info = iterator_range(boost::begin(path.get()), + boost::begin(path.get())); + } + } + + if (!host) { + host = iterator_range(boost::begin(path.get()), + boost::begin(path.get())); + } + + if (!port) { + port = iterator_range(boost::end(host.get()), + boost::end(host.get())); + } + + if (!path) { + path = iterator_range(boost::end(port.get()), + boost::end(port.get())); + } + } +}; + +template +struct uri_parts { + iterator_range scheme; + hierarchical_part hier_part; + optional > query; + optional > fragment; + + FwdIter begin() const { return boost::begin(scheme); } + + FwdIter end() const { return boost::end(fragment); } + + void update() { + + hier_part.update(); + + if (!query) { + query = iterator_range(boost::end(hier_part.path.get()), + boost::end(hier_part.path.get())); + } + + if (!fragment) { + fragment = iterator_range(boost::end(query.get()), + boost::end(query.get())); + } + } +}; +} // namespace detail +} // namespace uri +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_URL_DETAIL_URL_PARTS_HPP_ diff --git a/cpp-netlib/boost/network/uri/directives.hpp b/cpp-netlib/boost/network/uri/directives.hpp new file mode 100644 index 00000000..caf15de5 --- /dev/null +++ b/cpp-netlib/boost/network/uri/directives.hpp @@ -0,0 +1,39 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 __BOOST_NETWORK_URI_DIRECTIVES_INC__ +#define __BOOST_NETWORK_URI_DIRECTIVES_INC__ + +#include + +namespace boost { +namespace network { +namespace uri { +inline uri &operator<<(uri &uri_, const uri &root_uri) { + if (empty(uri_) && valid(root_uri)) { + uri_.append(boost::begin(root_uri), boost::end(root_uri)); + } + return uri_; +} + +template +inline uri &operator<<(uri &uri_, const Directive &directive) { + directive(uri_); + return uri_; +} +} // namespace uri +} // namespace network +} // namespace boost + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // __BOOST_NETWORK_URI_DIRECTIVES_INC__ diff --git a/cpp-netlib/boost/network/uri/directives/authority.hpp b/cpp-netlib/boost/network/uri/directives/authority.hpp new file mode 100644 index 00000000..2f0bbaef --- /dev/null +++ b/cpp-netlib/boost/network/uri/directives/authority.hpp @@ -0,0 +1,32 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 __BOOST_NETWORK_URI_DIRECTIVES_AUTHORITY_INC__ +#define __BOOST_NETWORK_URI_DIRECTIVES_AUTHORITY_INC__ + +namespace boost { +namespace network { +namespace uri { +struct authority_directive { + + explicit authority_directive(const std::string &authority) + : authority(authority) {} + + template + void operator()(Uri &uri) const { + uri.append(authority); + } + + std::string authority; +}; + +inline authority_directive authority(const std::string &authority) { + return authority_directive(authority); +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_DIRECTIVES_AUTHORITY_INC__ diff --git a/cpp-netlib/boost/network/uri/directives/fragment.hpp b/cpp-netlib/boost/network/uri/directives/fragment.hpp new file mode 100644 index 00000000..6f3291d9 --- /dev/null +++ b/cpp-netlib/boost/network/uri/directives/fragment.hpp @@ -0,0 +1,37 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 __BOOST_NETWORK_URI_DIRECTIVES_FRAGMENT_INC__ +#define __BOOST_NETWORK_URI_DIRECTIVES_FRAGMENT_INC__ + +#include +#include +#include + +namespace boost { +namespace network { +namespace uri { +struct fragment_directive { + + explicit fragment_directive(const std::string &fragment) + : fragment(fragment) {} + + template + void operator()(Uri &uri) const { + uri.append("#"); + uri.append(fragment); + } + + std::string fragment; +}; + +inline fragment_directive fragment(const std::string &fragment) { + return fragment_directive(fragment); +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_DIRECTIVES_FRAGMENT_INC__ diff --git a/cpp-netlib/boost/network/uri/directives/host.hpp b/cpp-netlib/boost/network/uri/directives/host.hpp new file mode 100644 index 00000000..ac1d2ab5 --- /dev/null +++ b/cpp-netlib/boost/network/uri/directives/host.hpp @@ -0,0 +1,34 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 __BOOST_NETWORK_URI_DIRECTIVES_HOST_INC__ +#define __BOOST_NETWORK_URI_DIRECTIVES_HOST_INC__ + +#include +#include + +namespace boost { +namespace network { +namespace uri { +struct host_directive { + + explicit host_directive(const std::string &host) : host(host) {} + + template + void operator()(Uri &uri) const { + uri.append(host); + } + + std::string host; +}; + +inline host_directive host(const std::string &host) { + return host_directive(host); +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_DIRECTIVES_HOST_INC__ diff --git a/cpp-netlib/boost/network/uri/directives/path.hpp b/cpp-netlib/boost/network/uri/directives/path.hpp new file mode 100644 index 00000000..21af8ca2 --- /dev/null +++ b/cpp-netlib/boost/network/uri/directives/path.hpp @@ -0,0 +1,51 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 __BOOST_NETWORK_URI_DIRECTIVES_PATH_INC__ +#define __BOOST_NETWORK_URI_DIRECTIVES_PATH_INC__ + +#include +#include + +namespace boost { +namespace network { +namespace uri { +struct path_directive { + + explicit path_directive(const std::string &path) : path(path) {} + + template + void operator()(Uri &uri) const { + uri.append(path); + } + + std::string path; +}; + +struct encoded_path_directive { + + explicit encoded_path_directive(const std::string &path) : path(path) {} + + void operator()(uri &uri_) const { + std::string encoded_path; + encode(path, std::back_inserter(encoded_path)); + uri_.append(encoded_path); + } + + std::string path; +}; + +inline path_directive path(const std::string &path) { + return path_directive(path); +} + +inline encoded_path_directive encoded_path(const std::string &path) { + return encoded_path_directive(path); +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_DIRECTIVES_PATH_INC__ diff --git a/cpp-netlib/boost/network/uri/directives/port.hpp b/cpp-netlib/boost/network/uri/directives/port.hpp new file mode 100644 index 00000000..181bf6b8 --- /dev/null +++ b/cpp-netlib/boost/network/uri/directives/port.hpp @@ -0,0 +1,44 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 __BOOST_NETWORK_URI_DIRECTIVES_PORT_INC__ +#define __BOOST_NETWORK_URI_DIRECTIVES_PORT_INC__ + +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace uri { +struct port_directive { + + explicit port_directive(const std::string &port) : port(port) {} + + explicit port_directive(boost::uint16_t port) + : port(boost::lexical_cast(port)) {} + + template + void operator()(Uri &uri) const { + uri.append(":"); + uri.append(port); + } + + std::string port; +}; + +inline port_directive port(const std::string &port) { + return port_directive(port); +} + +inline port_directive port(boost::uint16_t port) { + return port_directive(port); +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_DIRECTIVES_PORT_INC__ diff --git a/cpp-netlib/boost/network/uri/directives/query.hpp b/cpp-netlib/boost/network/uri/directives/query.hpp new file mode 100644 index 00000000..07987867 --- /dev/null +++ b/cpp-netlib/boost/network/uri/directives/query.hpp @@ -0,0 +1,63 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 __BOOST_NETWORK_URI_DIRECTIVES_QUERY_INC__ +#define __BOOST_NETWORK_URI_DIRECTIVES_QUERY_INC__ + +#include +#include +#include + +namespace boost { +namespace network { +namespace uri { +struct query_directive { + + explicit query_directive(const std::string &query) : query(query) {} + + template + void operator()(Uri &uri) const { + uri.append("?"); + uri.append(query); + } + + std::string query; +}; + +inline query_directive query(const std::string &query) { + return query_directive(query); +} + +struct query_key_query_directive { + + query_key_query_directive(const std::string &key, const std::string &query) + : key(key), query(query) {} + + template + void operator()(Uri &uri) const { + std::string encoded_key, encoded_query; + if (boost::empty(uri.query())) { + uri.append("?"); + } else { + uri.append("&"); + } + uri.append(key); + uri.append("="); + uri.append(query); + } + + std::string key; + std::string query; +}; + +inline query_key_query_directive query(const std::string &key, + const std::string &query) { + return query_key_query_directive(key, query); +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_DIRECTIVES_QUERY_INC__ diff --git a/cpp-netlib/boost/network/uri/directives/scheme.hpp b/cpp-netlib/boost/network/uri/directives/scheme.hpp new file mode 100644 index 00000000..7787d350 --- /dev/null +++ b/cpp-netlib/boost/network/uri/directives/scheme.hpp @@ -0,0 +1,48 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 __BOOST_NETWORK_URI_DIRECTIVES_SCHEME_INC__ +#define __BOOST_NETWORK_URI_DIRECTIVES_SCHEME_INC__ + +#include +#include +#include + +namespace boost { +namespace network { +namespace uri { +struct scheme_directive { + + explicit scheme_directive(const std::string &scheme) : scheme(scheme) {} + + template + void operator()(Uri &uri) const { + uri.append(scheme); + if (opaque_schemes::exists(scheme)) { + uri.append(":"); + } else { + uri.append("://"); + } + } + + std::string scheme; +}; + +inline scheme_directive scheme(const std::string &scheme) { + return scheme_directive(scheme); +} + +namespace schemes { +inline uri &http(uri &uri_) { return uri_ << scheme("http"); } + +inline uri &https(uri &uri_) { return uri_ << scheme("https"); } + +inline uri &file(uri &uri_) { return uri_ << scheme("file"); } +} // namespace schemes +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_DIRECTIVES_SCHEME_INC__ diff --git a/cpp-netlib/boost/network/uri/directives/user_info.hpp b/cpp-netlib/boost/network/uri/directives/user_info.hpp new file mode 100644 index 00000000..003469ae --- /dev/null +++ b/cpp-netlib/boost/network/uri/directives/user_info.hpp @@ -0,0 +1,36 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 __BOOST_NETWORK_URI_DIRECTIVES_USER_INFO_INC__ +#define __BOOST_NETWORK_URI_DIRECTIVES_USER_INFO_INC__ + +#include +#include + +namespace boost { +namespace network { +namespace uri { +struct user_info_directive { + + explicit user_info_directive(const std::string &user_info) + : user_info(user_info) {} + + template + void operator()(Uri &uri) const { + uri.append(user_info); + uri.append("@"); + } + + std::string user_info; +}; + +inline user_info_directive user_info(const std::string &user_info) { + return user_info_directive(user_info); +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_DIRECTIVES_USER_INFO_INC__ diff --git a/cpp-netlib/boost/network/uri/encode.hpp b/cpp-netlib/boost/network/uri/encode.hpp new file mode 100644 index 00000000..bf6b0768 --- /dev/null +++ b/cpp-netlib/boost/network/uri/encode.hpp @@ -0,0 +1,153 @@ +// Copyright (c) Glyn Matthews 2011. +// 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 __BOOST_NETWORK_URI_ENCODE_INC__ +#define __BOOST_NETWORK_URI_ENCODE_INC__ + +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace uri { +namespace detail { +template +inline CharT hex_to_letter(CharT in) { + switch (in) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + return in + '0'; + case 10: + case 11: + case 12: + case 13: + case 14: + default: + return in - 10 + 'A'; + } + return CharT(); +} + +template +void encode_char(CharT in, OutputIterator &out) { + switch (in) { + case 'a': + case 'A': + case 'b': + case 'B': + case 'c': + case 'C': + case 'd': + case 'D': + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + case 'h': + case 'H': + case 'i': + case 'I': + case 'j': + case 'J': + case 'k': + case 'K': + case 'l': + case 'L': + case 'm': + case 'M': + case 'n': + case 'N': + case 'o': + case 'O': + case 'p': + case 'P': + case 'q': + case 'Q': + case 'r': + case 'R': + case 's': + case 'S': + case 't': + case 'T': + case 'u': + case 'U': + case 'v': + case 'V': + case 'w': + case 'W': + case 'x': + case 'X': + case 'y': + case 'Y': + case 'z': + case 'Z': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + case '.': + case '_': + case '~': + case '/': + out++ = in; + break; + default: + out++ = '%'; + out++ = hex_to_letter((in >> 4) & 0x0f); + out++ = hex_to_letter(in & 0x0f); + ; + } +} +} // namespace detail + +template +OutputIterator encode(const InputIterator &in_begin, + const InputIterator &in_end, + const OutputIterator &out_begin) { + InputIterator it = in_begin; + OutputIterator out = out_begin; + while (it != in_end) { + detail::encode_char(*it, out); + ++it; + } + return out; +} + +template +inline OutputIterator encode(const SinglePassRange &range, + const OutputIterator &out) { + return encode(boost::begin(range), boost::end(range), out); +} + +inline std::string encoded(const std::string &input) { + std::string encoded; + encode(input, std::back_inserter(encoded)); + return encoded; +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_ENCODE_INC__ diff --git a/cpp-netlib/boost/network/uri/schemes.hpp b/cpp-netlib/boost/network/uri/schemes.hpp new file mode 100644 index 00000000..6aef3726 --- /dev/null +++ b/cpp-netlib/boost/network/uri/schemes.hpp @@ -0,0 +1,29 @@ +// Copyright 2012 Glyn Matthews. +// 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 __BOOST_NETWORK_URI_SCHEMES_INC__ +#define __BOOST_NETWORK_URI_SCHEMES_INC__ + +#include + +namespace boost { +namespace network { +namespace uri { +class hierarchical_schemes { + + public: + static bool exists(const std::string &scheme); +}; + +class opaque_schemes { + + public: + static bool exists(const std::string &scheme); +}; +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_SCHEMES_INC__ diff --git a/cpp-netlib/boost/network/uri/uri.hpp b/cpp-netlib/boost/network/uri/uri.hpp new file mode 100644 index 00000000..d2df2282 --- /dev/null +++ b/cpp-netlib/boost/network/uri/uri.hpp @@ -0,0 +1,375 @@ +// Copyright 2009, 2010, 2011, 2012 Dean Michael Berris, Jeroen Habraken, Glyn +// Matthews. +// 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 __BOOST_NETWORK_URI_INC__ +#define __BOOST_NETWORK_URI_INC__ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace uri { +namespace detail { +bool parse(std::string::const_iterator first, std::string::const_iterator last, + uri_parts &parts); +} // namespace detail + +class BOOST_URI_DECL uri { + + friend class builder; + + public: + typedef std::string string_type; + typedef string_type::value_type value_type; + typedef string_type::const_iterator const_iterator; + typedef boost::iterator_range const_range_type; + + uri() : is_valid_(false) {} + + // uri(const value_type *uri) + // : uri_(uri), is_valid_(false) { + // parse(); + //} + + uri(const string_type &uri) : uri_(uri), is_valid_(false) { parse(); } + + template + uri(const FwdIter &first, const FwdIter &last) + : uri_(first, last), is_valid_(false) { + parse(); + } + + uri(const uri &other) : uri_(other.uri_) { parse(); } + + uri &operator=(const uri &other) { + uri(other).swap(*this); + return *this; + } + + uri &operator=(const string_type &uri_string) { + uri(uri_string).swap(*this); + return *this; + } + + ~uri() {} + + void swap(uri &other) { + boost::swap(uri_, other.uri_); + other.parse(); + boost::swap(is_valid_, other.is_valid_); + } + + const_iterator begin() const { return uri_.begin(); } + + const_iterator end() const { return uri_.end(); } + + const_range_type scheme_range() const { return uri_parts_.scheme; } + + const_range_type user_info_range() const { + return uri_parts_.hier_part.user_info ? uri_parts_.hier_part.user_info.get() + : const_range_type(); + } + + const_range_type host_range() const { + auto result = uri_parts_.hier_part.host ? uri_parts_.hier_part.host.get() + : const_range_type(); + if (result.begin () != result.end ()) + if (result [0] == '[') + result = {result.begin () + 1, result.end () - 1}; + return result; + } + + const_range_type port_range() const { + return uri_parts_.hier_part.port ? uri_parts_.hier_part.port.get() + : const_range_type(); + } + + const_range_type path_range() const { + return uri_parts_.hier_part.path ? uri_parts_.hier_part.path.get() + : const_range_type(); + } + + const_range_type query_range() const { + return uri_parts_.query ? uri_parts_.query.get() : const_range_type(); + } + + const_range_type fragment_range() const { + return uri_parts_.fragment ? uri_parts_.fragment.get() : const_range_type(); + } + + string_type scheme() const { + const_range_type range = scheme_range(); + return range ? string_type(boost::begin(range), boost::end(range)) + : string_type(); + } + + string_type user_info() const { + const_range_type range = user_info_range(); + return range ? string_type(boost::begin(range), boost::end(range)) + : string_type(); + } + + string_type host() const { + const_range_type range = host_range(); + return range ? string_type(boost::begin(range), boost::end(range)) + : string_type(); + } + + string_type port() const { + const_range_type range = port_range(); + return range ? string_type(boost::begin(range), boost::end(range)) + : string_type(); + } + + string_type path() const { + const_range_type range = path_range(); + return range ? string_type(boost::begin(range), boost::end(range)) + : string_type(); + } + + string_type query() const { + const_range_type range = query_range(); + return range ? string_type(boost::begin(range), boost::end(range)) + : string_type(); + } + + string_type fragment() const { + const_range_type range = fragment_range(); + return range ? string_type(boost::begin(range), boost::end(range)) + : string_type(); + } + + string_type string() const { return uri_; } + + bool is_valid() const { return is_valid_; } + + void append(const string_type &data) { + uri_.append(data); + parse(); + } + + template + void append(const FwdIter &first, const FwdIter &last) { + uri_.append(first, last); + parse(); + } + + private: + void parse(); + + string_type uri_; + detail::uri_parts uri_parts_; + bool is_valid_; +}; + +inline void uri::parse() { + const_iterator first(boost::begin(uri_)), last(boost::end(uri_)); + is_valid_ = detail::parse(first, last, uri_parts_); + if (is_valid_) { + if (!uri_parts_.scheme) { + uri_parts_.scheme = + const_range_type(boost::begin(uri_), boost::begin(uri_)); + } + uri_parts_.update(); + } +} + +inline uri::string_type scheme(const uri &uri_) { return uri_.scheme(); } + +inline uri::string_type user_info(const uri &uri_) { return uri_.user_info(); } + +inline uri::string_type host(const uri &uri_) { return uri_.host(); } + +inline uri::string_type port(const uri &uri_) { return uri_.port(); } + +inline boost::optional port_us(const uri &uri_) { + uri::string_type port = uri_.port(); + return (port.empty()) ? boost::optional() + : boost::optional( + boost::lexical_cast(port)); +} + +inline uri::string_type path(const uri &uri_) { return uri_.path(); } + +inline uri::string_type query(const uri &uri_) { return uri_.query(); } + +inline uri::string_type fragment(const uri &uri_) { return uri_.fragment(); } + +inline uri::string_type hierarchical_part(const uri &uri_) { + uri::string_type::const_iterator first, last; + uri::const_range_type user_info = uri_.user_info_range(); + uri::const_range_type host = uri_.host_range(); + uri::const_range_type port = uri_.port_range(); + uri::const_range_type path = uri_.path_range(); + if (user_info) { + first = boost::begin(user_info); + } else { + first = boost::begin(host); + } + if (path) { + last = boost::end(path); + } else if (port) { + last = boost::end(port); + } else { + last = boost::end(host); + } + return uri::string_type(first, last); +} + +inline uri::string_type authority(const uri &uri_) { + uri::string_type::const_iterator first, last; + uri::const_range_type user_info = uri_.user_info_range(); + uri::const_range_type host = uri_.host_range(); + uri::const_range_type port = uri_.port_range(); + if (user_info) { + first = boost::begin(user_info); + } else { + first = boost::begin(host); + } + + if (port) { + last = boost::end(port); + } else { + last = boost::end(host); + } + return uri::string_type(first, last); +} + +inline bool valid(const uri &uri_) { return uri_.is_valid(); } + +inline bool is_absolute(const uri &uri_) { + return uri_.is_valid() && !boost::empty(uri_.scheme_range()); +} + +inline bool is_relative(const uri &uri_) { + return uri_.is_valid() && boost::empty(uri_.scheme_range()); +} + +inline bool is_hierarchical(const uri &uri_) { + return is_absolute(uri_) && hierarchical_schemes::exists(scheme(uri_)); +} + +inline bool is_opaque(const uri &uri_) { + return is_absolute(uri_) && opaque_schemes::exists(scheme(uri_)); +} + +inline bool is_valid(const uri &uri_) { return valid(uri_); } + +inline void swap(uri &lhs, uri &rhs) { lhs.swap(rhs); } + +inline std::size_t hash_value(const uri &uri_) { + std::size_t seed = 0; + for (uri::const_iterator it = begin(uri_); it != end(uri_); ++it) { + hash_combine(seed, *it); + } + return seed; +} + +inline bool operator==(const uri &lhs, const uri &rhs) { + return boost::equal(lhs, rhs); +} + +inline bool operator==(const uri &lhs, const uri::string_type &rhs) { + return boost::equal(lhs, rhs); +} + +inline bool operator==(const uri::string_type &lhs, const uri &rhs) { + return boost::equal(lhs, rhs); +} + +inline bool operator==(const uri &lhs, const uri::value_type *rhs) { + return boost::equal(lhs, boost::as_literal(rhs)); +} + +inline bool operator==(const uri::value_type *lhs, const uri &rhs) { + return boost::equal(boost::as_literal(lhs), rhs); +} + +inline bool operator!=(const uri &lhs, const uri &rhs) { return !(lhs == rhs); } + +inline bool operator<(const uri &lhs, const uri &rhs) { + return lhs.string() < rhs.string(); +} +} // namespace uri +} // namespace network +} // namespace boost + +#include +#include +#include + +namespace boost { +namespace network { +namespace uri { +inline uri from_parts(const uri &base_uri, const uri::string_type &path_, + const uri::string_type &query_, + const uri::string_type &fragment_) { + uri uri_(base_uri); + builder(uri_).path(path_).query(query_).fragment(fragment_); + return uri_; +} + +inline uri from_parts(const uri &base_uri, const uri::string_type &path_, + const uri::string_type &query_) { + uri uri_(base_uri); + builder(uri_).path(path_).query(query_); + return uri_; +} + +inline uri from_parts(const uri &base_uri, const uri::string_type &path_) { + uri uri_(base_uri); + builder(uri_).path(path_); + return uri_; +} + +inline uri from_parts(const uri::string_type &base_uri, + const uri::string_type &path, + const uri::string_type &query, + const uri::string_type &fragment) { + return from_parts(uri(base_uri), path, query, fragment); +} + +inline uri from_parts(const uri::string_type &base_uri, + const uri::string_type &path, + const uri::string_type &query) { + return from_parts(uri(base_uri), path, query); +} + +inline uri from_parts(const uri::string_type &base_uri, + const uri::string_type &path) { + return from_parts(uri(base_uri), path); +} +} // namespace uri +} // namespace network +} // namespace boost + +#include + +namespace boost { +namespace network { +namespace uri { +inline uri from_file(const filesystem::path &path_) { + uri uri_; + builder(uri_).scheme("file").path(path_.string()); + return uri_; +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_INC__ diff --git a/cpp-netlib/boost/network/uri/uri.ipp b/cpp-netlib/boost/network/uri/uri.ipp new file mode 100644 index 00000000..c58bd295 --- /dev/null +++ b/cpp-netlib/boost/network/uri/uri.ipp @@ -0,0 +1,255 @@ +// Copyright 2009, 2010, 2011, 2012 Dean Michael Berris, Jeroen Habraken, Glyn +// Matthews. +// 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 +#include +#include +#include + +BOOST_FUSION_ADAPT_TPL_STRUCT( + (FwdIter), (boost::network::uri::detail::hierarchical_part)(FwdIter), + (boost::optional >, + user_info)(boost::optional >, + host)(boost::optional >, + port)(boost::optional >, + path)); + +BOOST_FUSION_ADAPT_TPL_STRUCT( + (FwdIter), (boost::network::uri::detail::uri_parts)(FwdIter), + (boost::iterator_range, + scheme)(boost::network::uri::detail::hierarchical_part, + hier_part)(boost::optional >, + query)(boost::optional >, + fragment)); + +namespace boost { +namespace network { +namespace uri { +namespace detail { +namespace qi = boost::spirit::qi; + +template +struct uri_grammar + : qi::grammar()> { + + typedef String string_type; + typedef typename String::const_iterator const_iterator; + + uri_grammar() : uri_grammar::base_type(start, "uri") { + // gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + gen_delims %= qi::char_(":/?#[]@"); + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," + // / ";" / "=" + sub_delims %= qi::char_("!$&'()*+,;="); + // reserved = gen-delims / sub-delims + reserved %= gen_delims | sub_delims; + // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + unreserved %= qi::alnum | qi::char_("-._~"); + // pct-encoded = "%" HEXDIG HEXDIG + pct_encoded %= qi::char_("%") >> qi::repeat(2)[qi::xdigit]; + + // pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + pchar %= qi::raw[unreserved | pct_encoded | sub_delims | qi::char_(":@")]; + + // segment = *pchar + segment %= qi::raw[*pchar]; + // segment-nz = 1*pchar + segment_nz %= qi::raw[+pchar]; + // segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + segment_nz_nc %= + qi::raw[+(unreserved | pct_encoded | sub_delims | qi::char_("@"))]; + // path-abempty = *( "/" segment ) + path_abempty %= qi::raw[*(qi::char_("/") >> segment)]; + // path-absolute = "/" [ segment-nz *( "/" segment ) ] + path_absolute %= qi::raw + [qi::char_("/") >> -(segment_nz >> *(qi::char_("/") >> segment))]; + // path-rootless = segment-nz *( "/" segment ) + path_rootless %= qi::raw[segment_nz >> *(qi::char_("/") >> segment)]; + // path-empty = 0 + path_empty %= qi::raw[qi::eps]; + + // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + scheme %= qi::raw[qi::alpha >> *(qi::alnum | qi::char_("+.-"))]; + + // user_info = *( unreserved / pct-encoded / sub-delims / ":" ) + user_info %= + qi::raw[*(unreserved | pct_encoded | sub_delims | qi::char_(":"))]; + + ip_literal %= qi::lit('[') >> (ipv6address | ipvfuture) >> ']'; + + ipvfuture %= + qi::lit('v') >> +qi::xdigit >> '.' >> +(unreserved | sub_delims | ':'); + + ipv6addresses[0] %= qi::repeat(6)[h16 >> ':'] >> ls32; + ipv6addresses[1] %= "::" >> qi::repeat(5)[h16 >> ':'] >> ls32; + ipv6addresses[2] %= -qi::raw[h16] >> "::" >> qi::repeat(4)[h16 >> ':'] + >> ls32; + ipv6addresses[3] %= -qi::raw[h16] >> "::" >> qi::repeat(3)[h16 >> ':'] + >> ls32; + ipv6addresses[4] %= -qi::raw[h16] >> "::" >> qi::repeat(2)[h16 >> ':'] + >> ls32; + ipv6addresses[5] %= -qi::raw[h16] >> "::" >> h16 >> ':' >> ls32; + ipv6addresses[6] %= -qi::raw[h16] >> "::" >> ls32; + ipv6addresses[7] %= -qi::raw[h16] >> "::" >> h16; + ipv6addresses[8] %= -qi::raw[h16] >> "::"; + ipv6addresses[9] %= -qi::raw[qi::repeat(1)[(h16 >> ':')] >> h16] >> + "::" >> qi::repeat(3)[h16 >> ':'] >> ls32; + ipv6addresses[10] %= -qi::raw[qi::repeat(1)[(h16 >> ':')] >> h16] >> + "::" >> qi::repeat(2)[h16 >> ':'] >> ls32; + ipv6addresses[11] %= -qi::raw[qi::repeat(1)[(h16 >> ':')] >> h16] >> + "::" >> h16 >> ':' >> ls32; + ipv6addresses[12] %= -qi::raw[qi::repeat(1)[(h16 >> ':')] >> h16] >> + "::" >> ls32; + ipv6addresses[13] %= -qi::raw[qi::repeat(1)[(h16 >> ':')] >> h16] >> + "::" >> h16; + ipv6addresses[14] %= -qi::raw[qi::repeat(1)[(h16 >> ':')] >> h16] >> + "::"; + ipv6addresses[15] %= -qi::raw[qi::repeat(2)[(h16 >> ':')] >> h16] >> + "::" >> qi::repeat(2)[h16 >> ':'] >> ls32; + ipv6addresses[16] %= -qi::raw[qi::repeat(2)[(h16 >> ':')] >> h16] >> + "::" >> h16 >> ':' >> ls32; + ipv6addresses[17] %= -qi::raw[qi::repeat(2)[(h16 >> ':')] >> h16] >> + "::" >> ls32; + ipv6addresses[18] %= -qi::raw[qi::repeat(2)[(h16 >> ':')] >> h16] >> + "::" >> h16; + ipv6addresses[19] %= -qi::raw[qi::repeat(2)[(h16 >> ':')] >> h16] >> + "::"; + ipv6addresses[20] %= -qi::raw[qi::repeat(3)[(h16 >> ':')] >> h16] >> + "::" >> h16 >> ':' >> ls32; + ipv6addresses[21] %= -qi::raw[qi::repeat(3)[(h16 >> ':')] >> h16] >> + "::" >> ls32; + ipv6addresses[22] %= -qi::raw[qi::repeat(3)[(h16 >> ':')] >> h16] >> + "::" >> h16; + ipv6addresses[23] %= -qi::raw[qi::repeat(3)[(h16 >> ':')] >> h16] >> + "::"; + ipv6addresses[24] %= -qi::raw[qi::repeat(4)[(h16 >> ':')] >> h16] >> + "::" >> ls32; + ipv6addresses[25] %= -qi::raw[qi::repeat(4)[(h16 >> ':')] >> h16] >> + "::" >> h16; + ipv6addresses[26] %= -qi::raw[qi::repeat(4)[(h16 >> ':')] >> h16] >> + "::"; + ipv6addresses[27] %= -qi::raw[qi::repeat(5)[(h16 >> ':')] >> h16] >> + "::" >> h16; + ipv6addresses[28] %= -qi::raw[qi::repeat(5)[(h16 >> ':')] >> h16] >> + "::"; + ipv6addresses[29] %= -qi::raw[qi::repeat(6)[(h16 >> ':')] >> h16] >> + "::"; + + ipv6address %= qi::raw + [ipv6addresses[0] | + ipv6addresses[1] | + ipv6addresses[2] | + ipv6addresses[3] | + ipv6addresses[4] | + ipv6addresses[5] | + ipv6addresses[6] | + ipv6addresses[7] | + ipv6addresses[8] | + ipv6addresses[9] | + ipv6addresses[10] | + ipv6addresses[11] | + ipv6addresses[12] | + ipv6addresses[13] | + ipv6addresses[14] | + ipv6addresses[15] | + ipv6addresses[16] | + ipv6addresses[17] | + ipv6addresses[18] | + ipv6addresses[19] | + ipv6addresses[20] | + ipv6addresses[21] | + ipv6addresses[22] | + ipv6addresses[23] | + ipv6addresses[24] | + ipv6addresses[25] | + ipv6addresses[26] | + ipv6addresses[27] | + ipv6addresses[28] | + ipv6addresses[29]]; + + // ls32 = ( h16 ":" h16 ) / IPv4address + ls32 %= (h16 >> ':' >> h16) | ipv4address; + + // h16 = 1*4HEXDIG + h16 %= qi::repeat(1, 4)[qi::xdigit]; + + // dec-octet = DIGIT / %x31-39 DIGIT / "1" 2DIGIT / "2" %x30-34 + // DIGIT / "25" %x30-35 + dec_octet %= !(qi::lit('0') >> qi::digit) >> + qi::raw[qi::uint_parser()]; + + // IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + ipv4address %= + qi::raw[dec_octet >> qi::repeat(3)[qi::lit('.') >> dec_octet]]; + + // reg-name = *( unreserved / pct-encoded / sub-delims ) + reg_name %= qi::raw[*(unreserved | pct_encoded | sub_delims)]; + + // TODO, host = IP-literal / IPv4address / reg-name + host %= qi::raw[ip_literal | ipv4address | reg_name]; + + // port %= qi::ushort_; + port %= qi::raw[*qi::digit]; + + // query = *( pchar / "/" / "?" ) + query %= qi::raw[*(pchar | qi::char_("/?"))]; + + // fragment = *( pchar / "/" / "?" ) + fragment %= qi::raw[*(pchar | qi::char_("/?"))]; + + // hier-part = "//" authority path-abempty / path-absolute / + // path-rootless / path-empty + // authority = [ userinfo "@" ] host [ ":" port ] + hier_part %= ((("//" >> user_info >> '@') | "//") >> host >> + -(':' >> port) >> path_abempty) | + (qi::attr(iterator_range()) >> + qi::attr(iterator_range()) >> + qi::attr(iterator_range()) >> + (path_absolute | path_rootless | path_empty)); + + start %= + (scheme >> ':') >> hier_part >> -('?' >> query) >> -('#' >> fragment); + } + + qi::rule::value_type()> gen_delims, + sub_delims, reserved, unreserved; + qi::rule pct_encoded, pchar; + + qi::rule segment, segment_nz, segment_nz_nc; + qi::rule()> path_abempty, + path_absolute, path_rootless, path_empty; + + qi::rule dec_octet, ipv4address, reg_name, + ipv6address, ipvfuture, ip_literal; + + qi::rule ipv6addresses[30]; + + qi::rule h16, ls32; + + qi::rule()> host, port; + + qi::rule()> scheme, user_info, + query, fragment; + + qi::rule()> hier_part; + + // actual uri parser + qi::rule()> start; +}; + +bool parse(std::string::const_iterator first, std::string::const_iterator last, + uri_parts &parts) { + namespace qi = boost::spirit::qi; + static detail::uri_grammar grammar; + bool is_valid = qi::parse(first, last, grammar, parts); + return is_valid && (first == last); +} +} // namespace detail +} // namespace uri +} // namespace network +} // namespace boost diff --git a/cpp-netlib/boost/network/uri/uri_io.hpp b/cpp-netlib/boost/network/uri/uri_io.hpp new file mode 100644 index 00000000..5b7b22bc --- /dev/null +++ b/cpp-netlib/boost/network/uri/uri_io.hpp @@ -0,0 +1,22 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 __BOOST_NETWORK_URI_URI_IO_INC__ +#define __BOOST_NETWORK_URI_URI_IO_INC__ + +#include + +namespace boost { +namespace network { +namespace uri { + +inline std::ostream &operator<<(std::ostream &os, const uri &uri_) { + return os << uri_.string(); +} +} // namespace uri +} // namespace network +} // namespace boost + +#endif // __BOOST_NETWORK_URI_URI_IO_INC__ diff --git a/cpp-netlib/boost/network/utils/base64/encode-io.hpp b/cpp-netlib/boost/network/utils/base64/encode-io.hpp new file mode 100644 index 00000000..704cc5af --- /dev/null +++ b/cpp-netlib/boost/network/utils/base64/encode-io.hpp @@ -0,0 +1,270 @@ +#ifndef BOOST_NETWORK_UTILS_BASE64_ENCODE_IO_HPP +#define BOOST_NETWORK_UTILS_BASE64_ENCODE_IO_HPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace utils { + +// Offers an interface to the BASE64 converter from encode.hpp, which is +// based on stream manipulators to be friendly to the usage with output +// streams combining heterogenous output by using the output operators. +// The encoding state is serialized to long and maintained in te +// extensible +// internal array of the output stream. +// +// Summarized interface - ostream manipulators and one function: +// +// encode(InputIterator begin, InputIterator end) +// encode(InputRange const & value) +// encode(char const * value) +// encode_rest +// clear_state +// bool empty_state(std::basic_ostream & output) + +namespace base64 { +namespace io { + +// force using the ostream_iterator from boost::archive to write wide +// characters reliably, althoth wchar_t may not be a native character +// type +using namespace boost::archive::iterators; + +namespace detail { + +// Enables transferring of the input sequence for the BASE64 +// encoding into +// the ostream operator defined for it, which performs the +// operation. It +// is to be used from ostream manipulators. +// +// std::basic_ostream & output = ...; +// output << input_wrapper(value.begin(), +// value.end()); +template +struct input_wrapper { + input_wrapper(InputIterator begin, InputIterator end) + : begin(begin), end(end) {} + + private: + InputIterator begin, end; + + // only encoding of an input sequence needs access to it + template + friend std::basic_ostream &operator<<( + std::basic_ostream &output, + input_wrapper input_wrapper); +}; + +// The output stream state should be used only in a single scope +// around +// encoding operations. Constructor performs initialization from +// the +// output stream internal extensible array and destructor updates it +// according to the encoding result. It inherits from the +// base64::state +// to gain access to its protected members and allow easy value +// passing +// to base64::encode. +// +// +// std::basic_ostream & output = ...; +// { +// state rest(output); +// base64::encode(..., ostream_iterator(output), rest); +// } +template +struct state : public boost::network::utils::base64::state { + typedef boost::network::utils::base64::state super_t; + + // initialize the (inherited) contents of the base64::state<> from + // the + // output stream internal extensible array + state(std::basic_ostream &output) : super_t(), output(output) { + const unsigned triplet_index_size = sizeof(super_t::triplet_index) * 8; + unsigned long data = static_cast(storage()); + // mask the long value with the bit-size of the triplet_index + // member + super_t::triplet_index = data & ((1 << triplet_index_size) - 1); + // shift the long value right to remove the the triplet_index + // value; + // masking is not necessary because the last_encoded_value it is + // the + // last record stored in the data value + super_t::last_encoded_value = data >> triplet_index_size; + } + + // update the value in the output stream internal extensible array + // by + // the last (inherited) contents of the base64::state<> + ~state() { + const unsigned triplet_index_size = sizeof(super_t::triplet_index) * 8; + // store the last_encoded_value in the data value first + unsigned long data = + static_cast(super_t::last_encoded_value); + // shift the long data value left to make place for storing the + // full triplet_index value there + data <<= triplet_index_size; + data |= static_cast(super_t::triplet_index); + storage() = static_cast(data); + } + + private: + // all data of the base64::state<> must be serializable into a + // long + // value allocated in the output stream internal extensible array + BOOST_STATIC_ASSERT(sizeof(super_t) <= sizeof(long)); + + // allow only the construction with an output stream (strict RAII) + state(); + state(state const &); + + std::basic_ostream &output; + + long &storage() { + static int index = std::ios_base::xalloc(); + return output.iword(index); + } +}; + +// Output operator implementing the BASE64 encoding for an input +// sequence +// which was wrapped by the ostream manipulator; the state must be +// preserved +// because multiple sequences can be sent in the ouptut by this +// operator. +template +std::basic_ostream &operator<<(std::basic_ostream &output, + input_wrapper input) { + typedef typename iterator_value::type value_type; + state rest(output); + base64::encode(input.begin, input.end, ostream_iterator(output), rest); + return output; +} + +} // namespace detail + +// Encoding ostream manipulator for sequences specified by the pair of +// begin +// and end iterators. +// +// std::vector buffer = ...; +// std::basic_ostream & output = ...; +// output << base64::io::encode(buffer.begin(), buffer.end()) << ... +// << +// base64::io::encode_rest; +template +detail::input_wrapper encode(InputIterator begin, + InputIterator end) { + return detail::input_wrapper(begin, end); +} + +// Encoding ostream manipulator processing whole sequences which +// either +// support begin() and end() methods returning boundaries of the +// sequence +// or the boundaries can be computed by the Boost::Range. +// +// Warning: Buffers identified by C-pointers are processed including +// their +// termination character, if they have any. This is unexpected at +// least +// for the storing literals, which have a specialization here to avoid +// it. +// +// std::vector buffer = ...; +// std::basic_ostream & output = ...; +// output << base64::io::encode(buffer) << ... << +// base64::io::encode_rest; +template +detail::input_wrapper::type> +encode(InputRange const &value) { + typedef typename boost::range_const_iterator::type InputIterator; + return detail::input_wrapper(boost::begin(value), + boost::end(value)); +} + +// Encoding ostream manipulator processing string literals; the usual +// expectation from their encoding is processing only the string +// content +// without the terminating zero character. +// +// std::basic_ostream & output = ...; +// output << base64::io::encode("ab") << ... << +// base64::io::encode_rest; +inline detail::input_wrapper encode(char const *value) { + return detail::input_wrapper(value, value + strlen(value)); +} + +// Encoding ostream manipulator which finishes encoding of the +// previously +// processed chunks. If their total byte-length was divisible by +// three, +// nothing is needed, if not, the last quantum will be encoded as if +// padded +// with zeroes, which will be indicated by appending '=' characters to +// the +// output. This manipulator must be always used at the end of +// encoding, +// after previous usages of the encode manipulator. +// +// std::basic_ostream & output = ...; +// output << base64::io::encode("ab") << ... << +// base64::io::encode_rest; +template +std::basic_ostream &encode_rest(std::basic_ostream &output) { + detail::state rest(output); + base64::encode_rest(ostream_iterator(output), rest); + return output; +} + +// Clears the encoding state in the internal array of the output +// stream. +// Use it to re-use a state object in an unknown state only; Encoding +// of +// the last chunk must be followed by encode_rest otherwise the end of +// the +// input sequence may be missing in the encoded output. The +// encode_rest +// ensures that the rest of the input sequence will be encoded +// corectly and +// the '=' padding applied as necessary. The encode rest clears the +// state +// when finished. +// +// std::basic_ostream & output = ...; +// output << base64::io::encode("ab") << ...; +// output << clear_state; +template +std::basic_ostream &clear_state(std::basic_ostream &output) { + detail::state rest(output); + rest.clear(); + return output; +} + +// Checks if the encoding state in the internal array of the output +// stream +// is empty. +// +// std::basic_ostream & output = ...; +// output << base64::io::encode("ab") << ...; +// bool is_complete = base64::io::empty_state(output); +template +bool empty_state(std::basic_ostream &output) { + detail::state rest(output); + return rest.empty(); +} + +} // namespace io +} // namespace base64 + +} // namespace utils +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_UTILS_BASE64_ENCODE_IO_HPP diff --git a/cpp-netlib/boost/network/utils/base64/encode.hpp b/cpp-netlib/boost/network/utils/base64/encode.hpp new file mode 100644 index 00000000..f7f98a5f --- /dev/null +++ b/cpp-netlib/boost/network/utils/base64/encode.hpp @@ -0,0 +1,418 @@ +#ifndef BOOST_NETWORK_UTILS_BASE64_ENCODE_HPP +#define BOOST_NETWORK_UTILS_BASE64_ENCODE_HPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace utils { + +// Implements a BASE64 converter working on an iterator range. +// If the input sequence does not end at the three-byte boundary, the last +// encoded value part is remembered in an encoding state to be able to +// continue with the next chunk; the BASE64 encoding processes the input +// by byte-triplets. +// +// Summarized interface: +// +// struct state { +// bool empty () const; +// void clear(); +// } +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output, State & rest) +// OutputIterator encode_rest(OutputIterator output, State & rest) +// OutputIterator encode(InputRange const & input, OutputIterator output, +// State & rest) +// OutputIterator encode(char const * value, OutputIterator output, +// state & rest) +// std::basic_string encode(InputRange const & value, State & rest) +// std::basic_string encode(char const * value, state & rest) +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output) +// OutputIterator encode(InputRange const & input, OutputIterator output) +// OutputIterator encode(char const * value, OutputIterator output) +// std::basic_string encode(InputRange const & value) +// std::basic_string encode(char const * value) { +// +// See also http://libb64.sourceforge.net, which served as inspiration. +// See also http://tools.ietf.org/html/rfc4648 for the specification. + +namespace base64 { + +namespace detail { + +// Picks a character from the output alphabet for another 6-bit value +// from the input sequence to encode. +template +char encode_value(Value value) { + static char const encoding[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + "+/"; + return encoding[static_cast(value)]; +} + +} // namespace detail + +// Stores the state after processing the last chunk by the encoder. If +// the +// chunk byte-length is not divisible by three, the last (incomplete) +// value +// quantum canot be encoded right away; it has to wait for the next +// chunk +// of octets which will be processed joined (as if the trailing rest +// from +// the previous one was at its beinning). +template +struct state { + state() : triplet_index(0), last_encoded_value(0) {} + + state(state const& source) + : triplet_index(source.triplet_index), + last_encoded_value(source.last_encoded_value) {} + + bool empty() const { return triplet_index == 0; } + + void clear() { + // indicate that no rest has been left in the last encoded value + // and no padding is needed for the encoded output + triplet_index = 0; + // the last encoded value, which may have been left from the last + // encoding step, must be zeroed too; it is important before the + // next encoding begins, because it works as a cyclic buffer and + // must start empty - with zero + last_encoded_value = 0; + } + + protected: + // number of the octet in the incomplete quantum, which has been + // processed the last time; 0 means that the previous quantum was + // complete 3 octets, 1 that just one octet was avalable and 2 that + // two octets were available + unsigned char triplet_index; + // the value made of the previously shifted and or-ed octets which + // was not completely split to 6-bit codes, because the last quantum + // did not stop on the boundary of three octets + Value last_encoded_value; + + // encoding of an input chunk needs to read and update the state + template + friend OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output, State& rest); + + // finishing the encoding needs to read and clear the state + template + friend OutputIterator encode_rest(OutputIterator output, State& rest); +}; + +// Encodes an input sequence to BASE64 writing it to the output iterator +// and stopping if the last input tree-octet quantum was not complete, +// in +// which case it stores the state for the later continuation, when +// another +// input chunk is ready for the encoding. The encoding must be finished +// by calling the encode_rest after processing the last chunk. +// +// std::vector buffer = ...; +// std::basic_string result; +// std::back_insert_iterator > appender(result); +// base64::state rest; +// base64::encode(buffer.begin(), buffer.end(), appender, rest); +// ... +// base64::encode_rest(appender, rest); +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output, State& rest) { + typedef typename iterator_value::type value_type; + // continue with the rest of the last chunk - 2 or 4 bits which + // are already shifted to the left and need to be or-ed with the + // continuing data up to the target 6 bits + value_type encoded_value = rest.last_encoded_value; + // if the previous chunk stopped at encoding the first (1) or the + // second + // (2) octet of the three-byte quantum, jump to the right place, + // otherwise start the loop with an empty encoded value buffer + switch (rest.triplet_index) { + // this loop processes the input sequence of bit-octets by bits, + // shifting the current_value (used as a cyclic buffer) left and + // or-ing next bits there, while pulling the bit-sextets from the + // high word of the current_value + for (value_type current_value;;) { + case 0: + // if the input sequence is empty or reached its end at the + // 3-byte boundary, finish with an empty encoding state + if (begin == end) { + rest.triplet_index = 0; + // the last encoded value is not interesting - it would not + // be used, because processing of the next chunk will start + // at the 3-byte boundary + rest.last_encoded_value = 0; + return output; + } + // read the first octet from the current triplet + current_value = *begin++; + // use just the upper 6 bits to encode it to the target alphabet + encoded_value = (current_value & 0xfc) >> 2; + *output++ = detail::encode_value(encoded_value); + // shift the remaining two bits up to make place for the upoming + // part of the next octet + encoded_value = (current_value & 0x03) << 4; + case 1: + // if the input sequence reached its end after the first octet + // from the quantum triplet, store the encoding state and finish + if (begin == end) { + rest.triplet_index = 1; + rest.last_encoded_value = encoded_value; + return output; + } + // read the second first octet from the current triplet + current_value = *begin++; + // combine the upper four bits (as the lower part) with the + // previous two bits to encode it to the target alphabet + encoded_value |= (current_value & 0xf0) >> 4; + *output++ = detail::encode_value(encoded_value); + // shift the remaining four bits up to make place for the + // upoming + // part of the next octet + encoded_value = (current_value & 0x0f) << 2; + case 2: + // if the input sequence reached its end after the second octet + // from the quantum triplet, store the encoding state and finish + if (begin == end) { + rest.triplet_index = 2; + rest.last_encoded_value = encoded_value; + return output; + } + // read the third octet from the current triplet + current_value = *begin++; + // combine the upper two bits (as the lower part) with the + // previous four bits to encode it to the target alphabet + encoded_value |= (current_value & 0xc0) >> 6; + *output++ = detail::encode_value(encoded_value); + // encode the remaining 6 bits to the target alphabet + encoded_value = current_value & 0x3f; + *output++ = detail::encode_value(encoded_value); + } + } + return output; +} + +// Finishes encoding of the previously processed chunks. If their total +// byte-length was divisible by three, nothing is needed, if not, the +// last +// quantum will be encoded as if padded with zeroes, which will be +// indicated +// by appending '=' characters to the output. This method must be +// always +// used at the end of encoding, if the previous chunks were encoded by +// the +// method overload accepting the encoding state. +// +// std::vector buffer = ...; +// std::basic_string result; +// std::back_insert_iterator > appender(result); +// base64::state rest; +// base64::encode(buffer.begin(), buffer.end(), appender, rest); +// ... +// base64::encode_rest(appender, rest); +template +OutputIterator encode_rest(OutputIterator output, State& rest) { + if (!rest.empty()) { + // process the last part of the trailing octet (either 4 or 2 bits) + // as if the input was padded with zeros - without or-ing the next + // input value to it; it has been already shifted to the left + *output++ = detail::encode_value(rest.last_encoded_value); + // at least one padding '=' will be always needed - at least two + // bits are missing in the finally encoded 6-bit value + *output++ = '='; + // if the last octet was the first in the triplet (the index was + // 1), four bits are missing in the finally encoded 6-bit value; + // another '=' character is needed for the another two bits + if (rest.triplet_index < 2) *output++ = '='; + // clear the state all the time to make sure that another call to + // the encode_rest would not cause damage; the last encoded value, + // which may have been left there, must be zeroed too; it is + // important before the next encoding begins, because it works as + // a cyclic buffer and must start empty - with zero + rest.clear(); + } + return output; +} + +// Encodes a part of an input sequence specified by the pair of begin +// and +// end iterators.to BASE64 writing it to the output iterator. If its +// total +// byte-length was not divisible by three, the output will be padded by +// the +// '=' characters. If you encode an input consisting of mutiple chunks, +// use the method overload maintaining the encoding state. +// +// std::vector buffer = ...; +// std::basic_string result; +// base64::encode(buffer.begin(), buffer.end(), +// std::back_inserter(result)); +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output) { + state::type> rest; + output = encode(begin, end, output, rest); + return encode_rest(output, rest); +} + +// Encodes an entire input sequence to BASE64, which either supports +// begin() +// and end() methods returning boundaries of the sequence or the +// boundaries +// can be computed by the Boost::Range, writing it to the output +// iterator +// and stopping if the last input tree-octet quantum was not complete, +// in +// which case it stores the state for the later continuation, when +// another +// input chunk is ready for the encoding. The encoding must be finished +// by calling the encode_rest after processing the last chunk. +// +// Warning: Buffers identified by C-pointers are processed including +// their +// termination character, if they have any. This is unexpected at least +// for the storing literals, which have a specialization here to avoid +// it. +// +// std::vector buffer = ...; +// std::basic_string result; +// std::back_insert_iterator > appender(result); +// base64::state rest; +// base64::encode(buffer, appender, rest); +// ... +// base64::encode_rest(appender, rest); +template +OutputIterator encode(InputRange const& input, OutputIterator output, + State& rest) { + return encode(boost::begin(input), boost::end(input), output, rest); +} + +// Encodes an entire string literal to BASE64, writing it to the output +// iterator and stopping if the last input tree-octet quantum was not +// complete, in which case it stores the state for the later +// continuation, +// when another input chunk is ready for the encoding. The encoding +// must +// be finished by calling the encode_rest after processing the last +// chunk. +// +// The string literal is encoded without processing its terminating zero +// character, which is the usual expectation. +// +// std::basic_string result; +// std::back_insert_iterator > appender(result); +// base64::state rest; +// base64::encode("ab", appender, rest); +// ... +// base64::encode_rest(appender, rest); +template +OutputIterator encode(char const* value, OutputIterator output, + state& rest) { + return encode(value, value + strlen(value), output, rest); +} + +// Encodes an entire input sequence to BASE64 writing it to the output +// iterator, which either supports begin() and end() methods returning +// boundaries of the sequence or the boundaries can be computed by the +// Boost::Range. If its total byte-length was not divisible by three, +// the output will be padded by the '=' characters. If you encode an +// input consisting of mutiple chunks, use the method overload +// maintaining +// the encoding state. +// +// Warning: Buffers identified by C-pointers are processed including +// their +// termination character, if they have any. This is unexpected at least +// for the storing literals, which have a specialization here to avoid +// it. +// +// std::vector buffer = ...; +// std::basic_string result; +// base64::encode(buffer, std::back_inserter(result)); +template +OutputIterator encode(InputRange const& value, OutputIterator output) { + return encode(boost::begin(value), boost::end(value), output); +} + +// Encodes an entire string literal to BASE64 writing it to the output +// iterator. If its total length (without the trailing zero) was not +// divisible by three, the output will be padded by the '=' characters. +// If you encode an input consisting of mutiple chunks, use the method +// overload maintaining the encoding state. +// +// The string literal is encoded without processing its terminating zero +// character, which is the usual expectation. +// +// std::basic_string result; +// base64::encode("ab", std::back_inserter(result)); +template +OutputIterator encode(char const* value, OutputIterator output) { + return encode(value, value + strlen(value), output); +} + +// Encodes an entire input sequence to BASE64 returning the result as +// string, which either supports begin() and end() methods returning +// boundaries of the sequence or the boundaries can be computed by the +// Boost::Range. If its total byte-length was not divisible by three, +// the output will be padded by the '=' characters. If you encode an +// input consisting of mutiple chunks, use other method maintaining +// the encoding state writing to an output iterator. +// +// Warning: Buffers identified by C-pointers are processed including +// their +// termination character, if they have any. This is unexpected at least +// for the storing literals, which have a specialization here to avoid +// it. +// +// std::vector buffer = ...; +// std::basic_string result = base64::encode(buffer); +template +std::basic_string encode(InputRange const& value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +// Encodes an entire string literal to BASE64 returning the result as +// string. If its total byte-length was not divisible by three, the +// output will be padded by the '=' characters. If you encode an +// input consisting of mutiple chunks, use other method maintaining +// the encoding state writing to an output iterator. +// +// The string literal is encoded without processing its terminating zero +// character, which is the usual expectation. +// +// std::basic_string result = base64::encode("ab"); +template +std::basic_string encode(char const* value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +// The function overloads for string literals encode the input without +// the terminating zero, which is usually expected, because the trailing +// zero byte is not considered a part of the string value; the overloads +// for an input range would wrap the string literal by Boost.Range and +// encode the full memory occupated by the string literal - including +// the +// unwanted last zero byte. + +} // namespace base64 + +} // namespace utils +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_UTILS_BASE64_ENCODE_HPP diff --git a/cpp-netlib/boost/network/utils/thread_pool.hpp b/cpp-netlib/boost/network/utils/thread_pool.hpp new file mode 100644 index 00000000..3f33cf6f --- /dev/null +++ b/cpp-netlib/boost/network/utils/thread_pool.hpp @@ -0,0 +1,110 @@ +#ifndef BOOST_NETWORK_UTILS_THREAD_POOL_HPP_20101020 +#define BOOST_NETWORK_UTILS_THREAD_POOL_HPP_20101020 + +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace utils { + +typedef boost::shared_ptr io_service_ptr; +typedef boost::shared_ptr worker_threads_ptr; +typedef boost::shared_ptr sentinel_ptr; + +template +struct basic_thread_pool { + basic_thread_pool(std::size_t threads = 1, + io_service_ptr io_service = io_service_ptr(), + worker_threads_ptr worker_threads = worker_threads_ptr()) + : threads_(threads), + io_service_(io_service), + worker_threads_(worker_threads), + sentinel_() { + bool commit = false; + BOOST_SCOPE_EXIT_TPL( + (&commit)(&io_service_)(&worker_threads_)(&sentinel_)) { + if (!commit) { + sentinel_.reset(); + io_service_.reset(); + if (worker_threads_.get()) { + worker_threads_->interrupt_all(); + worker_threads_->join_all(); + } + worker_threads_.reset(); + } + } + BOOST_SCOPE_EXIT_END + + if (!io_service_.get()) { + io_service_.reset(new boost::asio::io_service); + } + + if (!worker_threads_.get()) { + worker_threads_.reset(new boost::thread_group); + } + + if (!sentinel_.get()) { + sentinel_.reset(new boost::asio::io_service::work(*io_service_)); + } + + for (std::size_t counter = 0; counter < threads_; ++counter) + worker_threads_->create_thread( + boost::bind(&boost::asio::io_service::run, io_service_)); + + commit = true; + } + + std::size_t thread_count() const { return threads_; } + + void post(boost::function f) { io_service_->post(f); } + + ~basic_thread_pool() throw() { + sentinel_.reset(); + try { + worker_threads_->join_all(); + } + catch (...) { + BOOST_ASSERT(false && + "A handler was not supposed to throw, but one did."); + } + } + + void swap(basic_thread_pool &other) { + std::swap(other.threads_, threads_); + std::swap(other.io_service_, io_service_); + std::swap(other.worker_threads_, worker_threads_); + std::swap(other.sentinel_, sentinel_); + } + + protected: + std::size_t threads_; + io_service_ptr io_service_; + worker_threads_ptr worker_threads_; + sentinel_ptr sentinel_; + + private: + basic_thread_pool(basic_thread_pool const &); // no copies please + basic_thread_pool &operator=(basic_thread_pool); // no assignment + // please +}; + +typedef basic_thread_pool thread_pool; + +} /* utils */ + +} /* network */ + +} /* boost */ + +#endif /* BOOST_NETWORK_UTILS_THREAD_POOL_HPP_20101020 */ diff --git a/cpp-netlib/boost/network/version.hpp b/cpp-netlib/boost/network/version.hpp new file mode 100644 index 00000000..14d6770f --- /dev/null +++ b/cpp-netlib/boost/network/version.hpp @@ -0,0 +1,22 @@ +#ifndef BOOST_NETWORK_VERSION_HPP_20091214 +#define BOOST_NETWORK_VERSION_HPP_20091214 + +// Copyright 2009, 2013 Dean Michael Berris +// Copyright Glyn Matthews 2010. +// 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 + +#define BOOST_NETLIB_VERSION_MAJOR 0 +#define BOOST_NETLIB_VERSION_MINOR 11 +#define BOOST_NETLIB_VERSION_INCREMENT 2 + +#ifndef BOOST_NETLIB_VERSION +#define BOOST_NETLIB_VERSION \ + BOOST_STRINGIZE(BOOST_NETLIB_VERSION_MAJOR) "." BOOST_STRINGIZE( \ + BOOST_NETLIB_VERSION_MINOR) "." BOOST_STRINGIZE(BOOST_NETLIB_VERSION_INCREMENT) +#endif // BOOST_NETLIB_VERSION + +#endif // BOOST_NETWORK_VERSION_HPP_20091214 diff --git a/cpp-netlib/cppnetlibConfig.cmake.in b/cpp-netlib/cppnetlibConfig.cmake.in new file mode 100644 index 00000000..952a5f63 --- /dev/null +++ b/cpp-netlib/cppnetlibConfig.cmake.in @@ -0,0 +1,24 @@ +# - Config file for the cppnetlib package +# It defines the following variables +# CPPNETLIB_INCLUDE_DIRS - include directories for cppnetlib +# CPPNETLIB_LIBRARIES - libraries to link against +# CPPNETLIB_EXECUTABLE - the bar executable + +# Compute paths +get_filename_component(CPPNETLIB_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +set(CPPNETLIB_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") + +# Our library dependencies (contains definitions for IMPORTED targets) +if( NOT TARGET cppnetlib-client-connections + AND NOT TARGET cppnetlib-server-parsers + AND NOT TARGET cppnetlib-uri + AND NOT CPPNETLIB_BINARY_DIR) + include("${CPPNETLIB_CMAKE_DIR}/cppnetlibTargets.cmake") +endif() + +# These are IMPORTED targets created by cppnetlibTargets.cmake +set(CPPNETLIB_LIBRARIES + cppnetlib-client-connections + cppnetlib-server-parsers + cppnetlib-uri) +#set(CPPNETLIB_EXECUTABLE ...) # maybe the examples? diff --git a/cpp-netlib/cppnetlibConfigVersion.cmake.in b/cpp-netlib/cppnetlibConfigVersion.cmake.in new file mode 100644 index 00000000..e459ca32 --- /dev/null +++ b/cpp-netlib/cppnetlibConfigVersion.cmake.in @@ -0,0 +1,11 @@ +set(PACKAGE_VERSION "@CPPNETLIB_VERSION_STRING@") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() \ No newline at end of file diff --git a/cpp-netlib/index.html b/cpp-netlib/index.html new file mode 100644 index 00000000..2cac53c9 --- /dev/null +++ b/cpp-netlib/index.html @@ -0,0 +1,25 @@ + + + + + + + + + + + + Automatic redirection failed, please go to index.html. + + + + diff --git a/cpp-netlib/libs/mime/To-Do.txt b/cpp-netlib/libs/mime/To-Do.txt new file mode 100644 index 00000000..690daeaf --- /dev/null +++ b/cpp-netlib/libs/mime/To-Do.txt @@ -0,0 +1,16 @@ +To Do list for Boost.Mime: + +General: +* Finish the test suites +** Compare results to python parser +** Try to parse some bad mime inputs +--> Added 0019-NoBoundary test +* Integrate into cpp-netlib +* Write some docs + +Specific: +* Rename make_mime into something better. Parse, Encode? +--> Changed the name to 'parse_mime', and made the stream and iterator versions use the same name +* Start using boost::exception +* Look into making the parsing restartable +* Figure out how to \ No newline at end of file diff --git a/cpp-netlib/libs/mime/doc/mime.qbk b/cpp-netlib/libs/mime/doc/mime.qbk new file mode 100644 index 00000000..b51bf064 --- /dev/null +++ b/cpp-netlib/libs/mime/doc/mime.qbk @@ -0,0 +1,58 @@ +[/ + (C) Copyright 2010 Marshall Clow + 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). +] + +[article C++ Mime Library + [quickbook 1.4] + [version 0.5] + [authors [Clow, Marshall]] + [copyright 2010 Marshall Clow] + [purpose C++ library for MIME parsing, manipulation and printing] + [category text] + [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]) + ] +] + + +[def __boost__ [@http://www.boost.org/ the Boost C++ Libraries]] +[def __boost_org__ [@http://www.boost.org/]] +[def __boost_asio__ [@http://www.boost.org/libs/asio/index.html Boost.Asio]] +[def __boost_system__ [@http://www.boost.org/libs/system/index.html Boost.System]] +[def __boost_type_traits__ [@http://www.boost.org/libs/type_traits/index.html Boost.TypeTraits]] +[def __boost_doc__ [@http://www.boost.org/doc/libs/]] +[def __pion__ [@http://www.pion.org/projects/pion-network-library the Pion Network Library]] +[def __cnl__ C++ Network Library] +[def __message__ `basic_message`] +[def __uri__ `basic_uri`] +[def __python__ [@http://www.python.org Python]] +[def __libcurl__ [@http://curl.haxx.se/ libcurl]] +[def __mozilla_netlib__ [@http://www.mozilla.org/projects/netlib/ mozilla-netlib]] +[def __sf_cpp_netlib__ [@http://sourceforge.net/projects/cpp-netlib/ sourceforge]] +[def __github__ [@http://github.com/mikhailberis/cpp-netlib github]] +[def __default_constructible__ [@http://www.boost.org/doc/html/DefaultConstructible.html DefaultConstructible]] +[def __copy_constructible__ [@http://www.boost.org/doc/html/CopyConstructible.html CopyConstructible]] +[def __assignable__ [@http://www.boost.org/doc/html/Assignable.html Assignable]] +[def __equality_comparable__ [@http://www.boost.org/doc/html/Assignable.html Assignable]] + + +[def __quick_start__ quick start] + + +[include quick_start.qbk] +#[include intro.qbk] +#[include using.qbk] +#[/include architecture.qbk] +#[include message.qbk] +#[include uri.qbk] +#[include protocol.qbk] +#[include examples.qbk] +#[include reference.qbk] +#[include acknowledgements.qbk] +#[include appendices.qbk] +#[include contributors.qbk] diff --git a/cpp-netlib/libs/mime/doc/quick_start.qbk b/cpp-netlib/libs/mime/doc/quick_start.qbk new file mode 100644 index 00000000..2ed1ec7a --- /dev/null +++ b/cpp-netlib/libs/mime/doc/quick_start.qbk @@ -0,0 +1,11 @@ +[/ + (C) Copyright 2010 Marshall Clow + 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:quick_start Quick Start] + +[endsect] [/ quick_start] diff --git a/cpp-netlib/libs/mime/example/basic_parsing.cpp b/cpp-netlib/libs/mime/example/basic_parsing.cpp new file mode 100644 index 00000000..bdf7a029 --- /dev/null +++ b/cpp-netlib/libs/mime/example/basic_parsing.cpp @@ -0,0 +1,127 @@ +// +// Copyright Marshall Clow 2009-2010 +// 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 + +#include +#include +#include +#include + +struct my_traits { + typedef std::string string_type; + // typedef std::pair < std::string, string_type > header_type; + typedef std::string body_type; +}; + +// typedef boost::mime::mime_part<> mime_part; +typedef boost::mime::basic_mime mime_part; + +template +void DumpContainer(std::ostream &out, const std::string &prefix, + const Container &c) { + out << prefix << ' '; + if (c.size() < 10) { + for (typename Container::const_iterator iter = c.begin(); iter != c.end(); + ++iter) + out << (int)*iter << ' '; + } else { + for (int i = 0; i < 5; i++) out << int(c.begin()[i]) << ' '; + out << "... "; + for (int i = 0; i < 5; i++) out << int(c.rbegin()[i]) << ' '; + } + out << std::endl; +} + +void DumpStructure(std::ostream &out, const char *title, const mime_part &mp, + std::string prefix) { + std::string content_type = mp.get_content_type(); + if (NULL != title) out << prefix << "Data from: " << title << std::endl; + out << prefix << "Content-Type: " << content_type << std::endl; + out << prefix << "There are " + << std::distance(mp.header_begin(), mp.header_end()) << " headers" + << std::endl; + size_t subpart_count = std::distance(mp.subpart_begin(), mp.subpart_end()); + switch (mp.get_part_kind()) { + case mime_part::simple_part: + if (subpart_count != 0) + out << str(boost::format("%s ### %d subparts on a simple (%s) type!") % + prefix % subpart_count % content_type) << std::endl; + out << prefix << "The body is " << mp.body_size() << " bytes long" + << std::endl; + DumpContainer(out, prefix, *mp.body()); + break; + + case mime_part::multi_part: + break; + + case mime_part::message_part: + if (boost::iequals(content_type, "message/delivery-status")) + out << prefix << "The body is " << mp.body_size() << " bytes long" + << std::endl; + else if (1 != subpart_count) + out << str(boost::format("%s ### %d subparts on a message (%s) type!") % + subpart_count % prefix % content_type) << std::endl; + break; + } + + if (subpart_count != 0) { + out << prefix << "There are " + << std::distance(mp.subpart_begin(), mp.subpart_end()) << " sub parts" + << std::endl; + for (mime_part::constPartIter iter = mp.subpart_begin(); + iter != mp.subpart_end(); ++iter) + DumpStructure(out, NULL, **iter, prefix + " "); + } +} + +int main(int argc, char *argv[]) { + + if (argc == 1) + std::cerr << "Usage: basic_parsing " << std::endl; + + for (int i = 1; i < argc; ++i) { + boost::shared_ptr rmp; + try { + std::ifstream in(argv[i]); + if (!in) { + std::cerr << "Can't open file " << argv[i] << std::endl; + continue; + } + + in >> std::noskipws; + std::cout << "**********************************" << std::endl; + rmp = mime_part::parse_mime(in); + } + catch (const boost::mime::mime_parsing_error &err) { + std::cout << "Caught an error parsing '" << argv[i] << "'" << std::endl; + std::cout << " " << err.what() << std::endl; + continue; + } + catch (const boost::exception &berr) { + std::cout << "Caught an boost error parsing '" << argv[i] << "'" + << std::endl; + // std::cout << " " << berr.what () << std::endl; + continue; + } + + try { + DumpStructure(std::cout, argv[i], *rmp, std::string()); + // std::ofstream out ( (std::string ( argv[i] ) + "-Results").c_str (), + // std::ios::binary ); + // out << rmp; + } + catch (const std::runtime_error &err) { + std::cout << "Caught an error writing '" << argv[i] << "'" << std::endl; + std::cout << " " << err.what() << std::endl; + continue; + } + } + + return 0; +} diff --git a/cpp-netlib/libs/mime/example/basic_usage.cpp b/cpp-netlib/libs/mime/example/basic_usage.cpp new file mode 100644 index 00000000..b90e3ff4 --- /dev/null +++ b/cpp-netlib/libs/mime/example/basic_usage.cpp @@ -0,0 +1,70 @@ +// +// Copyright Marshall Clow 2009-2010 +// 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 + +#include +#include +#include +#include + +struct my_traits { + typedef std::string string_type; + // typedef std::pair < std::string, string_type > header_type; + typedef std::string body_type; +}; + +typedef boost::mime::basic_mime mime_part; + +int main(int argc, char* argv[]) { + + // (1) a really simple part + mime_part mp("text", "plain"); + mp.set_body("Hello World\n", 12); + std::cout << mp; + + // Three trips around the house before we go through the door. + // Make a part, copy it onto the heap, and wrap it into a shared pointer. + std::cout << "*******" << std::endl; + std::string str("Hi Mom!\n"); + boost::shared_ptr mp0(new mime_part( + mime_part::make_simple_part("text", "html", str.begin(), str.end()))); + std::cout << mp0; + + std::cout << "*******" << std::endl; + boost::shared_ptr mp1(new mime_part("text", "plain")); + mp1->set_body("This is a test.....\n", 20); + mp1->append_phrase_to_content_type("charset", "usascii"); + std::cout << mp1; + + // Build a multipart + mime_part mp2("multipart", "multiple"); + mp2.set_body("This is the body of a multipart\n", 32); + mp2.append_part(mp0); + mp2.append_part(mp1); + + // stream it out to a string, then make a new part from the string + std::ostringstream os1, os2; + os1 << mp2; + std::istringstream is(os1.str()); + is >> std::noskipws; + boost::shared_ptr strmp = mime_part::parse_mime(is); + os2 << strmp; + if (os1.str() == os2.str()) + std::cout << "Strings match!!" << std::endl; + else { + // Write the differences out to files for examination + std::cout << "##Strings differ!!" << std::endl; + std::ofstream t1("test1.out", std::ios::binary); + t1 << os1.str(); + std::ofstream t2("test2.out", std::ios::binary); + t2 << os2.str(); + } + + return 0; +} diff --git a/cpp-netlib/libs/mime/test/CMakeLists.txt b/cpp-netlib/libs/mime/test/CMakeLists.txt new file mode 100644 index 00000000..f81f8a39 --- /dev/null +++ b/cpp-netlib/libs/mime/test/CMakeLists.txt @@ -0,0 +1,16 @@ +include_directories(${CPP-NETLIB_SOURCE_DIR}) +file ( COPY TestMessages DESTINATION ${CMAKE_CURRENT_BINARY_DIR} ) + +#This test causes a "too many sections" error on Windows MinGW64 +#(MSVC has /bigobj, MinGW does not) +if (NOT(${CMAKE_CXX_COMPILER_ID} MATCHES GNU AND ${CMAKE_SYSTEM_NAME} MATCHES "Windows")) + if ( Boost_FOUND ) + add_executable ( mime-roundtrip mime-roundtrip.cpp ) + target_link_libraries ( mime-roundtrip ${Boost_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT}) + set_target_properties( mime-roundtrip + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/tests) + add_test ( mime-roundtrip ${CPP-NETLIB_BINARY_DIR}/tests/mime-roundtrip ) + endif () +endif() + diff --git a/cpp-netlib/libs/mime/test/TestMessages/.gitattributes b/cpp-netlib/libs/mime/test/TestMessages/.gitattributes new file mode 100644 index 00000000..2bdd027c --- /dev/null +++ b/cpp-netlib/libs/mime/test/TestMessages/.gitattributes @@ -0,0 +1 @@ +* -crlf diff --git a/cpp-netlib/libs/mime/test/TestMessages/00000001 b/cpp-netlib/libs/mime/test/TestMessages/00000001 new file mode 100644 index 00000000..b6c9dd6c --- /dev/null +++ b/cpp-netlib/libs/mime/test/TestMessages/00000001 @@ -0,0 +1,40 @@ +Resent-To: mail.app@flagg2.qualcomm.com +Resent-From: win-eudora-bugs@flagg2.qualcomm.com +Resent-Message-Id: +Resent-Date: Mon, 1 Nov 2004 15:38:13 -0800 +Received: from flagg2.qualcomm.com [129.46.154.229] + by localhost with IMAP (fetchmail-6.2.5) + for marshall@localhost (single-drop); Tue, 02 Nov 2004 11:38:25 -0800 (PST) +Received: from snape.qualcomm.com (unverified [129.46.132.184]) (using TLSv1 with Cipher RC4(128), Exch RSA_SIGN(1024), Hash MD5(128)) by flagg2.qualcomm.com + (Rockliffe SMTPRA 6.1.16) with ESMTP id for ; + Mon, 1 Nov 2004 15:38:13 -0800 +Received: from sabrina.qualcomm.com (sabrina.qualcomm.com [129.46.61.150]) + by snape.qualcomm.com (8.12.10/8.12.3/1.0) with ESMTP id iA1NcAcH015308 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL); + Mon, 1 Nov 2004 15:38:11 -0800 (PST) +Received: from moria.qualcomm.com (qualcomm.com [199.106.114.68]) + by sabrina.qualcomm.com (8.12.10/8.12.5/1.0) with ESMTP id iA1Nc8HJ019370 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT) + for ; Mon, 1 Nov 2004 15:38:09 -0800 (PST) +Received: from isengard.qualcomm.com (isengard.qualcomm.com [199.106.114.75]) by moria.qualcomm.com (qualnet-external) with ESMTP id iA1Nc7Rg028808 for ; Mon, 1 Nov 2004 15:38:07 -0800 (PST) +Received: from coyote.rain.org (coyote.rain.org [198.68.144.2]) by isengard.qualcomm.com with ESMTP id iA1Nc7uA020987 for ; Mon, 1 Nov 2004 15:38:07 -0800 (PST) +Received: from sanders.rain.org (maxmp-189.rain.org [198.68.144.189]) + by coyote.rain.org (Postfix) with ESMTP id 648227775 + for ; Mon, 1 Nov 2004 15:38:06 -0800 (PST) +Message-Id: <5.0.2.1.2.20041101153017.00a26ec0@rain.org> +X-Sender: maia3@rain.org +X-Mailer: QUALCOMM Windows Eudora Version 5.0.2 +Date: Mon, 01 Nov 2004 15:31:46 -0800 +To: win-eudora6-bugs@qualcomm.com +From: Maia +Subject: New Bugs +Mime-Version: 1.0 +Content-Type: text/plain; charset="us-ascii"; format=flowed +X-PMX-Version: 4.6.0.97784, Antispam-Core: 4.6.0.97340, Antispam-Data: 2004.11.1.3 + +Just now, without any reason, an email of mine was turned into a mixture of +text and directions and numbers and letters and is now unusable. Do you +know why this is happening? + Thanks, Maia + + diff --git a/cpp-netlib/libs/mime/test/TestMessages/00000019 b/cpp-netlib/libs/mime/test/TestMessages/00000019 new file mode 100644 index 00000000..47961876 --- /dev/null +++ b/cpp-netlib/libs/mime/test/TestMessages/00000019 @@ -0,0 +1,81 @@ +Resent-To: mail.app@flagg2.qualcomm.com +Resent-From: win-eudora-bugs@flagg2.qualcomm.com +Resent-Message-Id: +Resent-Date: Mon, 1 Nov 2004 16:01:16 -0800 +Received: from flagg2.qualcomm.com [129.46.154.229] + by localhost with IMAP (fetchmail-6.2.5) + for marshall@localhost (single-drop); Tue, 02 Nov 2004 11:38:27 -0800 (PST) +Received: from snape.qualcomm.com (unverified [129.46.132.184]) (using TLSv1 with Cipher RC4(128), Exch RSA_SIGN(1024), Hash MD5(128)) by flagg2.qualcomm.com + (Rockliffe SMTPRA 6.1.16) with ESMTP id for ; + Mon, 1 Nov 2004 16:01:16 -0800 +Received: from neophyte.qualcomm.com (neophyte.qualcomm.com [129.46.61.149]) + by snape.qualcomm.com (8.12.10/8.12.3/1.0) with ESMTP id iA201FcH022189 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL); + Mon, 1 Nov 2004 16:01:15 -0800 (PST) +Received: from hobbiton.qualcomm.com (hobbiton.qualcomm.com [199.106.114.69]) + by neophyte.qualcomm.com (8.12.10/8.12.5/1.0) with ESMTP id iA201D9A029029 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT) + for ; Mon, 1 Nov 2004 16:01:13 -0800 (PST) +Received: from isengard.qualcomm.com (isengard.qualcomm.com [199.106.114.75]) by hobbiton.qualcomm.com (qualnet-external) with ESMTP id iA201BhJ016885 for ; Mon, 1 Nov 2004 16:01:12 -0800 (PST) +Received: from localhost (localhost) by isengard.qualcomm.com id iA201CuA023535; Mon, 1 Nov 2004 16:01:12 -0800 (PST) +Date: Mon, 1 Nov 2004 16:01:12 -0800 (PST) +From: Mail Delivery Subsystem +Message-Id: <200411020001.iA201CuA023535@isengard.qualcomm.com> +To: +MIME-Version: 1.0 +Content-Type: multipart/report; report-type=delivery-status; + boundary="iA201CuA023535.1099353672/isengard.qualcomm.com" +Subject: Returned mail: see transcript for details +Auto-Submitted: auto-generated (failure) +X-PMX-Version: 4.6.0.99824, Antispam-Core: 4.6.0.97340, Antispam-Data: 2004.11.1.3 + +This is a MIME-encapsulated message + +--iA201CuA023535.1099353672/isengard.qualcomm.com + +The original message was received at Mon, 1 Nov 2004 16:01:09 -0800 (PST) +from [210.193.18.250] + + ----- The following addresses had permanent fatal errors ----- + + (reason: 550 5.6.1 Prohibited attachment type) + + ----- Transcript of session follows ----- +... while talking to hobbiton.qualcomm.com.: +>>> DATA +<<< 550 5.6.1 Prohibited attachment type +554 5.0.0 Service unavailable + +--iA201CuA023535.1099353672/isengard.qualcomm.com +Content-Type: message/delivery-status + +Reporting-MTA: dns; isengard.qualcomm.com +Received-From-MTA: DNS; [210.193.18.250] +Arrival-Date: Mon, 1 Nov 2004 16:01:09 -0800 (PST) + +Final-Recipient: RFC822; win-eudora6-bugs@eudora.com +Action: failed +Status: 5.6.1 +Remote-MTA: DNS; hobbiton.qualcomm.com +Diagnostic-Code: SMTP; 550 5.6.1 Prohibited attachment type +Last-Attempt-Date: Mon, 1 Nov 2004 16:01:12 -0800 (PST) + +--iA201CuA023535.1099353672/isengard.qualcomm.com +Content-Type: text/rfc822-headers + +Return-Path: +Received: from eudora.com ([210.193.18.250]) by isengard.qualcomm.com with ESMTP id iA2018uA023523 for ; Mon, 1 Nov 2004 16:01:09 -0800 (PST) +Message-Id: <200411020001.iA2018uA023523@isengard.qualcomm.com> +From: win-eudora6-bugs@eudora.com +To: win-eudora6-bugs@eudora.com +Subject: Re: Excel file +Date: Tue, 2 Nov 2004 08:00:34 +0800 +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_NextPart_000_0001_00000AE6.000070CC" +X-Priority: 3 +X-MSMail-Priority: Normal + +--iA201CuA023535.1099353672/isengard.qualcomm.com-- + + diff --git a/cpp-netlib/libs/mime/test/TestMessages/00000431 b/cpp-netlib/libs/mime/test/TestMessages/00000431 new file mode 100644 index 00000000..7559066c --- /dev/null +++ b/cpp-netlib/libs/mime/test/TestMessages/00000431 @@ -0,0 +1,140 @@ +Marshall-Sez: This message has nested multiparts; with the last part of a + multipart being another multipart +Resent-To: mail.app@flagg2.qualcomm.com +Resent-From: eudora-suggest@flagg2.qualcomm.com +Resent-Message-Id: +Resent-Date: Mon, 1 Nov 2004 22:33:29 -0800 +Received: from flagg2.qualcomm.com [129.46.154.229] + by localhost with IMAP (fetchmail-6.2.5) + for marshall@localhost (single-drop); Tue, 02 Nov 2004 11:39:31 -0800 (PST) +Received: from snape.qualcomm.com (unverified [129.46.132.184]) (using TLSv1 with Cipher RC4(128), Exch RSA_SIGN(1024), Hash MD5(128)) by flagg2.qualcomm.com + (Rockliffe SMTPRA 6.1.16) with ESMTP id for ; + Mon, 1 Nov 2004 22:33:29 -0800 +Received: from sabrina.qualcomm.com (sabrina.qualcomm.com [129.46.61.150]) + by snape.qualcomm.com (8.12.10/8.12.3/1.0) with ESMTP id iA26XQcH013328 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) + for ; Mon, 1 Nov 2004 22:33:26 -0800 (PST) +Received: from moria.qualcomm.com (qualcomm.com [199.106.114.68]) + by sabrina.qualcomm.com (8.12.10/8.12.5/1.0) with ESMTP id iA26XNHJ013973 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT) + for ; Mon, 1 Nov 2004 22:33:24 -0800 (PST) +Received: from isengard.qualcomm.com (isengard.qualcomm.com [199.106.114.75]) by moria.qualcomm.com (qualnet-external) with ESMTP id iA26XMha015651 for ; Mon, 1 Nov 2004 22:33:22 -0800 (PST) +Received: from d60-65-159-220.col.wideopenwest.com (d60-65-159-220.col.wideopenwest.com [65.60.220.159]) by isengard.qualcomm.com with ESMTP id iA26XFuA029259 for ; Mon, 1 Nov 2004 22:33:16 -0800 (PST) +Received: from lopezclub.com (lopezclub-com.mr.outblaze.com [205.158.62.177]) + by d60-65-159-220.col.wideopenwest.com with esmtp + id 1F1D2A4AC2 for ; Tue, 02 Nov 2004 00:35:33 -0600 +Message-ID: <010001c4c0a6$2e00ef5b$f3fa62fd@lopezclub.com> +From: "Coarsest A. Spading" +To: Eudora +Subject: =?windows-1251?B?zeUg5OD+8iDv8O717uTgIOru4uDr5fD7Pw==?= +Date: Tue, 02 Nov 2004 00:35:33 -0600 +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_NextPart_000_0036_D092C96B.3CE29AF1" +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2800.1106 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000 +X-RAV-Antivirus: This e-mail has been scanned for viruses on host: d60-65-159-220.col.wideopenwest.com +X-PMX-Version: 4.6.0.97784, Antispam-Core: 4.6.0.97340, Antispam-Data: 2004.11.1.6 +X-PerlMx-Spam: Gauge=XXXXXXXXXIIIIII, Probability=96%, Report='MR_OUTBLAZE 5, IMGSPAM_BODY 3.2, RCVD_IN_CBL 3, __SANE_MSGID 0, __TO_MALFORMED_2 0, __MIME_VERSION 0, __NEXTPART_NORMAL 0, __NEXTPART_ALL 0, __CT 0, __CTYPE_HAS_BOUNDARY 0, __CTYPE_MULTIPART 0, __HAS_X_PRIORITY 0, __HAS_MSMAIL_PRI 0, __OUTLOOK_MUA_1 0, __HAS_X_MAILER 0, SUBJ_FULL_OF_8BITS 0, __HIGHBITS 0, __IMGSPAM_BODY 0, __TAG_EXISTS_BODY 0, __TAG_EXISTS_META 0, __TAG_EXISTS_HTML 0, HTML_FONT_COLOR_BLUE 0, __TAG_EXISTS_HEAD 0, __IMGSPAM_BODY_1 0, HTML_90_100 0, __HAS_MSGID 0, __OUTLOOK_MUA 0, IMGSPAM_BODY_1 0, __OUTLOOK_MSGID_1 0' +X-Maybe-Spam: X-Maybe-Spam + +This is a multi-part message in MIME format. + +------=_NextPart_000_0036_D092C96B.3CE29AF1 +Content-Type: multipart/related; + type="multipart/alternative"; + boundary="----=_NextPart_001_0037_D092C96B.3CE29AF1" + +------=_NextPart_001_0037_D092C96B.3CE29AF1 +Content-Type: image/gif; + name="ani.gif" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="ani.gif" +Content-ID: + +R0lGODlh/ABLAMQAAP///wAAgAAA/wAAADMzmRERiEREoVVVqoiIw+7u9szM5SIikLu73d3d +7qqq1GZmsnd3u5mZzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +ACH5BAAAAAAALAAAAAD8AEsAAAX/ICCOZGmeaKqubOu+cCzPdG2LCUQEQXEwt6BwyIoYCrzk +gsgcGpHJwJLIIzmg0cCjye3GGossjwD0mltgcYDMrOKQi3IigkSc73jAooBQ5P8re313bgAP +UiYKiICMQg4Bfo2SI4+RhAEjYQ4nhSJGSQeWIp0ApJ2kB1VqSSOopIkHcHYlCQ9IPg0kBwQA +DDtrsyQKqWIsDbY9D7mjq5gqw7Imx7fKury+Y8EknzyhJYVXzswjCgYnirwjv1ll4ySm4qXx +iqrNrfOsKY9Z6SINWEk2iSDw4FCWAst62VOxL0oBgc3imWiYpB8AijweqisoBiGJdVHaycOR +zx2KBAiQ/7RDsGZZgx0W4X2L12ndTE7xbJ7kASEBAAU7gtXxeayHz1Jh2ABoYGARgB0Pjpo8 +kQDJAZ8JUhWQOjVFAp4+gQaYVTXAVQBZjY5KWoapU5YEXMJ85yxCgAg3cWYUGSYh2lMSZd6j +FKBpYIkmHxlOAcGssEUstQFoDIHZlI93u45kXLhE08p0WzQ+8HhKY3MkPls2sQOvngB+v9J0 +RuDyYL1j/OIMzfu2yTD08goH/kodpBRNTXxNx0MgCQZrRCAxUdy4SIUWN6/YIarEjuvQmQdw +PiK8CsB/JWtHwUCr7gQMEBxB33uqG5akBefFv144bjWaudMYAaJUF6B+5yFW3/9t1ZECn3xQ +hBbLbizwJwIDYRTjW1foleUTgoN52N+CMy3UoDiGaYhCcSCuqOCGDL5YCIYA3tMchT8ZwBVv +0EkBQQQKyLYgglUcMkuLIxkZ4JJMipAcjksBZOCI/U0Jo3+3PUmdMz0u8GOQ6B1C3m9auCiC +Jv6BCJgiBcDIIiQ9XGlcd5hdV8IhdiqWWplNfleCeSSewF0Kfj4XnSEB5NnZa2PSV6hv+4yJ +KGn9sTQbloA15RySPGgqpwiNbTHCV6YtWt6ij2T3mmsA2BXTi6Ca6mQAoH1aQqgkkBoraiOo +dtGhJIThGimW8sbmdjwgcNQwPCwThqi1JCGVmrM5VaX/gkoEStJYIohFFhIG5MKAQQk1pRQ2 +FiHh15RlnZXWVljuxO1PQb1hFlZaSWVuGehmwme0PEwrziG1ogBSEhp5IgYEYbQTUY3yHOcm +tjwUCOuv/FihxpgH95AQwfGWgNGNIZ8wskUjj+ddRwnZlQXDiW6IhMATpUiAetgUBgR0vD6s +YqeYUsxrkz8Rs4B6tUDxwwkI/LKAqN3GWTIJ0ySzI9HCGK1e1QVExbTTUJf3iwE7m9oJSz1f +nIeVk7Tt9ttwu8B23HTXbTcjc9+t995835B334AHLviWgxdu+OGIJ6744ow37vjjkEcu+eSU +Bz7A5Zg3PgAAm+stwOefnyBA/wmggw5A6aafjvoIpUfe+QivJ5655ySMXvvpKNhuuwm7izB6 +770zHjvnlccdPPC488567qQr//jwnb8u/ewiUM/55SdIDzv22XNfvffaY8499cMnb37ovrO+ ++/rN37588OnH7/zy7d/+O/18iw/+97BX37//xAMgCbQXwAL+L4AEjB4BC1g+/K2Pfb6DoPnk +Jz8JUhB16Dve/NRXQcBBD4D7Y+D/FnjA8plQBdHjnwBJqLz76Q5394OhDOvXQQpOEH4RbB0N +HYi/vX2QeJtL4PZmx8Lrkc96AhwgEYFYQvGpwIXJg+ILobhD3WGwhxN0Xxa3WEMu1u2H4xvh +AUtoAv8hJvGMIrzeCsf4RBlOcYZS3GAU66dB0WnRi+fD4t3AmMI0prGIZvQeGRGowDUaMgUW +TKQeb2jD9MEPh4xspBYtqDf9LTCIlhyiEht4ySB2L3bY66MfjchGHpqyiw9MHRcxGDpW2vB3 +q8uj+tDnuB8W75a4LGMJGvg4Vvryl8AMpjCHSUxh5vKYyEymMpfJzGY685nQjKY0p0nNalrz +mtjMpja3yc1uevOb4AynOMdJznKa85zoTKc618nOdrrznfCMpzznSc96WlMR5mgAMQ6QELHw +iRlRmBWdijYGh2WBEr8ggKT8sc+E6LMbukHoGJzjAKepx54naAoQANKmn2T/zKMHVcjQopaF +TdAjoACwVBRYRQKOjsClJlBpEvDisigUDKPKQYSFUmGHVIAmFXh5BKVKEIYdpUJULFmCUE1Q +BxGwpKMk2Cm3pKqepqY0Tk1xTXDeuYoU2KUyTYkEPtfTmcicoDEsBYCWRmLWNCEmrFEzB1w9 +OlKyIsYutmFnV1GQCiCgBz2pyJABLAGdoZ4jOoHtVCSaMgu0EW4w9NlTY2VlGI/Ik21Ftata ++WSQp4ghEroilMo65oeXREFVmo3sCExbkRJAoQAD1avaNoOekwb0CK45RD+qkwZR4VYEuo2S +QyL610uV4B/DNUFwLztbN9CnHGu4AlR7Uxzkhu0my4x16qFUNBL6RCG7V0Xt38jJNjfMday0 +6ExTaKYZ5BZsvZA17nclNtbzLoq7VTgCe+PJth3kgqqbBUICPJUKSh2CUsthamZ04ZhJAcCq +SY1pg3l6VUpR2LXzinCBgdtg/hqXwWWAaWNO6w+OHqWwdwIQchHmk5EtFKYPdojJxLCJFWdk +GeP9pmoVBpq0mCUhEIjGag3DzxGgFcMacsuPxVbQkzR0VE8+Qc6UspQoU8meoSVCZnG6zLkK +QRGG5TIy0SsEL4v5zGiOWwgAADs= + +------=_NextPart_001_0037_D092C96B.3CE29AF1 +Content-Type: multipart/alternative; + boundary="----=_NextPart_002_0038_D092C96B.3CE29AF1" + +------=_NextPart_002_0038_D092C96B.3CE29AF1 +Content-Type: text/plain; + charset=windows-1251 +Content-Transfer-Encoding: quoted-printable + +=c2=e4=ee=e1=e0=e2=ee=ea =ea =f0=e0=f1=f1=ea=e0=e7=e0=ec =ee =f1=f2=f0= +=e0=ed=ed=fb=f5 =ef=f0=ee=e8=f1=f8=e5=f1=f2=e2=e8=ff=f5 +------=_NextPart_002_0038_D092C96B.3CE29AF1 +Content-Type: text/html; + charset=windows-1251 +Content-Transfer-Encoding: quoted-printable + + + + + + + + +
+
 
+
 
+
=f1=ee=e2=f0=e5=ec=e5=ed=ed=e0=ff =ed=e0=f3=ea=e0=2e = +=c8=ed=ee=e3=e4=e0 =f2=e0=ea=ee=e9 =ea=eb=fe=f7 =e1=fc=e5=f2 =e8=e7
+ +------=_NextPart_002_0038_D092C96B.3CE29AF1-- + +------=_NextPart_001_0037_D092C96B.3CE29AF1-- + +------=_NextPart_000_0036_D092C96B.3CE29AF1-- + + + diff --git a/cpp-netlib/libs/mime/test/TestMessages/00000975 b/cpp-netlib/libs/mime/test/TestMessages/00000975 new file mode 100644 index 00000000..7b3ef638 --- /dev/null +++ b/cpp-netlib/libs/mime/test/TestMessages/00000975 @@ -0,0 +1,115 @@ +Resent-To: mail.app@flagg2.qualcomm.com +Resent-From: eudora-suggest@flagg2.qualcomm.com +Resent-Message-Id: +Resent-Date: Tue, 2 Nov 2004 08:05:31 -0800 +Received: from flagg2.qualcomm.com [129.46.154.229] + by localhost with IMAP (fetchmail-6.2.5) + for marshall@localhost (single-drop); Tue, 02 Nov 2004 11:40:47 -0800 (PST) +Received: from snape.qualcomm.com (unverified [129.46.132.184]) (using TLSv1 with Cipher RC4(128), Exch RSA_SIGN(1024), Hash MD5(128)) by flagg2.qualcomm.com + (Rockliffe SMTPRA 6.1.16) with ESMTP id for ; + Tue, 2 Nov 2004 08:05:31 -0800 +Received: from neophyte.qualcomm.com (neophyte.qualcomm.com [129.46.61.149]) + by snape.qualcomm.com (8.12.10/8.12.3/1.0) with ESMTP id iA2G5TcH006140 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) + for ; Tue, 2 Nov 2004 08:05:30 -0800 (PST) +Received: from hobbiton.qualcomm.com (hobbiton.qualcomm.com [199.106.114.69]) + by neophyte.qualcomm.com (8.12.10/8.12.5/1.0) with ESMTP id iA2G5R9A004119 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT) + for ; Tue, 2 Nov 2004 08:05:28 -0800 (PST) +Received: from mailserver.internal.evanstech.com ([216.235.152.49]) by hobbiton.qualcomm.com (qualnet-external) with ESMTP id iA2G5QBU029487 for ; Tue, 2 Nov 2004 08:05:26 -0800 (PST) +From: postmaster@evanstech.com +To: eudora-suggest@qualcomm.com +Date: Tue, 2 Nov 2004 11:04:00 -0500 +MIME-Version: 1.0 +Content-Type: multipart/report; report-type=delivery-status; + boundary="9B095B5ADSN=_01C4A240558054EB0030F626mailserver.inter" +X-DSNContext: 335a7efd - 4457 - 00000001 - 80040546 +Message-ID: +Subject: Delivery Status Notification (Failure) +X-PMX-Version: 4.6.0.99824, Antispam-Core: 4.6.0.97340, Antispam-Data: 2004.11.1.8 +X-PerlMx-Spam: Gauge=XXXXX, Probability=50%, Report='VBOUNCE 5, __TO_MALFORMED_2 0, __MIME_VERSION 0, __CT 0, __CTYPE_HAS_BOUNDARY 0, __CTYPE_MULTIPART 0, __HAS_MSGID 0, __SANE_MSGID 0, __UNUSABLE_MSGID 0, __VIRUS_MYDOOM_1 0, NO_REAL_NAME 0' + +This is a MIME-formatted message. +Portions of this message may be unreadable without a MIME-capable mail program. + +--9B095B5ADSN=_01C4A240558054EB0030F626mailserver.inter +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +------------------ Virus Warning Message (on echelon) + +Found virus WORM_SWASH.A in file message.pif (in message.zip) +The uncleanable file is deleted. + +Visit http://qualnet.qualcomm.com/it/virus for more information + +--------------------------------------------------------- + +--9B095B5ADSN=_01C4A240558054EB0030F626mailserver.inter +Content-Type: text/plain; charset=unicode-1-1-utf-7 + +This is an automatically generated Delivery Status Notification. + +Delivery to the following recipients failed. + + john@evanstech.com + + + + +--9B095B5ADSN=_01C4A240558054EB0030F626mailserver.inter +Content-Type: message/delivery-status + +Reporting-MTA: dns;mailserver.internal.evanstech.com +Received-From-MTA: dns;qualcomm.com +Arrival-Date: Tue, 2 Nov 2004 11:03:49 -0500 + +Final-Recipient: rfc822;john@evanstech.com +Action: failed +Status: 5.1.1 + +--9B095B5ADSN=_01C4A240558054EB0030F626mailserver.inter +Content-Type: message/rfc822 + +Received: from qualcomm.com ([80.231.132.37] RDNS failed) by mailserver.internal.evanstech.com with Microsoft SMTPSVC(5.0.2195.6713); + Tue, 2 Nov 2004 11:03:49 -0500 +From: eudora-suggest@qualcomm.com +To: john@evanstech.com +Subject: Status +Date: Tue, 2 Nov 2004 17:03:42 +0100 +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_NextPart_000_0007_BF11B844.031F7FC2" +X-Priority: 3 +X-MSMail-Priority: Normal +Return-Path: eudora-suggest@qualcomm.com +Message-ID: +X-OriginalArrivalTime: 02 Nov 2004 16:03:50.0928 (UTC) FILETIME=[8B44D100:01C4C0F5] + +This is a multi-part message in MIME format. + +------=_NextPart_000_0007_BF11B844.031F7FC2 +Content-Type: text/html; + charset="Windows-1252" +Content-Transfer-Encoding: 7bit + +The message cannot be represented in 7-bit ASCII encoding and has been sent as a binary attachment. + + +------=_NextPart_000_0007_BF11B844.031F7FC2 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + + +------------------ Virus Warning Message (on echelon) + +message.zip is removed from here because it contains a virus. + +--------------------------------------------------------- +------=_NextPart_000_0007_BF11B844.031F7FC2-- + + + + +--9B095B5ADSN=_01C4A240558054EB0030F626mailserver.inter-- + diff --git a/cpp-netlib/libs/mime/test/TestMessages/0019-NoBoundary b/cpp-netlib/libs/mime/test/TestMessages/0019-NoBoundary new file mode 100644 index 00000000..df297920 --- /dev/null +++ b/cpp-netlib/libs/mime/test/TestMessages/0019-NoBoundary @@ -0,0 +1,80 @@ +Resent-To: mail.app@flagg2.qualcomm.com +Resent-From: win-eudora-bugs@flagg2.qualcomm.com +Resent-Message-Id: +Resent-Date: Mon, 1 Nov 2004 16:01:16 -0800 +Received: from flagg2.qualcomm.com [129.46.154.229] + by localhost with IMAP (fetchmail-6.2.5) + for marshall@localhost (single-drop); Tue, 02 Nov 2004 11:38:27 -0800 (PST) +Received: from snape.qualcomm.com (unverified [129.46.132.184]) (using TLSv1 with Cipher RC4(128), Exch RSA_SIGN(1024), Hash MD5(128)) by flagg2.qualcomm.com + (Rockliffe SMTPRA 6.1.16) with ESMTP id for ; + Mon, 1 Nov 2004 16:01:16 -0800 +Received: from neophyte.qualcomm.com (neophyte.qualcomm.com [129.46.61.149]) + by snape.qualcomm.com (8.12.10/8.12.3/1.0) with ESMTP id iA201FcH022189 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL); + Mon, 1 Nov 2004 16:01:15 -0800 (PST) +Received: from hobbiton.qualcomm.com (hobbiton.qualcomm.com [199.106.114.69]) + by neophyte.qualcomm.com (8.12.10/8.12.5/1.0) with ESMTP id iA201D9A029029 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT) + for ; Mon, 1 Nov 2004 16:01:13 -0800 (PST) +Received: from isengard.qualcomm.com (isengard.qualcomm.com [199.106.114.75]) by hobbiton.qualcomm.com (qualnet-external) with ESMTP id iA201BhJ016885 for ; Mon, 1 Nov 2004 16:01:12 -0800 (PST) +Received: from localhost (localhost) by isengard.qualcomm.com id iA201CuA023535; Mon, 1 Nov 2004 16:01:12 -0800 (PST) +Date: Mon, 1 Nov 2004 16:01:12 -0800 (PST) +From: Mail Delivery Subsystem +Message-Id: <200411020001.iA201CuA023535@isengard.qualcomm.com> +To: +MIME-Version: 1.0 +Content-Type: multipart/report; report-type=delivery-status +Subject: Returned mail: see transcript for details +Auto-Submitted: auto-generated (failure) +X-PMX-Version: 4.6.0.99824, Antispam-Core: 4.6.0.97340, Antispam-Data: 2004.11.1.3 + +This is a MIME-encapsulated message + +--iA201CuA023535.1099353672/isengard.qualcomm.com + +The original message was received at Mon, 1 Nov 2004 16:01:09 -0800 (PST) +from [210.193.18.250] + + ----- The following addresses had permanent fatal errors ----- + + (reason: 550 5.6.1 Prohibited attachment type) + + ----- Transcript of session follows ----- +... while talking to hobbiton.qualcomm.com.: +>>> DATA +<<< 550 5.6.1 Prohibited attachment type +554 5.0.0 Service unavailable + +--iA201CuA023535.1099353672/isengard.qualcomm.com +Content-Type: message/delivery-status + +Reporting-MTA: dns; isengard.qualcomm.com +Received-From-MTA: DNS; [210.193.18.250] +Arrival-Date: Mon, 1 Nov 2004 16:01:09 -0800 (PST) + +Final-Recipient: RFC822; win-eudora6-bugs@eudora.com +Action: failed +Status: 5.6.1 +Remote-MTA: DNS; hobbiton.qualcomm.com +Diagnostic-Code: SMTP; 550 5.6.1 Prohibited attachment type +Last-Attempt-Date: Mon, 1 Nov 2004 16:01:12 -0800 (PST) + +--iA201CuA023535.1099353672/isengard.qualcomm.com +Content-Type: text/rfc822-headers + +Return-Path: +Received: from eudora.com ([210.193.18.250]) by isengard.qualcomm.com with ESMTP id iA2018uA023523 for ; Mon, 1 Nov 2004 16:01:09 -0800 (PST) +Message-Id: <200411020001.iA2018uA023523@isengard.qualcomm.com> +From: win-eudora6-bugs@eudora.com +To: win-eudora6-bugs@eudora.com +Subject: Re: Excel file +Date: Tue, 2 Nov 2004 08:00:34 +0800 +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_NextPart_000_0001_00000AE6.000070CC" +X-Priority: 3 +X-MSMail-Priority: Normal + +--iA201CuA023535.1099353672/isengard.qualcomm.com-- + + diff --git a/cpp-netlib/libs/mime/test/mime-roundtrip.cpp b/cpp-netlib/libs/mime/test/mime-roundtrip.cpp new file mode 100644 index 00000000..f5bca8ac --- /dev/null +++ b/cpp-netlib/libs/mime/test/mime-roundtrip.cpp @@ -0,0 +1,118 @@ +/* + Read in a mime structure, parse it, and write it back to a file + with the same name as the input file, but with "-Results" appended to the + name + + We don't just write to stdout, because we want to read/write binary data, + and stdout on some systems eats CRLF, and turns them into newlines. + + Returns 0 for success, non-zero for failure + +*/ + +#include +#include + +#ifdef BOOST_TEST_DYN_LINK +#define BOOST_TEST_ALTERNATIVE_INIT_API +#endif +#include + +#include +#include +#include +#include +#include +#include + +namespace { + +std::string readfile(const char *fileName) { + std::ifstream in(fileName); + if (!in) { + std::cerr << std::string("Can't open file: ") + fileName << std::endl; + throw std::runtime_error(std::string("Can't open file: ") + fileName); + } + + std::istreambuf_iterator src(in); + std::istreambuf_iterator eof; + std::string retVal; + + in >> std::noskipws; + std::copy(src, eof, std::back_inserter(retVal)); + return retVal; +} + +struct my_traits { + typedef std::string string_type; + // typedef std::pair < std::string, string_type > header_type; + typedef std::string body_type; +}; + +// using namespace boost::mime; +typedef boost::mime::basic_mime mime_part; +typedef boost::shared_ptr smp; + +smp to_mime(const char *fileName) { + std::ifstream in(fileName); + if (!in) { + std::cerr << std::string("Can't open file: ") + fileName << std::endl; + throw std::runtime_error(std::string("Can't open file: ") + fileName); + } + + in >> std::noskipws; + return mime_part::parse_mime(in); +} + +std::string from_mime(smp mp) { + std::ostringstream oss; + oss << *mp; + return oss.str(); +} + +void test_roundtrip(const char *fileName) { + smp mp; + BOOST_REQUIRE_NO_THROW(mp = to_mime(fileName)); + BOOST_CHECK_EQUAL(readfile(fileName), from_mime(mp)); +} + +} + +using namespace boost::unit_test; + +#ifdef BOOST_TEST_DYN_LINK +bool init_unit_test() +#else +test_suite *init_unit_test_suite(int, char **) +#endif +{ + framework::master_test_suite().add( + BOOST_TEST_CASE(boost::bind(test_roundtrip, "TestMessages/00000001"))); + framework::master_test_suite().add( + BOOST_TEST_CASE(boost::bind(test_roundtrip, "TestMessages/00000019"))); + framework::master_test_suite().add( + BOOST_TEST_CASE(boost::bind(test_roundtrip, "TestMessages/00000431"))); + framework::master_test_suite().add( + BOOST_TEST_CASE(boost::bind(test_roundtrip, "TestMessages/00000975"))); + + // Following test is removed because the file it used often tripped + // false-positives when scanned by virus checkers. + // framework::master_test_suite().add ( BOOST_TEST_CASE( boost::bind ( + // test_roundtrip, "TestMessages/00001136" ))); + + // test cases that fail + // framework::master_test_suite().add ( BOOST_TEST_CASE( boost::bind ( + // test_roundtrip, "TestMessages/0019-NoBoundary" ))); + return +#ifdef BOOST_TEST_DYN_LINK + true; +#else + 0; +#endif +} + +#ifdef BOOST_TEST_DYN_LINK +int main(int argc, char *argv[]) { + return unit_test_main(&init_unit_test, argc, argv); +} +#endif diff --git a/cpp-netlib/libs/mime/test/mime-structure.cpp b/cpp-netlib/libs/mime/test/mime-structure.cpp new file mode 100644 index 00000000..6e148c69 --- /dev/null +++ b/cpp-netlib/libs/mime/test/mime-structure.cpp @@ -0,0 +1,123 @@ +/* + Read in a mime structure, parse it, dump the structure to stdout + + Returns 0 for success, non-zero for failure +*/ + +#include + +#include +#include +#include +#include + +struct my_traits { + typedef std::string string_type; + // typedef std::pair < std::string, string_type > header_type; + typedef std::string body_type; +}; + +typedef boost::mime::basic_mime mime_part; + +template +void DumpContainer(std::ostream &out, const std::string &prefix, + const Container &c) { + out << prefix << ' '; + if (c.size() < 10) { + for (typename Container::const_iterator iter = c.begin(); iter != c.end(); + ++iter) + out << (int)*iter << ' '; + } else { + for (int i = 0; i < 5; i++) out << int(c.begin()[i]) << ' '; + out << "... "; + for (int i = 0; i < 5; i++) out << int(c.rbegin()[i]) << ' '; + } + out << std::endl; +} + +void DumpStructure(std::ostream &out, const char *title, const mime_part &mp, + std::string prefix) { + std::string content_type = mp.get_content_type(); + if (NULL != title) out << prefix << "Data from: " << title << std::endl; + out << prefix << "Content-Type: " << content_type << std::endl; + out << prefix << "There are " + << std::distance(mp.header_begin(), mp.header_end()) << " headers" + << std::endl << std::flush; + size_t subpart_count = std::distance(mp.subpart_begin(), mp.subpart_end()); + switch (mp.get_part_kind()) { + case mime_part::simple_part: + if (subpart_count != 0) + out << str(boost::format("%s ### %d subparts on a simple (%s) type!") % + prefix % subpart_count % content_type) << std::endl; + out << prefix << "The body is " << mp.body_size() << " bytes long" + << std::endl; + DumpContainer(out, prefix, *mp.body()); + break; + + case mime_part::multi_part: + break; + + case mime_part::message_part: + if (boost::iequals(content_type, "message/delivery-status")) + out << prefix << "The body is " << mp.body_size() << " bytes long" + << std::endl; + else if (1 != subpart_count) + out << str(boost::format("%s ### %d subparts on a message (%s) type!") % + subpart_count % prefix % content_type) << std::endl; + break; + } + + if (subpart_count != 0) { + out << prefix << "There are " + << std::distance(mp.subpart_begin(), mp.subpart_end()) << " sub parts" + << std::endl << std::flush; + for (mime_part::constPartIter iter = mp.subpart_begin(); + iter != mp.subpart_end(); ++iter) + DumpStructure(out, NULL, **iter, prefix + " "); + } +} + +int main(int argc, char *argv[]) { + int retVal = 0; + + for (int i = 1; i < argc; ++i) { + boost::shared_ptr rmp; + try { + std::ifstream in(argv[i]); + if (!in) { + std::cerr << "Can't open file " << argv[i] << std::endl; + retVal += 100; + continue; + } + + in >> std::noskipws; + std::cout << "**********************************" << std::endl; + rmp = mime_part::parse_mime(in); + } + + catch (const boost::mime::mime_parsing_error &err) { + std::cout << "Caught an error parsing '" << argv[i] << "'" << std::endl; + std::cout << " " << err.what() << std::endl; + retVal += 10; + continue; + } + catch (const boost::exception &berr) { + std::cout << "Caught an boost error parsing '" << argv[i] << "'" + << std::endl; + // std::cout << " " << berr.what () << std::endl; + retVal += 10; + continue; + } + catch (const std::runtime_error &rerr) { + std::cout << "Caught an runtime error parsing '" << argv[i] << "'" + << std::endl; + std::cout << " " << rerr.what() << std::endl; + retVal += 10; + continue; + } + + DumpStructure(std::cout, argv[i], *rmp, std::string()); + } + + return retVal; +} diff --git a/cpp-netlib/libs/mime/test/mimeParse.py b/cpp-netlib/libs/mime/test/mimeParse.py new file mode 100755 index 00000000..7db7bef2 --- /dev/null +++ b/cpp-netlib/libs/mime/test/mimeParse.py @@ -0,0 +1,52 @@ +#!/usr/bin/python +# +# A python program to compare against the output from "mime-structure" tool. +# +# Usage: python mimeParse.py +# + +import sys +import email + +def parseOne ( msg, title, prefix ): +# if prefix != "": +# print msg + if title != None: + print "%sData from: %s" % ( prefix, title ) + print "%sContent-Type: %s" % ( prefix, msg.get_content_type ()) + print "%sThere are %d headers" % ( prefix, msg.__len__ ()) + payload = msg.get_payload (); + if msg.is_multipart (): + print "%sThere are %s sub parts" % ( prefix, len ( payload )) + for p in payload: + parseOne ( p, None, prefix + " " ) + else: + bodyLen = 0 + aBody = "" + for p in payload: + bodyLen += len (p) + aBody += p + + print "%sThe body is %d bytes long" % ( prefix, bodyLen ) + print prefix, + if bodyLen < 10: + for c in aBody: + print ord(c), + else: + for i in range(0,5): + print ord (aBody[i]), + + print "... ", + for i in range(1,6): + print ord (aBody[-i]), + print '' + +# _structure ( msg ) + + +def main(): + for a in sys.argv[1:]: + print "**********************************" + parseOne ( email.message_from_file ( open ( a )), a, "" ) + +main () \ No newline at end of file diff --git a/cpp-netlib/libs/network/benchmarks/README.rst b/cpp-netlib/libs/network/benchmarks/README.rst new file mode 100644 index 00000000..edf40940 --- /dev/null +++ b/cpp-netlib/libs/network/benchmarks/README.rst @@ -0,0 +1,3 @@ +Here we can collect some statistics about different areas of +performance in the :mod:`cpp-netlib`, including run-time and +compile-time. diff --git a/cpp-netlib/libs/network/build/CMakeLists.txt b/cpp-netlib/libs/network/build/CMakeLists.txt new file mode 100644 index 00000000..dc1c0d0b --- /dev/null +++ b/cpp-netlib/libs/network/build/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories(${CPP-NETLIB_SOURCE_DIR}) +find_package( Boost 1.45.0 COMPONENTS unit_test_framework system regex thread filesystem ) + +add_library(cppnetlib-uri STATIC ${CPP-NETLIB_SOURCE_DIR}/libs/network/src/parse_uri_impl.cpp) +add_library(cppnetlib-server-parsers STATIC ${CPP-NETLIB_SOURCE_DIR}/libs/network/src/server_request_parsers_impl.cpp) + diff --git a/cpp-netlib/libs/network/doc/.gitignore b/cpp-netlib/libs/network/doc/.gitignore new file mode 100644 index 00000000..9c5f5782 --- /dev/null +++ b/cpp-netlib/libs/network/doc/.gitignore @@ -0,0 +1 @@ +_build \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/_ext/adjusts.py b/cpp-netlib/libs/network/doc/_ext/adjusts.py new file mode 100644 index 00000000..c03554b4 --- /dev/null +++ b/cpp-netlib/libs/network/doc/_ext/adjusts.py @@ -0,0 +1,11 @@ +from sphinx.writers import html as sphinx_htmlwriter + +class CppNetlibHTMLTranslator(sphinx_htmlwriter.SmartyPantsHTMLTranslator): + """ + cpp-netlib-customized HTML transformations of documentation. Based on + djangodocs.DjangoHTMLTranslator + """ + + def visit_section(self, node): + node['ids'] = map(lambda x: "cpp-netlib-%s" % x, node['ids']) + sphinx_htmlwriter.SmartyPantsHTMLTranslator.visit_section(self, node) diff --git a/cpp-netlib/libs/network/doc/_static/Button-Info-icon.png b/cpp-netlib/libs/network/doc/_static/Button-Info-icon.png new file mode 100644 index 00000000..4f318491 Binary files /dev/null and b/cpp-netlib/libs/network/doc/_static/Button-Info-icon.png differ diff --git a/cpp-netlib/libs/network/doc/_static/Button-Warning-icon.png b/cpp-netlib/libs/network/doc/_static/Button-Warning-icon.png new file mode 100644 index 00000000..edcd6624 Binary files /dev/null and b/cpp-netlib/libs/network/doc/_static/Button-Warning-icon.png differ diff --git a/cpp-netlib/libs/network/doc/_static/cpp-netlib.css b/cpp-netlib/libs/network/doc/_static/cpp-netlib.css new file mode 100644 index 00000000..3c4f3b61 --- /dev/null +++ b/cpp-netlib/libs/network/doc/_static/cpp-netlib.css @@ -0,0 +1,721 @@ +@import url('reset-fonts-grids.css'); + +html,body +{ + background-repeat: no-repeat; + background-position: left top; + background-attachment: fixed; + background-color: #fa2; +} + +body +{ + font: 12pt sans-serif; + color: black; +} + +#custom-doc +{ + width: 80%; + *width: 960px; + min-width: 960px; + max-width: 1240px; + margin: auto; + text-align: left; + padding-top: 16px; + margin-top: 0; +} + +#hd +{ + padding: 4px 0 12px 0; +} + +#bd +{ + /*background: #C5D88A;*/ +} + +#ft +{ + color: #C5D88A; + font-size: 90%; + padding-bottom: 2em; +} + +pre +{ + font-family: Monaco,monospace; + font-size: 14px; + background: #333; + background: -moz-linear-gradient(-90deg,#333,#222 60%); + background: -webkit-gradient(linear,0 top,0 bottom,from(#333),to(#222),color-stop(60%,#222)); + border-width: 1px 0; + margin: 1em 0; + padding: .3em .4em; + overflow: auto; + line-height: 1.3em; + color: #CCC; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + padding: 1em; +} + +/*** links ***/ +a +{ + text-decoration: none; + font-weight: bold +} + +a img +{ + border: none +} + +a: link,a: visited +{ + color: #800000 +} + +#bd a: link,#bd a: visited +{ + color: #800000; + text-decoration: underline +} + +#bd #sidebar a: link,#bd #sidebar a: visited +{ + color: #8B4513; + text-decoration: none +} + +a: hover +{ + color: #000 +} + +#bd a: hover +{ + background-color: #FF9955; + color: black; + text-decoration: none +} + +#bd #sidebar a: hover +{ + color: #FF9955; + background: none +} + +h2 a,h3 a,h4 a +{ + text-decoration: none !important +} + +a.reference em +{ + /*color: #FF9955;*/ + font-style: normal; + font-weight: bold; +} + +/*** sidebar ***/ +#sidebar div.sphinxsidebarwrapper +{ + font-size: 92%; + margin-right: 14px +} + +#sidebar h3,#sidebar h4 +{ + color: #487858; + font-size: 125% +} + +#sidebar a +{ + color: #8B4513 +} + +#sidebar ul ul +{ + margin-top: 0; + margin-bottom: 0 +} + +#sidebar li +{ + margin-top: 0.2em; + margin-bottom: 0.2em; + list-style-position: inside; + list-style-type: square; +} + +/*** nav ***/ +div.nav +{ + margin: 0; + font-size: 14px; + text-align: right; + color: #fff +} + +div.nav a: link,div.nav a: visited +{ + color: white +} + +#hd div.nav +{ + margin-top: -27px +} + +#ft div.nav +{ + margin-bottom: -18px +} + +#hd h1 a +{ + color: #EFFFEF +} + +#global-nav +{ + position: absolute; + top: 5px; + margin-left: -5px; + padding: 7px 0; + color: #263E2B +} + +#global-nav a +{ + padding: 0 4px +} + +#global-nav a.about +{ + padding-left: 0 +} + +#global-nav a +{ + color: #fff +} + +/*** content ***/ +#yui-main +{ + -moz-border-radius: 3px; + -moz-box-shadow: 0 0 9px rgba(0,0,0,0.5); + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 0 9px rgba(0,0,0,0.5); + border-radius: 3px; + box-shadow: 0 0 9px rgba(0,0,0,0.5); + background: none repeat scroll 0 0 #6ABDFB; +} + +#yui-main div.yui-b +{ + position: relative +} + +#yui-main div.yui-b +{ + background: #FFF; + min-height: 330px; + color: #164B2B; + padding: 0.3em 2em 1em 2em +} + +/*** basic styles ***/ +dd +{ + margin-left: 15px +} + +h1,h2,h3,h4 +{ + margin-top: 1em; + font-weight: normal +} + +h1 +{ + font-size: 218%; + font-weight: bold; + margin-top: 0.6em; + margin-bottom: .4em; + line-height: 1.1em +} + +h2 +{ + font-size: 175%; + font-weight: bold; + margin-bottom: .6em; + line-height: 1.2em; + color: #092e20 +} + +h3 +{ + font-size: 150%; + font-weight: bold; + margin-bottom: .2em; + color: #487858 +} + +h4 +{ + font-size: 125%; + font-weight: bold; + margin-top: 1.5em; + margin-bottom: 3px +} + +div.figure +{ + text-align: center +} + +div.figure p.caption +{ + font-size: 1em; + margin-top: 0; + margin-bottom: 1.5em; + color: black +} + +hr +{ + color: #ccc; + background-color: #ccc; + height: 1px; + border: 0 +} + +p,ul,dl +{ + margin-top: .6em; + color: #333 +} + +#yui-main div.yui-b img +{ + max-width: 50em; + margin-left: auto; + margin-right: auto; + display: block; + margin-top: 10px; + margin-bottom: 10px +} + +caption +{ + font-size: 1em; + font-weight: bold; + margin-top: 0.5em; + margin-bottom: 0.5em; + margin-left: 2px; + text-align: center +} + +blockquote +{ + padding: 0 1em; + margin: 1em 0; + font: "Times New Roman",serif; + color: #234f32 +} + +strong +{ + font-weight: bold +} + +em +{ + font-style: italic +} + +ins +{ + font-weight: bold; + text-decoration: none +} + +/*** lists ***/ +ol.arabic li +{ + list-style-type: decimal +} + +ul li +{ + font-size: 1em +} + +ol li +{ + margin-bottom: .4em +} + +ul ul +{ + padding-left: 1.2em +} + +ul ul ul +{ + padding-left: 1em +} + +ul.linklist,ul.toc +{ + padding-left: 0 +} + +ul.toc ul +{ + margin-left: .6em +} + +ul.toc ul li +{ + list-style-type: square +} + +ul.toc ul ul li +{ + list-style-type: disc +} + +ul.linklist li,ul.toc li +{ + list-style-type: none +} + +dt +{ + font-weight: bold; + margin-top: .5em; + font-size: 1em +} + +dd +{ + margin-bottom: .8em +} + +ol.toc +{ + margin-bottom: 2em +} + +ol.toc li +{ + font-size: 125%; + padding: .5em; + line-height: 1.2em; + clear: right +} + +ol.toc li.b +{ + background-color: #E0FFB8 +} + +ol.toc li a: hover +{ + background-color: transparent !important; + text-decoration: underline !important +} + +ol.toc span.release-date +{ + color: #487858; + float: right; + font-size: 85%; + padding-right: .5em +} + +ol.toc span.comment-count +{ + font-size: 75%; + color: #999 +} + +ul.simple li +{ + list-style-type: disc; + margin-left: 2em +} + +/*** tables ***/ +table +{ + color: #000; + margin-bottom: 1em; + width: 100% +} + +table.docutils td p +{ + margin-top: 0; + margin-bottom: .5em +} + +table.docutils td,table.docutils th +{ + border-bottom: 1px solid #dfdfdf; + padding: 4px 2px +} + +table.docutils thead th +{ + border-bottom: 2px solid #dfdfdf; + text-align: left; + font-weight: bold; + #487858-space: nowrap +} + +table.docutils thead th p +{ + margin: 0; + padding: 0 +} + +table.docutils +{ + border-collapse: collapse +} + +/*** code blocks ***/ +.literal +{ + #487858-space: nowrap +} + +.literal +{ + color: #234f32 +} + +#sidebar .literal +{ + color: #487858; + background: transparent; + font-size: 11px +} + +h4 .literal +{ + color: #234f32; + font-size: 13px +} + +dt .literal,table .literal +{ + background: none +} + +#bd a.reference +{ + text-decoration: none +} + +#bd a.reference tt.literal +{ + border-bottom: 1px #234f32 dotted +} + +/*** notes & admonitions ***/ +.note,.admonition +{ + padding: .8em 1em .8em; + margin: 1em 0; + background-color: #6ABDFB; + -moz-border-radius: 3px; + -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.3); + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.3); + border-radius: 3px; + box-shadow: 0 1px 2px rgba(0,0,0,0.3); +} + +.admonition-title +{ + font-weight: bold; + margin-top: 0 !important; + margin-bottom: 0 !important +} + +.admonition .last +{ + margin-bottom: 0 !important +} + +.note +{ + padding-left: 85px; + background: #6ABDFB url(Button-Info-icon.png) .8em .8em no-repeat +} + +.warning +{ + padding-left: 85px; + background: #6ABDFB url(Button-Warning-icon.png) .8em .8em no-repeat +} + +/*** versoinadded/changes ***/ +div.versionadded,div.versionchanged +{ +} + +div.versionadded span.title,div.versionchanged span.title +{ + font-weight: bold +} + +/*** p-links ***/ +a.headerlink +{ + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; + visibility: hidden +} + +h1: hover > a.headerlink,h2: hover > a.headerlink,h3: hover > a.headerlink,h4: hover > a.headerlink,h5: hover > a.headerlink,h6: hover > a.headerlink,dt: hover > a.headerlink +{ + visibility: visible +} + +/*** index ***/ +table.indextable td +{ + text-align: left; + vertical-align: top +} + +table.indextable dl,table.indextable dd +{ + margin-top: 0; + margin-bottom: 0 +} + +table.indextable tr.pcap +{ + height: 10px +} + +table.indextable tr.cap +{ + margin-top: 10px; + background-color: #f2f2f2 +} + +/*** page-specific overrides ***/ +div#contents ul +{ + margin-bottom: 0 +} + +div#contents ul li +{ + margin-bottom: 0 +} + +div#contents ul ul li +{ + margin-top: 0.3em +} + +/*** IE hacks ***/ +* pre +{ +} + +.footer +{ + color: white; +} + +.footer a +{ + color: #333; +} + +img +{ + margin: 10px 0 10px 0; +} + +#index p.rubric +{ + font-size: 150%; + font-weight: normal; + margin-bottom: .2em; + color: #252; +} + +#index div.section dt +{ + font-weight: normal; +} + +#index #cpp-netlib-getting-cpp-netlib, #index #cpp-netlib-boost { + background:none repeat scroll 0 0 #6ABDFB; + margin: 2em 0 2em 2em; + + border-radius:6px 6px; + -webkit-border-radius:6px; + -moz-border-radius:6px 6px; + + box-shadow:0 1px 2px rgba(0, 0, 0, 0.6); + -webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.6); + -moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.6); + + overflow:visible; + float:right; + clear:both; + padding:1em; + width: 380px; +} + +#index #cpp-netlib-getting-cpp-netlib a +{ + font-weight: bold; + font-size: 14px; +} + +#index #cpp-netlib-getting-cpp-netlib h1 +{ + color: #333; +} + +#index #cpp-netlib-getting-cpp-netlib h2 +{ + margin: 0; +} + +#index #cpp-netlib-getting-cpp-netlib strong +{ + font-size: 20px; +} + +tt.py-exc.literal +{ + color: red; +} + +tt.xref span.pre +{ + color: green; +} + diff --git a/cpp-netlib/libs/network/doc/_static/ftp_uri.png b/cpp-netlib/libs/network/doc/_static/ftp_uri.png new file mode 100644 index 00000000..f77d3c87 Binary files /dev/null and b/cpp-netlib/libs/network/doc/_static/ftp_uri.png differ diff --git a/cpp-netlib/libs/network/doc/_static/http_uri.png b/cpp-netlib/libs/network/doc/_static/http_uri.png new file mode 100644 index 00000000..a7bf7561 Binary files /dev/null and b/cpp-netlib/libs/network/doc/_static/http_uri.png differ diff --git a/cpp-netlib/libs/network/doc/_static/mailto_uri.png b/cpp-netlib/libs/network/doc/_static/mailto_uri.png new file mode 100644 index 00000000..118d6f4b Binary files /dev/null and b/cpp-netlib/libs/network/doc/_static/mailto_uri.png differ diff --git a/cpp-netlib/libs/network/doc/_static/orange-background.jpg b/cpp-netlib/libs/network/doc/_static/orange-background.jpg new file mode 100644 index 00000000..e8ac2b48 Binary files /dev/null and b/cpp-netlib/libs/network/doc/_static/orange-background.jpg differ diff --git a/cpp-netlib/libs/network/doc/_static/pygments.css b/cpp-netlib/libs/network/doc/_static/pygments.css new file mode 100644 index 00000000..284fb591 --- /dev/null +++ b/cpp-netlib/libs/network/doc/_static/pygments.css @@ -0,0 +1,69 @@ +.hll { background-color: #404040 } +.c { color: #999999; font-style: italic } /* Comment */ +.err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.g { color: #d0d0d0 } /* Generic */ +.k { color: #6ab825; font-weight: bold } /* Keyword */ +.l { color: #d0d0d0 } /* Literal */ +.n { color: #d0d0d0 } /* Name */ +.o { color: #d0d0d0 } /* Operator */ +.x { color: #d0d0d0 } /* Other */ +.p { color: #d0d0d0 } /* Punctuation */ +.cm { color: #999999; font-style: italic } /* Comment.Multiline */ +.cp { color: #cd2828; font-weight: bold } /* Comment.Preproc */ +.c1 { color: #999999; font-style: italic } /* Comment.Single */ +.cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +.gd { color: #d22323 } /* Generic.Deleted */ +.ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +.gr { color: #d22323 } /* Generic.Error */ +.gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +.gi { color: #589819 } /* Generic.Inserted */ +.go { color: #cccccc } /* Generic.Output */ +.gp { color: #aaaaaa } /* Generic.Prompt */ +.gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +.gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +.gt { color: #d22323 } /* Generic.Traceback */ +.kc { color: #6ab825; font-weight: bold } /* Keyword.Constant */ +.kd { color: #6ab825; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #6ab825; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #6ab825 } /* Keyword.Pseudo */ +.kr { color: #6ab825; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #6ab825; font-weight: bold } /* Keyword.Type */ +.ld { color: #d0d0d0 } /* Literal.Date */ +.m { color: #3677a9 } /* Literal.Number */ +.s { color: #ed9d13 } /* Literal.String */ +.na { color: #bbbbbb } /* Name.Attribute */ +.nb { color: #24909d } /* Name.Builtin */ +.nc { color: #447fcf; text-decoration: underline } /* Name.Class */ +.no { color: #6AB825 } /* Name.Constant */ +.nd { color: #ffa500 } /* Name.Decorator */ +.ni { color: #d0d0d0 } /* Name.Entity */ +.ne { color: #bbbbbb } /* Name.Exception */ +.nf { color: #447fcf } /* Name.Function */ +.nl { color: #d0d0d0 } /* Name.Label */ +.nn { color: #447fcf; text-decoration: underline } /* Name.Namespace */ +.nx { color: #d0d0d0 } /* Name.Other */ +.py { color: #d0d0d0 } /* Name.Property */ +.nt { color: #6ab825; font-weight: bold } /* Name.Tag */ +.nv { color: #40ffff } /* Name.Variable */ +.ow { color: #6ab825; font-weight: bold } /* Operator.Word */ +.w { color: #666666 } /* Text.Whitespace */ +.mf { color: #3677a9 } /* Literal.Number.Float */ +.mh { color: #3677a9 } /* Literal.Number.Hex */ +.mi { color: #3677a9 } /* Literal.Number.Integer */ +.mo { color: #3677a9 } /* Literal.Number.Oct */ +.sb { color: #ed9d13 } /* Literal.String.Backtick */ +.sc { color: #ed9d13 } /* Literal.String.Char */ +.sd { color: #ed9d13 } /* Literal.String.Doc */ +.s2 { color: #ed9d13 } /* Literal.String.Double */ +.se { color: #ed9d13 } /* Literal.String.Escape */ +.sh { color: #ed9d13 } /* Literal.String.Heredoc */ +.si { color: #ed9d13 } /* Literal.String.Interpol */ +.sx { color: #ffa500 } /* Literal.String.Other */ +.sr { color: #ed9d13 } /* Literal.String.Regex */ +.s1 { color: #ed9d13 } /* Literal.String.Single */ +.ss { color: #ed9d13 } /* Literal.String.Symbol */ +.bp { color: #24909d } /* Name.Builtin.Pseudo */ +.vc { color: #40ffff } /* Name.Variable.Class */ +.vg { color: #40ffff } /* Name.Variable.Global */ +.vi { color: #40ffff } /* Name.Variable.Instance */ +.il { color: #3677a9 } /* Literal.Number.Integer.Long */ diff --git a/cpp-netlib/libs/network/doc/_static/reset-fonts-grids.css b/cpp-netlib/libs/network/doc/_static/reset-fonts-grids.css new file mode 100644 index 00000000..f5238d7c --- /dev/null +++ b/cpp-netlib/libs/network/doc/_static/reset-fonts-grids.css @@ -0,0 +1,8 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.5.1 +*/ +html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;font-variant:normal;}sup {vertical-align:text-top;}sub {vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}body {font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}table {font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;} +body{text-align:center;}#ft{clear:both;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;min-width:750px;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}s .yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#bd:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#bd,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;} \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/_static/uri.svg b/cpp-netlib/libs/network/doc/_static/uri.svg new file mode 100644 index 00000000..a9106d16 --- /dev/null +++ b/cpp-netlib/libs/network/doc/_static/uri.svg @@ -0,0 +1,650 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + mailto:john.doe@example.com + + { + scheme + + + { + path + + + + ftp://john.doe:password@www.example.com:8021 + + { + scheme + + + { + host + + + { + port + + + password + { + + + { + username + + + { + user_info + + + { + authority + + + + http://www.example.com/resource/?key=value#page1 + + { + scheme + + + path + { + + + { + authority + + + { + query + + + { + fragment + + + + diff --git a/cpp-netlib/libs/network/doc/conf.py b/cpp-netlib/libs/network/doc/conf.py new file mode 100644 index 00000000..ea39c376 --- /dev/null +++ b/cpp-netlib/libs/network/doc/conf.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- +# +# cpp-netlib documentation build configuration file, created by +# sphinx-quickstart on Wed Jun 23 20:50:04 2010. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.append(os.path.abspath('_ext')) + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. + +extensions = ['sphinx.ext.todo', + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.coverage', + ] + +todo_include_todos = True + +# Add any paths that contain templates here, relative to this directory. +# templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +source_encoding = 'utf-8' + +# The master toctree document. +master_doc = 'contents' + +# General information about the project. +project = u'cpp-netlib' +copyright = u'2008-2014, Glyn Matthews, Dean Michael Berris; 2013 Google, Inc.' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.11' +# The full version, including alpha/beta/rc tags. +release = '0.11.2' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +unused_docs = [ '' ] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = ['build', 'doxyxml', 'ext'] + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +# pygments_style = 'sphinx' +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'pyramid' + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = 'cpp-netlib v0.11.2' + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = 'cpp-netlib' + +# Use an HTML index. +html_use_index = False + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_style = 'cpp-netlib.css' +# html_static_path = ['_static'] +# html_translator_class = "adjusts.CppNetlibHTMLTranslator" + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +html_use_smartypants = True + +# Output file base name for HTML help builder. +# htmlhelp_basename = 'cpp-netlibdoc' diff --git a/cpp-netlib/libs/network/doc/contents.rst b/cpp-netlib/libs/network/doc/contents.rst new file mode 100644 index 00000000..b014eab0 --- /dev/null +++ b/cpp-netlib/libs/network/doc/contents.rst @@ -0,0 +1,17 @@ +.. _contents: + +Contents +-------- + +.. toctree:: + :maxdepth: 4 + + index.rst + whats_new.rst + getting_started.rst + examples.rst + in_depth.rst + techniques.rst + history.rst + reference.rst + references.rst diff --git a/cpp-netlib/libs/network/doc/examples.rst b/cpp-netlib/libs/network/doc/examples.rst new file mode 100644 index 00000000..0e359144 --- /dev/null +++ b/cpp-netlib/libs/network/doc/examples.rst @@ -0,0 +1,27 @@ +.. _examples: + +Examples +======== + +The :mod:`cpp-netlib` is a practical library that is designed to aid +the development of applications for that need to communicate using +common networking protocols. The following set of examples describe a +series of realistic examples that use the :mod:`cpp-netlib` for these +kinds of application. All examples are built using CMake. + +HTTP examples +````````````` + +The HTTP component of the :mod:`cpp-netlib` contains a client and server. +The examples that follow show how to use both for programs that can be +embedded into larger applications. + +.. toctree:: + :maxdepth: 1 + + examples/http/http_client + examples/http/simple_wget + examples/http/hello_world_server + examples/http/hello_world_client + examples/http/atom_reader + examples/http/twitter_search diff --git a/cpp-netlib/libs/network/doc/examples/http/atom_reader.rst b/cpp-netlib/libs/network/doc/examples/http/atom_reader.rst new file mode 100644 index 00000000..2e0a9917 --- /dev/null +++ b/cpp-netlib/libs/network/doc/examples/http/atom_reader.rst @@ -0,0 +1,78 @@ +.. _atom_reader: + +****************** + Atom feed reader +****************** + +The next examples show some simple, more practical applications using +the HTTP client. The first one reads a simple Atom_ feed and prints +the titles of each entry to the console. + +.. _Atom: http://en.wikipedia.org/wiki/Atom_(standard) + +The code +======== + +.. code-block:: c++ + + #include "atom.hpp" + #include + #include + #include + + int main(int argc, char * argv[]) { + using namespace boost::network; + + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + try { + http::client client; + http::client::request request(argv[1]); + request << header("Connection", "close"); + http::client::response response = client.get(request); + atom::feed feed(response); + + std::cout << "Feed: " << feed.title() + << " (" << feed.subtitle() << ")" << std::endl; + BOOST_FOREACH(const atom::entry &entry, feed) { + std::cout << entry.title() + << " (" << entry.published() << ")" << std::endl; + } + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + } + + return 0; + } + +Building and running ``atom_reader`` +==================================== + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make atom_reader + +And to run the example from the command line to access the feed that +lists of all the commits on cpp-netlib's master branch: + +.. code-block:: bash + + $ ./example/atom_reader https://github.com/cpp-netlib/cpp-netlib/commits/master.atom + +Diving into the code +==================== + +Most of this will now be familiar. The response is passed to the +constructor to the ``atom::feed`` class, which parses the resultant +XML. To keep this example as simple as possible, `rapidxml`_, a +header-only XML parser library, was used to parse the response. + +.. _`rapidxml`: http://rapidxml.sourceforge.net/ + +A similar example using RSS feeds exists in +``libs/network/example/rss``. diff --git a/cpp-netlib/libs/network/doc/examples/http/hello_world_client.rst b/cpp-netlib/libs/network/doc/examples/http/hello_world_client.rst new file mode 100644 index 00000000..e4163926 --- /dev/null +++ b/cpp-netlib/libs/network/doc/examples/http/hello_world_client.rst @@ -0,0 +1,94 @@ +.. _hello_world_http_client: + +*************************** + "Hello world" HTTP client +*************************** + +Since we have a "Hello World" HTTP server, let's then create an HTTP client to +access that server. This client will be similar to the HTTP client we made +earlier in the documentation. + +The code +======== + +We want to create a simple HTTP client that just makes a request to the HTTP +server that we created earlier. This really simple client will look like this: + +.. code-block:: c++ + + #include + #include + #include + #include + + namespace http = boost::network::http; + + int main(int argc, char * argv[]) { + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " address port" << std::endl; + return 1; + } + + try { + http::client client; + std::ostringstream url; + url << "http://" << argv[1] << ":" << argv[2] << "/"; + http::client::request request(url.str()); + http::client::response response = + client.get(request); + std::cout << body(response) << std::endl; + } catch (std::exception & e) { + std::cerr << e.what() << std::endl; + return 1; + } + return 0; + } + +Building and running the client +=============================== + +Just like with the HTTP Server and HTTP client example before, we can build this +example by doing the following on the shell: + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make hello_world_client + +This example can be run from the command line as follows: + +.. code-block:: bash + + $ ./example/hello_world_client http://127.0.0.1:8000 + +.. note:: This assumes that you have the ``hello_world_server`` running on + localhost port 8000. + +Diving into the code +==================== + +All this example shows is how easy it is to write an HTTP client that connects +to an HTTP server, and gets the body of the response. The relevant lines are: + +.. code-block:: c++ + + http::client client; + http::client::request request(url.str()); + http::client::response response = + client.get(request); + std::cout << body(response) << std::endl; + +You can then imagine using this in an XML-RPC client, where you can craft the +XML-RPC request as payload which you can pass as the body to a request, then +perform the request via HTTP: + +.. code-block:: c++ + + http::client client; + http::client::request request("http://my.webservice.com/"); + http::client::response = + client.post(request, some_xml_string, "application/xml"); + std::data = body(response); + +The next set of examples show some more practical applications using +the :mod:`cpp-netlib` HTTP client. diff --git a/cpp-netlib/libs/network/doc/examples/http/hello_world_server.rst b/cpp-netlib/libs/network/doc/examples/http/hello_world_server.rst new file mode 100644 index 00000000..6d5c0294 --- /dev/null +++ b/cpp-netlib/libs/network/doc/examples/http/hello_world_server.rst @@ -0,0 +1,139 @@ +.. _hello_world_http_server: + +*************************** + "Hello world" HTTP server +*************************** + +Now that we've seen how we can deal with request and response objects from the +client side, we'll see how we can then use the same abstractions on the server +side. In this example we're going to create a simple HTTP Server in C++ using +:mod:`cpp-netlib`. + +The code +======== + +The :mod:`cpp-netlib` provides the framework to develop embedded HTTP +servers. For this example, the server is configured to return a +simple response to any HTTP request. + +.. code-block:: c++ + + #include + #include + #include + + namespace http = boost::network::http; + + struct hello_world; + typedef http::server server; + + struct hello_world { + void operator() (server::request const &request, + server::response &response) { + std::string ip = source(request); + response = server::response::stock_reply( + server::response::ok, std::string("Hello, ") + ip + "!"); + } + }; + + int + main(int argc, char * argv[]) { + + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " address port" << std::endl; + return 1; + } + + try { + hello_world handler; + server server_(argv[1], argv[2], handler); + server_.run(); + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + return 1; + } + + return 0; + } + +This is about a straightforward as server programming will get in C++. + +Building and running the server +=============================== + +Just like with the HTTP client, we can build this example by doing the following +on the shell: + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make hello_world_server + +The first two arguments to the ``server`` constructor are the host and +the port on which the server will listen. The third argument is the +the handler object defined previously. This example can be run from +a command line as follows: + +.. code-block:: bash + + $ ./example/hello_world_server 0.0.0.0 8000 + +.. note:: If you're going to run the server on port 80, you may have to run it + as an administrator. + +Diving into the code +==================== + +Let's take a look at the code listing above in greater detail. + +.. code-block:: c++ + + #include + +This header contains all the code needed to develop an HTTP server with +:mod:`cpp-netlib`. + +.. code-block:: c++ + + struct hello_world; + typedef http::server server; + + struct hello_world { + void operator () (server::request const &request, + server::response &response) { + std::string ip = source(request); + response = server::response::stock_reply( + server::response::ok, std::string("Hello, ") + ip + "!"); + } + }; + +``hello_world`` is a functor class which handles HTTP requests. All +the operator does here is return an HTTP response with HTTP code 200 +and the body ``"Hello, !"``. The ```` in this case would be +the IP address of the client that made the request. + +There are a number of pre-defined stock replies differentiated by +status code with configurable bodies. + +All the supported enumeration values for the response status codes can be found +in ``boost/network/protocol/http/impl/response.ipp``. + +.. code-block:: c++ + + hello_world handler; + server server_(argv[1], argv[2], handler); + server_.run(); + +The first two arguments to the ``server`` constructor are the host and +the port on which the server will listen. The third argument is the +the handler object defined previously. + +.. note:: In this example, the server is specifically made to be single-threaded. + In a multi-threaded server, you would invoke the ``hello_world::run`` member + method in a set of threads. In a multi-threaded environment you would also + make sure that the handler does all the necessary synchronization for shared + resources across threads. The handler is passed by reference to the server + constructor and you should ensure that any calls to the ``operator()`` overload + are thread-safe. + diff --git a/cpp-netlib/libs/network/doc/examples/http/http_client.rst b/cpp-netlib/libs/network/doc/examples/http/http_client.rst new file mode 100644 index 00000000..9b423dd0 --- /dev/null +++ b/cpp-netlib/libs/network/doc/examples/http/http_client.rst @@ -0,0 +1,125 @@ +.. _http_client: + +************* + HTTP client +************* + +The first code example is the simplest thing you can do with the +:mod:`cpp-netlib`. The application is a simple HTTP client, which can +be found in the subdirectory ``libs/network/example/http_client.cpp``. +All this example doing is creating and sending an HTTP request to a server +and printing the response body. + +The code +======== + +Without further ado, the code to do this is as follows: + +.. code-block:: c++ + + #include + #include + + int main(int argc, char *argv[]) { + using namespace boost::network; + + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " [url]" << std::endl; + return 1; + } + + http::client client; + http::client::request request(argv[1]); + request << header("Connection", "close"); + http::client::response response = client.get(request); + std::cout << body(response) << std::endl; + + return 0; + } + +Running the example +=================== + +You can then run this to get the Boost_ website: + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make http_client + $ ./example/http_client http://www.boost.org/ + +.. _Boost: http://www.boost.org/ + +.. note:: + + The instructions for all these examples assume that + :mod:`cpp-netlib` is build outside the source tree, + according to `CMake conventions`_. For the sake of + consistency we assume that this is in the + ``~/cpp-netlib-build`` directory. + +.. _`CMake conventions`: http://www.cmake.org/Wiki/CMake_FAQ#What_is_an_.22out-of-source.22_build.3F + +Diving into the code +==================== + +Since this is the first example, each line will be presented and +explained in detail. + +.. code-block:: c++ + + #include + +All the code needed for the HTTP client resides in this header. + +.. code-block:: c++ + + http::client client; + +First we create a ``client`` object. The ``client`` abstracts all the +connection and protocol logic. The default HTTP client is version +1.1, as specified in `RFC 2616`_. + +.. code-block:: c++ + + http::client::request request(argv[1]); + +Next, we create a ``request`` object, with a URI string passed as a +constructor argument. + +.. code-block:: c++ + + request << header("Connection", "close"); + +:mod:`cpp-netlib` makes use of stream syntax and *directives* to allow +developers to build complex message structures with greater +flexibility and clarity. Here, we add the HTTP header "Connection: +close" to the request in order to signal that the connection will be +closed after the request has completed. + +.. code-block:: c++ + + http::client::response response = client.get(request); + +Once we've built the request, we then make an HTTP GET request +throught the ``http::client`` from which an ``http::response`` is +returned. ``http::client`` supports all common HTTP methods: GET, +POST, HEAD, DELETE. + +.. code-block:: c++ + + std::cout << body(response) << std::endl; + +Finally, though we don't do any error checking, the response body is +printed to the console using the ``body`` directive. + +That's all there is to the HTTP client. In fact, it's possible to +compress this to a single line: + +.. code-block:: c++ + + std::cout << body(http::client().get(http::request("http://www.boost.org/"))); + +The next example will introduce the ``uri`` class. + +.. _`RFC 2616`: http://www.w3.org/Protocols/rfc2616/rfc2616.html diff --git a/cpp-netlib/libs/network/doc/examples/http/simple_wget.rst b/cpp-netlib/libs/network/doc/examples/http/simple_wget.rst new file mode 100644 index 00000000..c7849162 --- /dev/null +++ b/cpp-netlib/libs/network/doc/examples/http/simple_wget.rst @@ -0,0 +1,110 @@ +.. _simple_wget: + +*************** + Simple `wget` +*************** + +This example is a very simple implementation of a ``wget`` style +clone. It's very similar to the previous example, but introduces the +``uri`` class. + +The code +======== + +.. code-block:: c++ + + #include + #include + #include + #include + #include + + namespace http = boost::network::http; + namespace uri = boost::network::uri; + + namespace { + std::string get_filename(const uri::uri &url) { + std::string path = uri::path(url); + std::size_t index = path.find_last_of('/'); + std::string filename = path.substr(index + 1); + return filename.empty()? "index.html" : filename; + } + } // namespace + + int + main(int argc, char *argv[]) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " url" << std::endl; + return 1; + } + + try { + http::client client; + http::client::request request(argv[1]); + http::client::response response = client.get(request); + + std::string filename = get_filename(request.uri()); + std::cout << "Saving to: " << filename << std::endl; + std::ofstream ofs(filename.c_str()); + ofs << static_cast(body(response)) << std::endl; + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + return 1; + } + + return 0; + } + +Running the example +=================== + +You can then run this to copy the Boost_ website: + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make simple_wget + $ ./example/simple_wget http://www.boost.org/ + $ cat index.html + +.. _Boost: http://www.boost.org/ + +Diving into the code +==================== + +As with ``wget``, this example simply makes an HTTP request to the +specified resource, and saves it on the filesystem. If the file name +is not specified, it names the resultant file as ``index.html``. + +The new thing to note here is use of the ``uri`` class. The ``uri`` +takes a string as a constructor argument and parses it. The ``uri`` +parser is fully-compliant with `RFC 3986`_. The URI is provided in +the following header: + +.. _`RFC 3986`: http://www.ietf.org/rfc/rfc3986.txt + +.. code-block:: c++ + + #include + +Most of the rest of the code is familiar from the previous example. +To retrieve the URI resource's file name, the following function is +provided: + +.. code-block:: c++ + + std::string get_filename(const uri::uri &url) { + std::string path = uri::path(url); + std::size_t index = path.find_last_of('/'); + std::string filename = path.substr(index + 1); + return filename.empty()? "index.html" : filename; + } + +The ``uri`` interface provides access to its different components: +``scheme``, ``user_info``, ``host``, ``port``, ``path``, ``query`` and +``fragment``. The code above takes the URI path to determine the +resource name. + +Next we'll develop a simple client/server application using +``http::server`` and ``http::client``. diff --git a/cpp-netlib/libs/network/doc/examples/http/twitter_search.rst b/cpp-netlib/libs/network/doc/examples/http/twitter_search.rst new file mode 100644 index 00000000..6c0f2b60 --- /dev/null +++ b/cpp-netlib/libs/network/doc/examples/http/twitter_search.rst @@ -0,0 +1,117 @@ +.. _twitter_search: + +**************** + Twitter search +**************** + +This example uses `Twitter's search API`_ to list recent tweets given +a user query. New features introduced here include the URI builder +and ``uri::encoded`` function. + +.. _`Twitter's search API`: https://dev.twitter.com/docs/using-search + +The code +======== + +.. code-block:: c++ + + #include + #include "rapidjson/rapidjson.h" + #include "rapidjson/document.h" + #include + + int main(int argc, char *argv[]) { + using namespace boost::network; + using namespace rapidjson; + + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + try { + http::client client; + + uri::uri base_uri("http://search.twitter.com/search.json"); + + std::cout << "Searching Twitter for query: " << argv[1] << std::endl; + uri::uri search; + search << base_uri << uri::query("q", uri::encoded(argv[1])); + http::client::request request(search); + http::client::response response = client.get(request); + + Document d; + if (!d.Parse<0>(response.body().c_str()).HasParseError()) { + const Value &results = d["results"]; + for (SizeType i = 0; i < results.Size(); ++i) + { + const Value &user = results[i]["from_user_name"]; + const Value &text = results[i]["text"]; + std::cout << "From: " << user.GetString() << std::endl + << " " << text.GetString() << std::endl + << std::endl; + } + } + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + } + + return 0; + } + +.. note:: To parse the results of these queries, this example uses + `rapidjson`_, a header-only library that is released under + the `MIT License`_. + +.. _`rapidjson`: http://code.google.com/p/rapidjson/ +.. _`MIT License`: http://www.opensource.org/licenses/mit-license.php + +Building and running ``twitter_search`` +======================================= + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make twitter_search + +Twitter provides a powerful set of operators to modify the behaviour +of search queries. Some examples are provided below: + +.. code-block:: bash + + $ ./example/twitter_search "Lady Gaga" + +Returns any results that contain the exact phrase "Lady Gaga". + +.. code-block:: bash + + $ ./example/twitter_search "#olympics" + +Returns any results with the #olympics hash tag. + +.. code-block:: bash + + $ ./example/twitter_search "flight :(" + +Returns any results that contain "flight" and have a negative +attitude. + +More examples can be found on `Twitter's search API`_ page. + +Diving into the code +==================== + +.. code-block:: c++ + + uri::uri base_uri("http://search.twitter.com/search.json"); + + std::cout << "Searching Twitter for query: " << argv[1] << std::endl; + uri::uri search; + search << base_uri << uri::query("q", uri::encoded(argv[1])); + +The :mod:`cpp-netlib` URI builder uses a stream-like syntax to allow +developers to construct more complex URIs. The example above re-uses +the same base URI and allows the command line argument to be used as +part of the URI query. The builder also supports percent encoding +using the ``encoded`` directive. diff --git a/cpp-netlib/libs/network/doc/getting_started.rst b/cpp-netlib/libs/network/doc/getting_started.rst new file mode 100644 index 00000000..7350acad --- /dev/null +++ b/cpp-netlib/libs/network/doc/getting_started.rst @@ -0,0 +1,262 @@ +.. _getting_started: + +***************** + Getting Started +***************** + +Downloading an official release +=============================== + +You can find links to the latest official release from the project's official +website: + + http://cpp-netlib.org/ + +All previous stable versions of :mod:`cpp-netlib` can be downloaded from +Github_ from this url: + + http://github.com/cpp-netlib/cpp-netlib/downloads + +Each release is available as gzipped (Using the command +``tar xzf cpp-netlib.tar.gz``) or bzipped (Using ``tar xjf +cpp-netlib.tar.bz2``) tarball, or as a zipfile (``unzip +cpp-netlib.zip``, or on Windows using a tool such as 7zip_). + +.. _Github: http://github.com/cpp-netlib/cpp-netlib/downloads +.. _7zip: http://www.7-zip.org/ + +Downloading a development version +================================= + +The :mod:`cpp-netlib` uses Git_ for source control, so to use any +development versions Git must be installed on your system. + +Using the command line, the command to get the latest code is: + +:: + + shell$ git clone git://github.com/cpp-netlib/cpp-netlib.git + +This should be enough information get to started. To do more complex +things with Git, such as pulling changes or checking out a new branch, +refer to the `Git documentation`_. + +.. note:: Previous versions of :mod:`cpp-netlib` referred to the + *mikhailberis* repository as the main development repository. This + account is still valid, but not always up-to-date. In the interest of + consistency, the main repository has been changed to *cpp-netlib*. + +Windows users need to use msysGit_, and to invoke the command above +from a shell. + +For fans of Subversion_, the same code can be checked out from +http://svn.github.com/cpp-netlib/cpp-netlib.git. + +.. _Git: http://git-scm.com/ +.. _`Git documentation`: http://git-scm.com/documentation +.. _msysGit: http://code.google.com/p/msysgit/downloads/list +.. _Subversion: http://subversion.tigris.org/ + +.. note:: The :mod:`cpp-netlib` project is hosted on GitHub_ and follows the + prescribed development model for GitHub_ based projects. This means in case + you want to submit patches, you will have to create a fork of the project + (read up on forking_) and then submit a pull request (read up on submitting + `pull requests`_). + +.. _forking: http://help.github.com/forking/ +.. _`pull requests`: http://help.github.com/pull-requests/ + +Getting Boost +============= + +:mod:`cpp-netlib` depends on Boost_. It should work for any version +of Boost above 1.50.0. If Boost is not installed on your system, the +latest package can be found on the `Boost web-site`_. The environment +variable ``BOOST_ROOT`` must be defined, which must be the full path +name of the top directory of the Boost distribution. Although Boost +is mostly header only, applications built using :mod:`cpp-netlib` +still requires linking with `Boost.System`_, `Boost.Date_time`_, and +`Boost.Regex`_. + +.. _Boost: http://www.boost.org/doc/libs/release/more/getting_started/index.html +.. _`Boost web-site`: http://www.boost.org/users/download/ +.. _`Boost.System`: http://www.boost.org/libs/system/index.html +.. _`Boost.Date_time`: http://www.boost.org/libs/date_time/index.html +.. _`Boost.Regex`: http://www.boost.org/libs/regex/index.html + +.. note:: You can follow the steps in the `Boost Getting Started`_ guide to + install Boost into your development system. + +.. _`Boost Getting Started`: + http://www.boost.org/doc/libs/release/more/getting_started/index.html + +.. warning:: There is a known incompatibility between :mod:`cpp-netlib` and + Boost 1.46.1 on some compilers. It is not recommended to use :mod:`cpp-netlib` + with Boost 1.46.1. Some have reported though that Boost 1.47.0 + and :mod:`cpp-netlib` work together better. + +Getting CMake +============= + +The :mod:`cpp-netlib` uses CMake_ to generate platform-specific build files. If +you intend to run the test suite, you can follow the instructions below. +Otherwise, you don't need CMake to use :mod:`cpp-netlib` in your project. The +:mod:`cpp-netlib` requires CMake version 2.8 or higher. + +.. _CMake: http://www.cmake.org/ + +Let's assume that you have unpacked the :mod:`cpp-netlib` at the top of your +HOME directory. On Unix-like systems you will typically be able to change into +your HOME directory using the command ``cd ~``. This sample below assumes that +the ``~/cpp-netlib`` directory exists, and is the top-level directory of the +:mod:`cpp-netlib` release. + +Building with CMake +=================== + +To build the tests that come with :mod:`cpp-netlib`, we first need to configure the +build system to use our compiler of choice. This is done by running the +``cmake`` command at the top-level directory of :mod:`cpp-netlib` with +additional parameters:: + + $ mkdir ~/cpp-netlib-build + $ cd ~/cpp-netlib-build + $ cmake -DCMAKE_BUILD_TYPE=Debug \ + > -DCMAKE_C_COMPILER=gcc \ + > -DCMAKE_CXX_COMPILER=g++ \ + > ../cpp-netlib + +.. note:: + + While it's not compulsory, it's recommended that + :mod:`cpp-netlib` is built outside the source directory. + For the purposes of documentation, we'll assume that all + builds are done in ``~/cpp-netlib-build``. + +If you intend to use the SSL support when using the HTTP client libraries in +:mod:`cpp-netlib`, you may need to build it with OpenSSL_ installed or at least +available to CMake. If you have the development headers for OpenSSL_ installed +on your system when you build :mod:`cpp-netlib`, CMake will be able to detect it +and set the ``BOOST_NETWORK_ENABLE_HTTPS`` macro when building the library to +support HTTPS URIs. + +One example for building the library with OpenSSL_ support with a custom +(non-installed) version of OpenSSL_ is by doing the following:: + + $ cmake -DCMAKE_BUILD_TYPE=Debug \ + > -DCMAKE_C_COMPILER=clang \ + > -DCMAKE_CXX_COMPILER=clang++ \ + > -DOPENSSL_ROOT_DIR=/Users/dberris/homebrew/Cellar/openssl/1.0.1f + > ../cpp-netlib + +.. _OpenSSL: http://www.openssl.org/ + +You can also use a different root directory for the Boost_ project by using the +``-DBOOST_ROOT`` configuration option to CMake. This is useful if you intend to +build the library with a specific version of Boost that you've built in a +separate directory:: + + $ cmake -DCMAKE_BUILD_TYPE=Debug \ + > -DCMAKE_C_COMPILER=clang \ + > -DCMAKE_CXX_COMPILER=clang++ \ + > -DOPENSSL_ROOT_DIR=/Users/dberris/homebrew/Cellar/openssl/1.0.1f \ + > -DBOOST_ROOT=/Users/dberris/Source/boost_1_55_0 + > ../cpp-netlib + +Building on Linux +~~~~~~~~~~~~~~~~~ + +On Linux, this will generate the appropriate Makefiles that will enable you to +build and run the tests and examples that come with :mod:`cpp-netlib`. To build +the tests, you can run ``make`` in the same top-level directory of +``~/cpp-netlib-build``:: + + $ make + +.. note:: Just like with traditional GNU Make, you can add the ``-j`` parameter + to specify how many parallel builds to run. In case you're in a sufficiently + powerful system and would like to parallelize the build into 4 jobs, you can + do this with:: + + make -j4 + + As a caveat, :mod:`cpp-netlib` is heavy on template metaprogramming and will + require a lot of computing and memory resources to build the individual + tests. Do this at the risk of thrashing_ your system. However, this + compile-time burden is much reduced in recent versions. + +.. _thrashing: http://en.wikipedia.org/wiki/Thrashing_(computer_science) + +Once the build has completed, you can now run the test suite by issuing:: + + $ make test + +You can install :mod:`cpp-netlib` by issuing:: + + $ sudo make install + +By default this installs :mod:`cpp-netlib` into ``/usr/local``. + +.. note:: As of version 0.9.3, :mod:`cpp-netlib` produces three static + libraries. Using GCC on Linux these are:: + + libcppnetlib-client-connections.a + libcppnetlib-server-parsers.a + libcppnetlib-uri.a + + Users can find them in ``~/cpp-netlib-build/libs/network/src``. + +Building On Windows +~~~~~~~~~~~~~~~~~~~ + +If you're using the Microsoft Visual C++ compiler or the Microsoft Visual Studio +IDE and you would like to build :mod:`cpp-netlib` from within Visual Studio, you +can look for the solution and project files as the artifacts of the call to +``cmake`` -- the file should be named ``CPP-NETLIB.sln`` (the solution) along +with a number of project files for Visual Studio. + +.. note:: As of version 0.9.3, :mod:`cpp-netlib` produces three static + libraries. Using Visual C++ on Windows they are:: + + cppnetlib-client-connections.lib + cppnetlib-server-parsers.lib + cppnetlib-uri.lib + + Users can find them in ``~/cpp-netlib-build/libs/network/src``. + +Using :mod:`cpp-netlib` +======================= + +CMake projects +~~~~~~~~~~~~~~ + +Projects using CMake can add the following lines in their ``CMakeLists.txt`` to +be able to use :mod:`cpp-netlib`:: + + set ( CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ~/cpp-netlib-build ) + find_package ( cppnetlib 0.11.0 REQUIRED ) + include_directories ( ${CPPNETLIB_INCLUDE_DIRS} ) + target_link_libraries ( MyApplication ${CPPNETLIB_LIBRARIES} ) + +.. note:: Setting ``CMAKE_PREFIX_PATH`` is only required when :mod:`cpp-netlib` + is not installed to a location that CMake searches. When :mod:`cpp-netlib` + is installed to the default location (``/usr/local``), ``CMake`` can find it. + +.. note:: We assume that ``MyApplication`` is the application that you are + building and which depends on :mod:`cpp-netlib`. + + +Reporting Issues, Getting Support +================================= + +In case you find yourself stuck or if you've found a bug (or you want to just +join the discussion) you have a few options to choose from. + +For reporting bugs, feature requests, and asking questions about the +implementation and/or the documentation, you can go to the GitHub issues page +for the project at http://github.com/cpp-netlib/cpp-netlib/issues. + +You can also opt to join the developers mailing list for a more personal +interaction with the developers of the project. You can join the mailing list +through http://groups.google.com/forum/#!forum/cpp-netlib. + diff --git a/cpp-netlib/libs/network/doc/history.rst b/cpp-netlib/libs/network/doc/history.rst new file mode 100644 index 00000000..24f503f0 --- /dev/null +++ b/cpp-netlib/libs/network/doc/history.rst @@ -0,0 +1,54 @@ +Project history +=============== + +The :mod:`cpp-netlib` was founded by Dean Michael Berris in 2007. +Initially it consisted of a message template and an HTTP client. It +found a home on Sourceforge_ but was migrated at the end of 2009 to +Github_ where development is actively continued by a committed +community. + +Motivation +~~~~~~~~~~ + +We're a group of C++ developers and we kept becoming annoyed that we +had to repeatedly write the same code when building applications that +needed to be network-aware. + +We found that there was a lack of accessible networking libraries, +either standard or open source, that fulfilled our needs. Such +libraries exist for every other major language. So, building on top +of `Boost.Asio`_, we decided to get together and build our own. + +Objectives +~~~~~~~~~~ + +The objectives of the :mod:`cpp-netlib` are to: + +* develop a high quality, portable, easy to use C++ networking library +* enable developers to easily extend the library +* lower the barrier to entry for cross-platform network-aware C++ + applications + +The goal the of :mod:`cpp-netlib` has never been to build a +fully-featured web server - there are plenty of excellent options +already available. The niche that this library targets is for +light-weight networking functionality for C++ applications that have +demanding performance requirements or memory constraints, but that +also need to be portable. This type of application is becoming +increasingly common as software becomes more distributed, and +applications need to communicate with services. + +While many languages provide direct library support for high level +network programming, this feature is missing in C++. Therefore, this +library has been developed with the intention of eventually being +submitted to Boost_, a collection of general, high quality +libraries for C++ developers. + +Eventually, the :mod:`cpp-netlib` will be extended to support many of +the application layer protocols such as SMTP, FTP, SOAP, XMPP etc. + + +.. _Sourceforge: http://sourceforge.net/projects/cpp-netlib/ +.. _Github: http://github.com/cpp-netlib/cpp-netlib +.. _Boost: http://www.boost.org/ +.. _`Boost.Asio`: http://www.boost.org/libs/asio/ diff --git a/cpp-netlib/libs/network/doc/html/.buildinfo b/cpp-netlib/libs/network/doc/html/.buildinfo new file mode 100644 index 00000000..d90c273d --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: ae0de19b7b7891744d7373f4a9b6c125 +tags: fbb0d17656682115ca4d033fb2f83ba1 diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/contents.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/contents.doctree new file mode 100644 index 00000000..fb474d66 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/contents.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/environment.pickle b/cpp-netlib/libs/network/doc/html/.doctrees/environment.pickle new file mode 100644 index 00000000..d23c854d Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/environment.pickle differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/examples.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/examples.doctree new file mode 100644 index 00000000..a94c2d8f Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/examples.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/atom_reader.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/atom_reader.doctree new file mode 100644 index 00000000..c66f575e Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/atom_reader.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/hello_world_client.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/hello_world_client.doctree new file mode 100644 index 00000000..5e411455 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/hello_world_client.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/hello_world_server.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/hello_world_server.doctree new file mode 100644 index 00000000..b600d795 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/hello_world_server.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/http_client.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/http_client.doctree new file mode 100644 index 00000000..72b06c63 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/http_client.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/simple_wget.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/simple_wget.doctree new file mode 100644 index 00000000..cbb58d18 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/simple_wget.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/twitter_search.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/twitter_search.doctree new file mode 100644 index 00000000..ec38d150 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/examples/http/twitter_search.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/getting_started.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/getting_started.doctree new file mode 100644 index 00000000..00d721a9 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/getting_started.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/history.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/history.doctree new file mode 100644 index 00000000..d3b7c8d0 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/history.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/in_depth.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/in_depth.doctree new file mode 100644 index 00000000..21e7e21c Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/in_depth.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/http.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/http.doctree new file mode 100644 index 00000000..15e0e29a Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/http.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/http_client_tags.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/http_client_tags.doctree new file mode 100644 index 00000000..b15c2e45 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/http_client_tags.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/message.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/message.doctree new file mode 100644 index 00000000..cb062fba Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/message.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/uri.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/uri.doctree new file mode 100644 index 00000000..3862e20e Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/in_depth/uri.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/index.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/index.doctree new file mode 100644 index 00000000..7a6a470a Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/index.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/reference.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/reference.doctree new file mode 100644 index 00000000..b17e43bb Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/reference.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_client.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_client.doctree new file mode 100644 index 00000000..5002cccb Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_client.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_request.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_request.doctree new file mode 100644 index 00000000..4c38915e Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_request.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_response.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_response.doctree new file mode 100644 index 00000000..bc931026 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_response.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_server.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_server.doctree new file mode 100644 index 00000000..f290b920 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/reference/http_server.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/references.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/references.doctree new file mode 100644 index 00000000..5997a51d Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/references.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/techniques.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/techniques.doctree new file mode 100644 index 00000000..4aa34b1a Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/techniques.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/techniques/directives.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/techniques/directives.doctree new file mode 100644 index 00000000..02e00338 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/techniques/directives.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/techniques/polymorphism.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/techniques/polymorphism.doctree new file mode 100644 index 00000000..01940cc0 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/techniques/polymorphism.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/techniques/tag_metafunctions.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/techniques/tag_metafunctions.doctree new file mode 100644 index 00000000..91d826ed Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/techniques/tag_metafunctions.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/.doctrees/whats_new.doctree b/cpp-netlib/libs/network/doc/html/.doctrees/whats_new.doctree new file mode 100644 index 00000000..6fad46aa Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/.doctrees/whats_new.doctree differ diff --git a/cpp-netlib/libs/network/doc/html/_images/boost.png b/cpp-netlib/libs/network/doc/html/_images/boost.png new file mode 100644 index 00000000..0714ca20 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_images/boost.png differ diff --git a/cpp-netlib/libs/network/doc/html/_images/ftp_uri.png b/cpp-netlib/libs/network/doc/html/_images/ftp_uri.png new file mode 100644 index 00000000..f77d3c87 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_images/ftp_uri.png differ diff --git a/cpp-netlib/libs/network/doc/html/_images/http_uri.png b/cpp-netlib/libs/network/doc/html/_images/http_uri.png new file mode 100644 index 00000000..a7bf7561 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_images/http_uri.png differ diff --git a/cpp-netlib/libs/network/doc/html/_images/mailto_uri.png b/cpp-netlib/libs/network/doc/html/_images/mailto_uri.png new file mode 100644 index 00000000..118d6f4b Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_images/mailto_uri.png differ diff --git a/cpp-netlib/libs/network/doc/html/_sources/contents.txt b/cpp-netlib/libs/network/doc/html/_sources/contents.txt new file mode 100644 index 00000000..b014eab0 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/contents.txt @@ -0,0 +1,17 @@ +.. _contents: + +Contents +-------- + +.. toctree:: + :maxdepth: 4 + + index.rst + whats_new.rst + getting_started.rst + examples.rst + in_depth.rst + techniques.rst + history.rst + reference.rst + references.rst diff --git a/cpp-netlib/libs/network/doc/html/_sources/examples.txt b/cpp-netlib/libs/network/doc/html/_sources/examples.txt new file mode 100644 index 00000000..0e359144 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/examples.txt @@ -0,0 +1,27 @@ +.. _examples: + +Examples +======== + +The :mod:`cpp-netlib` is a practical library that is designed to aid +the development of applications for that need to communicate using +common networking protocols. The following set of examples describe a +series of realistic examples that use the :mod:`cpp-netlib` for these +kinds of application. All examples are built using CMake. + +HTTP examples +````````````` + +The HTTP component of the :mod:`cpp-netlib` contains a client and server. +The examples that follow show how to use both for programs that can be +embedded into larger applications. + +.. toctree:: + :maxdepth: 1 + + examples/http/http_client + examples/http/simple_wget + examples/http/hello_world_server + examples/http/hello_world_client + examples/http/atom_reader + examples/http/twitter_search diff --git a/cpp-netlib/libs/network/doc/html/_sources/examples/http/atom_reader.txt b/cpp-netlib/libs/network/doc/html/_sources/examples/http/atom_reader.txt new file mode 100644 index 00000000..2e0a9917 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/examples/http/atom_reader.txt @@ -0,0 +1,78 @@ +.. _atom_reader: + +****************** + Atom feed reader +****************** + +The next examples show some simple, more practical applications using +the HTTP client. The first one reads a simple Atom_ feed and prints +the titles of each entry to the console. + +.. _Atom: http://en.wikipedia.org/wiki/Atom_(standard) + +The code +======== + +.. code-block:: c++ + + #include "atom.hpp" + #include + #include + #include + + int main(int argc, char * argv[]) { + using namespace boost::network; + + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + try { + http::client client; + http::client::request request(argv[1]); + request << header("Connection", "close"); + http::client::response response = client.get(request); + atom::feed feed(response); + + std::cout << "Feed: " << feed.title() + << " (" << feed.subtitle() << ")" << std::endl; + BOOST_FOREACH(const atom::entry &entry, feed) { + std::cout << entry.title() + << " (" << entry.published() << ")" << std::endl; + } + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + } + + return 0; + } + +Building and running ``atom_reader`` +==================================== + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make atom_reader + +And to run the example from the command line to access the feed that +lists of all the commits on cpp-netlib's master branch: + +.. code-block:: bash + + $ ./example/atom_reader https://github.com/cpp-netlib/cpp-netlib/commits/master.atom + +Diving into the code +==================== + +Most of this will now be familiar. The response is passed to the +constructor to the ``atom::feed`` class, which parses the resultant +XML. To keep this example as simple as possible, `rapidxml`_, a +header-only XML parser library, was used to parse the response. + +.. _`rapidxml`: http://rapidxml.sourceforge.net/ + +A similar example using RSS feeds exists in +``libs/network/example/rss``. diff --git a/cpp-netlib/libs/network/doc/html/_sources/examples/http/hello_world_client.txt b/cpp-netlib/libs/network/doc/html/_sources/examples/http/hello_world_client.txt new file mode 100644 index 00000000..e4163926 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/examples/http/hello_world_client.txt @@ -0,0 +1,94 @@ +.. _hello_world_http_client: + +*************************** + "Hello world" HTTP client +*************************** + +Since we have a "Hello World" HTTP server, let's then create an HTTP client to +access that server. This client will be similar to the HTTP client we made +earlier in the documentation. + +The code +======== + +We want to create a simple HTTP client that just makes a request to the HTTP +server that we created earlier. This really simple client will look like this: + +.. code-block:: c++ + + #include + #include + #include + #include + + namespace http = boost::network::http; + + int main(int argc, char * argv[]) { + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " address port" << std::endl; + return 1; + } + + try { + http::client client; + std::ostringstream url; + url << "http://" << argv[1] << ":" << argv[2] << "/"; + http::client::request request(url.str()); + http::client::response response = + client.get(request); + std::cout << body(response) << std::endl; + } catch (std::exception & e) { + std::cerr << e.what() << std::endl; + return 1; + } + return 0; + } + +Building and running the client +=============================== + +Just like with the HTTP Server and HTTP client example before, we can build this +example by doing the following on the shell: + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make hello_world_client + +This example can be run from the command line as follows: + +.. code-block:: bash + + $ ./example/hello_world_client http://127.0.0.1:8000 + +.. note:: This assumes that you have the ``hello_world_server`` running on + localhost port 8000. + +Diving into the code +==================== + +All this example shows is how easy it is to write an HTTP client that connects +to an HTTP server, and gets the body of the response. The relevant lines are: + +.. code-block:: c++ + + http::client client; + http::client::request request(url.str()); + http::client::response response = + client.get(request); + std::cout << body(response) << std::endl; + +You can then imagine using this in an XML-RPC client, where you can craft the +XML-RPC request as payload which you can pass as the body to a request, then +perform the request via HTTP: + +.. code-block:: c++ + + http::client client; + http::client::request request("http://my.webservice.com/"); + http::client::response = + client.post(request, some_xml_string, "application/xml"); + std::data = body(response); + +The next set of examples show some more practical applications using +the :mod:`cpp-netlib` HTTP client. diff --git a/cpp-netlib/libs/network/doc/html/_sources/examples/http/hello_world_server.txt b/cpp-netlib/libs/network/doc/html/_sources/examples/http/hello_world_server.txt new file mode 100644 index 00000000..6d5c0294 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/examples/http/hello_world_server.txt @@ -0,0 +1,139 @@ +.. _hello_world_http_server: + +*************************** + "Hello world" HTTP server +*************************** + +Now that we've seen how we can deal with request and response objects from the +client side, we'll see how we can then use the same abstractions on the server +side. In this example we're going to create a simple HTTP Server in C++ using +:mod:`cpp-netlib`. + +The code +======== + +The :mod:`cpp-netlib` provides the framework to develop embedded HTTP +servers. For this example, the server is configured to return a +simple response to any HTTP request. + +.. code-block:: c++ + + #include + #include + #include + + namespace http = boost::network::http; + + struct hello_world; + typedef http::server server; + + struct hello_world { + void operator() (server::request const &request, + server::response &response) { + std::string ip = source(request); + response = server::response::stock_reply( + server::response::ok, std::string("Hello, ") + ip + "!"); + } + }; + + int + main(int argc, char * argv[]) { + + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " address port" << std::endl; + return 1; + } + + try { + hello_world handler; + server server_(argv[1], argv[2], handler); + server_.run(); + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + return 1; + } + + return 0; + } + +This is about a straightforward as server programming will get in C++. + +Building and running the server +=============================== + +Just like with the HTTP client, we can build this example by doing the following +on the shell: + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make hello_world_server + +The first two arguments to the ``server`` constructor are the host and +the port on which the server will listen. The third argument is the +the handler object defined previously. This example can be run from +a command line as follows: + +.. code-block:: bash + + $ ./example/hello_world_server 0.0.0.0 8000 + +.. note:: If you're going to run the server on port 80, you may have to run it + as an administrator. + +Diving into the code +==================== + +Let's take a look at the code listing above in greater detail. + +.. code-block:: c++ + + #include + +This header contains all the code needed to develop an HTTP server with +:mod:`cpp-netlib`. + +.. code-block:: c++ + + struct hello_world; + typedef http::server server; + + struct hello_world { + void operator () (server::request const &request, + server::response &response) { + std::string ip = source(request); + response = server::response::stock_reply( + server::response::ok, std::string("Hello, ") + ip + "!"); + } + }; + +``hello_world`` is a functor class which handles HTTP requests. All +the operator does here is return an HTTP response with HTTP code 200 +and the body ``"Hello, !"``. The ```` in this case would be +the IP address of the client that made the request. + +There are a number of pre-defined stock replies differentiated by +status code with configurable bodies. + +All the supported enumeration values for the response status codes can be found +in ``boost/network/protocol/http/impl/response.ipp``. + +.. code-block:: c++ + + hello_world handler; + server server_(argv[1], argv[2], handler); + server_.run(); + +The first two arguments to the ``server`` constructor are the host and +the port on which the server will listen. The third argument is the +the handler object defined previously. + +.. note:: In this example, the server is specifically made to be single-threaded. + In a multi-threaded server, you would invoke the ``hello_world::run`` member + method in a set of threads. In a multi-threaded environment you would also + make sure that the handler does all the necessary synchronization for shared + resources across threads. The handler is passed by reference to the server + constructor and you should ensure that any calls to the ``operator()`` overload + are thread-safe. + diff --git a/cpp-netlib/libs/network/doc/html/_sources/examples/http/http_client.txt b/cpp-netlib/libs/network/doc/html/_sources/examples/http/http_client.txt new file mode 100644 index 00000000..9b423dd0 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/examples/http/http_client.txt @@ -0,0 +1,125 @@ +.. _http_client: + +************* + HTTP client +************* + +The first code example is the simplest thing you can do with the +:mod:`cpp-netlib`. The application is a simple HTTP client, which can +be found in the subdirectory ``libs/network/example/http_client.cpp``. +All this example doing is creating and sending an HTTP request to a server +and printing the response body. + +The code +======== + +Without further ado, the code to do this is as follows: + +.. code-block:: c++ + + #include + #include + + int main(int argc, char *argv[]) { + using namespace boost::network; + + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " [url]" << std::endl; + return 1; + } + + http::client client; + http::client::request request(argv[1]); + request << header("Connection", "close"); + http::client::response response = client.get(request); + std::cout << body(response) << std::endl; + + return 0; + } + +Running the example +=================== + +You can then run this to get the Boost_ website: + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make http_client + $ ./example/http_client http://www.boost.org/ + +.. _Boost: http://www.boost.org/ + +.. note:: + + The instructions for all these examples assume that + :mod:`cpp-netlib` is build outside the source tree, + according to `CMake conventions`_. For the sake of + consistency we assume that this is in the + ``~/cpp-netlib-build`` directory. + +.. _`CMake conventions`: http://www.cmake.org/Wiki/CMake_FAQ#What_is_an_.22out-of-source.22_build.3F + +Diving into the code +==================== + +Since this is the first example, each line will be presented and +explained in detail. + +.. code-block:: c++ + + #include + +All the code needed for the HTTP client resides in this header. + +.. code-block:: c++ + + http::client client; + +First we create a ``client`` object. The ``client`` abstracts all the +connection and protocol logic. The default HTTP client is version +1.1, as specified in `RFC 2616`_. + +.. code-block:: c++ + + http::client::request request(argv[1]); + +Next, we create a ``request`` object, with a URI string passed as a +constructor argument. + +.. code-block:: c++ + + request << header("Connection", "close"); + +:mod:`cpp-netlib` makes use of stream syntax and *directives* to allow +developers to build complex message structures with greater +flexibility and clarity. Here, we add the HTTP header "Connection: +close" to the request in order to signal that the connection will be +closed after the request has completed. + +.. code-block:: c++ + + http::client::response response = client.get(request); + +Once we've built the request, we then make an HTTP GET request +throught the ``http::client`` from which an ``http::response`` is +returned. ``http::client`` supports all common HTTP methods: GET, +POST, HEAD, DELETE. + +.. code-block:: c++ + + std::cout << body(response) << std::endl; + +Finally, though we don't do any error checking, the response body is +printed to the console using the ``body`` directive. + +That's all there is to the HTTP client. In fact, it's possible to +compress this to a single line: + +.. code-block:: c++ + + std::cout << body(http::client().get(http::request("http://www.boost.org/"))); + +The next example will introduce the ``uri`` class. + +.. _`RFC 2616`: http://www.w3.org/Protocols/rfc2616/rfc2616.html diff --git a/cpp-netlib/libs/network/doc/html/_sources/examples/http/simple_wget.txt b/cpp-netlib/libs/network/doc/html/_sources/examples/http/simple_wget.txt new file mode 100644 index 00000000..c7849162 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/examples/http/simple_wget.txt @@ -0,0 +1,110 @@ +.. _simple_wget: + +*************** + Simple `wget` +*************** + +This example is a very simple implementation of a ``wget`` style +clone. It's very similar to the previous example, but introduces the +``uri`` class. + +The code +======== + +.. code-block:: c++ + + #include + #include + #include + #include + #include + + namespace http = boost::network::http; + namespace uri = boost::network::uri; + + namespace { + std::string get_filename(const uri::uri &url) { + std::string path = uri::path(url); + std::size_t index = path.find_last_of('/'); + std::string filename = path.substr(index + 1); + return filename.empty()? "index.html" : filename; + } + } // namespace + + int + main(int argc, char *argv[]) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " url" << std::endl; + return 1; + } + + try { + http::client client; + http::client::request request(argv[1]); + http::client::response response = client.get(request); + + std::string filename = get_filename(request.uri()); + std::cout << "Saving to: " << filename << std::endl; + std::ofstream ofs(filename.c_str()); + ofs << static_cast(body(response)) << std::endl; + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + return 1; + } + + return 0; + } + +Running the example +=================== + +You can then run this to copy the Boost_ website: + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make simple_wget + $ ./example/simple_wget http://www.boost.org/ + $ cat index.html + +.. _Boost: http://www.boost.org/ + +Diving into the code +==================== + +As with ``wget``, this example simply makes an HTTP request to the +specified resource, and saves it on the filesystem. If the file name +is not specified, it names the resultant file as ``index.html``. + +The new thing to note here is use of the ``uri`` class. The ``uri`` +takes a string as a constructor argument and parses it. The ``uri`` +parser is fully-compliant with `RFC 3986`_. The URI is provided in +the following header: + +.. _`RFC 3986`: http://www.ietf.org/rfc/rfc3986.txt + +.. code-block:: c++ + + #include + +Most of the rest of the code is familiar from the previous example. +To retrieve the URI resource's file name, the following function is +provided: + +.. code-block:: c++ + + std::string get_filename(const uri::uri &url) { + std::string path = uri::path(url); + std::size_t index = path.find_last_of('/'); + std::string filename = path.substr(index + 1); + return filename.empty()? "index.html" : filename; + } + +The ``uri`` interface provides access to its different components: +``scheme``, ``user_info``, ``host``, ``port``, ``path``, ``query`` and +``fragment``. The code above takes the URI path to determine the +resource name. + +Next we'll develop a simple client/server application using +``http::server`` and ``http::client``. diff --git a/cpp-netlib/libs/network/doc/html/_sources/examples/http/twitter_search.txt b/cpp-netlib/libs/network/doc/html/_sources/examples/http/twitter_search.txt new file mode 100644 index 00000000..6c0f2b60 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/examples/http/twitter_search.txt @@ -0,0 +1,117 @@ +.. _twitter_search: + +**************** + Twitter search +**************** + +This example uses `Twitter's search API`_ to list recent tweets given +a user query. New features introduced here include the URI builder +and ``uri::encoded`` function. + +.. _`Twitter's search API`: https://dev.twitter.com/docs/using-search + +The code +======== + +.. code-block:: c++ + + #include + #include "rapidjson/rapidjson.h" + #include "rapidjson/document.h" + #include + + int main(int argc, char *argv[]) { + using namespace boost::network; + using namespace rapidjson; + + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + try { + http::client client; + + uri::uri base_uri("http://search.twitter.com/search.json"); + + std::cout << "Searching Twitter for query: " << argv[1] << std::endl; + uri::uri search; + search << base_uri << uri::query("q", uri::encoded(argv[1])); + http::client::request request(search); + http::client::response response = client.get(request); + + Document d; + if (!d.Parse<0>(response.body().c_str()).HasParseError()) { + const Value &results = d["results"]; + for (SizeType i = 0; i < results.Size(); ++i) + { + const Value &user = results[i]["from_user_name"]; + const Value &text = results[i]["text"]; + std::cout << "From: " << user.GetString() << std::endl + << " " << text.GetString() << std::endl + << std::endl; + } + } + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + } + + return 0; + } + +.. note:: To parse the results of these queries, this example uses + `rapidjson`_, a header-only library that is released under + the `MIT License`_. + +.. _`rapidjson`: http://code.google.com/p/rapidjson/ +.. _`MIT License`: http://www.opensource.org/licenses/mit-license.php + +Building and running ``twitter_search`` +======================================= + +.. code-block:: bash + + $ cd ~/cpp-netlib-build + $ make twitter_search + +Twitter provides a powerful set of operators to modify the behaviour +of search queries. Some examples are provided below: + +.. code-block:: bash + + $ ./example/twitter_search "Lady Gaga" + +Returns any results that contain the exact phrase "Lady Gaga". + +.. code-block:: bash + + $ ./example/twitter_search "#olympics" + +Returns any results with the #olympics hash tag. + +.. code-block:: bash + + $ ./example/twitter_search "flight :(" + +Returns any results that contain "flight" and have a negative +attitude. + +More examples can be found on `Twitter's search API`_ page. + +Diving into the code +==================== + +.. code-block:: c++ + + uri::uri base_uri("http://search.twitter.com/search.json"); + + std::cout << "Searching Twitter for query: " << argv[1] << std::endl; + uri::uri search; + search << base_uri << uri::query("q", uri::encoded(argv[1])); + +The :mod:`cpp-netlib` URI builder uses a stream-like syntax to allow +developers to construct more complex URIs. The example above re-uses +the same base URI and allows the command line argument to be used as +part of the URI query. The builder also supports percent encoding +using the ``encoded`` directive. diff --git a/cpp-netlib/libs/network/doc/html/_sources/getting_started.txt b/cpp-netlib/libs/network/doc/html/_sources/getting_started.txt new file mode 100644 index 00000000..7350acad --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/getting_started.txt @@ -0,0 +1,262 @@ +.. _getting_started: + +***************** + Getting Started +***************** + +Downloading an official release +=============================== + +You can find links to the latest official release from the project's official +website: + + http://cpp-netlib.org/ + +All previous stable versions of :mod:`cpp-netlib` can be downloaded from +Github_ from this url: + + http://github.com/cpp-netlib/cpp-netlib/downloads + +Each release is available as gzipped (Using the command +``tar xzf cpp-netlib.tar.gz``) or bzipped (Using ``tar xjf +cpp-netlib.tar.bz2``) tarball, or as a zipfile (``unzip +cpp-netlib.zip``, or on Windows using a tool such as 7zip_). + +.. _Github: http://github.com/cpp-netlib/cpp-netlib/downloads +.. _7zip: http://www.7-zip.org/ + +Downloading a development version +================================= + +The :mod:`cpp-netlib` uses Git_ for source control, so to use any +development versions Git must be installed on your system. + +Using the command line, the command to get the latest code is: + +:: + + shell$ git clone git://github.com/cpp-netlib/cpp-netlib.git + +This should be enough information get to started. To do more complex +things with Git, such as pulling changes or checking out a new branch, +refer to the `Git documentation`_. + +.. note:: Previous versions of :mod:`cpp-netlib` referred to the + *mikhailberis* repository as the main development repository. This + account is still valid, but not always up-to-date. In the interest of + consistency, the main repository has been changed to *cpp-netlib*. + +Windows users need to use msysGit_, and to invoke the command above +from a shell. + +For fans of Subversion_, the same code can be checked out from +http://svn.github.com/cpp-netlib/cpp-netlib.git. + +.. _Git: http://git-scm.com/ +.. _`Git documentation`: http://git-scm.com/documentation +.. _msysGit: http://code.google.com/p/msysgit/downloads/list +.. _Subversion: http://subversion.tigris.org/ + +.. note:: The :mod:`cpp-netlib` project is hosted on GitHub_ and follows the + prescribed development model for GitHub_ based projects. This means in case + you want to submit patches, you will have to create a fork of the project + (read up on forking_) and then submit a pull request (read up on submitting + `pull requests`_). + +.. _forking: http://help.github.com/forking/ +.. _`pull requests`: http://help.github.com/pull-requests/ + +Getting Boost +============= + +:mod:`cpp-netlib` depends on Boost_. It should work for any version +of Boost above 1.50.0. If Boost is not installed on your system, the +latest package can be found on the `Boost web-site`_. The environment +variable ``BOOST_ROOT`` must be defined, which must be the full path +name of the top directory of the Boost distribution. Although Boost +is mostly header only, applications built using :mod:`cpp-netlib` +still requires linking with `Boost.System`_, `Boost.Date_time`_, and +`Boost.Regex`_. + +.. _Boost: http://www.boost.org/doc/libs/release/more/getting_started/index.html +.. _`Boost web-site`: http://www.boost.org/users/download/ +.. _`Boost.System`: http://www.boost.org/libs/system/index.html +.. _`Boost.Date_time`: http://www.boost.org/libs/date_time/index.html +.. _`Boost.Regex`: http://www.boost.org/libs/regex/index.html + +.. note:: You can follow the steps in the `Boost Getting Started`_ guide to + install Boost into your development system. + +.. _`Boost Getting Started`: + http://www.boost.org/doc/libs/release/more/getting_started/index.html + +.. warning:: There is a known incompatibility between :mod:`cpp-netlib` and + Boost 1.46.1 on some compilers. It is not recommended to use :mod:`cpp-netlib` + with Boost 1.46.1. Some have reported though that Boost 1.47.0 + and :mod:`cpp-netlib` work together better. + +Getting CMake +============= + +The :mod:`cpp-netlib` uses CMake_ to generate platform-specific build files. If +you intend to run the test suite, you can follow the instructions below. +Otherwise, you don't need CMake to use :mod:`cpp-netlib` in your project. The +:mod:`cpp-netlib` requires CMake version 2.8 or higher. + +.. _CMake: http://www.cmake.org/ + +Let's assume that you have unpacked the :mod:`cpp-netlib` at the top of your +HOME directory. On Unix-like systems you will typically be able to change into +your HOME directory using the command ``cd ~``. This sample below assumes that +the ``~/cpp-netlib`` directory exists, and is the top-level directory of the +:mod:`cpp-netlib` release. + +Building with CMake +=================== + +To build the tests that come with :mod:`cpp-netlib`, we first need to configure the +build system to use our compiler of choice. This is done by running the +``cmake`` command at the top-level directory of :mod:`cpp-netlib` with +additional parameters:: + + $ mkdir ~/cpp-netlib-build + $ cd ~/cpp-netlib-build + $ cmake -DCMAKE_BUILD_TYPE=Debug \ + > -DCMAKE_C_COMPILER=gcc \ + > -DCMAKE_CXX_COMPILER=g++ \ + > ../cpp-netlib + +.. note:: + + While it's not compulsory, it's recommended that + :mod:`cpp-netlib` is built outside the source directory. + For the purposes of documentation, we'll assume that all + builds are done in ``~/cpp-netlib-build``. + +If you intend to use the SSL support when using the HTTP client libraries in +:mod:`cpp-netlib`, you may need to build it with OpenSSL_ installed or at least +available to CMake. If you have the development headers for OpenSSL_ installed +on your system when you build :mod:`cpp-netlib`, CMake will be able to detect it +and set the ``BOOST_NETWORK_ENABLE_HTTPS`` macro when building the library to +support HTTPS URIs. + +One example for building the library with OpenSSL_ support with a custom +(non-installed) version of OpenSSL_ is by doing the following:: + + $ cmake -DCMAKE_BUILD_TYPE=Debug \ + > -DCMAKE_C_COMPILER=clang \ + > -DCMAKE_CXX_COMPILER=clang++ \ + > -DOPENSSL_ROOT_DIR=/Users/dberris/homebrew/Cellar/openssl/1.0.1f + > ../cpp-netlib + +.. _OpenSSL: http://www.openssl.org/ + +You can also use a different root directory for the Boost_ project by using the +``-DBOOST_ROOT`` configuration option to CMake. This is useful if you intend to +build the library with a specific version of Boost that you've built in a +separate directory:: + + $ cmake -DCMAKE_BUILD_TYPE=Debug \ + > -DCMAKE_C_COMPILER=clang \ + > -DCMAKE_CXX_COMPILER=clang++ \ + > -DOPENSSL_ROOT_DIR=/Users/dberris/homebrew/Cellar/openssl/1.0.1f \ + > -DBOOST_ROOT=/Users/dberris/Source/boost_1_55_0 + > ../cpp-netlib + +Building on Linux +~~~~~~~~~~~~~~~~~ + +On Linux, this will generate the appropriate Makefiles that will enable you to +build and run the tests and examples that come with :mod:`cpp-netlib`. To build +the tests, you can run ``make`` in the same top-level directory of +``~/cpp-netlib-build``:: + + $ make + +.. note:: Just like with traditional GNU Make, you can add the ``-j`` parameter + to specify how many parallel builds to run. In case you're in a sufficiently + powerful system and would like to parallelize the build into 4 jobs, you can + do this with:: + + make -j4 + + As a caveat, :mod:`cpp-netlib` is heavy on template metaprogramming and will + require a lot of computing and memory resources to build the individual + tests. Do this at the risk of thrashing_ your system. However, this + compile-time burden is much reduced in recent versions. + +.. _thrashing: http://en.wikipedia.org/wiki/Thrashing_(computer_science) + +Once the build has completed, you can now run the test suite by issuing:: + + $ make test + +You can install :mod:`cpp-netlib` by issuing:: + + $ sudo make install + +By default this installs :mod:`cpp-netlib` into ``/usr/local``. + +.. note:: As of version 0.9.3, :mod:`cpp-netlib` produces three static + libraries. Using GCC on Linux these are:: + + libcppnetlib-client-connections.a + libcppnetlib-server-parsers.a + libcppnetlib-uri.a + + Users can find them in ``~/cpp-netlib-build/libs/network/src``. + +Building On Windows +~~~~~~~~~~~~~~~~~~~ + +If you're using the Microsoft Visual C++ compiler or the Microsoft Visual Studio +IDE and you would like to build :mod:`cpp-netlib` from within Visual Studio, you +can look for the solution and project files as the artifacts of the call to +``cmake`` -- the file should be named ``CPP-NETLIB.sln`` (the solution) along +with a number of project files for Visual Studio. + +.. note:: As of version 0.9.3, :mod:`cpp-netlib` produces three static + libraries. Using Visual C++ on Windows they are:: + + cppnetlib-client-connections.lib + cppnetlib-server-parsers.lib + cppnetlib-uri.lib + + Users can find them in ``~/cpp-netlib-build/libs/network/src``. + +Using :mod:`cpp-netlib` +======================= + +CMake projects +~~~~~~~~~~~~~~ + +Projects using CMake can add the following lines in their ``CMakeLists.txt`` to +be able to use :mod:`cpp-netlib`:: + + set ( CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ~/cpp-netlib-build ) + find_package ( cppnetlib 0.11.0 REQUIRED ) + include_directories ( ${CPPNETLIB_INCLUDE_DIRS} ) + target_link_libraries ( MyApplication ${CPPNETLIB_LIBRARIES} ) + +.. note:: Setting ``CMAKE_PREFIX_PATH`` is only required when :mod:`cpp-netlib` + is not installed to a location that CMake searches. When :mod:`cpp-netlib` + is installed to the default location (``/usr/local``), ``CMake`` can find it. + +.. note:: We assume that ``MyApplication`` is the application that you are + building and which depends on :mod:`cpp-netlib`. + + +Reporting Issues, Getting Support +================================= + +In case you find yourself stuck or if you've found a bug (or you want to just +join the discussion) you have a few options to choose from. + +For reporting bugs, feature requests, and asking questions about the +implementation and/or the documentation, you can go to the GitHub issues page +for the project at http://github.com/cpp-netlib/cpp-netlib/issues. + +You can also opt to join the developers mailing list for a more personal +interaction with the developers of the project. You can join the mailing list +through http://groups.google.com/forum/#!forum/cpp-netlib. + diff --git a/cpp-netlib/libs/network/doc/html/_sources/history.txt b/cpp-netlib/libs/network/doc/html/_sources/history.txt new file mode 100644 index 00000000..24f503f0 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/history.txt @@ -0,0 +1,54 @@ +Project history +=============== + +The :mod:`cpp-netlib` was founded by Dean Michael Berris in 2007. +Initially it consisted of a message template and an HTTP client. It +found a home on Sourceforge_ but was migrated at the end of 2009 to +Github_ where development is actively continued by a committed +community. + +Motivation +~~~~~~~~~~ + +We're a group of C++ developers and we kept becoming annoyed that we +had to repeatedly write the same code when building applications that +needed to be network-aware. + +We found that there was a lack of accessible networking libraries, +either standard or open source, that fulfilled our needs. Such +libraries exist for every other major language. So, building on top +of `Boost.Asio`_, we decided to get together and build our own. + +Objectives +~~~~~~~~~~ + +The objectives of the :mod:`cpp-netlib` are to: + +* develop a high quality, portable, easy to use C++ networking library +* enable developers to easily extend the library +* lower the barrier to entry for cross-platform network-aware C++ + applications + +The goal the of :mod:`cpp-netlib` has never been to build a +fully-featured web server - there are plenty of excellent options +already available. The niche that this library targets is for +light-weight networking functionality for C++ applications that have +demanding performance requirements or memory constraints, but that +also need to be portable. This type of application is becoming +increasingly common as software becomes more distributed, and +applications need to communicate with services. + +While many languages provide direct library support for high level +network programming, this feature is missing in C++. Therefore, this +library has been developed with the intention of eventually being +submitted to Boost_, a collection of general, high quality +libraries for C++ developers. + +Eventually, the :mod:`cpp-netlib` will be extended to support many of +the application layer protocols such as SMTP, FTP, SOAP, XMPP etc. + + +.. _Sourceforge: http://sourceforge.net/projects/cpp-netlib/ +.. _Github: http://github.com/cpp-netlib/cpp-netlib +.. _Boost: http://www.boost.org/ +.. _`Boost.Asio`: http://www.boost.org/libs/asio/ diff --git a/cpp-netlib/libs/network/doc/html/_sources/in_depth.txt b/cpp-netlib/libs/network/doc/html/_sources/in_depth.txt new file mode 100644 index 00000000..39af9a4f --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/in_depth.txt @@ -0,0 +1,15 @@ +.. _in_depth: + +An in-depth look at the :mod:`cpp-netlib` +========================================= + +The :mod:`cpp-netlib` is composed of three different sets of +functionality: a **message** template, a **URI** template and +different **protocol** implementations. + +.. toctree:: + :maxdepth: 2 + + in_depth/message + in_depth/uri + in_depth/http diff --git a/cpp-netlib/libs/network/doc/html/_sources/in_depth/http.txt b/cpp-netlib/libs/network/doc/html/_sources/in_depth/http.txt new file mode 100644 index 00000000..711bf6b3 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/in_depth/http.txt @@ -0,0 +1,180 @@ +HTTP implementation +=================== + +HTTP client +``````````` + +At the heart of the HTTP client implementation is a single class aptly named +``basic_client``, which is also a template. The template ``basic_client`` takes +three template parameters: + +.. code-block:: c++ + + namespace boost { namespace http { + + template + struct basic_client; + + } // namespace http + + } // namespace boost + +The ``Tag`` template parameter follows the same tag-dispatch mechanism to +determine the behavior of the ``basic_client``. The interface of +``basic_client`` may change depending on certain properties defined for the tag +you provide. Below is a table of predefined supported tags you can use in your +overload of the ``basic_client``: + +------------ + +.. include:: http_client_tags.rst + +.. _Boost.Thread: http://www.boost.org/libs/thread + + +The default typedef for the HTTP client that is provided uses the +``http_async_8bit_udp_resolve`` tag, and implements HTTP 1.1. The exact +typedef is in the ``boost::network::http`` namespace as the following: + +.. code-block:: c++ + + namespace boost { namespace network { namespace http { + + typedef basic_client + client; + + }}} + + +This type has nested typedefs for the correct types for the ``basic_request`` +and ``basic_response`` templates. To use the correct types for ``basic_request`` +or ``basic_response`` you can use these nested typedefs like so: + + +.. code-block:: c++ + + boost::network::http::client::request request; + boost::network::http::client::response response; + + // or... + using namespace boost::network; + http::client::request request; + http::client::response response; + + +Typical use cases for the HTTP client would look something like the following: + + +.. code-block:: c++ + + using namespace boost::network; + http::request request("http://www.boost.org/"); + request << header("Connection", "close"); + + +The ``basic_client`` implements all HTTP methods as member functions +(HEAD, GET, POST, PUT, DELETE). Therefore, the code to make an HTTP +request looks trivially simple: + + +.. code-block:: c++ + + using namespace boost::network; + http::client client; + http::client::request request("http://www.boost.org/"); + http::client::response response = client.get(request); + + +Accessing data from ``http::response`` is done using wrappers. +To get the response headers, we use the ``headers`` wrapper which +returns, in the default case, a multimap of strings to strings: + + +.. code-block:: c++ + + using namespace boost::network; + typedef headers_range::type response_headers; + boost::range_iterator::type iterator; + + response_headers headers_ = headers(response); + for (iterator it = headers_.begin(); it != headers_.end(); ++it) { + std::cout << it->first << ": " << it->second << std::endl; + } + std::cout << std::endl; + + +HTTP server +``````````` + +As with the HTTP client, the HTTP server that is provided with +cpp-netlib is extensible through the tag mechanism and is embeddable. +The template class declaration of ``basic_server`` is given below: + + +.. code-block:: c++ + + namespace boost { namespace network { namespace http { + + template basic_server; + + }}} + + +The second template argument is used to specify the request handler +type. The request handler type is a functor type which should overload +the function call operator (``RequestHandler::operator()`` should be +overloaded) that takes two parameters: the first one being a reference +to a ``const basic_request`` and the second being a reference to +a ``basic_response`` instance. + +All the logic for parsing the HTTP request and building the ``const +basic_request`` object resides internally in the ``basic_server`` +template. Processing the request is delegated to the +``RequestHandler`` type, and the assumption of which would be that the +response is formed inside the ``RequestHandler`` function call +operator overload. + +The ``basic_server`` template however is only an underlying +implementation while the user-visible implementation is the +``http::server`` template. This simply specializes the +``basic_server`` template to use the ``default_`` tag and forwards the +``RequestHandler`` parameter: + +.. code-block:: c++ + + namespace boost { namespace network { namespace http { + + template + class server : + public basic_server {}; + + }}} + +To use the forwarding server type you just supply the request handler +implementation as the parameter. For example, an "echo" server example +might look something like this: + + +.. code-block:: c++ + + using namespace boost::network; + struct echo; + typedef http::server echo_server; + + struct echo { + void operator () (const echo_server::request &request, + echo_server::response &response) const { + std::string ip = source(request); + response = echo_server::response::stock_reply( + echo_server::response::ok, + body(request)); + std::cerr << "[" << ip << "]: " << request.uri << + " status = " << echo_server::response::ok << '\n'; + } + }; + + +Here, all we're doing is returning the original request body with an +HTTP OK response (200). We are also printing the IP address from where the +request came from. Notice that we are using a wrapper to access the source of +the request. diff --git a/cpp-netlib/libs/network/doc/html/_sources/in_depth/http_client_tags.txt b/cpp-netlib/libs/network/doc/html/_sources/in_depth/http_client_tags.txt new file mode 100644 index 00000000..5d79ed1e --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/in_depth/http_client_tags.txt @@ -0,0 +1,42 @@ ++---------------------------------+---------------------------------------------+ +| Tag | Description | ++=================================+=============================================+ +| http_default_8bit_tcp_resolve | This is the default HTTP implementation tag | +| | that resolves addresses with a TCP resolver | +| | and provides a synchronous/blocking HTTP | +| | client interface. | ++---------------------------------+---------------------------------------------+ +| http_default_8bit_udp_resolve | This is similar to the above tag except that| +| | it specifies the HTTP client to use a UDP | +| | resolver. It also provides a synchronous/ | +| | blocking HTTP client interface. | ++---------------------------------+---------------------------------------------+ +| http_keepalive_8bit_tcp_resolve | This tag specifies that the HTTP client by | +| | default will keep connections to the server | +| | alive. It only makes sense if the | +| | ``version_major`` and ``version_minor`` are | +| | both ``1``, to indicate HTTP 1.1. This tag | +| | causes the HTTP client to resolve using a | +| | TCP resolver and provides a synchronous/ | +| | blocking HTTP client interface. | ++---------------------------------+---------------------------------------------+ +| http_keepalive_8bit_udp_resolve | This is similar to the above tag except that| +| | it specifies the HTTP client to use a UDP | +| | resolver. It also provides a synchronous/ | +| | blocking HTTP client interface. | ++---------------------------------+---------------------------------------------+ +| http_async_8bit_tcp_resolve | This tag provides an active HTTP client | +| | object implementation that uses a TCP | +| | resolver. Response objects returned will | +| | encapsulate a number of Boost.Thread_ | +| | shared futures to hold values. Users don't | +| | have to see this as they are implementation | +| | details. | ++---------------------------------+---------------------------------------------+ +| http_async_8bit_udp_resolve | This is similar to the above tag except that| +| | specifies the HTTP client to use a UDP | +| | resolver. | ++---------------------------------+---------------------------------------------+ + +.. _Boost.Thread: http://www.boost.org/libs/thread + diff --git a/cpp-netlib/libs/network/doc/html/_sources/in_depth/message.txt b/cpp-netlib/libs/network/doc/html/_sources/in_depth/message.txt new file mode 100644 index 00000000..51512314 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/in_depth/message.txt @@ -0,0 +1,233 @@ +The message template +==================== + +One of the core components in the library is the concept and the +implementation of a common message type. In most (not all) network +protocols, the concept of a message is central to the definition of +the protocol. In HTTP, SMTP, XMPP, and even other protocols like SNMP +and ICMP, there is a common notion of a "packet" or a message. In +cpp-netlib we chose to implement the concept of a message that has the +following common parts: + + * **Source** - every message has a source identifier which varies + from protocol to protocol. + + * **Destination** - every message has a destination identifier which + varies from protocol to protocol. + + * **Headers** - each message is assumed to contain headers, which + may be empty in cases where the protocol does not support it, but + is nonetheless supported by cpp-netlib messages. + + * **Body** - the content area of a message which varies from + protocol to protocol (also sometimes referred to as payload). + +This division is purely logical -- in the underlying implementation, +the message type can choose to have different means of storing the +data, depending on the type used to tag the message. This section +covers the `Message Concept`_ as well as the `basic_message`_ +implementation. + +Message Concept +``````````````` + +.. warning:: The Message framework is deprecated in the 0.11 release, and will + be removed in future versions of the library. + +The Message Concept specifies what the valid operations on a message +are as well as what messages look like semantically. The following +table summarize the operations and syntactic as well as semantic +properties of messages. + +**Legend** + +:M: The message type. +:H: A headers container type. +:m,n: An instance of **M**. +:S: A string type. +:s,k,v: An instance of **S**. +:O: The source type. +:D: The destination type. +:B: The body type. +:T: The Tag type. + ++----------------------------+----------------------+-----------------------------------------+ +| Construct | Result | Description | ++============================+======================+=========================================+ +| ``typename M::tag`` | T | The nested tag type. | ++----------------------------+----------------------+-----------------------------------------+ +| ``M()`` | Instance of M | Default constructible. | ++----------------------------+----------------------+-----------------------------------------+ +| ``M(m)`` | Instance of M | Copy constructible. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m = n;`` | Reference to m | Assignable. | ++----------------------------+----------------------+-----------------------------------------+ +| ``swap(m, n);`` | ``void`` | Swappable. | ++----------------------------+----------------------+-----------------------------------------+ +| ``source(m);`` | Convertible to O | Retrieve the source of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``destination(m);`` | Convertible to D | Retrieve the destination of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``headers(m);`` | Convertible to H | Retrieve the headers of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``body(m);`` | Convertible to B | Retrieve the body of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m << source(s);`` | ``M &`` | Set the source of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m << destination(s);`` | ``M &`` | Set the destination of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m << header(k, v);`` | ``M &`` | Add a header to ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m << remove_header(k);`` | ``M &`` | Remove a header from ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m << body(s);`` | ``M &`` | Set the body of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``source(m,s);`` | ``void`` | Set the source of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``destination(m,s);`` | ``void`` | Set the destination of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``add_header(m, k, v);`` | ``void`` | Add a header to ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``remove_header(m, k);`` | ``void`` | Remove a header from ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``clear_headers(m);`` | ``void`` | Clear the headers of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``body(m,s);`` | ``M &`` | Set the body of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ + +Types that model the Message Concept are meant to encapsulate data +that has a source, a destination, one or more named headers, and a +body/payload. Because the accessors and the directives are not +required to be part of the message type that models the Message +Concept, a message can be implemented as a POD type and have all +manipulations performed in the directive implementations, as well as +value transformations done in the accessors. + +Directives, Modifiers, and Wrappers +``````````````````````````````````` + +In the Message Concept definition there are three basic constructs that follow a +certain pattern. These patterns are Directives_, Modifiers_, and Wrappers_. + +Directives +~~~~~~~~~~ + +A directive is a function object that is applied to a Message. Directives +encapsulate a set of operations that apply to messages. The general requirement +for a Directive is that it should apply these operations on a message. + +A directive may dispatch on the type of the message passed to it at the point of +the function call. Typically, directives are generated using a factory function +that returns the correct directive type. + +For a given directive ``foo_directive`` a generator function called ``foo`` is +typically implemented: + +.. code-block:: c++ + + struct foo_directive { + template + Message & operator()(Message & m) const { + // do something to m + return m; + } + }; + + foo_directive const foo() { + return foo_directive(); + } + + // to apply a directive, we use the << operator + message m; + m << foo(); + +Modifiers +~~~~~~~~~ + +A modifier is generally defined as a free function that takes a reference to a +non-const lvalue message as the first parameter, and any number of parameters. +In the concept definition of the Message Concept, a modifier follows the form: + +.. code-block:: c++ + + modifier(message, ...) + +Modifiers are meant to imply modifications on a message, which also allows for +easier dispatch based on Argument Dependent Lookup (ADL_) on the type of the +message. Note that Directives_ can be implemented in terms of Modifiers and +vice versa, although that is not required nor specified. + +.. _ADL: http://en.wikipedia.org/wiki/Argument-dependent_name_lookup + +Wrappers +~~~~~~~~ + +A Wrapper is basically an implementation detail that ensures that a given +message, when wrapped, can be converted to the associated part of the message. A +wrapper has a type that encapsulates the conversion logic from a message to a +given type. + +An example of a Wrapper would be ``source_wrapper`` which would be returned by a +call to the wrapper generator function ``source``. An example implementation of +the ``source_wrapper`` would look like: + +.. code-block:: c++ + + template class Message> + struct source_wrapper { + Message const & m; + explicit source_wrapper(Message const & m) + : m(m) {} + typedef typename source::type source_type; + operator source_type const & () { + return m.source; + } + operator source_type const () { + return m.source; + } + operator source_type () { + return m.source; + } + }; + + template class Message> + source_wrapper const + source(Message const & message) { + return source_wrapper(message); + } + +This pattern is similar to an adapter, but the specific notion of wrapping a +data type (in this case, an object of a type that models the Message Concept) +using an intermediary wrapper is what is pertained to by the Wrapper pattern. +In this case, the Wrapper is ``source_wrapper`` while ``source`` is merely a +wrapper generator function. + +``basic_message`` +````````````````` + +The default implementation of a simple type that models the Message +Concept is available in cpp-netlib. This default implementation is +named ``basic_message`` which supports a ``Tag`` template +parameter. The definition of ``basic_message`` looks like this: + +.. code-block:: c++ + + template + class basic_message; + +The ``basic_message`` template requires that the following +tag-dispatched metafunctions are defined for the type ``Tag``: + +.. code-block:: c++ + + template + struct string; + + template + struct headers_container; + +All the operations defined by the message concept are implemented by +this basic message type. Other message implementations can either use +this common message type or specialize it according to whether they +want to use different containers or whether it's going to be just a +POD type. diff --git a/cpp-netlib/libs/network/doc/html/_sources/in_depth/uri.txt b/cpp-netlib/libs/network/doc/html/_sources/in_depth/uri.txt new file mode 100644 index 00000000..84eca62e --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/in_depth/uri.txt @@ -0,0 +1,151 @@ +The URI class +============= + +In addition to protocol implementations, the :mod:`cpp-netlib` +provides a powerful URI class. The class implements a parser based +on `RFC 3986`_ and `RFC 2732`_. + +Generic URI syntax overview +``````````````````````````` + +A generic URI will take the form:: + + [scheme:]scheme-specific-part[#fragment] + +A URI is known as `absolute` if it specifies the scheme. Otherwise, +it is known as a relative URI. Currently, ``uri`` supports only +absolute URIs. + +URIs can be further classified according to whether they're +hierarchical or opaque (non-hierarchical). + +Some examples of non-hierarchical URIs include:: + + mailto:john.doe@example.com + news:comp.infosystems.www.servers.unix + tel:+1-816-555-1212 + +The data following the first ``":"`` is said to be opaque to the URI +parser and requires no further parsing. By way of example, the +following shows how a non-hierarchical URI is processed by the parser +by defining everything after the ``":"`` to be a part of the path: + +.. image:: ../_static/mailto_uri.png + +A hierarchical URI is identified by a double slash (``"//"``) after +the scheme and a scheme-specific component, which `RFC 3986`_ defines +to be:: + + [scheme:][//authority][path][?query][#fragment] + +The authority component can be further broken down to:: + + [user_info@]host[:port] + +Examples of hierarchical URIs include:: + + http://www.boost.org/ + file:///bin/bash + +The following example, describing a complex URI using FTP, shows how +a URI is broken down by the parser: + +.. image:: ../_static/ftp_uri.png + +Note that the ``authority`` is further subdivided into different +elements. Another example, using HTTP is given below: + +.. image:: ../_static/http_uri.png + +The difference here between the path in a hierarchical URI and that in +the example above for the non-hierarchical URI. + +The ``uri`` class +````````````````` + +As of version 0.9.3, ``uri`` supplies a URI parser and builder. +To use the parser, it's as simple as supplying a string to the +constructor: + +.. code-block:: c++ + + using namespace boost::network; + uri::uri instance("http://cpp-netlib.github.com/"); + assert(instance.is_valid()); + std::cout << "scheme: " << instance.scheme() << std::endl + << "host: " << instance.host() << std::endl; + +The command-line output of this program will be:: + + scheme: http + host: cpp-netlib.github.com + +The ``uri`` builder +``````````````````` + +``uri`` support a stream style syntax to create a URI from it's +elements. For example the program: + +.. code-block:: c++ + + #include + #include + #include + using namespace boost::network; + + int main() { + uri::uri url; + url << uri::scheme("http") + << uri::host("www.github.com") + << uri::path("/cpp-netlib"); + std::cout << url << std::endl; + return 0; + } + +will output:: + + http://www.github.com/cpp-netlib + +``URI Concept`` +``````````````` + +**Legend** + +:U: The URI type. +:u,u_: An instance of **M**. +:S: A string type. +:s,v: An instance of **S**. +:T: The Tag type. + ++----------------------------+----------------------+-----------------------------------------+ +| Construct | Result | Description | ++============================+======================+=========================================+ +| ``U(u)`` | Instance of U | Copy constructible. | ++----------------------------+----------------------+-----------------------------------------+ +| ``U(s)`` | Instance of U | Constructible from string. | ++----------------------------+----------------------+-----------------------------------------+ +| ``u = u_;`` | Reference to u | Assignable. | ++----------------------------+----------------------+-----------------------------------------+ +| ``u = s;`` | Reference to u | Assignable from string. | ++----------------------------+----------------------+-----------------------------------------+ +| ``swap(u, u_);`` | ``void`` | Swappable. | ++----------------------------+----------------------+-----------------------------------------+ +| ``scheme(u);`` | Convertible to S | Retrieve the URI scheme of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``user_info(u);`` | Convertible to S | Retrieve the user info of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``host(u);`` | Convertible to S | Retrieve the host of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``port(u);`` | Convertible to H | Retrieve the port of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``path(u);`` | Convertible to S | Retrieve the path of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``query(u);`` | Convertible to S | Retrieve the query string of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``fragment(u);`` | Convertible to S | Retrieve the fragment of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ + +.. _`RFC 3986`: http://tools.ietf.org/html/rfc3986 +.. _`RFC 2368`: http://tools.ietf.org/html/rfc2368 +.. _`RFC 3513`: http://tools.ietf.org/html/rfc3513 +.. _`RFC 2732`: http://tools.ietf.org/html/rfc2732 diff --git a/cpp-netlib/libs/network/doc/html/_sources/index.txt b/cpp-netlib/libs/network/doc/html/_sources/index.txt new file mode 100644 index 00000000..fc9e6540 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/index.txt @@ -0,0 +1,124 @@ +.. _index: +.. rubric:: Straightforward network programming in modern C++ + +.. :Authors: Glyn Matthews +.. Dean Michael Berris +.. :Date: 2014-10-01 +.. :Version: 0.11.0 +.. :Description: Complete user documentation, with examples, for the :mod:`cpp-netlib`. +.. :Copyright: Copyright Glyn Matthews, Dean Michael Berris 2008-2013. +.. Copyrigh 2013 Google, Inc. +.. 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) + +Getting cpp-netlib +================== + +You can find out more about the :mod:`cpp-netlib` project at +http://cpp-netlib.org/. + +**Download** + +You can get the latest official version of the library from the official +project website at: + + http://cpp-netlib.org/ + +This version of :mod:`cpp-netlib` is tagged as cpp-netlib-0.11.0 in the GitHub_ +repository. You can find more information about the progress of the development +by checking our GitHub_ project page at: + + http://github.com/cpp-netlib/cpp-netlib + +**Support** + +You can ask questions, join the discussion, and report issues to the +developers mailing list by joining via: + + https://groups.google.com/group/cpp-netlib + +You can also file issues on the Github_ issue tracker at: + + http://github.com/cpp-netlib/cpp-netlib/issues + +We are a growing community and we are happy to accept new +contributions and ideas. + +C++ Network Library +=================== + +:mod:`cpp-netlib` is a library collection that provides application layer +protocol support using modern C++ techniques. It is light-weight, fast, +portable and is intended to be as easy to configure as possible. + +Hello, world! +============= + +The :mod:`cpp-netlib` allows developers to write fast, portable +network applications with the minimum of fuss. + +An HTTP server-client example can be written in tens of lines of code. +The client is as simple as this: + +.. code-block:: cpp + + using namespace boost::network; + using namespace boost::network::http; + + client::request request_("http://127.0.0.1:8000/"); + request_ << header("Connection", "close"); + client client_; + client::response response_ = client_.get(request_); + std::string body_ = body(response_); + +And the corresponding server code is listed below: + +.. code-block:: cpp + + namespace http = boost::network::http; + + struct handler; + typedef http::server http_server; + + struct handler { + void operator() (http_server::request const &request, + http_server::response &response) { + response = http_server::response::stock_reply( + http_server::response::ok, "Hello, world!"); + } + + void log(http_server::string_type const &info) { + std::cerr << "ERROR: " << info << '\n'; + } + }; + + int main(int arg, char * argv[]) { + handler handler_; + http_server::options options(handler_); + http_server server_( + options.address("0.0.0.0") + .port("8000")); + server_.run(); + } + +Want to learn more? +=================== + + * :ref:`Take a look at the getting started guide ` + * :ref:`Learn from some simple examples ` + * :ref:`Find out what's new ` + * :ref:`Study the library in more depth ` + * :ref:`Discover more through the full reference ` + * :ref:`Full table of contents ` + +.. warning:: Be aware that not all features are stable. The generic + message design is under review and the URI and HTTP + client implementation will continue to undergo + refactoring. Future versions will include support for + other network protocols. + + +.. _Boost: http://www.boost.org/ +.. _GitHub: http://github.com/ + diff --git a/cpp-netlib/libs/network/doc/html/_sources/reference.txt b/cpp-netlib/libs/network/doc/html/_sources/reference.txt new file mode 100644 index 00000000..d4cbf99d --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/reference.txt @@ -0,0 +1,16 @@ +.. _reference: + +Reference Manual +================ + +This reference manual refers to the API documentation of the public interfaces +to the different client and/or server implementations within :mod:`cpp-netlib`. + +.. toctree:: + :maxdepth: 2 + + reference/http_client + reference/http_request + reference/http_response + reference/http_server + diff --git a/cpp-netlib/libs/network/doc/html/_sources/reference/http_client.txt b/cpp-netlib/libs/network/doc/html/_sources/reference/http_client.txt new file mode 100644 index 00000000..1277c83e --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/reference/http_client.txt @@ -0,0 +1,475 @@ + +HTTP Client API +=============== + +General +------- + +:mod:`cpp-netlib` includes and implements a number of HTTP clients that you can +use and embed in your own applications. All of the HTTP client implementations: + + * **Cannot be copied.** This means you may have to store instances of the + clients in dynamic memory if you intend to use them as function parameters + or pass them around in smart pointers or by reference. + * **Assume that requests made are independent of each other.** There currently + is no cookie or session management system built-in to cpp-netlib's HTTP client + implementations. + +The HTTP clients all share the same API, but the internals are documented in +terms of what is different and what to expect with the different +implementations. + +As of 0.9.1 the default implementation for the :mod:`cpp-netlib` HTTP client is +asynchronous. + +As of 0.11 the `Synchronous Clients`_ are now *DEPRECATED* and will be removed +in subsequent releases. + +Features +-------- + +The HTTP client implementation supports requesting secure HTTP (HTTPS) content +only in the following situations: + + * **Client libraries are built with ``BOOST_NETWORK_ENABLE_HTTPS``.** This + tells the implementation to use HTTPS-specific code to handle HTTPS-based + content when making connections associated with HTTPS URI's. This requires + a dependency on OpenSSL_. + * **The ``BOOST_NETWORK_ENABLE_HTTPS`` macro is set when compiling user + code.** It is best to define this either at compile-time of all code using + the library, or before including any of the client headers. + +To use the client implementations that support HTTPS URIs, you may explicitly +do the following: + +.. code-block:: c++ + + #define BOOST_NETWORK_ENABLE_HTTPS + #include + +This forces HTTPS support to be enabled and forces a dependency on OpenSSL_. +This dependency is imposed by `Boost.Asio`_ + +.. _OpenSSL: http://www.openssl.org/ +.. _`Boost.Asio`: http://www.boost.org/libs/asio + +Implementations +--------------- + +There is a single user-facing template class named ``basic_client`` which takes +three template parameters: + + * **Tag** - which static tag you choose that defines the behavior of the client. + + * **http_version_major** - an unsigned int that defines the HTTP major version + number, this directly affects the HTTP messages sent by the client. + + * **http_version_minor** - an unsigned int that defines the HTTP minor version + number. + +There are two major different class of implementations of the ``basic_client`` +template that depend on which tag you choose: `Synchronous Clients`_ and +`Asynchronous Clients`_. These two different classes are described in their own +sections following this one. What follows is a table of all tags supported by +the HTTP client implementation provided by :mod:`cpp-netlib`. + +--------------- + +.. include:: ../in_depth/http_client_tags.rst + +In the above table the tags follow a pattern for describing the behavior +introduced by the tags. This pattern is shown below: + + ___ + +For example, the tag ``http_default_8bit_tcp_resolve`` indicates the protocol +``http``, a modifier ``default``, a character width of ``8bit``, and a resolve +strategy of ``tcp_resolve``. + +Synchronous Clients +~~~~~~~~~~~~~~~~~~~ + +Of the client tags shown in the table, the following makes the ``basic_client`` +behave as a fully synchronous client. + + * **http_default_8bit_tcp_resolve** + * **http_default_8bit_udp_resolve** + * **http_keepalive_8bit_tcp_resolve** + * **http_keepalive_8bit_udp_resolve** + +The synchronous client implements all the operations of the client underneath +the interface all block to wait for I/O to finish. All the member methods are +synchronous and will block until the response object is ready or throws if errors +are encountered in the performance of the HTTP requests. + +.. warning:: The synchronous clients are **NOT** thread safe. You will need to do + external synchronization to use synchronous client implementations. + +.. note:: As of version 0.11, all the synchronous client implementations are + deprecated. They will be removed in the next version of the library. + +Asynchronous Clients +~~~~~~~~~~~~~~~~~~~~ + +The following tags specify the ``basic_client`` to behave in an asynchronous +manner: + + * **http_async_8bit_tcp_resolve** + * **http_async_8bit_udp_resolve** + +An asynchronous client implementation means that``basic_client<...>`` is an +`Active Object`_. This means that the client has and manages its own lifetime +thread, and returns values that are asynchronously filled in. The response +object encapsulates Boost.Thread_ futures which get filled in once the values +are available. + +.. _Boost.Thread: http://www.boost.org/libs/thread +.. _`Active Object`: http://en.wikipedia.org/wiki/Active_object + +The asynchronous clients implement all operations asynchronously which are hidden +from the user. The interface is still synchronous but the fetching of data +happens on a different thread. + +.. note:: The asynchronous clients are thread safe, and can be shared across + many threads. Each request starts a sequence of asynchronous operations + dedicated to that request. The client does not re-cycle connections and uses + a one-request-one-connection model. + +When an asynchronous client object is destroyed, it waits for all pending +asynchronous operations to finish. Errors encountered during operations on +retrieving data from the response objects cause exceptions to be thrown -- +therefore it is best that if a client object is constructed, it should outlive +the response object or be outside the try-catch block handling the errors from +operations on responses. In code, usage should look like the following: + +.. code-block:: c++ + + http::client client; + try { + http::client::response response = client.get("http://www.example.com/"); + std::cout << body(response); + } catch (std::exception& e) { + // deal with exceptions here + } + +A common mistake is to declare the client inside the try block which invokes +undefined behavior when errors arise from the handling of response objects. +Previous examples cited by the documentation showed the short version of the +code which didn't bother moving the ``http::client`` object outside of the same +``try`` block where the request/response objects are being used. + +Member Functions +---------------- + +In this section we assume that the following typedef is in effect: + +.. code-block:: c++ + + typedef boost::network::http::basic_client< + boost::network::http::tags::http_default_8bit_udp_resolve + , 1 + , 1 + > + client; + +Also, that code using the HTTP client will have use the following header: + +.. code-block:: c++ + + #include + +.. note:: Starting version 0.9, cpp-netlib clients and server implementations + by default now have an externally-linked component. This is a breaking change + for code that used to rely on cpp-netlib being a header-only library, but can + inhibited by defining the ``BOOST_NETWORK_NO_LIB`` preprocessor macro before + including any cpp-netlib header. + +.. note:: Starting version 0.11, cpp-netlib clients and server implementations + no longer support the ``BOOST_NETWORK_NO_LIB`` option. + +Constructors +~~~~~~~~~~~~ + +The client implementation can be default constructed, or customized at +initialization. + +``client()`` + Default constructor. +``explicit client(client::options const &)`` + Constructor taking a ``client_options`` object. The following table + shows the options you can set on a ``client_options`` instance. + ++--------------------------+----------------------------+--------------------------+ +| Parameter Name | Type | Description | ++==========================+============================+==========================+ +| follow_redirects | ``bool`` | Boolean to specify | +| | | whether the client | +| | | should follow HTTP | +| | | redirects. Default is | +| | | ``false``. | ++--------------------------+----------------------------+--------------------------+ +| cache_resolved | ``bool`` | Boolean to specify | +| | | whether the client | +| | | should cache resolved | +| | | endpoints. The default | +| | | is ``false``. | ++--------------------------+----------------------------+--------------------------+ +| io_service | ``shared_ptr`` | Shared pointer to a | +| | | Boost.Asio | +| | | ``io_service``. | ++--------------------------+----------------------------+--------------------------+ +| openssl_certificate | ``string`` | The filename of the | +| | | certificate to load for | +| | | the SSL connection for | +| | | verification. | ++--------------------------+----------------------------+--------------------------+ +| openssl_verify_path | ``string`` | The directory from | +| | | which the certificate | +| | | authority files are | +| | | located. | ++--------------------------+----------------------------+--------------------------+ +| always_verify_peer | ``bool`` | Boolean to specify | +| | | whether the client | +| | | should always verify | +| | | peers in SSL connections | ++--------------------------+----------------------------+--------------------------+ +| openssl_certificate_file | ``string`` | Filename of the | +| | | certificate to use for | +| | | client-side SSL session | +| | | establishment. | ++--------------------------+----------------------------+--------------------------+ +| openssl_private_key_file | ``string`` | Filename of the | +| | | private key to use for | +| | | client-side SSL session | +| | | establishment. | ++--------------------------+----------------------------+--------------------------+ +| timeout | ``int`` | Number of seconds to | +| | | wait for client requests | +| | | before considering a | +| | | timeout has occurred. | ++--------------------------+----------------------------+--------------------------+ + + +To use the above supported named parameters, you'll have code that looks like +the following: + +.. code-block:: c++ + + using namespace boost::network::http; // parameters are in this namespace + client::options options; + options.follow_redirects(true) + .cache_resolved(true) + .io_service(boost::make_shared()) + .openssl_certificate("/tmp/my-cert") + .openssl_verify_path("/tmp/ca-certs") + .timeout(10); + client client_(options); + // use client_ as normal from here on out. + +HTTP Methods +~~~~~~~~~~~~ + +The client implementation supports various HTTP methods. The following +constructs assume that a client has been properly constructed named ``client_`` +and that there is an appropriately constructed request object named ``request_`` +and that there is an appropriately constructed response object named +``response_`` like the following: + +.. code-block:: c++ + + using namespace boost::network::http; // parameters are here + client client_(); + client::request request_("http://cpp-netib.github.com/"); + client::response response_; + +``response_ = client_.get(request_)`` + Perform an HTTP GET request. +``response_ = client_.get(request_, callback)`` + Perform an HTTP GET request, and have the body chunks be handled by the + ``callback`` parameter. The signature of ``callback`` should be the following: + ``void(iterator_range const &, boost::system::error_code const + &)``. +``response_ = client_.head(request_)`` + Perform an HTTP HEAD request. +``response_ = client_.post(request_)`` + Perform an HTTP POST, use the data already set in the request object which + includes the headers, and the body. +``response_ = client_.post(request_, callback)`` + Perform an HTTP POST request, and have the body chunks be handled by the + ``callback`` parameter. The signature of ``callback`` should be the following: + ``void(iterator_range const &, boost::system::error_code const + &)``. +``response_ = client_.post(request_, body)`` + Body is a string of type ``boost::network::string::type`` where ``Tag`` + is the HTTP Client's ``Tag``. The default content-type used is + ``x-application/octet-stream``. +``response_ = client_.post(request_, body, callback)`` + Body is a string of type ``boost::network::string::type`` where ``Tag`` + is the HTTP Client's ``Tag``. The default content-type used is + ``x-application/octet-stream``. Have the response body chunks be handled by + the ``callback`` parameter. The signature of ``callback`` should be the + following: ``void(iterator_range const &, + boost::system::error_code const &)``. +``response_ = client_.post(request_, body, content_type)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. +``response_ = client_.post(request_, body, content_type, callback)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. Have the response + body chunks be handled by the ``callback`` parameter. The signature of + ``callback`` should be the following: ``void(iterator_range const + &, boost::system::error_code const &)``. +``response_ = client_.post(request_, body, content_type, callback, streaming_callback)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. Have the response + body chunks be handled by the ``callback`` parameter. The signature of + ``callback`` should be the following: ``void(iterator_range const + &, boost::system::error_code const &)``. The ``streaming_callback`` + argument should have a which has a signature of the form: + ``bool(string_type&)``. The provided ``string_type&`` will be streamed as + soon as the function returns. A return value of ``false`` signals the + client that the most recent invocation is the last chunk to be sent. +``response_ = client_.post(request_, streaming_callback)`` + Perform and HTTP POST request, and have the request's body chunks be + generated by the ``streaming_callback`` which has a signature of the form: + ``bool(string_type&)``. The provided ``string_type&`` will be streamed as + soon as the function returns. A return value of ``false`` signals the client + that the most recent invocation is the last chunk to be sent. +``response_ = client_.post(request_, callback, streaming_callback)`` + Perform an HTTP POST request, and have the body chunks be handled by the + ``callback`` parameter. The signature of ``callback`` should be the + following: ``void(iterator_range const &, + boost::system::error_code const &)``. This form also has the request's body + chunks be generated by the ``streaming_callback`` which has a signature of + the form: ``bool(string_type&)``. The provided ``string_type&`` will be + streamed as soon as the function returns. A return value of ``false`` + signals the client that the most recent invocation is the last chunk to be + sent. +``response_ = client_.put(request_)`` + Perform an HTTP PUT, use the data already set in the request object which + includes the headers, and the body. +``response_ = client_.put(request_, callback)`` + Perform an HTTP PUT request, and have the body chunks be handled by the + ``callback`` parameter. The signature of ``callback`` should be the following: + ``void(iterator_range const &, boost::system::error_code const + &)``. +``response_ = client_.put(request_, body)`` + Body is a string of type ``boost::network::string::type`` where ``Tag`` + is the HTTP Client's ``Tag``. The default content-type used is + ``x-application/octet-stream``. +``response_ = client_.put(request_, body, callback)`` + Body is a string of type ``boost::network::string::type`` where ``Tag`` + is the HTTP Client's ``Tag``. The default content-type used is + ``x-application/octet-stream``. Have the response body chunks be handled by + the ``callback`` parameter. The signature of ``callback`` should be the + following: ``void(iterator_range const &, + boost::system::error_code const &)``. +``response_ = client_.put(request_, body, content_type)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. +``response_ = client_.put(request_, body, content_type, callback)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. Have the response + body chunks be handled by the ``callback`` parameter. The signature of + ``callback`` should be the following: ``void(iterator_range const + &, boost::system::error_code const &)``. +``response_ = client_.put(request_, body, content_type, callback, streaming_callback)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. Have the response + body chunks be handled by the ``callback`` parameter. The signature of + ``callback`` should be the following: ``void(iterator_range const + &, boost::system::error_code const &)``. This form also has the request's body + chunks be generated by the ``streaming_callback`` which has a signature of + the form: ``bool(string_type&)``. The provided ``string_type&`` will be + streamed as soon as the function returns. A return value of ``false`` + signals the client that the most recent invocation is the last chunk to be + sent +``response_ = client_.put(request_, streaming_callback)`` + Perform and HTTP PUT request, and have the request's body chunks be + generated by the ``streaming_callback`` which has a signature of the form: + ``bool(string_type&)``. The provided ``string_type&`` will be streamed as + soon as the function returns. A return value of ``false`` signals the client + that the most recent invocation is the last chunk to be sent. +``response_ = client_.put(request_, callback, streaming_callback)`` + Perform an HTTP PUT request, and have the body chunks be handled by the + ``callback`` parameter. The signature of ``callback`` should be the + following: ``void(iterator_range const &, + boost::system::error_code const &)``. This form also has the request's body + chunks be generated by the ``streaming_callback`` which has a signature of + the form: ``bool(string_type&)``. The provided ``string_type&`` will be + streamed as soon as the function returns. A return value of ``false`` + signals the client that the most recent invocation is the last chunk to be + sent. +``response_ = client_.delete_(request_)`` + Perform an HTTP DELETE request. +``response_ = client_.delete_(request_, body_handler=callback)`` + Perform an HTTP DELETE request, and have the response body chunks be handled + by the ``callback`` parameter. The signature of ``callback`` should be the + following: ``void(iterator_range const &, + boost::system::error_code const &)``. + +Client-Specific +~~~~~~~~~~~~~~~ + +``client_.clear_resolved_cache()`` + Clear the cache of resolved endpoints. + + +Streaming Body Handler +~~~~~~~~~~~~~~~~~~~~~~ + +As of v0.9.1 the library now offers a way to support a streaming body callback +function in all HTTP requests that expect a body part (GET, PUT, POST, DELETE). +A convenience macro is also provided to make callback handlers easier to write. +This macro is called ``BOOST_NETWORK_HTTP_BODY_CALLBACK`` which allows users to +write the following code to easily create functions or function objects that +are compatible with the callback function requirements. + +An example of how to use the macro is shown below: + +.. code-block:: c++ + + struct body_handler { + explicit body_handler(std::string & body) + : body(body) {} + + BOOST_NETWORK_HTTP_BODY_CALLBACK(operator(), range, error) { + // in here, range is the Boost.Range iterator_range, and error is + // the Boost.System error code. + if (!error) + body.append(boost::begin(range), boost::end(range)); + } + + std::string & body; + }; + + // somewhere else + std::string some_string; + response_ = client_.get(request("http://cpp-netlib.github.com/"), + body_handler(some_string)); + +You can also use if for standalone functions instead if you don't want or need +to create a function object. + +.. code-block:: c++ + + BOOST_NETWORK_HTTP_BODY_CALLBACK(print_body, range, error) { + if (!error) + std::cout << "Received " << boost::distance(range) << "bytes." + << std::endl; + else + std::cout << "Error: " << error << std::endl; + } + + // somewhere else + response_ = client_.get(request("http://cpp-netlib.github.com/"), + print_body); + +The ``BOOST_NETWORK_HTTP_BODY_CALLBACK`` macro is defined in +``boost/network/protocol/http/client/macros.hpp``. diff --git a/cpp-netlib/libs/network/doc/html/_sources/reference/http_request.txt b/cpp-netlib/libs/network/doc/html/_sources/reference/http_request.txt new file mode 100644 index 00000000..cbef6e18 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/reference/http_request.txt @@ -0,0 +1,254 @@ + +HTTP Request +============ + +This part of the documentation talks about the publicly accessible API of the +HTTP Request objects. This section details the `Request Concepts`_ requirements, +the implemented and required Directives_, Modifiers_, and Wrappers_ that work +with the HTTP Request objects. + +Request Concepts +---------------- + +There are two generally supported Request Concepts implemented in the library. +The first of two is the `Normal Client Request Concept`_ and the second is the +`Pod Server Request Concept`_. + +The `Normal Client Request Concept`_ is what the HTTP Client interface requires. +All operations performed internally by the HTTP Client abide by the interface +required by this concept definition. + +The `Pod Server Request Concept`_ is as the name suggests what the HTTP Server +implementation requires from Request Objects. + +Switching on whether the `Request` concept chooses either of the `Normal Client +Request Concept`_ or the `Pod Server Request Concept`_ is done through the +nested ``tag`` type and whether that tag derives from the root tag ``pod``. +Simply, if the Request type's nested ``tag`` type derives from +``boost::network::tags::pod`` then it chooses to enforce the `Pod Server Request +Concept`_, otherwise it chooses the `Normal Client Request Concept`_. + +Normal Client Request Concept +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A type models the Normal Client Request Concept if it models the `Message +Concept`_ and also supports the following constructs. + +**Legend** + +:R: The request type. +:r: An instance of R. +:S: The string type. +:s: An instance of S. +:P: The port type. +:p: An instance of P. + ++-----------------------+-------------+----------------------------------------+ +| Construct | Result | Description | ++=======================+=============+========================================+ +| ``R::string_type`` | ``S`` | The nested ``string_type`` type. | ++-----------------------+-------------+----------------------------------------+ +| ``R::port_type`` | ``P`` | The nested ``port_type`` type. | ++-----------------------+-------------+----------------------------------------+ +| ``R r(s)`` | **NA** | Construct a Request with an ``s`` | +| | | provided. This treats ``s`` as the URI | +| | | to where the request is destined for. | ++-----------------------+-------------+----------------------------------------+ +| ``host(request)`` | Convertible | Return the host to where the request | +| | to ``S`` | is destined for. | ++-----------------------+-------------+----------------------------------------+ +| ``port(request)`` | Convertible | Return the port to where the request | +| | to ``P`` | is destined for. | ++-----------------------+-------------+----------------------------------------+ +| ``path(request)`` | Convertible | Return the path included in the URI. | +| | to ``S`` | | ++-----------------------+-------------+----------------------------------------+ +| ``query(request)`` | Convertible | Return the query part of the URI. | +| | to ``S`` | | ++-----------------------+-------------+----------------------------------------+ +| ``anchor(request)`` | Convertible | Return the anchor part of the URI. | +| | to ``S`` | | ++-----------------------+-------------+----------------------------------------+ +| ``protocol(request)`` | Convertible | Return the protocol/scheme part of the | +| | to ``S`` | URI. | ++-----------------------+-------------+----------------------------------------+ +| ``r << uri(s)`` | ``R&`` | Set the URI of the request. | ++-----------------------+-------------+----------------------------------------+ +| ``uri(r, s)`` | ``void`` | Set the URI of the request. | ++-----------------------+-------------+----------------------------------------+ + +Pod Server Request Concept +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A type models the Pod Server Request Concept if it models the `Message Concept`_ +and also supports the following constructs. + +**Legend** + +:R: The request type. +:r: An instance of R. +:S: The string type. +:I: An unsigned 8 bit integer. +:V: The vector type for headers. + ++-------------------------------+--------+-------------------------------------+ +| Construct | Result | Description | ++===============================+========+=====================================+ +| ``R::string_type`` | ``S`` | The nested ``string_type`` type. | ++-------------------------------+--------+-------------------------------------+ +| ``R::headers_container_type`` | ``V`` | The nested | +| | | ``headers_container_type`` type. | ++-------------------------------+--------+-------------------------------------+ +| ``r.source`` | ``S`` | The nested source of the request. | ++-------------------------------+--------+-------------------------------------+ +| ``r.method`` | ``S`` | The method of the request. | ++-------------------------------+--------+-------------------------------------+ +| ``r.destination`` | ``S`` | The destination of the request. | +| | | This is normally the URI of the | +| | | request. | ++-------------------------------+--------+-------------------------------------+ +| ``r.version_major`` | ``I`` | The major version number part of | +| | | the request. | ++-------------------------------+--------+-------------------------------------+ +| ``r.version_minor`` | ``I`` | The minor version number part of | +| | | the request. | ++-------------------------------+--------+-------------------------------------+ +| ``r.headers`` | ``V`` | The vector of headers. | ++-------------------------------+--------+-------------------------------------+ +| ``r.body`` | ``S`` | The body of the request. | ++-------------------------------+--------+-------------------------------------+ + +.. _Message Concept: ../in_depth/message.html#message-concept + +Directives +---------- + +This section details the provided directives that are provided by +:mod:`cpp-netlib`. The section was written to assume that an appropriately +constructed request instance is either of the following: + +.. code-block:: c++ + + boost::network::http::basic_request< + boost::network::http::tags::http_default_8bit_udp_resolve + > request; + + // or + + boost::network::http::basic_request< + boost::network::http::tags::http_server + > request; + +The section also assumes that there following using namespace declaration is in +effect: + +.. code-block:: c++ + + using namespace boost::network; + +Directives are meant to be used in the following manner: + +.. code-block:: c++ + + request << directive(...); + +.. warning:: + + There are two versions of directives, those that are applicable to + messages that support narrow strings (``std::string``) and those that are + applicable to messages that support wide strings (``std::wstring``). The + :mod:`cpp-netlib` implementation still does not convert wide strings into + UTF-8 encoded narrow strings. This will be implemented in subsequent + library releases. + + For now all the implemented directives are listed, even if some of them still + do not implement things correctly. + +*unspecified* ``source(std::string const & source_)`` + Create a source directive with a ``std::string`` as a parameter, to be set + as the source of the request. +*unspecified* ``source(std::wstring const & source_)`` + Create a source directive with a ``std::wstring`` as a parameter, to be set + as the source of the request. +*unspecified* ``destination(std::string const & source_)`` + Create a destination directive with a ``std::string`` as a parameter, to be + set as the destination of the request. +*unspecified* ``destination(std::wstring const & source_)`` + Create a destination directive with a ``std::wstring`` as a parameter, to be + set as the destination of the request. +*unspecified* ``header(std::string const & name, std::string const & value)`` + Create a header directive that will add the given name and value pair to the + headers already associated with the request. In this case the name and + values are both ``std::string``. +*unspecified* ``header(std::wstring const & name, std::wstring const & value)`` + Create a header directive that will add the given name and value pair to the + headers already associated with the request. In this case the name and + values are both ``std::wstring``. +*unspecified* ``remove_header(std::string const & name)`` + Create a remove_header directive that will remove all the occurences of the + given name from the headers already associated with the request. In this + case the name of the header is of type ``std::string``. +*unspecified* ``remove_header(std::wstring const & name)`` + Create a remove_header directive that will remove all the occurences of the + given name from the headers already associated with the request. In this + case the name of the header is of type ``std::wstring``. +*unspecified* ``body(std::string const & body_)`` + Create a body directive that will set the request's body to the given + parameter. In this case the type of the body is an ``std::string``. +*unspecified* ``body(std::wstring const & body_)`` + Create a body directive that will set the request's body to the given + parameter. In this case the type of the body is an ``std::wstring``. + +Modifiers +--------- + +This section details the provided modifiers that are provided by +:mod:`cpp-netlib`. + +``template inline void source(basic_request & request, typename string::type const & source_)`` + Modifies the source of the given ``request``. The type of ``source_`` is + dependent on the ``Tag`` specialization of ``basic_request``. +``template inline void destination(basic_request & request, typename string::type const & destination_)`` + Modifies the destination of the given ``request``. The type of ``destination_`` is + dependent on the ``Tag`` specialization of ``basic_request``. +``template inline void add_header(basic_request & request, typename string::type const & name, typename string::type const & value)`` + Adds a header to the given ``request``. The type of the ``name`` and + ``value`` parameters are dependent on the ``Tag`` specialization of + ``basic_request``. +``template inline void remove_header(basic_request & request, typename string::type const & name)`` + Removes a header from the given ``request``. The type of the ``name`` + parameter is dependent on the ``Tag`` specialization of ``basic_request``. +``template inline void clear_headers(basic_request & request)`` + Removes all headers from the given ``request``. +``template inline void body(basic_request & request, typename string::type const & body_)`` + Modifies the body of the given ``request``. The type of ``body_`` is + dependent on the ``Tag`` specialization of ``basic_request``. + +Wrappers +-------- + +This section details the provided request wrappers that come with +:mod:`cpp-netlib`. Wrappers are used to convert a message into a different type, +usually providing accessor operations to retrieve just part of the message. This +section assumes that the following using namespace directives are in +effect: + +.. code-block:: c++ + + using namespace boost::network; + using namespace boost::network::http; + +``template `` *unspecified* ``source(basic_request const & request)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the source of a given request. +``template `` *unspecified* ``destination(basic_request const & request)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the destination of a given request. +``template `` *unspecified* ``headers(basic_request const & request)`` + Returns a wrapper convertible to ``typename headers_range + >::type`` or ``typename basic_request::headers_container_type`` that + provides the headers of a given request. +``template `` *unspecified* ``body(basic_request const & request)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the body of a given request. + diff --git a/cpp-netlib/libs/network/doc/html/_sources/reference/http_response.txt b/cpp-netlib/libs/network/doc/html/_sources/reference/http_response.txt new file mode 100644 index 00000000..d0a97399 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/reference/http_response.txt @@ -0,0 +1,309 @@ + +HTTP Response +============= + +This part of the documentation talks about the publicly accessible API of the +HTTP Response objects. This section details the `Response Concept`_ requirements, +the implemented and required Directives_, Modifiers_, and Wrappers_ that work +with the HTTP Response objects. + +.. note:: The HTTP server response object is a POD type, which doesn't support + any of the following details. There are only a few fields available in the + HTTP server response type, which can be seen in + ``boost/network/protocol/http/impl/response.ipp``. + +Response Concept +---------------- + +A type models the Response Concept if it models the `Message Concept`_ and also +supports the following constructs. + +**Legend** + +:R: The response type. +:r: An instance of R. +:S: The string type. +:s,e,g: Instances of S. +:P: The port type. +:p: An instance of P. +:V: The version type. +:v: An instance of v. +:T: The status type. +:t: An instance of T. +:M: The status message type. +:m: An instance of M. +:U: An unsigned 16-bit int. +:u: An instance of U. + +.. note:: In the table below, the namespace ``traits`` is an alias for + ``boost::network::http::traits``. + ++-------------------------------------+----------+-----------------------------+ +| Construct | Result | Description | ++=====================================+==========+=============================+ +| ``R::string_type`` | ``S`` | The nested ``string_type`` | +| | | type. | ++-------------------------------------+----------+-----------------------------+ +| ``traits::version::type`` | ``V`` | The version type associated | +| | | with R. | ++-------------------------------------+----------+-----------------------------+ +| ``traits::status::type`` | ``T`` | The status type associated | +| | | with R. | ++-------------------------------------+----------+-----------------------------+ +| ``traits::status_message::type`` | ``M`` | The status message type | +| | | associated with R. | ++-------------------------------------+----------+-----------------------------+ +| ``r << version(v)`` | ``R&`` | Sets the version of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``r << status(t)`` | ``R&`` | Sets the status of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``r << status_message(m)`` | ``R&`` | Sets the status message of | +| | | ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``version(r, v)`` | ``void`` | Sets the version of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``status(r, t)`` | ``void`` | Sets the status of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``status_message(r, m)`` | ``void`` | Sets the status message of | +| | | ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``S e = version(r)`` | **NA** | Get the version of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``U u = status(r)`` | **NA** | Get the status of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``S g = status_message(r)`` | **NA** | Get the status message of | +| | | ``r``. | ++-------------------------------------+----------+-----------------------------+ + +.. _Message Concept: ../in_depth/message.html#message-concept + +Directives +---------- + +This section details the provided directives that are provided by +:mod:`cpp-netlib`. The section was written to assume that an appropriately +constructed response instance is either of the following: + +.. code-block:: c++ + + boost::network::http::basic_response< + boost::network::http::tags::http_default_8bit_udp_resolve + > response; + + // or + + boost::network::http::basic_response< + boost::network::http::tags::http_server + > response; + +The section also assumes that there following using namespace declaration is in +effect: + +.. code-block:: c++ + + using namespace boost::network; + +Directives are meant to be used in the following manner: + +.. code-block:: c++ + + response << directive(...); + +.. warning:: There are four versions of directives, those that are applicable + to messages that support narrow strings (``std::string``), those that are + applicable to messages that support wide strings (``std::wstring``), those + that are applicable to messages that support future-wrapped narrow and wide + strings (``boost::shared_future`` and + ``boost::shared_future``). + + The :mod:`cpp-netlib` implementation still does not convert wide strings into + UTF-8 encoded narrow strings. This will be implemented in subsequent + library releases. + + For now all the implemented directives are listed, even if some of them still + do not implement things correctly. + +*unspecified* ``source(std::string const & source_)`` + Create a source directive with a ``std::string`` as a parameter, to be set + as the source of the response. +*unspecified* ``source(std::wstring const & source_)`` + Create a source directive with a ``std::wstring`` as a parameter, to be set + as the source of the response. +*unspecified* ``source(boost::shared_future const & source_)`` + Create a source directive with a ``boost::shared_future`` as a parameter, to be set + as the source of the response. +*unspecified* ``source(boost::shared_future const & source_)`` + Create a source directive with a ``boost::shared_future`` as a parameter, to be set + as the source of the response. +*unspecified* ``destination(std::string const & source_)`` + Create a destination directive with a ``std::string`` as a parameter, to be + set as the destination of the response. +*unspecified* ``destination(std::wstring const & source_)`` + Create a destination directive with a ``std::wstring`` as a parameter, to be + set as the destination of the response. +*unspecified* ``destination(boost::shared_future const & destination_)`` + Create a destination directive with a ``boost::shared_future`` as a parameter, to be set + as the destination of the response. +*unspecified* ``destination(boost::shared_future const & destination_)`` + Create a destination directive with a ``boost::shared_future`` as a parameter, to be set + as the destination of the response. +*unspecified* ``header(std::string const & name, std::string const & value)`` + Create a header directive that will add the given name and value pair to the + headers already associated with the response. In this case the name and + values are both ``std::string``. +*unspecified* ``header(std::wstring const & name, std::wstring const & value)`` + Create a header directive that will add the given name and value pair to the + headers already associated with the response. In this case the name and + values are both ``std::wstring``. +*unspecified* ``remove_header(std::string const & name)`` + Create a remove_header directive that will remove all the occurences of the + given name from the headers already associated with the response. In this + case the name of the header is of type ``std::string``. +*unspecified* ``remove_header(std::wstring const & name)`` + Create a remove_header directive that will remove all the occurences of the + given name from the headers already associated with the response. In this + case the name of the header is of type ``std::wstring``. +*unspecified* ``body(std::string const & body_)`` + Create a body directive that will set the response's body to the given + parameter. In this case the type of the body is an ``std::string``. +*unspecified* ``body(std::wstring const & body_)`` + Create a body directive that will set the response's body to the given + parameter. In this case the type of the body is an ``std::wstring``. +*unspecified* ``body(boost::shared_future const & body_)`` + Create a body directive that will set the response's body to the given + parameter. In this case the type of the body is an ``boost::shared_future``. +*unspecified* ``body(boost::shared_future const & body_)`` + Create a body directive that will set the response's body to the given + parameter. In this case the type of the body is an ``boost::shared_future``. +*unspecified* ``version(std::string const & version_)`` + Create a version directive that will set the response's version to the given + parameter. In this case the type of the version is an ``std::string``. + + Note that this version includes the full ``"HTTP/"`` string. +*unspecified* ``version(std::wstring const & version_)`` + Create a version directive that will set the response's version to the given + parameter. In this case the type of the version is an ``std::wstring``. + + Note that this version includes the full ``"HTTP/"`` string. +*unspecified* ``version(boost::shared_future const & version_)`` + Create a version directive that will set the response's version to the given + parameter. In this case the type of the version is an ``boost::shared_future``. + + Note that this version includes the full ``"HTTP/"`` string. +*unspecified* ``version(boost::shared_future const & version_)`` + Create a version directive that will set the response's version to the given + parameter. In this case the type of the version is an ``boost::shared_future``. + + Note that this version includes the full ``"HTTP/"`` string. +*unspecified* ``status_message(std::string const & status_message_)`` + Create a status_message directive that will set the response's status_message to the given + parameter. In this case the type of the status_message is an ``std::string``. + + Note that this status_message includes the full ``"HTTP/"`` string. +*unspecified* ``status_message(std::wstring const & status_message_)`` + Create a status_message directive that will set the response's status_message to the given + parameter. In this case the type of the status_message is an ``std::wstring``. + + Note that this status_message includes the full ``"HTTP/"`` string. +*unspecified* ``status_message(boost::shared_future const & status_message_)`` + Create a status_message directive that will set the response's status_message to the given + parameter. In this case the type of the status_message is an ``boost::shared_future``. + + Note that this status_message includes the full ``"HTTP/"`` string. +*unspecified* ``status_message(boost::shared_future const & status_message_)`` + Create a status_message directive that will set the response's status_message to the given + parameter. In this case the type of the status_message is an ``boost::shared_future``. + + Note that this status_message includes the full ``"HTTP/"`` string. +*unspecified* ``status(boost::uint16_t status_)`` + Create a status directive that will set the response's status to the given + parameter. In this case the type of ``status_`` is ``boost::uint16_t``. +*unspecified* ``status(boost::shared_future const & status_)`` + Create a status directive that will set the response's status to the given + parameter. In this case the type of ``status_`` is ``boost::shared_future``. + +Modifiers +--------- + +This section details the provided modifiers that are provided by +:mod:`cpp-netlib`. + +``template inline void source(basic_response & response, typename string::type const & source_)`` + Modifies the source of the given ``response``. The type of ``source_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void source(basic_response & response, boost::shared_future::type> const & source_)`` + Modifies the source of the given ``response``. The type of ``source_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void destination(basic_response & response, typename string::type const & destination_)`` + Modifies the destination of the given ``response``. The type of ``destination_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void destination(basic_response & response, boost::shared_future::type> const & destination_)`` + Modifies the destination of the given ``response``. The type of ``destination_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void add_header(basic_response & response, typename string::type const & name, typename string::type const & value)`` + Adds a header to the given ``response``. The type of the ``name`` and + ``value`` parameters are dependent on the ``Tag`` specialization of + ``basic_response``. +``template inline void remove_header(basic_response & response, typename string::type const & name)`` + Removes a header from the given ``response``. The type of the ``name`` + parameter is dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void headers(basic_response & response, typename headers_container >::type const & headers_)`` + Sets the whole headers contained in ``response`` as the given parameter + ``headers_``. +``template inline void headers(basic_response & response, boost::shared_future >::type> const & headers_)`` + Sets the whole headers contained in ``response`` as the given parameter + ``headers_``. +``template inline void clear_headers(basic_response & response)`` + Removes all headers from the given ``response``. +``template inline void body(basic_response & response, typename string::type const & body_)`` + Modifies the body of the given ``response``. The type of ``body_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void body(basic_response & response, boost::shared_future::type> const & body_)`` + Modifies the body of the given ``response``. The type of ``body_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void version(basic_response & response, typename traits::version >::type const & version_)`` + Modifies the version of the given ``response``. The type of ``version_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void status(basic_response & response, typename traits::status >::type const & status_)`` + Modifies the status of the given ``response``. The type of ``status_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void status_message(basic_response & response, typename traits::status_message >::type const & status_message_)`` + Modifies the status message of the given ``response``. The type of ``status_message_`` is + dependent on the ``Tag`` specialization of ``basic_response``. + +Wrappers +-------- + +This section details the provided response wrappers that come with +:mod:`cpp-netlib`. Wrappers are used to convert a message into a different type, +usually providing accessor operations to retrieve just part of the message. This +section assumes that the following using namespace directives are in +effect: + +.. code-block:: c++ + + using namespace boost::network; + using namespace boost::network::http; + +``template `` *unspecified* ``source(basic_response const & response)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the source of a given response. +``template `` *unspecified* ``destination(basic_response const & response)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the destination of a given response. +``template `` *unspecified* ``headers(basic_response const & response)`` + Returns a wrapper convertible to ``typename headers_range + >::type`` or ``typename basic_response::headers_container_type`` that + provides the headers of a given response. +``template `` *unspecified* ``body(basic_response const & response)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the body of a given response. +``template `` *unspecified* ``version(basic_response const & response)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the version of the given response. +``template `` *unspecified* ``status(basic_response const & response)`` + Returns a wrapper convertible to ``typename boost::uint16_t`` that + provides the status of the given response. +``template `` *unspecified* ``status_message(basic_response const & response)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the status message of the given response. diff --git a/cpp-netlib/libs/network/doc/html/_sources/reference/http_server.txt b/cpp-netlib/libs/network/doc/html/_sources/reference/http_server.txt new file mode 100644 index 00000000..26ceb9b6 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/reference/http_server.txt @@ -0,0 +1,559 @@ + +HTTP Server API +=============== + +General +------- + +:mod:`cpp-netlib` includes and implements two distinct HTTP server +implementations that you can use and embed in your own applications. Both HTTP +Server implementations: + + * **Cannot be copied.** This means you may have to store instances of the HTTP + Server in dynamic memory if you intend to use them as function parameters or + pass them around in smart pointers of by reference. + * **Assume that requests made are independent of each other.** None of the + HTTP Server implementations support request pipelining (yet) so a single + connection only deals with a single request. + * **Are header-only and are compiled-into your application.** Future releases + in case you want to upgrade the implementation you are using in your + application will be distributed as header-only implementations, which means + you have to re-compile your application to use a newer version of the + implementations. + +The HTTP Servers have different semantics, and in some cases require different +APIs from the supplied template parameters. + +Implementations +--------------- + +There are two different user-facing template classes that differentiate the +`Synchronous Servers`_ from the `Asynchronous Servers`_. Both templates take a +single template parameter named ``Handler`` which describes the type of the +Handler function object. + +There are two different Handler concepts, one concept for `Synchronous Servers`_ +and another for `Asynchronous Servers`. + +The SynchronousHandler concept for `Synchronous Servers`_ is described by the +following table: + +--------------- + +**Legend:** + +H + The Handler type. +h + An instance of H. +Req + A type that models the Request Concept. +Res + A type that models the Response Concept. +req + An instance of Req. +res + An instance of Res. + ++----------------+-------------+----------------------------------------------+ +| Construct | Return Type | Description | ++================+=============+==============================================+ +| ``h(req,res)`` | ``void`` | Handle the request; res is passed in as a | +| | | non-const lvalue, which represents the | +| | | response to be returned to the client | +| | | performing the request. | ++----------------+-------------+----------------------------------------------+ + +More information about the internals of the `Synchronous Servers`_ can be found +in the following section. + +The AsynchronousHandler concept for `Asynchronous Servers`_ is described by the +following table: + +--------------- + +**Legend:** + +H + The Handler type. +h + An instance of H. +Req + A type that models the Request Concept. +ConnectionPtr + A type that models the Connection Pointer Concept. +req + An instance of Req. +conn + An instance of ConncetionPtr. + ++------------------+-------------+--------------------------------------------+ +| Construct | Return Type | Description | ++==================+=============+============================================+ +| ``h(req, conn)`` | ``void`` | Handle the request; conn is a shared | +| | | pointer which exposes functions for | +| | | writing to and reading from the connection.| ++------------------+-------------+--------------------------------------------+ + +More information about the internals of the `Asynchronous Servers`_ can be found +in the following section. + +Synchronous Servers +------------------- + +The synchronous server implementation is represented by the template ``server`` +in namespace ``boost::network::http``. The ``server`` template takes in a single +template parameter named ``Handler`` which models the SynchronousHandler +concept (described above). + +An instance of Handler is taken in by reference to the constructor of the HTTP +server. This means the Handler is not copied around and only a single instance +of the handler is used for all connections and requests performed against the +HTTP server. + +.. warning:: It is important to note that the HTTP server does not implement any + locking upon invoking the Handler. In case you have any state in the Handler + that will be associated with the synchronous server, you would have to + implement your own synchronization internal to the Handler implementation. + This matters especially if you run the synchronous server in multiple + threads. + +The general pattern of usage for the HTTP Server template is shown below: + +.. code-block:: c++ + + struct handler; + typedef boost::network::http::server http_server; + + struct handler { + void operator()( + http_server::request const & req, + http_server::response & res + ) { + // do something, and then edit the res object here. + } + }; + +More information about the actual HTTP Server API follows in the next section. +It is important to understand that the HTTP Server is actually embedded in your +application, which means you can expose almost all your application logic +through the Handler type, which you can also initialize appropriately. + +API Documentation +~~~~~~~~~~~~~~~~~ + +The following sections assume that the following file has been included: + +.. code-block:: c++ + + #include + +And that the following typedef's have been put in place: + +.. code-block:: c++ + + struct handler_type; + typedef boost::network::http::server http_server; + + struct handler_type { + void operator()(http_server::request const & request, + http_server::response & response) { + // do something here + } + }; + +Constructor +``````````` + +``explicit http_server(options)`` + Construct an HTTP Server instance, passing in a ``server_options`` object. The following table shows the supported options in + ``server_options``. + ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| Parameter Name | Type | Description | ++=======================+==========================================+==================================================================================================+ +| address | string_type | The hostname or IP address from which the server should be bound to. This parameter is required. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| port | string_type | The port to which the server should bind and listen to. This parameter is required. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| thread_pool | ``shared_ptr`` | A shared pointer to an instance of ``boost::network::utils::thread_pool`` -- this is the | +| | | thread pool from where the handler is invoked. This parameter is only applicable and required | +| | | for ``async_server`` instances. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| io_service | ``shared_ptr`` | An optional lvalue to an instance of ``boost::asio::io_service`` which allows the server to use | +| | | an already-constructed ``boost::asio::io_service`` instance instead of instantiating one that it | +| | | manages. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| reuse_address | ``bool`` | A boolean that specifies whether to re-use the address and port on which the server will be | +| | | bound to. This enables or disables the socket option for listener sockets. The default is | +| | | ``false``. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| report_aborted | ``bool`` | A boolean that specifies whether the listening socket should report aborted connection attempts | +| | | to the accept handler (an internal detail of cpp-netlib). This is put in place to allow for | +| | | future-proofing the code in case an optional error handler function is supported in later | +| | | releases of cpp-netlib. The default is ``false``. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| receive_buffer_size | ``int`` | The size of the socket's receive buffer. The default is defined by Boost.Asio and is | +| | | platform-dependent. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| send_buffer_size | ``int`` | The size of the socket's send buffer. The default is defined by Boost.Asio and is | +| | | platform-dependent. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| receive_low_watermark | ``int`` | The size of the socket's low watermark for its receive buffer. The default is defined by | +| | | Boost.Asio and is platform-dependent. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| send_buffer_size | ``int`` | The size of the socket's send low watermark for its send buffer. The default is defined by | +| | | Boost.Asio and is platform-dependent. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| non_blocking_io | ``bool`` | An optional bool to define whether the socket should use non-blocking I/O in case the platform | +| | | supports it. The default is ``true``. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| linger | ``bool`` | An optional bool to determine whether the socket should linger in case there's still data to be | +| | | sent out at the time of its closing. The default is ``true``. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| linger_timeout | ``int`` | An optional int to define the timeout to wait for socket closes before it is set to linger. | +| | | The default is ``0``. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| context | ``shared_ptr`` | An optional shared pointer to an instance of ``boost::asio::ssl::context`` -- this contains the | +| | | settings needed to support SSL. This parameter is only applicable for ``async_server`` instances.| ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ + +To use the above supported named parameters, you'll have code that looks like the following: + +.. code-block:: c++ + + using namespace boost::network::http; // parameters are in this namespace + handler handler_instance; + sync_server::options options(handler_instance); + options.address("0.0.0.0") + .port("80") + .io_service(boost::make_shared()) + .reuse_address(true); + sync_server instance(options); + instance.run(); + +Public Members +`````````````` + +The following definitions assume that a properly constructed ``http_server`` +instance has been constructed in the following manner: + +.. code-block:: c++ + + handler_type handler; + http_server::options options(handler); + http_server server(options.address("127.0.0.1").port("8000")); + +``server.run()`` + Run the HTTP Server event loop. This function can be run on multiple threads + following the example: + +.. code-block:: c++ + + boost::thread t1(boost::bind(&http_server::run, &server)); + boost::thread t2(boost::bind(&http_server::run, &server)); + server.run(); + t1.join(); + t2.join(); + +``server.stop()`` + Stop the HTTP Server acceptor and wait for all pending requests to finish. + +Response Object +``````````````` + +The response object has its own public member functions which can be very +helpful in certain simple situations. + +``response = http_server::response::stock_reply(status, body)`` + Code like the above should go inside the handler's ``operator()`` overload. + The body parameter is an ``std::string``. The status parameter is any of + the following values from the ``http_server::response`` enum + ``status_type``: + +.. code-block:: c++ + + enum status_type { + ok = 200, + created = 201, + accepted = 202, + no_content = 204, + multiple_choices = 300, + moved_permanently = 301, + moved_temporarily = 302, + not_modified = 304, + bad_request = 400, + unauthorized = 401, + forbidden = 403, + not_found = 404, + not_supported = 405, + not_acceptable = 406, + internal_server_error = 500, + not_implemented = 501, + bad_gateway = 502, + service_unavailable = 503 + }; + +The response object also has the following publicly accessible member values +which can be directly manipulated by the handler. + ++------------------+----------------------+------------------------------------+ +| Member Name | Type | Description | ++==================+======================+====================================+ +| status | ``status_type`` | The HTTP status of the response. | ++------------------+----------------------+------------------------------------+ +| headers | ``vector
`` | Vector of headers. [#]_ | ++------------------+----------------------+------------------------------------+ +| content | ``string_type`` [#]_ | The contents of the response. | ++------------------+----------------------+------------------------------------+ + +.. [#] A header is a struct of type + ``response_header``. An instance always has the + members ``name`` and ``value`` both of which are of type ``string_type``. +.. [#] ``string_type`` is + ``boost::network::string::type``. + +Asynchronous Servers +-------------------- + +The asynchronous server implementation is significantly different to the +synchronous server implementation in three ways: + + #. **The Handler instance is invoked asynchronously**. This means the I/O + thread used to handle network-related events are free to handle only the + I/O related events. This enables the server to scale better as to the + number of concurrent connections it can handle. + #. **The Handler is able to schedule asynchronous actions on the thread pool + associated with the server.** This allows handlers to perform multiple + asynchronous computations that later on perform writes to the connection. + #. **The Handler is able to control the (asynchronous) writes to and reads from + the HTTP connection.** Because the connection is available to the Handler, + that means it can write out chunks of data at a time or stream data through + the connection continuously. + +The asynchronous server is meant to allow for better scalability in terms of the +number of concurrent connections and for performing asynchronous actions within +the handlers. If your application does not need to write out information +asynchronously or perform potentially long computations, then the synchronous +server gives a generally better performance profile than the asynchronous +server. + +The asynchronous server implementation is available from a single user-facing +template named ``async_server``. This template takes in a single template +parameter which is the type of the Handler to be called once a request has been +parsed from a connection. + +An instance of Handler is taken as a reference to the constructor similar to the +synchronous server implementation. + +.. warning:: The asynchronous server implementation, like the synchronous server + implementation, does not perform any synchronization on the calls to the + Handler invocation. This means if your handler contains or maintains internal + state, you are responsible for implementing your own synchronization on + accesses to the internal state of the Handler. + +The general pattern for using the ``async_server`` template is shown below: + +.. code-block:: c++ + + struct handler; + typedef boost::network::http::async_server http_server; + + struct handler { + void operator()( + http_server::request const & req, + http_server::connection_ptr connection + ) { + // handle the request here, and use the connection to + // either read more data or write data out to the client + } + }; + +API Documentation +~~~~~~~~~~~~~~~~~ + +The following sections assume that the following file has been included: + +.. code-block:: c++ + + #include + #include + +And that the following typedef's have been put in place: + +.. code-block:: c++ + + struct handler_type; + typedef boost::network::http::server http_server; + + struct handler_type { + void operator()(http_server::request const & request, + http_server::connection_ptr connection) { + // do something here + } + }; + +Constructor +``````````` + +``explicit http_server(options)`` + Construct an HTTP server instance passing in a ``server_options`` instance. + +Public Members +`````````````` + +The following definitions assume that a properly constructed ``http_server`` +instance has been constructed in the following manner: + +.. code-block:: c++ + + handler_type handler; + http_server::options options(handler); + options.thread_pool(boost::make_shared(2)); + http_server server(options.address("127.0.0.1").port("8000")); + +``server.run()`` + Run the HTTP Server event loop. This function can be run on multiple threads + following the example: + +.. code-block:: c++ + + boost::thread t1(boost::bind(&http_server::run, &server)); + boost::thread t2(boost::bind(&http_server::run, &server)); + server.run(); + t1.join(); + t2.join(); + +``server.stop()`` + Stop the HTTP Server acceptor and wait for all pending requests to finish. + +Connection Object +````````````````` + +The connection object has its own public member functions which will be the +primary means for reading from and writing to the connection. + +``template write(Range range)`` + The connection object exposes a function ``write`` that can be given a + parameter that adheres to the Boost.Range_ ``Single Pass Range`` Concept. + The write function, although it looks synchronous, starts of a series of + asynchronous writes to the connection as soon as the range is serialized to + appropriately sized buffers. + + To use this in your handler, it would look something like this: + +.. code-block:: c++ + + connection->write("Hello, world!"); + std::string sample = "I have a string!"; + connection->write(sample); + +``template void write(Range range, Callback callback)`` + The connection object also exposes a function ``write`` that can be given a + parameter that adheres to the Boost.Range_ ``Single Pass Range`` Concept, as + well as a Callback function that returns ``void`` and takes a + ``boost::system::error_code`` as a parameter. This overload of ``write`` is + useful for writing streaming applications that send out chunks of data at a + time, or for writing data that may not all fit in memory right away. + +``template void read(ReadCallback callback)`` + The connection object has a function ``read`` which can be used to read more + information from the connection. This ``read`` function takes in a callback + that can be assigned to a Boost.Function_ with the signature + ``void(input_range,error_code,size_t,connection_ptr)``. The following list + shows what the types actually mean: + + * **input_range** -- ``boost::iterator_range`` : The range + that denotes the data read from the connection. + * **error_code** -- ``boost::system::error_code`` : The error code if + there were any errors encountered from the read. + * **size_t** -- ``std::size_t`` : The number of bytes transferred. + * **connection_ptr** -- ``http_server::connection_ptr`` : A handle to the + current connection, so that it is kept alive at the time of the read + callback invocation. + + This interface is useful when doing reads of uploaded data that can be + potentially large and may not fit in memory. The read handler is then + responsible for dealing with the chunks of data available from the + connection. + +``void set_status(status_t new_status)`` + The ``set_status`` function takes a parameter of type ``status_t`` which is + an enum type nested in ``http_status::connection`` which is given in the + following code listing. + +.. code-block:: c++ + + enum status_t { + ok = 200 + , created = 201 + , accepted = 202 + , no_content = 204 + , multiple_choices = 300 + , moved_permanently = 301 + , moved_temporarily = 302 + , not_modified = 304 + , bad_request = 400 + , unauthorized = 401 + , forbidden = 403 + , not_found = 404 + , not_supported = 405 + , not_acceptable = 406 + , internal_server_error = 500 + , not_implemented = 501 + , bad_gateway = 502 + , service_unavailable = 503 + }; + +.. note:: You may set and re-set the status several times as long as you have + not set the headers or sent data through the connection. If you do this after + data has already been set, the function will throw an instance of + ``std::logic_error``. + +``template void set_headers(Range range)`` + The ``set_headers`` function takes a Single Pass Range of + ``boost::network::http::response_header`` + instances and linearizes them to a buffer with at most + ``BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE`` and + immediately schedules an asynchronous write once that is done. + + The function throws an instance of ``std::logic_error`` if you try to set + the headers for a connection more than once. + +Adding SSL support to Asynchronous Server +----------------------------------------- + +In order to setup SSL support for an Asynchronous Server, it is best to start from +a regular Asynchronous Server (see above). Once this server is setup, SSL can be +enabled by adding a Boost.Asio.Ssl.Context_ to the options. The settings that can be +used are defined in the link. + +.. code-block:: c++ + + // Initialize SSL context + boost::shared_ptr ctx = boost::make_shared(boost::asio::ssl::context::sslv23); + ctx->set_options( + boost::asio::ssl::context::default_workarounds + | boost::asio::ssl::context::no_sslv2 + | boost::asio::ssl::context::single_dh_use); + + // Set keys + ctx->set_password_callback(password_callback); + ctx->use_certificate_chain_file("server.pem"); + ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem); + ctx->use_tmp_dh_file("dh512.pem"); + + handler_type handler; + http_server::options options(handler); + options.thread_pool(boost::make_shared(2)); + http_server server(options.address("127.0.0.1").port("8442").context(ctx)); + + std::string password_callback(std::size_t max_length, boost::asio::ssl::context_base::password_purpose purpose) { + return std::string("test"); + } + +.. _Boost.Range: http://www.boost.org/libs/range +.. _Boost.Function: http://www.boost.org/libs/function +.. _Boost.Asio.SSL.Context: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/ssl__context.html diff --git a/cpp-netlib/libs/network/doc/html/_sources/references.txt b/cpp-netlib/libs/network/doc/html/_sources/references.txt new file mode 100644 index 00000000..7f2c97d4 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/references.txt @@ -0,0 +1,25 @@ +References +========== + +About :mod:`cpp-netlib` +~~~~~~~~~~~~~~~~~~~~~~~ + +* `BoostCon 2010 Slides`_ +* `BoostCon 2010 Paper`_ + +Other sources +~~~~~~~~~~~~~ + +* `Template Metaprogramming`_: The best guide to C++ template metaprogramming. +* `HTTP 1.0`_: The HTTP 1.0 specification. +* `HTTP 1.1 (RFC 2616)`_: The HTTP 1.1 specification. +* `URI Generic Syntax (RFC 3986)`_: Generic URI syntax specification. +* `Format for Literal IPv6 Addresses in URLs (RFC 2732)`_: Literal IPv6 Addresses in URLs. + +.. _`BoostCon 2010 Slides`: http://www.filetolink.com/b0e89d06 +.. _`BoostCon 2010 Paper`: http://github.com/downloads/mikhailberis/cpp-netlib-boostcon-paper/cpp-netlib.pdf +.. _`Template Metaprogramming`: http://www.boostpro.com/mplbook/ +.. _`HTTP 1.0`: http://www.w3.org/Protocols/HTTP/1.0/spec.html +.. _`HTTP 1.1 (RFC 2616)`: http://www.w3.org/Protocols/rfc2616/rfc2616.html +.. _`URI Generic Syntax (RFC 3986)`: http://www.ietf.org/rfc/rfc3986.txt +.. _`Format for Literal IPv6 Addresses in URLs (RFC 2732)`: http://www.ietf.org/rfc/rfc2732.txt diff --git a/cpp-netlib/libs/network/doc/html/_sources/techniques.txt b/cpp-netlib/libs/network/doc/html/_sources/techniques.txt new file mode 100644 index 00000000..b52bf7e3 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/techniques.txt @@ -0,0 +1,12 @@ +Techniques +========== + +The :mod:`cpp-netlib` uses several advanced techniques to achieve it's +aims. This chapter describes some of those techniques. + +.. toctree:: + :maxdepth: 1 + + techniques/tag_metafunctions + techniques/directives + techniques/polymorphism diff --git a/cpp-netlib/libs/network/doc/html/_sources/techniques/directives.txt b/cpp-netlib/libs/network/doc/html/_sources/techniques/directives.txt new file mode 100644 index 00000000..e40882d9 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/techniques/directives.txt @@ -0,0 +1,92 @@ +Directives +========== + +The :mod:`cpp-netlib` uses a technique for allowing message-passing +semantics in a chainable fashion in the form of directives. The basic +concept for directives is, in a general sense, an encapsulated +transformation that can be applied to objects that abide by the +directive protocol. + +Using the object-oriented notion of message passing, where an object +accepts a message (usually a function call) we define a simple DSEL in +order for the protocol to be supported by certain object types. In the +:mod:`cpp-netlib` the protocol implemented is similar to that of the +standard iostream formatting system: + +.. code-block:: c++ + + object << directive1(...) + << directive2(...) + ... + << directiveN(...); + +In :mod:`cpp-netlib` the directives are simple function objects that +take a target object as reference and returns a reference to the same +object as a result. In code the directive pattern looks like the +following: + +.. code-block:: c++ + + struct directive_type { + template + Input & operator()(Input & input) const { + // do something to input + return input; + } + }; + +To simplify directive creation, usually factory or generator functions +are defined to return concrete objects of the directive's type. + +.. code-block:: c++ + + inline + directive_type directive(...) { + return directive_type(); + } + +The trivial implementation of the directive protocol then boils down +to the specialization of the shift-left operator on the target type. + +.. code-block:: c++ + + template + inline target_type & operator<< + (target_type & x, Directive const & f) { + return f(x); + } + +.. todo:: + + An example using a directive. + +The rationale for implementing directives include the following: + + * **Encapsulation** - by moving logic into the directive types the + target object's interface can remain rudimentary and even hidden + to the user's immediate attention. Adding this layer of + indirection also allows for changing the underlying + implementations while maintaining the same syntactic and semantic + properties. + * **Flexibility** - by allowing the creation of directives that are + independent from the target object's type, generic operations can + be applied based on the concept being modeled by the target + type. The flexibility also afforded comes in the directive's + generator function, which can also generate different concrete + directive specializations based on parameters to the function. + * **Extensibility** - because the directives are independent of the + target object's type, new directives can be added and supported + without having to change the target object at all. + * **Reuse** - truly generic directives can then be used for a broad + set of target object types that model the same concepts supported + by the directive. Because the directives are self-contained + objects, the state and other object references it keeps are only + accessible to it and can be re-used in different contexts as well. + +Extending a system that uses directives is trivial in header-only +systems because new directives are simply additive. The protocol is +simple and can be applied to a broad class of situations. + +In a header-only library, the static nature of the wiring and chaining +of the operations lends itself to compiler abuse. A deep enough +nesting of the directives can lead to prolonged compilation times. diff --git a/cpp-netlib/libs/network/doc/html/_sources/techniques/polymorphism.txt b/cpp-netlib/libs/network/doc/html/_sources/techniques/polymorphism.txt new file mode 100644 index 00000000..d5e42f8c --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/techniques/polymorphism.txt @@ -0,0 +1,92 @@ +Static and dynamic polymorphism +=============================== + + +With a header only library, you can only do so much with static +polymorphism alone. There are some situations where you have to handle +dynamic polymorphism because of unavoidable runtime-based decision +making. Although you can deal with the base types that remain static, +behavior can vary greatly which derived type should be handling the +situation based on runtime values. + +This situation comes up in the :mod:`cpp-netlib` when we decide what +kind of connection handler to use for a given HTTP URI -- whether it's +plain HTTP or HTTPS. Although the HTTP semantics are the same for +HTTP and HTTPS the implementation of the connection handler greatly +varies on whether to use a plain TCP connection or an SSL-wrapped TCP +connection. + +The general pattern or technique is to combine tag-based dispatch with +a strategy factory, all while not requiring any externally built +libraries. Doing it in a header-only library requires a little +creativity and additional layers of indirection that you otherwise +will not need for a library with externally built static/dynamic +libraries. + +First we define the base type which we want to support dynamic +behavior with. There's nothing special with the base type, except +that it supports the tag dispatch earlier defined and has a virtual +destructor. In code it looks like this: + +.. code-block:: c++ + + template + struct base { + virtual void foo() = 0; // make this an abstract base + virtual ~base() { + // do the base destructor thing here. + } + }; + +We then define a set of derived types that specialize the +implementation of the ``foo`` member function. To facilitate the +dispatch of the correct type based on an input, we create a strategy +factory function: + +.. code-block:: c++ + + template + unique_ptr > strategy(int input, Tag) { + unique_ptr > ptr; + switch(input) { + case 0: ptr.reset(new derived0()); break; + case 1: ptr.reset(new derived1()); break; + // ... + default: ptr.reset(0); break; + } + return ptr; + } + + unique_ptr > ptr = + strategy(input, default_()); // input is a runtime value + +The strategy factory can be a standalone function, or a static member +of a factory class that is specialized by tag dispatch. This can be +done like the following: + +.. code-block:: c++ + + template + struct strategy; + + template <> + struct strategy { + static unique_ptr > create(int input) { + unique_ptr > ptr; + switch(input) { + case 0: ptr.reset(new derived0()); break; + case 1: ptr.reset(new derived1()); break; + //... + default: ptr.reset(0); break; + } + return ptr; + } + }; + +This approach allows the header-only libraries to define new dynamic +types in subsequent versions of the library while keeping the +static-dynamic bridge fluid. The only down-side to this is the +possibility of derived type explosion in case there are a lot of +different strategies or specializations available -- this though is +not unique to static-dynamic bridging, but is also a problem with pure +object oriented programming with dynamic polymorphism. diff --git a/cpp-netlib/libs/network/doc/html/_sources/techniques/tag_metafunctions.txt b/cpp-netlib/libs/network/doc/html/_sources/techniques/tag_metafunctions.txt new file mode 100644 index 00000000..68edd144 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/techniques/tag_metafunctions.txt @@ -0,0 +1,172 @@ +Tag metafunctions +================= + +Sometimes you want to vary a function or a type's behavior based on a +static parameter. In the :mod:`cpp-netlib` there are a number of +things you might want to change based on some such parameter -- like +what the underlying string type should be and how large a buffer +should be, among other things. The primary way to define this in a +header-only manner is to use tag-based metafunctions. + +The skeleton of the approach is based on a similar technique for +defining type traits. In the :mod:`cpp-netlib` however the type traits +are defined on opaque tag types which serve to associate results to a +family of metafunctions. + +Template Specialization +----------------------- + +To illustrate this point, let's define a tag ``default_`` which we use +to denote the default implementation of a certain type ``foo``. For +instance we decide that the default string type we will use for +``default_`` tagged ``foo`` specializations will be an +``std::string``. + +In the :mod:`cpp-netlib` this is done by defining a ``string`` +metafunction type that is specialized on the tag ``default_`` whose +nested ``type`` result is the type ``std::string``. In code this would +translate to: + +.. code-block:: c++ + + template + struct string { + typedef void type; + }; + + struct default_; + + template <> + struct string { + typedef std::string type; + }; + +Template Metaprogramming +------------------------ + +Starting with version 0.7, the tag dispatch mechanism changed slightly to use +Boost.MPL_. The idea is still the same, although we can get a little smarter +than just using template specializations. Instead of just defining an opaque +type ``default_``, we use the Boost.MPL equivalent of a vector to define which +root types of properties this ``default_`` tag supports. The idea is to make the +opaque type ``default_`` inherit property tags which the library supports +internally as definite extension points. + +.. _Boost.MPL: http://www.boost.org/libs/mpl/index.html + +Our definition of the ``default_`` tag will then look something like the +following: + +.. code-block:: c++ + + typedef mpl::vector default_tags; + + template + struct components; + + typedef mpl::inherit_linearly< + default_tags, + mpl::inherit + >::type default_; + + template + struct components { + typedef default_tags type; + }; + +In the above listing, ``default_string`` is what we call a "root" tag which is +meant to be combined with other "root" tags to form composite tags. In this case +our composite tag is the tag ``default_``. There are a number of these "root" +tags that :mod:`cpp-netlib` provides. These are in the namespace +``boost::network::tags`` and are defined in ``boost/network/tags.hpp``. + +Using this technique we change slightly our definition of the ``string`` +metafunction class into this: + +.. code-block:: c++ + + template + struct unsupported_tag; + + template + struct string : + mpl::if_< + is_base_of< + tags::default_string, + Tag + >, + std::string, + unsupported_tag + > + {}; + +Notice that we don't have the typedef for ``type`` in the body of ``string`` +anymore, but we do inherit from ``mpl::if_``. Since ``mpl::if_`` is a template +metafunction itself, it contains a definition of the resulting ``type`` which +``string`` inherits. + +You can see the real definition of the ``string`` metafunction in +``boost/network/traits/string.hpp``. + +Using Tags +---------- + +Once we have the defined tag, we can then use this in the definition of our +types. In the definition of the type ``foo`` we use this type function +``string`` and pass the tag type parameter to determine what to use as +the string type in the context of the type ``foo``. In code this would +translate into: + +.. code-block:: c++ + + template + struct foo { + typedef typename string::type string_type; + + // .. use string_type where you need a string. + }; + +Using this approach we can support different types of strings for +different tags on the type ``foo``. In case we want to use a different +type of string for the tag ``default_`` we only change the +composition of the ``string_tags`` MPL vector. For example, in :mod:`cpp-netlib` +there is a root tag ``default_wstring`` which causes the ``string`` metafunction +to define ``std::wstring`` as the resulting type. + +The approach also allows for the control of the structure and features +of types like ``foo`` based on the specialization of the tag. Whole +type function families can be defined on tags where they are supported +and ignored in cases where they are not. + +To illustrate let's define a new tag ``swappable``. Given the above +definition of ``foo``, we want to make the ``swappable``-tagged +``foo`` define a ``swap`` function that extends the original +``default_``-tagged ``foo``. In code this would look like: + +.. code-block:: c++ + + struct swappable; + + template <> + struct foo : foo { + void swap(foo & other) { + // ... + } + }; + +We also for example want to enable an ADL-reachable ``swap`` function: + +.. code-block:: c++ + + struct swappable; + + inline + void swap(foo & left, foo & right) { + left.swap(right); + } + +Overall what the tag-based definition approach allows is for static +definition of extension points that ensures type-safety and +invariants. This keeps the whole extension mechanism static and yet +flexible. + diff --git a/cpp-netlib/libs/network/doc/html/_sources/whats_new.txt b/cpp-netlib/libs/network/doc/html/_sources/whats_new.txt new file mode 100644 index 00000000..e09530a2 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_sources/whats_new.txt @@ -0,0 +1,229 @@ +.. _whats_new: + +************ + What's New +************ + +:mod:`cpp-netlib` 0.11 +---------------------- + +v0.11.2 +~~~~~~~ +* Support a source_port setting for connections made by the client per-request. +* Allow using cpp-netlib without OpenSSL. +* Fix build breakage for Visual Studio 2015. +* Add more options for HTTP client use of SSL/TLS options/ciphers. +* Made client_get_timeout_test less flaky. +* Fixes to URI encoding issues with multibyte strings. +* Make cpp-netlib not crash on unstable networks. +* Allow parsing empty query parameters (`#499`_). +* CMake build changes to simplify dependencies on cppnetlib-client-connections. +* Handle EOF correctly (`#496`_). +* Fix fileserver example to chunk data correctly. +* Copy hostname to avoid dangling reference to a temporary request object. (`#482`_) +* Catch exceptions in parse_headers to avoid propagating issues in parsing upwards. +* Fix some GCC warnings on signed/unsigned comparison. +* Support environment variable-based peer verification (via OpenSSL). +* Support IPv6 connections. +* Support certificate-based verification, and option to always verify hosts. + +.. _`#499`: https://github.com/cpp-netlib/cpp-netlib/issues/499 +.. _`#496`: https://github.com/cpp-netlib/cpp-netlib/issues/496 +.. _`#482`: https://github.com/cpp-netlib/cpp-netlib/issues/482 + + +v0.11.1 +~~~~~~~ +* Add support for request timeouts. +* Build configuration fixes. +* Support for Travis CI in-project config. +* Make the response parser more flexible to support older/ad-hoc servers that don't have standard format responses. +* Fix some instability in the client destructor. +* MSVC 2010 specific fixes. + +v0.11.0 +~~~~~~~ +* Fix thread leak in DNS resolution failure (`#245`_) +* Remove unsupported `client_fwd.hpp` header (`#277`_) +* Remove support for header-only usage (`#129`_) -- this means that the BOOST_NETWORK_NO_LIB option is no longer actually supported. +* Deprecate Synchronous Client implementations (`#279`_) +* Support streaming body chunks for PUT/POST client requests (`#27`_) +* Fix non-case-sensitive header parsing for some client tags (`#313`_) +* Remove unsupported Jamfiles from the whole project (`#316`_) +* Add ``make install`` for Linux and OS X (`#285`_) +* Fix incorrect Body processing (`#69`_) +* Support chunked transfer encoding from HTTP responses (`#86`_) +* Make OS X Clang builds use C++11 and libc++. +* Update Boost requirement to 1.54.0. +* Experimental Base64 encoding/decoding library (`#287`_) +* *Known test failure:* OS X Xcode Clang 5.0 + Boost 1.54.0 + libc++ don't play + well with Boost.Serialization issues, mitigate test breakage but + ``cpp-netlib-utils_base64_test`` still fails in this platform. (`#287`_) +* Provide a client option to always validate peers for HTTPS requests made by + the client. (`#349`_) +* Back-port fix for `#163`_ for improved URI parsing. +* Added support for client-side certificates and private keys (`#361`_). + +.. _`#129`: https://github.com/cpp-netlib/cpp-netlib/issues/129 +.. _`#163`: https://github.com/cpp-netlib/cpp-netlib/issues/163 +.. _`#245`: https://github.com/cpp-netlib/cpp-netlib/issues/245 +.. _`#277`: https://github.com/cpp-netlib/cpp-netlib/issues/277 +.. _`#279`: https://github.com/cpp-netlib/cpp-netlib/issues/279 +.. _`#27`: https://github.com/cpp-netlib/cpp-netlib/issues/27 +.. _`#285`: https://github.com/cpp-netlib/cpp-netlib/issues/285 +.. _`#287`: https://github.com/cpp-netlib/cpp-netlib/issues/287 +.. _`#313`: https://github.com/cpp-netlib/cpp-netlib/issues/313 +.. _`#316`: https://github.com/cpp-netlib/cpp-netlib/issues/316 +.. _`#349`: https://github.com/cpp-netlib/cpp-netlib/issues/349 +.. _`#69`: https://github.com/cpp-netlib/cpp-netlib/issues/69 +.. _`#86`: https://github.com/cpp-netlib/cpp-netlib/issues/86 +.. _`#361`: https://github.com/cpp-netlib/cpp-netlib/pull/361 + +:mod:`cpp-netlib` 0.10 +---------------------- + +v0.10.1 +~~~~~~~ +* Documentation updates (`#182`_, `#265`_, `#194`_, `#233`_, `#255`_) +* Fix issue with async server inadvertently stopping from listening when + accepting a connection fails. (`#172`_) +* Allow overriding and ultimately removing defaulted headers from HTTP + requests. (`#263`_) +* Add `-Wall` to the base rule for GCC builds. (`#264`_) +* Make the server implementation throw on startup errors. (`#166`_) + +.. _`#182`: https://github.com/cpp-netlib/cpp-netlib/issues/182 +.. _`#265`: https://github.com/cpp-netlib/cpp-netlib/issues/265 +.. _`#194`: https://github.com/cpp-netlib/cpp-netlib/issues/194 +.. _`#172`: https://github.com/cpp-netlib/cpp-netlib/issues/172 +.. _`#263`: https://github.com/cpp-netlib/cpp-netlib/issues/263 +.. _`#233`: https://github.com/cpp-netlib/cpp-netlib/issues/233 +.. _`#264`: https://github.com/cpp-netlib/cpp-netlib/issues/264 +.. _`#255`: https://github.com/cpp-netlib/cpp-netlib/issues/255 +.. _`#166`: https://github.com/cpp-netlib/cpp-netlib/issues/166 + +v0.10.0 +~~~~~~~ +* Added support for more HTTP status codes (206, 408, 412, 416, 507). +* Refactored the parser for chunked encoding. +* Fixed parsing chunked encoding if the response body has ``CLRFCLRF``. +* Added librt dependency on Linux. +* Check the callback in the asynchronous client before calling it. +* Fixed issues `#110`_, `#168`_, `#213`_. + +.. _`#110`: https://github.com/cpp-netlib/cpp-netlib/issues/110 +.. _`#168`: https://github.com/cpp-netlib/cpp-netlib/issues/168 +.. _`#213`: https://github.com/cpp-netlib/cpp-netlib/issues/213 + +:mod:`cpp-netlib` 0.9 +--------------------- + +v0.9.5 +~~~~~~ +* Removed dependency on Boost.Parameter from HTTP client and server. +* Fixed for Clang error on Twitter example. +* Added source port to the request (HTTP server). +* Updated CMake config for MSVC 2010/2012. +* Now support chunked content encoding in client response parsing. +* Fixed bug with client not invoking callback when a request fails. + +v0.9.4 +~~~~~~ +* Lots of URI fixes. +* Fixed async_server's request handler so it doesn't make copies of the supplied handler. +* Fix for issue `#73`_ regarding SSL connections ending in short read errors. +* Final C++03-only release. + +.. _`#73`: https://github.com/cpp-netlib/cpp-netlib/issues/73 + +v0.9.3 +~~~~~~ +* URI, HTTP client and HTTP server are now built as static libraries (``libcppnetlib-uri.a``, ``libcppnetlib-client-connections.a`` and ``libcppnetlib-server-parsers.a`` on Linux and ``cppnetlib-uri.lib``, ``cppnetlib-client-connections.lib`` and ``cppnetlib-server-parsers.lib`` on Windows). +* Updated URI parser. +* A new URI builder. +* URI support for IPv6 RFC 2732. +* Fixed issues `#67`_, `#72`_, `#78`_, `#79`_, `#80`_, `#81`_, `#82`_, `#83`_. +* New examples for the HTTP client, including an Atom feed, an RSS feed and a + very simple client that uses the Twitter Search API. + +.. _`#67`: https://github.com/cpp-netlib/cpp-netlib/issues/67 +.. _`#72`: https://github.com/cpp-netlib/cpp-netlib/issues/72 +.. _`#78`: https://github.com/cpp-netlib/cpp-netlib/issues/78 +.. _`#79`: https://github.com/cpp-netlib/cpp-netlib/issues/79 +.. _`#80`: https://github.com/cpp-netlib/cpp-netlib/issues/80 +.. _`#81`: https://github.com/cpp-netlib/cpp-netlib/issues/81 +.. _`#82`: https://github.com/cpp-netlib/cpp-netlib/issues/82 +.. _`#83`: https://github.com/cpp-netlib/cpp-netlib/issues/83 + +v0.9.2 +~~~~~~ +* Critial bug fixes to v0.9.1. + +v0.9.1 +~~~~~~ +* Introduced macro ``BOOST_NETWORK_DEFAULT_TAG`` to allow for programmatically + defining the default flag to use throughout the compilation unit. +* Support for streaming body handlers when performing HTTP client operations. + See documentation for HTTP client interface for more information. +* Numerous bug fixes from v0.9.0. +* Google, Inc. contributions. + +v0.9.0 +~~~~~~ +* **IMPORTANT BREAKING CHANGE**: By default all compile-time heavy parser + implementations are now compiled to external static libraries. In order to use + :mod:`cpp-netlib` in header-only mode, users must define the preprocessor + macro ``BOOST_NETWORK_NO_LIB`` before including any :mod:`cpp-netlib` header. + This breaks code that relied on the version 0.8.x line where the library is + strictly header-only. +* Fix issue #41: Introduce a macro ``BOOST_NETWORK_HTTP_CLIENT_DEFAULT_TAG`` + which makes the default HTTP client use ``tags::http_async_8bit_udp_resolve`` + as the tag. +* Fix issue #40: Write the status line and headers in a single buffer write + instead of two writes. +* More consistent message API for client and server messages (request and + response objects). +* Refactoring of internal implementations to allow better separation of concerns + and more manageable coding/documentation. +* Client and server constructors that support Boost.Parameter named parameters. +* Client and server constructors now take in an optional reference to a Boost.Asio + ``io_service`` to use internally. +* Documentation updates to reflect new APIs. + +:mod:`cpp-netlib` 0.8 +--------------------- + +* Updates to URI unit tests and documentation. +* More documentation, covering the HTTP Client and HTTP Server APIs +* Asynchronous HTTP Server that now supports running request handlers on a + different thread pool. +* An initial thread pool implementation, using Boost.Asio underneath. +* Adding a ready(...) wrapper to check whether a response object returned by + the asynchronous client in 0.7 already has all the parts available. +* Some attempts at lowering compile time costs. + +:mod:`cpp-netlib` 0.7 +--------------------- + +* Radical documentation overhaul +* Asynchronous HTTP client +* Tag dispatch overhaul, using Boost.MPL +* HTTP Client Facade refactoring +* Bug fixes for HTTP 1.1 response parsing +* Minimized code repetition with some header macro's +* Configurable HTTPS support in the library with ``BOOST_NETWORK_ENABLE_HTTPS`` + + +:mod:`cpp-netlib` 0.6 +--------------------- + +* Many fixes for MSVC compiler + +:mod:`cpp-netlib` 0.5 +--------------------- + +* An embeddable HTTP 1.1 server +* An HTTP 1.1 client upgraded to support HTTPS +* An updated URI parser implementation +* An asynchronous HTTP 1.1 client +* An HTTP 1.1 client that supports streaming function handlers diff --git a/cpp-netlib/libs/network/doc/html/_static/Button-Info-icon.png b/cpp-netlib/libs/network/doc/html/_static/Button-Info-icon.png new file mode 100644 index 00000000..4f318491 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/Button-Info-icon.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/Button-Warning-icon.png b/cpp-netlib/libs/network/doc/html/_static/Button-Warning-icon.png new file mode 100644 index 00000000..edcd6624 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/Button-Warning-icon.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/ajax-loader.gif b/cpp-netlib/libs/network/doc/html/_static/ajax-loader.gif new file mode 100644 index 00000000..61faf8ca Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/ajax-loader.gif differ diff --git a/cpp-netlib/libs/network/doc/html/_static/basic.css b/cpp-netlib/libs/network/doc/html/_static/basic.css new file mode 100644 index 00000000..967e36ce --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/basic.css @@ -0,0 +1,537 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + width: 30px; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/_static/boost.png b/cpp-netlib/libs/network/doc/html/_static/boost.png new file mode 100644 index 00000000..0714ca20 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/boost.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/comment-bright.png b/cpp-netlib/libs/network/doc/html/_static/comment-bright.png new file mode 100644 index 00000000..551517b8 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/comment-bright.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/comment-close.png b/cpp-netlib/libs/network/doc/html/_static/comment-close.png new file mode 100644 index 00000000..09b54be4 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/comment-close.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/comment.png b/cpp-netlib/libs/network/doc/html/_static/comment.png new file mode 100644 index 00000000..92feb52b Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/comment.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/cpp-netlib.css b/cpp-netlib/libs/network/doc/html/_static/cpp-netlib.css new file mode 100644 index 00000000..3c4f3b61 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/cpp-netlib.css @@ -0,0 +1,721 @@ +@import url('reset-fonts-grids.css'); + +html,body +{ + background-repeat: no-repeat; + background-position: left top; + background-attachment: fixed; + background-color: #fa2; +} + +body +{ + font: 12pt sans-serif; + color: black; +} + +#custom-doc +{ + width: 80%; + *width: 960px; + min-width: 960px; + max-width: 1240px; + margin: auto; + text-align: left; + padding-top: 16px; + margin-top: 0; +} + +#hd +{ + padding: 4px 0 12px 0; +} + +#bd +{ + /*background: #C5D88A;*/ +} + +#ft +{ + color: #C5D88A; + font-size: 90%; + padding-bottom: 2em; +} + +pre +{ + font-family: Monaco,monospace; + font-size: 14px; + background: #333; + background: -moz-linear-gradient(-90deg,#333,#222 60%); + background: -webkit-gradient(linear,0 top,0 bottom,from(#333),to(#222),color-stop(60%,#222)); + border-width: 1px 0; + margin: 1em 0; + padding: .3em .4em; + overflow: auto; + line-height: 1.3em; + color: #CCC; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + padding: 1em; +} + +/*** links ***/ +a +{ + text-decoration: none; + font-weight: bold +} + +a img +{ + border: none +} + +a: link,a: visited +{ + color: #800000 +} + +#bd a: link,#bd a: visited +{ + color: #800000; + text-decoration: underline +} + +#bd #sidebar a: link,#bd #sidebar a: visited +{ + color: #8B4513; + text-decoration: none +} + +a: hover +{ + color: #000 +} + +#bd a: hover +{ + background-color: #FF9955; + color: black; + text-decoration: none +} + +#bd #sidebar a: hover +{ + color: #FF9955; + background: none +} + +h2 a,h3 a,h4 a +{ + text-decoration: none !important +} + +a.reference em +{ + /*color: #FF9955;*/ + font-style: normal; + font-weight: bold; +} + +/*** sidebar ***/ +#sidebar div.sphinxsidebarwrapper +{ + font-size: 92%; + margin-right: 14px +} + +#sidebar h3,#sidebar h4 +{ + color: #487858; + font-size: 125% +} + +#sidebar a +{ + color: #8B4513 +} + +#sidebar ul ul +{ + margin-top: 0; + margin-bottom: 0 +} + +#sidebar li +{ + margin-top: 0.2em; + margin-bottom: 0.2em; + list-style-position: inside; + list-style-type: square; +} + +/*** nav ***/ +div.nav +{ + margin: 0; + font-size: 14px; + text-align: right; + color: #fff +} + +div.nav a: link,div.nav a: visited +{ + color: white +} + +#hd div.nav +{ + margin-top: -27px +} + +#ft div.nav +{ + margin-bottom: -18px +} + +#hd h1 a +{ + color: #EFFFEF +} + +#global-nav +{ + position: absolute; + top: 5px; + margin-left: -5px; + padding: 7px 0; + color: #263E2B +} + +#global-nav a +{ + padding: 0 4px +} + +#global-nav a.about +{ + padding-left: 0 +} + +#global-nav a +{ + color: #fff +} + +/*** content ***/ +#yui-main +{ + -moz-border-radius: 3px; + -moz-box-shadow: 0 0 9px rgba(0,0,0,0.5); + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 0 9px rgba(0,0,0,0.5); + border-radius: 3px; + box-shadow: 0 0 9px rgba(0,0,0,0.5); + background: none repeat scroll 0 0 #6ABDFB; +} + +#yui-main div.yui-b +{ + position: relative +} + +#yui-main div.yui-b +{ + background: #FFF; + min-height: 330px; + color: #164B2B; + padding: 0.3em 2em 1em 2em +} + +/*** basic styles ***/ +dd +{ + margin-left: 15px +} + +h1,h2,h3,h4 +{ + margin-top: 1em; + font-weight: normal +} + +h1 +{ + font-size: 218%; + font-weight: bold; + margin-top: 0.6em; + margin-bottom: .4em; + line-height: 1.1em +} + +h2 +{ + font-size: 175%; + font-weight: bold; + margin-bottom: .6em; + line-height: 1.2em; + color: #092e20 +} + +h3 +{ + font-size: 150%; + font-weight: bold; + margin-bottom: .2em; + color: #487858 +} + +h4 +{ + font-size: 125%; + font-weight: bold; + margin-top: 1.5em; + margin-bottom: 3px +} + +div.figure +{ + text-align: center +} + +div.figure p.caption +{ + font-size: 1em; + margin-top: 0; + margin-bottom: 1.5em; + color: black +} + +hr +{ + color: #ccc; + background-color: #ccc; + height: 1px; + border: 0 +} + +p,ul,dl +{ + margin-top: .6em; + color: #333 +} + +#yui-main div.yui-b img +{ + max-width: 50em; + margin-left: auto; + margin-right: auto; + display: block; + margin-top: 10px; + margin-bottom: 10px +} + +caption +{ + font-size: 1em; + font-weight: bold; + margin-top: 0.5em; + margin-bottom: 0.5em; + margin-left: 2px; + text-align: center +} + +blockquote +{ + padding: 0 1em; + margin: 1em 0; + font: "Times New Roman",serif; + color: #234f32 +} + +strong +{ + font-weight: bold +} + +em +{ + font-style: italic +} + +ins +{ + font-weight: bold; + text-decoration: none +} + +/*** lists ***/ +ol.arabic li +{ + list-style-type: decimal +} + +ul li +{ + font-size: 1em +} + +ol li +{ + margin-bottom: .4em +} + +ul ul +{ + padding-left: 1.2em +} + +ul ul ul +{ + padding-left: 1em +} + +ul.linklist,ul.toc +{ + padding-left: 0 +} + +ul.toc ul +{ + margin-left: .6em +} + +ul.toc ul li +{ + list-style-type: square +} + +ul.toc ul ul li +{ + list-style-type: disc +} + +ul.linklist li,ul.toc li +{ + list-style-type: none +} + +dt +{ + font-weight: bold; + margin-top: .5em; + font-size: 1em +} + +dd +{ + margin-bottom: .8em +} + +ol.toc +{ + margin-bottom: 2em +} + +ol.toc li +{ + font-size: 125%; + padding: .5em; + line-height: 1.2em; + clear: right +} + +ol.toc li.b +{ + background-color: #E0FFB8 +} + +ol.toc li a: hover +{ + background-color: transparent !important; + text-decoration: underline !important +} + +ol.toc span.release-date +{ + color: #487858; + float: right; + font-size: 85%; + padding-right: .5em +} + +ol.toc span.comment-count +{ + font-size: 75%; + color: #999 +} + +ul.simple li +{ + list-style-type: disc; + margin-left: 2em +} + +/*** tables ***/ +table +{ + color: #000; + margin-bottom: 1em; + width: 100% +} + +table.docutils td p +{ + margin-top: 0; + margin-bottom: .5em +} + +table.docutils td,table.docutils th +{ + border-bottom: 1px solid #dfdfdf; + padding: 4px 2px +} + +table.docutils thead th +{ + border-bottom: 2px solid #dfdfdf; + text-align: left; + font-weight: bold; + #487858-space: nowrap +} + +table.docutils thead th p +{ + margin: 0; + padding: 0 +} + +table.docutils +{ + border-collapse: collapse +} + +/*** code blocks ***/ +.literal +{ + #487858-space: nowrap +} + +.literal +{ + color: #234f32 +} + +#sidebar .literal +{ + color: #487858; + background: transparent; + font-size: 11px +} + +h4 .literal +{ + color: #234f32; + font-size: 13px +} + +dt .literal,table .literal +{ + background: none +} + +#bd a.reference +{ + text-decoration: none +} + +#bd a.reference tt.literal +{ + border-bottom: 1px #234f32 dotted +} + +/*** notes & admonitions ***/ +.note,.admonition +{ + padding: .8em 1em .8em; + margin: 1em 0; + background-color: #6ABDFB; + -moz-border-radius: 3px; + -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.3); + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.3); + border-radius: 3px; + box-shadow: 0 1px 2px rgba(0,0,0,0.3); +} + +.admonition-title +{ + font-weight: bold; + margin-top: 0 !important; + margin-bottom: 0 !important +} + +.admonition .last +{ + margin-bottom: 0 !important +} + +.note +{ + padding-left: 85px; + background: #6ABDFB url(Button-Info-icon.png) .8em .8em no-repeat +} + +.warning +{ + padding-left: 85px; + background: #6ABDFB url(Button-Warning-icon.png) .8em .8em no-repeat +} + +/*** versoinadded/changes ***/ +div.versionadded,div.versionchanged +{ +} + +div.versionadded span.title,div.versionchanged span.title +{ + font-weight: bold +} + +/*** p-links ***/ +a.headerlink +{ + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; + visibility: hidden +} + +h1: hover > a.headerlink,h2: hover > a.headerlink,h3: hover > a.headerlink,h4: hover > a.headerlink,h5: hover > a.headerlink,h6: hover > a.headerlink,dt: hover > a.headerlink +{ + visibility: visible +} + +/*** index ***/ +table.indextable td +{ + text-align: left; + vertical-align: top +} + +table.indextable dl,table.indextable dd +{ + margin-top: 0; + margin-bottom: 0 +} + +table.indextable tr.pcap +{ + height: 10px +} + +table.indextable tr.cap +{ + margin-top: 10px; + background-color: #f2f2f2 +} + +/*** page-specific overrides ***/ +div#contents ul +{ + margin-bottom: 0 +} + +div#contents ul li +{ + margin-bottom: 0 +} + +div#contents ul ul li +{ + margin-top: 0.3em +} + +/*** IE hacks ***/ +* pre +{ +} + +.footer +{ + color: white; +} + +.footer a +{ + color: #333; +} + +img +{ + margin: 10px 0 10px 0; +} + +#index p.rubric +{ + font-size: 150%; + font-weight: normal; + margin-bottom: .2em; + color: #252; +} + +#index div.section dt +{ + font-weight: normal; +} + +#index #cpp-netlib-getting-cpp-netlib, #index #cpp-netlib-boost { + background:none repeat scroll 0 0 #6ABDFB; + margin: 2em 0 2em 2em; + + border-radius:6px 6px; + -webkit-border-radius:6px; + -moz-border-radius:6px 6px; + + box-shadow:0 1px 2px rgba(0, 0, 0, 0.6); + -webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.6); + -moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.6); + + overflow:visible; + float:right; + clear:both; + padding:1em; + width: 380px; +} + +#index #cpp-netlib-getting-cpp-netlib a +{ + font-weight: bold; + font-size: 14px; +} + +#index #cpp-netlib-getting-cpp-netlib h1 +{ + color: #333; +} + +#index #cpp-netlib-getting-cpp-netlib h2 +{ + margin: 0; +} + +#index #cpp-netlib-getting-cpp-netlib strong +{ + font-size: 20px; +} + +tt.py-exc.literal +{ + color: red; +} + +tt.xref span.pre +{ + color: green; +} + diff --git a/cpp-netlib/libs/network/doc/html/_static/default.css b/cpp-netlib/libs/network/doc/html/_static/default.css new file mode 100644 index 00000000..21f3f509 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/default.css @@ -0,0 +1,256 @@ +/* + * default.css_t + * ~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- default theme. + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: sans-serif; + font-size: 100%; + background-color: #11303d; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + background-color: #1c4e63; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: #ffffff; + color: #000000; + padding: 0 20px 30px 20px; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #ffffff; + text-decoration: underline; +} + +div.related { + background-color: #133f52; + line-height: 30px; + color: #ffffff; +} + +div.related a { + color: #ffffff; +} + +div.sphinxsidebar { +} + +div.sphinxsidebar h3 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: #ffffff; +} + +div.sphinxsidebar h4 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: #ffffff; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: #ffffff; +} + +div.sphinxsidebar a { + color: #98dbcc; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + + + +/* -- hyperlink styles ------------------------------------------------------ */ + +a { + color: #355f7c; + text-decoration: none; +} + +a:visited { + color: #355f7c; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + + + +/* -- body styles ----------------------------------------------------------- */ + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Trebuchet MS', sans-serif; + background-color: #f2f2f2; + font-weight: normal; + color: #20435c; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li { + text-align: justify; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.admonition p { + margin-bottom: 5px; +} + +div.admonition pre { + margin-bottom: 5px; +} + +div.admonition ul, div.admonition ol { + margin-bottom: 5px; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: #eeffcc; + color: #333333; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +tt { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th { + background-color: #ede; +} + +.warning tt { + background: #efc2c2; +} + +.note tt { + background: #d6d6d6; +} + +.viewcode-back { + font-family: sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/_static/dialog-note.png b/cpp-netlib/libs/network/doc/html/_static/dialog-note.png new file mode 100644 index 00000000..263fbd58 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/dialog-note.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/dialog-seealso.png b/cpp-netlib/libs/network/doc/html/_static/dialog-seealso.png new file mode 100644 index 00000000..3eb7b05c Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/dialog-seealso.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/dialog-todo.png b/cpp-netlib/libs/network/doc/html/_static/dialog-todo.png new file mode 100644 index 00000000..babc4b6c Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/dialog-todo.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/dialog-topic.png b/cpp-netlib/libs/network/doc/html/_static/dialog-topic.png new file mode 100644 index 00000000..2ac57475 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/dialog-topic.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/dialog-warning.png b/cpp-netlib/libs/network/doc/html/_static/dialog-warning.png new file mode 100644 index 00000000..7233d45d Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/dialog-warning.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/doctools.js b/cpp-netlib/libs/network/doc/html/_static/doctools.js new file mode 100644 index 00000000..c5455c90 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/doctools.js @@ -0,0 +1,238 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s == 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node) { + if (node.nodeType == 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/cpp-netlib/libs/network/doc/html/_static/down-pressed.png b/cpp-netlib/libs/network/doc/html/_static/down-pressed.png new file mode 100644 index 00000000..6f7ad782 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/down-pressed.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/down.png b/cpp-netlib/libs/network/doc/html/_static/down.png new file mode 100644 index 00000000..3003a887 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/down.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/epub.css b/cpp-netlib/libs/network/doc/html/_static/epub.css new file mode 100644 index 00000000..7465a421 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/epub.css @@ -0,0 +1,310 @@ +/* + * default.css_t + * ~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- default theme. + * + * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: {{ theme_bodyfont }}; + font-size: 100%; + background-color: {{ theme_footerbgcolor }}; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + background-color: {{ theme_sidebarbgcolor }}; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: {{ theme_bgcolor }}; + color: {{ theme_textcolor }}; + padding: 0 20px 30px 20px; +} + +{%- if theme_rightsidebar|tobool %} +div.bodywrapper { + margin: 0 230px 0 0; +} +{%- endif %} + +div.footer { + color: {{ theme_footertextcolor }}; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: {{ theme_footertextcolor }}; + text-decoration: underline; +} + +div.related { + background-color: {{ theme_relbarbgcolor }}; + line-height: 30px; + color: {{ theme_relbartextcolor }}; +} + +div.related a { + color: {{ theme_relbarlinkcolor }}; +} + +div.sphinxsidebar { + {%- if theme_stickysidebar|tobool %} + top: 30px; + bottom: 0; + margin: 0; + position: fixed; + overflow: auto; + height: auto; + {%- endif %} + {%- if theme_rightsidebar|tobool %} + float: right; + {%- if theme_stickysidebar|tobool %} + right: 0; + {%- endif %} + {%- endif %} +} + +{%- if theme_stickysidebar|tobool %} +/* this is nice, but it it leads to hidden headings when jumping + to an anchor */ +/* +div.related { + position: fixed; +} + +div.documentwrapper { + margin-top: 30px; +} +*/ +{%- endif %} + +div.sphinxsidebar h3 { + font-family: {{ theme_headfont }}; + color: {{ theme_sidebartextcolor }}; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: {{ theme_sidebartextcolor }}; +} + +div.sphinxsidebar h4 { + font-family: {{ theme_headfont }}; + color: {{ theme_sidebartextcolor }}; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: {{ theme_sidebartextcolor }}; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: {{ theme_sidebartextcolor }}; +} + +div.sphinxsidebar a { + color: {{ theme_sidebarlinkcolor }}; +} + +div.sphinxsidebar input { + border: 1px solid {{ theme_sidebarlinkcolor }}; + font-family: sans-serif; + font-size: 1em; +} + +{% if theme_collapsiblesidebar|tobool %} +/* for collapsible sidebar */ +div#sidebarbutton { + background-color: {{ theme_sidebarbtncolor }}; +} +{% endif %} + +/* -- hyperlink styles ------------------------------------------------------ */ + +a { + color: {{ theme_linkcolor }}; + text-decoration: none; +} + +a:visited { + color: {{ theme_visitedlinkcolor }}; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +{% if theme_externalrefs|tobool %} +a.external { + text-decoration: none; + border-bottom: 1px dashed {{ theme_linkcolor }}; +} + +a.external:hover { + text-decoration: none; + border-bottom: none; +} + +a.external:visited { + text-decoration: none; + border-bottom: 1px dashed {{ theme_visitedlinkcolor }}; +} +{% endif %} + +/* -- body styles ----------------------------------------------------------- */ + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: {{ theme_headfont }}; + background-color: {{ theme_headbgcolor }}; + font-weight: normal; + color: {{ theme_headtextcolor }}; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: {{ theme_headlinkcolor }}; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: {{ theme_headlinkcolor }}; + color: white; +} + +div.body p, div.body dd, div.body li { + text-align: justify; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.admonition p { + margin-bottom: 5px; +} + +div.admonition pre { + margin-bottom: 5px; +} + +div.admonition ul, div.admonition ol { + margin-bottom: 5px; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: {{ theme_codebgcolor }}; + color: {{ theme_codetextcolor }}; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +tt { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th { + background-color: #ede; +} + +.warning tt { + background: #efc2c2; +} + +.note tt { + background: #d6d6d6; +} + +.viewcode-back { + font-family: {{ theme_bodyfont }}; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} diff --git a/cpp-netlib/libs/network/doc/html/_static/file.png b/cpp-netlib/libs/network/doc/html/_static/file.png new file mode 100644 index 00000000..d18082e3 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/file.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/footerbg.png b/cpp-netlib/libs/network/doc/html/_static/footerbg.png new file mode 100644 index 00000000..1fbc873d Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/footerbg.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/ftp_uri.png b/cpp-netlib/libs/network/doc/html/_static/ftp_uri.png new file mode 100644 index 00000000..f77d3c87 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/ftp_uri.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/headerbg.png b/cpp-netlib/libs/network/doc/html/_static/headerbg.png new file mode 100644 index 00000000..0596f202 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/headerbg.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/http_uri.png b/cpp-netlib/libs/network/doc/html/_static/http_uri.png new file mode 100644 index 00000000..a7bf7561 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/http_uri.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/ie6.css b/cpp-netlib/libs/network/doc/html/_static/ie6.css new file mode 100644 index 00000000..74baa5d5 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/ie6.css @@ -0,0 +1,7 @@ +* html img, +* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none", +this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')", +this.src = "_static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''), +this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')", +this.runtimeStyle.backgroundImage = "none")),this.pngSet=true) +);} diff --git a/cpp-netlib/libs/network/doc/html/_static/jquery.js b/cpp-netlib/libs/network/doc/html/_static/jquery.js new file mode 100644 index 00000000..83589daa --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/_static/mailto_uri.png b/cpp-netlib/libs/network/doc/html/_static/mailto_uri.png new file mode 100644 index 00000000..118d6f4b Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/mailto_uri.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/middlebg.png b/cpp-netlib/libs/network/doc/html/_static/middlebg.png new file mode 100644 index 00000000..2369cfb7 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/middlebg.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/minus.png b/cpp-netlib/libs/network/doc/html/_static/minus.png new file mode 100644 index 00000000..da1c5620 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/minus.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/orange-background.jpg b/cpp-netlib/libs/network/doc/html/_static/orange-background.jpg new file mode 100644 index 00000000..e8ac2b48 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/orange-background.jpg differ diff --git a/cpp-netlib/libs/network/doc/html/_static/plus.png b/cpp-netlib/libs/network/doc/html/_static/plus.png new file mode 100644 index 00000000..b3cb3742 Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/_static/plus.png differ diff --git a/cpp-netlib/libs/network/doc/html/_static/pygments.css b/cpp-netlib/libs/network/doc/html/_static/pygments.css new file mode 100644 index 00000000..d79caa15 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/pygments.css @@ -0,0 +1,62 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/_static/pyramid.css b/cpp-netlib/libs/network/doc/html/_static/pyramid.css new file mode 100644 index 00000000..aa38a96c --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/pyramid.css @@ -0,0 +1,342 @@ +/* + * pyramid.css_t + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- pylons theme. + * + * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: "Nobile", sans-serif; + font-size: 100%; + background-color: #393939; + color: #ffffff; + margin: 0; + padding: 0; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.document { + background-color: #eee; +} + +div.header { + width:100%; + background: #f4ad32 url(headerbg.png) repeat-x 0 top; + border-bottom: 2px solid #ffffff; +} + +div.logo { + text-align: center; + padding-top: 10px; +} + +div.body { + background-color: #ffffff; + color: #3E4349; + padding: 0 30px 30px 30px; + font-size: 1em; + border: 2px solid #ddd; + border-right-style: none; + overflow: auto; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 13px 0; + text-align: center; + font-size: 75%; + background: transparent; + clear:both; +} + +div.footer a { + color: #ffffff; + text-decoration: none; +} + +div.footer a:hover { + color: #e88f00; + text-decoration: underline; +} + +div.related { + line-height: 30px; + color: #373839; + font-size: 0.8em; + background-color: #eee; +} + +div.related a { + color: #1b61d6; +} + +div.related ul { + padding-left: 240px; +} + +div.sphinxsidebar { + font-size: 0.75em; + line-height: 1.5em; +} + +div.sphinxsidebarwrapper{ + padding: 10px 0; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: "Neuton", sans-serif; + color: #373839; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 5px 10px; + border-bottom: 2px solid #ddd; +} + +div.sphinxsidebar h4{ + font-size: 1.3em; +} + +div.sphinxsidebar h3 a { + color: #000000; +} + + +div.sphinxsidebar p { + color: #888; + padding: 5px 20px; +} + +div.sphinxsidebar p.topless { +} + +div.sphinxsidebar ul { + margin: 10px 20px; + padding: 0; + color: #373839; +} + +div.sphinxsidebar a { + color: #444; +} + +div.sphinxsidebar input { + border: 1px solid #ccc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar input[type=text]{ + margin-left: 20px; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 2px solid #c6d880; + background-color: #e6efc2; + width: 40%; + float: right; + border-right-style: none; + border-left-style: none; + padding: 10px 20px; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- body styles ----------------------------------------------------------- */ + +a, a .pre { + color: #1b61d6; + text-decoration: none; +} + +a:hover, a:hover .pre { + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: "Neuton", sans-serif; + background-color: #ffffff; + font-weight: normal; + color: #373839; + margin: 30px 0px 10px 0px; + padding: 5px 0; +} + +div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 150%; background-color: #ffffff; } +div.body h3 { font-size: 120%; background-color: #ffffff; } +div.body h4 { font-size: 110%; background-color: #ffffff; } +div.body h5 { font-size: 100%; background-color: #ffffff; } +div.body h6 { font-size: 100%; background-color: #ffffff; } + +a.headerlink { + color: #1b61d6; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + text-decoration: underline; +} + +div.body p, div.body dd, div.body li { + line-height: 1.5em; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.admonition { + background: #eeeeec; + border: 2px solid #babdb6; + border-right-style: none; + border-left-style: none; + padding: 10px 20px 10px 60px; +} + +div.highlight{ + background-color: white; +} + +div.note { + border: 2px solid #7a9eec; + border-right-style: none; + border-left-style: none; + padding: 10px 20px 10px 60px; + background: #e1ecfe url(dialog-note.png) no-repeat 10px 8px; +} + +div.seealso { + background: #fff6bf url(dialog-seealso.png) no-repeat 10px 8px; + border: 2px solid #ffd324; + border-left-style: none; + border-right-style: none; + padding: 10px 20px 10px 60px; +} + +div.topic { + background: #eeeeee; + border: 2px solid #C6C9CB; + padding: 10px 20px; + border-right-style: none; + border-left-style: none; +} + +div.warning { + background: #fbe3e4 url(dialog-warning.png) no-repeat 10px 8px; + border: 2px solid #fbc2c4; + border-right-style: none; + border-left-style: none; + padding: 10px 20px 10px 60px; +} + +div.admonition-todo { + background: #f2d9b4 url(dialog-todo.png) no-repeat 10px 8px; + border: 2px solid #e9b96e; + border-right-style: none; + border-left-style: none; + padding: 10px 20px 10px 60px; +} + +div.note p.admonition-title, +div.warning p.admonition-title, +div.seealso p.admonition-title, +div.admonition-todo p.admonition-title { + display: none; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 10px; + background-color: #fafafa; + color: #222; + line-height: 1.2em; + border: 2px solid #C6C9CB; + font-size: 1.1em; + margin: 1.5em 0 1.5em 0; + border-right-style: none; + border-left-style: none; +} + +tt { + background-color: transparent; + color: #222; + font-size: 1.1em; + font-family: monospace; +} + +.viewcode-back { + font-family: "Nobile", sans-serif; +} + +div.viewcode-block:target { + background-color: #fff6bf; + border: 2px solid #ffd324; + border-left-style: none; + border-right-style: none; + padding: 10px 20px; +} + +table.highlighttable { + width: 100%; +} + +table.highlighttable td { + padding: 0; +} + +a em.std-term { + color: #007f00; +} + +a:hover em.std-term { + text-decoration: underline; +} + +.download { + font-family: "Nobile", sans-serif; + font-weight: normal; + font-style: normal; +} + +tt.xref { + font-weight: normal; + font-style: normal; +} \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/_static/reset-fonts-grids.css b/cpp-netlib/libs/network/doc/html/_static/reset-fonts-grids.css new file mode 100644 index 00000000..f5238d7c --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/reset-fonts-grids.css @@ -0,0 +1,8 @@ +/* +Copyright (c) 2008, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.5.1 +*/ +html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;font-variant:normal;}sup {vertical-align:text-top;}sub {vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}body {font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}table {font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;} +body{text-align:center;}#ft{clear:both;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;min-width:750px;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}s .yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#bd:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#bd,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;} \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/_static/searchtools.js b/cpp-netlib/libs/network/doc/html/_static/searchtools.js new file mode 100644 index 00000000..6e1f06bd --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/_static/searchtools.js @@ -0,0 +1,622 @@ +/* + * searchtools.js_t + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilties for the full-text search. + * + * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + + + +/** + * Simple result scoring code. + */ +var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [filename, title, anchor, descr, score] + // and returns the new score. + /* + score: function(result) { + return result[4]; + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: {0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5}, // used to be unimportantResults + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + // query found in terms + term: 5 +}; + + +/** + * Search Module + */ +var Search = { + + _index : null, + _queued_query : null, + _pulse_status : -1, + + init : function() { + var params = $.getQueryParameters(); + if (params.q) { + var query = params.q[0]; + $('input[name="q"]')[0].value = query; + this.performSearch(query); + } + }, + + loadIndex : function(url) { + $.ajax({type: "GET", url: url, data: null, + dataType: "script", cache: true, + complete: function(jqxhr, textstatus) { + if (textstatus != "success") { + document.getElementById("searchindexloader").src = url; + } + }}); + }, + + setIndex : function(index) { + var q; + this._index = index; + if ((q = this._queued_query) !== null) { + this._queued_query = null; + Search.query(q); + } + }, + + hasIndex : function() { + return this._index !== null; + }, + + deferQuery : function(query) { + this._queued_query = query; + }, + + stopPulse : function() { + this._pulse_status = 0; + }, + + startPulse : function() { + if (this._pulse_status >= 0) + return; + function pulse() { + var i; + Search._pulse_status = (Search._pulse_status + 1) % 4; + var dotString = ''; + for (i = 0; i < Search._pulse_status; i++) + dotString += '.'; + Search.dots.text(dotString); + if (Search._pulse_status > -1) + window.setTimeout(pulse, 500); + } + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch : function(query) { + // create the required interface elements + this.out = $('#search-results'); + this.title = $('

' + _('Searching') + '

').appendTo(this.out); + this.dots = $('').appendTo(this.title); + this.status = $('

').appendTo(this.out); + this.output = $('
'); + } + // Prettify the comment rating. + comment.pretty_rating = comment.rating + ' point' + + (comment.rating == 1 ? '' : 's'); + // Make a class (for displaying not yet moderated comments differently) + comment.css_class = comment.displayed ? '' : ' moderate'; + // Create a div for this comment. + var context = $.extend({}, opts, comment); + var div = $(renderTemplate(commentTemplate, context)); + + // If the user has voted on this comment, highlight the correct arrow. + if (comment.vote) { + var direction = (comment.vote == 1) ? 'u' : 'd'; + div.find('#' + direction + 'v' + comment.id).hide(); + div.find('#' + direction + 'u' + comment.id).show(); + } + + if (opts.moderator || comment.text != '[deleted]') { + div.find('a.reply').show(); + if (comment.proposal_diff) + div.find('#sp' + comment.id).show(); + if (opts.moderator && !comment.displayed) + div.find('#cm' + comment.id).show(); + if (opts.moderator || (opts.username == comment.username)) + div.find('#dc' + comment.id).show(); + } + return div; + } + + /** + * A simple template renderer. Placeholders such as <%id%> are replaced + * by context['id'] with items being escaped. Placeholders such as <#id#> + * are not escaped. + */ + function renderTemplate(template, context) { + var esc = $(document.createElement('div')); + + function handle(ph, escape) { + var cur = context; + $.each(ph.split('.'), function() { + cur = cur[this]; + }); + return escape ? esc.text(cur || "").html() : cur; + } + + return template.replace(/<([%#])([\w\.]*)\1>/g, function() { + return handle(arguments[2], arguments[1] == '%' ? true : false); + }); + } + + /** Flash an error message briefly. */ + function showError(message) { + $(document.createElement('div')).attr({'class': 'popup-error'}) + .append($(document.createElement('div')) + .attr({'class': 'error-message'}).text(message)) + .appendTo('body') + .fadeIn("slow") + .delay(2000) + .fadeOut("slow"); + } + + /** Add a link the user uses to open the comments popup. */ + $.fn.comment = function() { + return this.each(function() { + var id = $(this).attr('id').substring(1); + var count = COMMENT_METADATA[id]; + var title = count + ' comment' + (count == 1 ? '' : 's'); + var image = count > 0 ? opts.commentBrightImage : opts.commentImage; + var addcls = count == 0 ? ' nocomment' : ''; + $(this) + .append( + $(document.createElement('a')).attr({ + href: '#', + 'class': 'sphinx-comment-open' + addcls, + id: 'ao' + id + }) + .append($(document.createElement('img')).attr({ + src: image, + alt: 'comment', + title: title + })) + .click(function(event) { + event.preventDefault(); + show($(this).attr('id').substring(2)); + }) + ) + .append( + $(document.createElement('a')).attr({ + href: '#', + 'class': 'sphinx-comment-close hidden', + id: 'ah' + id + }) + .append($(document.createElement('img')).attr({ + src: opts.closeCommentImage, + alt: 'close', + title: 'close' + })) + .click(function(event) { + event.preventDefault(); + hide($(this).attr('id').substring(2)); + }) + ); + }); + }; + + var opts = { + processVoteURL: '/_process_vote', + addCommentURL: '/_add_comment', + getCommentsURL: '/_get_comments', + acceptCommentURL: '/_accept_comment', + deleteCommentURL: '/_delete_comment', + commentImage: '/static/_static/comment.png', + closeCommentImage: '/static/_static/comment-close.png', + loadingImage: '/static/_static/ajax-loader.gif', + commentBrightImage: '/static/_static/comment-bright.png', + upArrow: '/static/_static/up.png', + downArrow: '/static/_static/down.png', + upArrowPressed: '/static/_static/up-pressed.png', + downArrowPressed: '/static/_static/down-pressed.png', + voting: false, + moderator: false + }; + + if (typeof COMMENT_OPTIONS != "undefined") { + opts = jQuery.extend(opts, COMMENT_OPTIONS); + } + + var popupTemplate = '\ +
\ +

\ + Sort by:\ + best rated\ + newest\ + oldest\ +

\ +
Comments
\ +
\ + loading comments...
\ +
    \ +
    \ +

    Add a comment\ + (markup):

    \ +
    \ + reStructured text markup: *emph*, **strong**, \ + ``code``, \ + code blocks: :: and an indented block after blank line
    \ +
    \ + \ +

    \ + \ + Propose a change ▹\ + \ + \ + Propose a change ▿\ + \ +

    \ + \ + \ + \ + \ + \ +
    \ +
    '; + + var commentTemplate = '\ +
    \ +
    \ +
    \ + \ + \ + \ + \ + \ + \ +
    \ +
    \ + \ + \ + \ + \ + \ + \ +
    \ +
    \ +
    \ +

    \ + <%username%>\ + <%pretty_rating%>\ + <%time.delta%>\ +

    \ +
    <#text#>
    \ +

    \ + \ + reply ▿\ + proposal ▹\ + proposal ▿\ + \ + \ +

    \ +
    \
    +<#proposal_diff#>\
    +        
    \ +
      \ +
      \ +
      \ +
      \ + '; + + var replyTemplate = '\ +
    • \ +
      \ +
      \ + \ + \ + \ + \ + \ + \ +
      \ +
    • '; + + $(document).ready(function() { + init(); + }); +})(jQuery); + +$(document).ready(function() { + // add comment anchors for all paragraphs that are commentable + $('.sphinx-has-comment').comment(); + + // highlight search words in search results + $("div.context").each(function() { + var params = $.getQueryParameters(); + var terms = (params.q) ? params.q[0].split(/\s+/) : []; + var result = $(this); + $.each(terms, function() { + result.highlightText(this.toLowerCase(), 'highlighted'); + }); + }); + + // directly open comment window if requested + var anchor = document.location.hash; + if (anchor.substring(0, 9) == '#comment-') { + $('#ao' + anchor.substring(9)).click(); + document.location.hash = '#s' + anchor.substring(9); + } +}); diff --git a/cpp-netlib/libs/network/doc/html/contents.html b/cpp-netlib/libs/network/doc/html/contents.html new file mode 100644 index 00000000..82fba3e4 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/contents.html @@ -0,0 +1,290 @@ + + + + + + + + Contents — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Contents

      +
      + +
      +
      + + +
      +
      +
      +
      +
      +

      Next topic

      +

      Getting cpp-netlib

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/examples.html b/cpp-netlib/libs/network/doc/html/examples.html new file mode 100644 index 00000000..8d741ab8 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/examples.html @@ -0,0 +1,136 @@ + + + + + + + + Examples — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Examples

      +

      The cpp-netlib is a practical library that is designed to aid +the development of applications for that need to communicate using +common networking protocols. The following set of examples describe a +series of realistic examples that use the cpp-netlib for these +kinds of application. All examples are built using CMake.

      +
      +

      HTTP examples

      +

      The HTTP component of the cpp-netlib contains a client and server. +The examples that follow show how to use both for programs that can be +embedded into larger applications.

      + +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      Getting Started

      +

      Next topic

      +

      HTTP client

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/examples/http/atom_reader.html b/cpp-netlib/libs/network/doc/html/examples/http/atom_reader.html new file mode 100644 index 00000000..20b3854f --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/examples/http/atom_reader.html @@ -0,0 +1,182 @@ + + + + + + + + Atom feed reader — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Atom feed reader

      +

      The next examples show some simple, more practical applications using +the HTTP client. The first one reads a simple Atom feed and prints +the titles of each entry to the console.

      +
      +

      The code

      +
      #include "atom.hpp"
      +#include <boost/network/protocol/http/client.hpp>
      +#include <boost/foreach.hpp>
      +#include <iostream>
      +
      +int main(int argc, char * argv[]) {
      +    using namespace boost::network;
      +
      +    if (argc != 2) {
      +        std::cout << "Usage: " << argv[0] << " <url>" << std::endl;
      +        return 1;
      +    }
      +
      +    try {
      +        http::client client;
      +        http::client::request request(argv[1]);
      +        request << header("Connection", "close");
      +        http::client::response response = client.get(request);
      +        atom::feed feed(response);
      +
      +        std::cout << "Feed: " << feed.title()
      +                  << " (" << feed.subtitle() << ")" << std::endl;
      +        BOOST_FOREACH(const atom::entry &entry, feed) {
      +            std::cout << entry.title()
      +                      << " (" << entry.published() << ")" << std::endl;
      +        }
      +    }
      +    catch (std::exception &e) {
      +        std::cerr << e.what() << std::endl;
      +    }
      +
      +    return 0;
      +}
      +
      +
      +
      +
      +

      Building and running atom_reader

      +
      $ cd ~/cpp-netlib-build
      +$ make atom_reader
      +
      +
      +

      And to run the example from the command line to access the feed that +lists of all the commits on cpp-netlib’s master branch:

      +
      $ ./example/atom_reader https://github.com/cpp-netlib/cpp-netlib/commits/master.atom
      +
      +
      +
      +
      +

      Diving into the code

      +

      Most of this will now be familiar. The response is passed to the +constructor to the atom::feed class, which parses the resultant +XML. To keep this example as simple as possible, rapidxml, a +header-only XML parser library, was used to parse the response.

      +

      A similar example using RSS feeds exists in +libs/network/example/rss.

      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      “Hello world” HTTP client

      +

      Next topic

      +

      Twitter search

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/examples/http/hello_world_client.html b/cpp-netlib/libs/network/doc/html/examples/http/hello_world_client.html new file mode 100644 index 00000000..20dc8709 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/examples/http/hello_world_client.html @@ -0,0 +1,199 @@ + + + + + + + + “Hello world” HTTP client — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      “Hello world” HTTP client

      +

      Since we have a “Hello World” HTTP server, let’s then create an HTTP client to +access that server. This client will be similar to the HTTP client we made +earlier in the documentation.

      +
      +

      The code

      +

      We want to create a simple HTTP client that just makes a request to the HTTP +server that we created earlier. This really simple client will look like this:

      +
      #include <boost/network/protocol/http/client.hpp>
      +#include <string>
      +#include <sstream>
      +#include <iostream>
      +
      +namespace http = boost::network::http;
      +
      +int main(int argc, char * argv[]) {
      +    if (argc != 3) {
      +        std::cerr << "Usage: " << argv[0] << " address port" << std::endl;
      +        return 1;
      +    }
      +
      +    try {
      +        http::client client;
      +        std::ostringstream url;
      +        url << "http://" << argv[1] << ":" << argv[2] << "/";
      +        http::client::request request(url.str());
      +        http::client::response response =
      +            client.get(request);
      +        std::cout << body(response) << std::endl;
      +    } catch (std::exception & e) {
      +        std::cerr << e.what() << std::endl;
      +        return 1;
      +    }
      +    return 0;
      +}
      +
      +
      +
      +
      +

      Building and running the client

      +

      Just like with the HTTP Server and HTTP client example before, we can build this +example by doing the following on the shell:

      +
      $ cd ~/cpp-netlib-build
      +$ make hello_world_client
      +
      +
      +

      This example can be run from the command line as follows:

      +
      $ ./example/hello_world_client http://127.0.0.1:8000
      +
      +
      +
      +

      Note

      +

      This assumes that you have the hello_world_server running on +localhost port 8000.

      +
      +
      +
      +

      Diving into the code

      +

      All this example shows is how easy it is to write an HTTP client that connects +to an HTTP server, and gets the body of the response. The relevant lines are:

      +
      http::client client;
      +http::client::request request(url.str());
      +http::client::response response =
      +    client.get(request);
      +std::cout << body(response) << std::endl;
      +
      +
      +

      You can then imagine using this in an XML-RPC client, where you can craft the +XML-RPC request as payload which you can pass as the body to a request, then +perform the request via HTTP:

      +
      http::client client;
      +http::client::request request("http://my.webservice.com/");
      +http::client::response =
      +    client.post(request, some_xml_string, "application/xml");
      +std::data = body(response);
      +
      +
      +

      The next set of examples show some more practical applications using +the cpp-netlib HTTP client.

      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      “Hello world” HTTP server

      +

      Next topic

      +

      Atom feed reader

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/examples/http/hello_world_server.html b/cpp-netlib/libs/network/doc/html/examples/http/hello_world_server.html new file mode 100644 index 00000000..5f9c5d88 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/examples/http/hello_world_server.html @@ -0,0 +1,240 @@ + + + + + + + + “Hello world” HTTP server — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      “Hello world” HTTP server

      +

      Now that we’ve seen how we can deal with request and response objects from the +client side, we’ll see how we can then use the same abstractions on the server +side. In this example we’re going to create a simple HTTP Server in C++ using +cpp-netlib.

      +
      +

      The code

      +

      The cpp-netlib provides the framework to develop embedded HTTP +servers. For this example, the server is configured to return a +simple response to any HTTP request.

      +
      #include <boost/network/protocol/http/server.hpp>
      +#include <string>
      +#include <iostream>
      +
      +namespace http = boost::network::http;
      +
      +struct hello_world;
      +typedef http::server<hello_world> server;
      +
      +struct hello_world {
      +    void operator() (server::request const &request,
      +                     server::response &response) {
      +        std::string ip = source(request);
      +        response = server::response::stock_reply(
      +            server::response::ok, std::string("Hello, ") + ip + "!");
      +    }
      +};
      +
      +int
      +main(int argc, char * argv[]) {
      +
      +    if (argc != 3) {
      +        std::cerr << "Usage: " << argv[0] << " address port" << std::endl;
      +        return 1;
      +    }
      +
      +    try {
      +        hello_world handler;
      +        server server_(argv[1], argv[2], handler);
      +        server_.run();
      +    }
      +    catch (std::exception &e) {
      +        std::cerr << e.what() << std::endl;
      +        return 1;
      +    }
      +
      +    return 0;
      +}
      +
      +
      +

      This is about a straightforward as server programming will get in C++.

      +
      +
      +

      Building and running the server

      +

      Just like with the HTTP client, we can build this example by doing the following +on the shell:

      +
      $ cd ~/cpp-netlib-build
      +$ make hello_world_server
      +
      +
      +

      The first two arguments to the server constructor are the host and +the port on which the server will listen. The third argument is the +the handler object defined previously. This example can be run from +a command line as follows:

      +
      $ ./example/hello_world_server 0.0.0.0 8000
      +
      +
      +
      +

      Note

      +

      If you’re going to run the server on port 80, you may have to run it +as an administrator.

      +
      +
      +
      +

      Diving into the code

      +

      Let’s take a look at the code listing above in greater detail.

      +
      #include <boost/network/protocol/http/server.hpp>
      +
      +
      +

      This header contains all the code needed to develop an HTTP server with +cpp-netlib.

      +
      struct hello_world;
      +typedef http::server<hello_world> server;
      +
      +struct hello_world {
      +    void operator () (server::request const &request,
      +                      server::response &response) {
      +        std::string ip = source(request);
      +        response = server::response::stock_reply(
      +            server::response::ok, std::string("Hello, ") + ip + "!");
      +    }
      +};
      +
      +
      +

      hello_world is a functor class which handles HTTP requests. All +the operator does here is return an HTTP response with HTTP code 200 +and the body "Hello, <ip>!". The <ip> in this case would be +the IP address of the client that made the request.

      +

      There are a number of pre-defined stock replies differentiated by +status code with configurable bodies.

      +

      All the supported enumeration values for the response status codes can be found +in boost/network/protocol/http/impl/response.ipp.

      +
      hello_world handler;
      +server server_(argv[1], argv[2], handler);
      +server_.run();
      +
      +
      +

      The first two arguments to the server constructor are the host and +the port on which the server will listen. The third argument is the +the handler object defined previously.

      +
      +

      Note

      +

      In this example, the server is specifically made to be single-threaded. +In a multi-threaded server, you would invoke the hello_world::run member +method in a set of threads. In a multi-threaded environment you would also +make sure that the handler does all the necessary synchronization for shared +resources across threads. The handler is passed by reference to the server +constructor and you should ensure that any calls to the operator() overload +are thread-safe.

      +
      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      Simple wget

      +

      Next topic

      +

      “Hello world” HTTP client

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/examples/http/http_client.html b/cpp-netlib/libs/network/doc/html/examples/http/http_client.html new file mode 100644 index 00000000..2d4b9d5e --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/examples/http/http_client.html @@ -0,0 +1,213 @@ + + + + + + + + HTTP client — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      HTTP client

      +

      The first code example is the simplest thing you can do with the +cpp-netlib. The application is a simple HTTP client, which can +be found in the subdirectory libs/network/example/http_client.cpp. +All this example doing is creating and sending an HTTP request to a server +and printing the response body.

      +
      +

      The code

      +

      Without further ado, the code to do this is as follows:

      +
      #include <boost/network/protocol/http/client.hpp>
      +#include <iostream>
      +
      +int main(int argc, char *argv[]) {
      +    using namespace boost::network;
      +
      +    if (argc != 2) {
      +        std::cout << "Usage: " << argv[0] << " [url]" << std::endl;
      +        return 1;
      +    }
      +
      +    http::client client;
      +    http::client::request request(argv[1]);
      +    request << header("Connection", "close");
      +    http::client::response response = client.get(request);
      +    std::cout << body(response) << std::endl;
      +
      +    return 0;
      +}
      +
      +
      +
      +
      +

      Running the example

      +

      You can then run this to get the Boost website:

      +
      $ cd ~/cpp-netlib-build
      +$ make http_client
      +$ ./example/http_client http://www.boost.org/
      +
      +
      +
      +

      Note

      +

      The instructions for all these examples assume that +cpp-netlib is build outside the source tree, +according to CMake conventions. For the sake of +consistency we assume that this is in the +~/cpp-netlib-build directory.

      +
      +
      +
      +

      Diving into the code

      +

      Since this is the first example, each line will be presented and +explained in detail.

      +
      #include <boost/network/protocol/http/client.hpp>
      +
      +
      +

      All the code needed for the HTTP client resides in this header.

      +
      http::client client;
      +
      +
      +

      First we create a client object. The client abstracts all the +connection and protocol logic. The default HTTP client is version +1.1, as specified in RFC 2616.

      +
      http::client::request request(argv[1]);
      +
      +
      +

      Next, we create a request object, with a URI string passed as a +constructor argument.

      +
      request << header("Connection", "close");
      +
      +
      +

      cpp-netlib makes use of stream syntax and directives to allow +developers to build complex message structures with greater +flexibility and clarity. Here, we add the HTTP header “Connection: +close” to the request in order to signal that the connection will be +closed after the request has completed.

      +
      http::client::response response = client.get(request);
      +
      +
      +

      Once we’ve built the request, we then make an HTTP GET request +throught the http::client from which an http::response is +returned. http::client supports all common HTTP methods: GET, +POST, HEAD, DELETE.

      +
      std::cout << body(response) << std::endl;
      +
      +
      +

      Finally, though we don’t do any error checking, the response body is +printed to the console using the body directive.

      +

      That’s all there is to the HTTP client. In fact, it’s possible to +compress this to a single line:

      +
      std::cout << body(http::client().get(http::request("http://www.boost.org/")));
      +
      +
      +

      The next example will introduce the uri class.

      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      Examples

      +

      Next topic

      +

      Simple wget

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/examples/http/simple_wget.html b/cpp-netlib/libs/network/doc/html/examples/http/simple_wget.html new file mode 100644 index 00000000..d840aa55 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/examples/http/simple_wget.html @@ -0,0 +1,210 @@ + + + + + + + + Simple wget — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Simple wget

      +

      This example is a very simple implementation of a wget style +clone. It’s very similar to the previous example, but introduces the +uri class.

      +
      +

      The code

      +
      #include <boost/network/protocol/http/client.hpp>
      +#include <boost/network/uri.hpp>
      +#include <string>
      +#include <fstream>
      +#include <iostream>
      +
      +namespace http = boost::network::http;
      +namespace uri = boost::network::uri;
      +
      +namespace {
      +std::string get_filename(const uri::uri &url) {
      +    std::string path = uri::path(url);
      +    std::size_t index = path.find_last_of('/');
      +    std::string filename = path.substr(index + 1);
      +    return filename.empty()? "index.html" : filename;
      +}
      +} // namespace
      +
      +int
      +main(int argc, char *argv[]) {
      +    if (argc != 2) {
      +        std::cerr << "Usage: " << argv[0] << " url" << std::endl;
      +        return 1;
      +    }
      +
      +    try {
      +        http::client client;
      +        http::client::request request(argv[1]);
      +        http::client::response response = client.get(request);
      +
      +        std::string filename = get_filename(request.uri());
      +        std::cout << "Saving to: " << filename << std::endl;
      +        std::ofstream ofs(filename.c_str());
      +        ofs << static_cast<std::string>(body(response)) << std::endl;
      +    }
      +    catch (std::exception &e) {
      +        std::cerr << e.what() << std::endl;
      +        return 1;
      +    }
      +
      +    return 0;
      +}
      +
      +
      +
      +
      +

      Running the example

      +

      You can then run this to copy the Boost website:

      +
      $ cd ~/cpp-netlib-build
      +$ make simple_wget
      +$ ./example/simple_wget http://www.boost.org/
      +$ cat index.html
      +
      +
      +
      +
      +

      Diving into the code

      +

      As with wget, this example simply makes an HTTP request to the +specified resource, and saves it on the filesystem. If the file name +is not specified, it names the resultant file as index.html.

      +

      The new thing to note here is use of the uri class. The uri +takes a string as a constructor argument and parses it. The uri +parser is fully-compliant with RFC 3986. The URI is provided in +the following header:

      +
      #include <boost/network/uri.hpp>
      +
      +
      +

      Most of the rest of the code is familiar from the previous example. +To retrieve the URI resource’s file name, the following function is +provided:

      +
      std::string get_filename(const uri::uri &url) {
      +    std::string path = uri::path(url);
      +    std::size_t index = path.find_last_of('/');
      +    std::string filename = path.substr(index + 1);
      +    return filename.empty()? "index.html" : filename;
      +}
      +
      +
      +

      The uri interface provides access to its different components: +scheme, user_info, host, port, path, query and +fragment. The code above takes the URI path to determine the +resource name.

      +

      Next we’ll develop a simple client/server application using +http::server and http::client.

      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      HTTP client

      +

      Next topic

      +

      “Hello world” HTTP server

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/examples/http/twitter_search.html b/cpp-netlib/libs/network/doc/html/examples/http/twitter_search.html new file mode 100644 index 00000000..dfd7b700 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/examples/http/twitter_search.html @@ -0,0 +1,216 @@ + + + + + + + + Twitter search — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + + + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      Atom feed reader

      +

      Next topic

      +

      An in-depth look at the cpp-netlib

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/genindex.html b/cpp-netlib/libs/network/doc/html/genindex.html new file mode 100644 index 00000000..1123dde9 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/genindex.html @@ -0,0 +1,92 @@ + + + + + + + + + Index — cpp-netlib v0.9.4 + + + + + + + + + + + + +
      +
      + + +
      +
      +
      +
      + + +

      Index

      + +
      + +
      + + +
      +
      +
      + +
      + +
      + +
      +
      + +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/getting_started.html b/cpp-netlib/libs/network/doc/html/getting_started.html new file mode 100644 index 00000000..71353660 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/getting_started.html @@ -0,0 +1,357 @@ + + + + + + + + Getting Started — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Getting Started

      +
      +

      Downloading an official release

      +

      You can find links to the latest official release from the project’s official +website:

      +
      +
      +

      All previous stable versions of cpp-netlib can be downloaded from +Github from this url:

      +
      +
      +

      Each release is available as gzipped (Using the command +tar xzf cpp-netlib.tar.gz) or bzipped (Using tar xjf +cpp-netlib.tar.bz2) tarball, or as a zipfile (unzip +cpp-netlib.zip, or on Windows using a tool such as 7zip).

      +
      +
      +

      Downloading a development version

      +

      The cpp-netlib uses Git for source control, so to use any +development versions Git must be installed on your system.

      +

      Using the command line, the command to get the latest code is:

      +
      shell$ git clone git://github.com/cpp-netlib/cpp-netlib.git
      +
      +
      +

      This should be enough information get to started. To do more complex +things with Git, such as pulling changes or checking out a new branch, +refer to the Git documentation.

      +
      +

      Note

      +

      Previous versions of cpp-netlib referred to the +mikhailberis repository as the main development repository. This +account is still valid, but not always up-to-date. In the interest of +consistency, the main repository has been changed to cpp-netlib.

      +
      +

      Windows users need to use msysGit, and to invoke the command above +from a shell.

      +

      For fans of Subversion, the same code can be checked out from +http://svn.github.com/cpp-netlib/cpp-netlib.git.

      +
      +

      Note

      +

      The cpp-netlib project is hosted on GitHub and follows the +prescribed development model for GitHub based projects. This means in case +you want to submit patches, you will have to create a fork of the project +(read up on forking) and then submit a pull request (read up on submitting +pull requests).

      +
      +
      +
      +

      Getting Boost

      +

      cpp-netlib depends on Boost. It should work for any version +of Boost above 1.50.0. If Boost is not installed on your system, the +latest package can be found on the Boost web-site. The environment +variable BOOST_ROOT must be defined, which must be the full path +name of the top directory of the Boost distribution. Although Boost +is mostly header only, applications built using cpp-netlib +still requires linking with Boost.System, Boost.Date_time, and +Boost.Regex.

      +
      +

      Note

      +

      You can follow the steps in the Boost Getting Started guide to +install Boost into your development system.

      +
      +
      +

      Warning

      +

      There is a known incompatibility between cpp-netlib and +Boost 1.46.1 on some compilers. It is not recommended to use cpp-netlib +with Boost 1.46.1. Some have reported though that Boost 1.47.0 +and cpp-netlib work together better.

      +
      +
      +
      +

      Getting CMake

      +

      The cpp-netlib uses CMake to generate platform-specific build files. If +you intend to run the test suite, you can follow the instructions below. +Otherwise, you don’t need CMake to use cpp-netlib in your project. The +cpp-netlib requires CMake version 2.8 or higher.

      +

      Let’s assume that you have unpacked the cpp-netlib at the top of your +HOME directory. On Unix-like systems you will typically be able to change into +your HOME directory using the command cd ~. This sample below assumes that +the ~/cpp-netlib directory exists, and is the top-level directory of the +cpp-netlib release.

      +
      +
      +

      Building with CMake

      +

      To build the tests that come with cpp-netlib, we first need to configure the +build system to use our compiler of choice. This is done by running the +cmake command at the top-level directory of cpp-netlib with +additional parameters:

      +
      $ mkdir ~/cpp-netlib-build
      +$ cd ~/cpp-netlib-build
      +$ cmake -DCMAKE_BUILD_TYPE=Debug \
      +>       -DCMAKE_C_COMPILER=gcc   \
      +>       -DCMAKE_CXX_COMPILER=g++ \
      +>       ../cpp-netlib
      +
      +
      +
      +

      Note

      +

      While it’s not compulsory, it’s recommended that +cpp-netlib is built outside the source directory. +For the purposes of documentation, we’ll assume that all +builds are done in ~/cpp-netlib-build.

      +
      +

      If you intend to use the SSL support when using the HTTP client libraries in +cpp-netlib, you may need to build it with OpenSSL installed or at least +available to CMake. If you have the development headers for OpenSSL installed +on your system when you build cpp-netlib, CMake will be able to detect it +and set the BOOST_NETWORK_ENABLE_HTTPS macro when building the library to +support HTTPS URIs.

      +

      One example for building the library with OpenSSL support with a custom +(non-installed) version of OpenSSL is by doing the following:

      +
      $ cmake -DCMAKE_BUILD_TYPE=Debug \
      +>       -DCMAKE_C_COMPILER=clang \
      +>       -DCMAKE_CXX_COMPILER=clang++ \
      +>       -DOPENSSL_ROOT_DIR=/Users/dberris/homebrew/Cellar/openssl/1.0.1f
      +>       ../cpp-netlib
      +
      +
      +

      You can also use a different root directory for the Boost project by using the +-DBOOST_ROOT configuration option to CMake. This is useful if you intend to +build the library with a specific version of Boost that you’ve built in a +separate directory:

      +
      $ cmake -DCMAKE_BUILD_TYPE=Debug \
      +>       -DCMAKE_C_COMPILER=clang \
      +>       -DCMAKE_CXX_COMPILER=clang++ \
      +>       -DOPENSSL_ROOT_DIR=/Users/dberris/homebrew/Cellar/openssl/1.0.1f \
      +>       -DBOOST_ROOT=/Users/dberris/Source/boost_1_55_0
      +>       ../cpp-netlib
      +
      +
      +
      +

      Building on Linux

      +

      On Linux, this will generate the appropriate Makefiles that will enable you to +build and run the tests and examples that come with cpp-netlib. To build +the tests, you can run make in the same top-level directory of +~/cpp-netlib-build:

      +
      $ make
      +
      +
      +
      +

      Note

      +

      Just like with traditional GNU Make, you can add the -j parameter +to specify how many parallel builds to run. In case you’re in a sufficiently +powerful system and would like to parallelize the build into 4 jobs, you can +do this with:

      +
      make -j4
      +
      +
      +

      As a caveat, cpp-netlib is heavy on template metaprogramming and will +require a lot of computing and memory resources to build the individual +tests. Do this at the risk of thrashing your system. However, this +compile-time burden is much reduced in recent versions.

      +
      +

      Once the build has completed, you can now run the test suite by issuing:

      +
      $ make test
      +
      +
      +

      You can install cpp-netlib by issuing:

      +
      $ sudo make install
      +
      +
      +

      By default this installs cpp-netlib into /usr/local.

      +
      +

      Note

      +

      As of version 0.9.3, cpp-netlib produces three static +libraries. Using GCC on Linux these are:

      +
      libcppnetlib-client-connections.a
      +libcppnetlib-server-parsers.a
      +libcppnetlib-uri.a
      +
      +
      +

      Users can find them in ~/cpp-netlib-build/libs/network/src.

      +
      +
      +
      +

      Building On Windows

      +

      If you’re using the Microsoft Visual C++ compiler or the Microsoft Visual Studio +IDE and you would like to build cpp-netlib from within Visual Studio, you +can look for the solution and project files as the artifacts of the call to +cmake – the file should be named CPP-NETLIB.sln (the solution) along +with a number of project files for Visual Studio.

      +
      +

      Note

      +

      As of version 0.9.3, cpp-netlib produces three static +libraries. Using Visual C++ on Windows they are:

      +
      cppnetlib-client-connections.lib
      +cppnetlib-server-parsers.lib
      +cppnetlib-uri.lib
      +
      +
      +

      Users can find them in ~/cpp-netlib-build/libs/network/src.

      +
      +
      +
      +
      +

      Using cpp-netlib

      +
      +

      CMake projects

      +

      Projects using CMake can add the following lines in their CMakeLists.txt to +be able to use cpp-netlib:

      +
      set ( CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ~/cpp-netlib-build )
      +find_package ( cppnetlib 0.11.0 REQUIRED )
      +include_directories ( ${CPPNETLIB_INCLUDE_DIRS} )
      +target_link_libraries ( MyApplication ${CPPNETLIB_LIBRARIES} )
      +
      +
      +
      +

      Note

      +

      Setting CMAKE_PREFIX_PATH is only required when cpp-netlib +is not installed to a location that CMake searches. When cpp-netlib +is installed to the default location (/usr/local), CMake can find it.

      +
      +
      +

      Note

      +

      We assume that MyApplication is the application that you are +building and which depends on cpp-netlib.

      +
      +
      +
      +
      +

      Reporting Issues, Getting Support

      +

      In case you find yourself stuck or if you’ve found a bug (or you want to just +join the discussion) you have a few options to choose from.

      +

      For reporting bugs, feature requests, and asking questions about the +implementation and/or the documentation, you can go to the GitHub issues page +for the project at http://github.com/cpp-netlib/cpp-netlib/issues.

      +

      You can also opt to join the developers mailing list for a more personal +interaction with the developers of the project. You can join the mailing list +through http://groups.google.com/forum/#!forum/cpp-netlib.

      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      What’s New

      +

      Next topic

      +

      Examples

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/history.html b/cpp-netlib/libs/network/doc/html/history.html new file mode 100644 index 00000000..45b8308b --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/history.html @@ -0,0 +1,156 @@ + + + + + + + + Project history — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Project history

      +

      The cpp-netlib was founded by Dean Michael Berris in 2007. +Initially it consisted of a message template and an HTTP client. It +found a home on Sourceforge but was migrated at the end of 2009 to +Github where development is actively continued by a committed +community.

      +
      +

      Motivation

      +

      We’re a group of C++ developers and we kept becoming annoyed that we +had to repeatedly write the same code when building applications that +needed to be network-aware.

      +

      We found that there was a lack of accessible networking libraries, +either standard or open source, that fulfilled our needs. Such +libraries exist for every other major language. So, building on top +of Boost.Asio, we decided to get together and build our own.

      +
      +
      +

      Objectives

      +

      The objectives of the cpp-netlib are to:

      +
        +
      • develop a high quality, portable, easy to use C++ networking library
      • +
      • enable developers to easily extend the library
      • +
      • lower the barrier to entry for cross-platform network-aware C++ +applications
      • +
      +

      The goal the of cpp-netlib has never been to build a +fully-featured web server - there are plenty of excellent options +already available. The niche that this library targets is for +light-weight networking functionality for C++ applications that have +demanding performance requirements or memory constraints, but that +also need to be portable. This type of application is becoming +increasingly common as software becomes more distributed, and +applications need to communicate with services.

      +

      While many languages provide direct library support for high level +network programming, this feature is missing in C++. Therefore, this +library has been developed with the intention of eventually being +submitted to Boost, a collection of general, high quality +libraries for C++ developers.

      +

      Eventually, the cpp-netlib will be extended to support many of +the application layer protocols such as SMTP, FTP, SOAP, XMPP etc.

      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      Static and dynamic polymorphism

      +

      Next topic

      +

      Reference Manual

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/in_depth.html b/cpp-netlib/libs/network/doc/html/in_depth.html new file mode 100644 index 00000000..ebd20ad6 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/in_depth.html @@ -0,0 +1,132 @@ + + + + + + + + An in-depth look at the cpp-netlib — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      An in-depth look at the cpp-netlib

      +

      The cpp-netlib is composed of three different sets of +functionality: a message template, a URI template and +different protocol implementations.

      + +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      Twitter search

      +

      Next topic

      +

      The message template

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/in_depth/http.html b/cpp-netlib/libs/network/doc/html/in_depth/http.html new file mode 100644 index 00000000..d4f5c774 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/in_depth/http.html @@ -0,0 +1,311 @@ + + + + + + + + HTTP implementation — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      HTTP implementation

      +
      +

      HTTP client

      +

      At the heart of the HTTP client implementation is a single class aptly named +basic_client, which is also a template. The template basic_client takes +three template parameters:

      +
      namespace boost { namespace http {
      +
      +    template <class Tag, unsigned version_major, unsigned version_minor>
      +    struct basic_client;
      +
      +} // namespace http
      +
      +} // namespace boost
      +
      +
      +

      The Tag template parameter follows the same tag-dispatch mechanism to +determine the behavior of the basic_client. The interface of +basic_client may change depending on certain properties defined for the tag +you provide. Below is a table of predefined supported tags you can use in your +overload of the basic_client:

      +
      +
      ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +
      TagDescription
      http_default_8bit_tcp_resolveThis is the default HTTP implementation tag +that resolves addresses with a TCP resolver +and provides a synchronous/blocking HTTP +client interface.
      http_default_8bit_udp_resolveThis is similar to the above tag except that +it specifies the HTTP client to use a UDP +resolver. It also provides a synchronous/ +blocking HTTP client interface.
      http_keepalive_8bit_tcp_resolveThis tag specifies that the HTTP client by +default will keep connections to the server +alive. It only makes sense if the +version_major and version_minor are +both 1, to indicate HTTP 1.1. This tag +causes the HTTP client to resolve using a +TCP resolver and provides a synchronous/ +blocking HTTP client interface.
      http_keepalive_8bit_udp_resolveThis is similar to the above tag except that +it specifies the HTTP client to use a UDP +resolver. It also provides a synchronous/ +blocking HTTP client interface.
      http_async_8bit_tcp_resolveThis tag provides an active HTTP client +object implementation that uses a TCP +resolver. Response objects returned will +encapsulate a number of Boost.Thread +shared futures to hold values. Users don’t +have to see this as they are implementation +details.
      http_async_8bit_udp_resolveThis is similar to the above tag except that +specifies the HTTP client to use a UDP +resolver.
      +

      The default typedef for the HTTP client that is provided uses the +http_async_8bit_udp_resolve tag, and implements HTTP 1.1. The exact +typedef is in the boost::network::http namespace as the following:

      +
      namespace boost { namespace network { namespace http {
      +
      +    typedef basic_client<tags::http_async_8bit_udp_resolve, 1, 1>
      +        client;
      +
      +}}}
      +
      +
      +

      This type has nested typedefs for the correct types for the basic_request +and basic_response templates. To use the correct types for basic_request +or basic_response you can use these nested typedefs like so:

      +
      boost::network::http::client::request request;
      +boost::network::http::client::response response;
      +
      +// or...
      +using namespace boost::network;
      +http::client::request request;
      +http::client::response response;
      +
      +
      +

      Typical use cases for the HTTP client would look something like the following:

      +
      using namespace boost::network;
      +http::request request("http://www.boost.org/");
      +request << header("Connection", "close");
      +
      +
      +

      The basic_client implements all HTTP methods as member functions +(HEAD, GET, POST, PUT, DELETE). Therefore, the code to make an HTTP +request looks trivially simple:

      +
      using namespace boost::network;
      +http::client client;
      +http::client::request request("http://www.boost.org/");
      +http::client::response response = client.get(request);
      +
      +
      +

      Accessing data from http::response is done using wrappers. +To get the response headers, we use the headers wrapper which +returns, in the default case, a multimap of strings to strings:

      +
      using namespace boost::network;
      +typedef headers_range<http_client::response>::type response_headers;
      +boost::range_iterator<response_headers>::type iterator;
      +
      +response_headers headers_ = headers(response);
      +for (iterator it = headers_.begin(); it != headers_.end(); ++it) {
      +    std::cout << it->first << ": " << it->second << std::endl;
      +}
      +std::cout << std::endl;
      +
      +
      + +
      +

      HTTP server

      +

      As with the HTTP client, the HTTP server that is provided with +cpp-netlib is extensible through the tag mechanism and is embeddable. +The template class declaration of basic_server is given below:

      +
      namespace boost { namespace network { namespace http {
      +
      +    template <class Tag, class RequestHandler> basic_server;
      +
      +}}}
      +
      +
      +

      The second template argument is used to specify the request handler +type. The request handler type is a functor type which should overload +the function call operator (RequestHandler::operator() should be +overloaded) that takes two parameters: the first one being a reference +to a const basic_request<Tag> and the second being a reference to +a basic_response<Tag> instance.

      +

      All the logic for parsing the HTTP request and building the const +basic_request<Tag> object resides internally in the basic_server +template. Processing the request is delegated to the +RequestHandler type, and the assumption of which would be that the +response is formed inside the RequestHandler function call +operator overload.

      +

      The basic_server template however is only an underlying +implementation while the user-visible implementation is the +http::server template. This simply specializes the +basic_server template to use the default_ tag and forwards the +RequestHandler parameter:

      +
      namespace boost { namespace network { namespace http {
      +
      +    template <class RequestHandler>
      +    class server :
      +        public basic_server<default_, RequestHandler> {};
      +
      +}}}
      +
      +
      +

      To use the forwarding server type you just supply the request handler +implementation as the parameter. For example, an “echo” server example +might look something like this:

      +
      using namespace boost::network;
      +struct echo;
      +typedef http::server<echo> echo_server;
      +
      +struct echo {
      +    void operator () (const echo_server::request &request,
      +                      echo_server::response &response) const {
      +        std::string ip = source(request);
      +        response = echo_server::response::stock_reply(
      +            echo_server::response::ok,
      +            body(request));
      +        std::cerr << "[" << ip << "]: " << request.uri <<
      +            " status = " << echo_server::response::ok << '\n';
      +    }
      +};
      +
      +
      +

      Here, all we’re doing is returning the original request body with an +HTTP OK response (200). We are also printing the IP address from where the +request came from. Notice that we are using a wrapper to access the source of +the request.

      +
      + + + + + + +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      The URI class

      +

      Next topic

      +

      Techniques

      + + +
      +
      +
      + + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/in_depth/http_client_tags.html b/cpp-netlib/libs/network/doc/html/in_depth/http_client_tags.html new file mode 100644 index 00000000..83188a49 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/in_depth/http_client_tags.html @@ -0,0 +1,139 @@ + + + + + + + + <no title> — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +
      TagDescription
      http_default_8bit_tcp_resolveThis is the default HTTP implementation tag +that resolves addresses with a TCP resolver +and provides a synchronous/blocking HTTP +client interface.
      http_default_8bit_udp_resolveThis is similar to the above tag except that +it specifies the HTTP client to use a UDP +resolver. It also provides a synchronous/ +blocking HTTP client interface.
      http_keepalive_8bit_tcp_resolveThis tag specifies that the HTTP client by +default will keep connections to the server +alive. It only makes sense if the +version_major and version_minor are +both 1, to indicate HTTP 1.1. This tag +causes the HTTP client to resolve using a +TCP resolver and provides a synchronous/ +blocking HTTP client interface.
      http_keepalive_8bit_udp_resolveThis is similar to the above tag except that +it specifies the HTTP client to use a UDP +resolver. It also provides a synchronous/ +blocking HTTP client interface.
      http_async_8bit_tcp_resolveThis tag provides an active HTTP client +object implementation that uses a TCP +resolver. Response objects returned will +encapsulate a number of Boost.Thread +shared futures to hold values. Users don’t +have to see this as they are implementation +details.
      http_async_8bit_udp_resolveThis is similar to the above tag except that +specifies the HTTP client to use a UDP +resolver.
      + + +
      +
      +
      +
      +
      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/in_depth/message.html b/cpp-netlib/libs/network/doc/html/in_depth/message.html new file mode 100644 index 00000000..357afe5f --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/in_depth/message.html @@ -0,0 +1,399 @@ + + + + + + + + The message template — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      The message template

      +

      One of the core components in the library is the concept and the +implementation of a common message type. In most (not all) network +protocols, the concept of a message is central to the definition of +the protocol. In HTTP, SMTP, XMPP, and even other protocols like SNMP +and ICMP, there is a common notion of a “packet” or a message. In +cpp-netlib we chose to implement the concept of a message that has the +following common parts:

      +
      +
        +
      • Source - every message has a source identifier which varies +from protocol to protocol.
      • +
      • Destination - every message has a destination identifier which +varies from protocol to protocol.
      • +
      • Headers - each message is assumed to contain headers, which +may be empty in cases where the protocol does not support it, but +is nonetheless supported by cpp-netlib messages.
      • +
      • Body - the content area of a message which varies from +protocol to protocol (also sometimes referred to as payload).
      • +
      +
      +

      This division is purely logical – in the underlying implementation, +the message type can choose to have different means of storing the +data, depending on the type used to tag the message. This section +covers the Message Concept as well as the basic_message +implementation.

      +
      +

      Message Concept

      +
      +

      Warning

      +

      The Message framework is deprecated in the 0.11 release, and will +be removed in future versions of the library.

      +
      +

      The Message Concept specifies what the valid operations on a message +are as well as what messages look like semantically. The following +table summarize the operations and syntactic as well as semantic +properties of messages.

      +

      Legend

      + +++ + + + + + + + + + + + + + + + + + + + +
      M:The message type.
      H:A headers container type.
      m,n:An instance of M.
      S:A string type.
      s,k,v:An instance of S.
      O:The source type.
      D:The destination type.
      B:The body type.
      T:The Tag type.
      + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      ConstructResultDescription
      typename M::tagTThe nested tag type.
      M()Instance of MDefault constructible.
      M(m)Instance of MCopy constructible.
      m = n;Reference to mAssignable.
      swap(m, n);voidSwappable.
      source(m);Convertible to ORetrieve the source of m.
      destination(m);Convertible to DRetrieve the destination of m.
      headers(m);Convertible to HRetrieve the headers of m.
      body(m);Convertible to BRetrieve the body of m.
      m << source(s);M &Set the source of m.
      m << destination(s);M &Set the destination of m.
      m << header(k, v);M &Add a header to m.
      m << remove_header(k);M &Remove a header from m.
      m << body(s);M &Set the body of m.
      source(m,s);voidSet the source of m.
      destination(m,s);voidSet the destination of m.
      add_header(m, k, v);voidAdd a header to m.
      remove_header(m, k);voidRemove a header from m.
      clear_headers(m);voidClear the headers of m.
      body(m,s);M &Set the body of m.
      +

      Types that model the Message Concept are meant to encapsulate data +that has a source, a destination, one or more named headers, and a +body/payload. Because the accessors and the directives are not +required to be part of the message type that models the Message +Concept, a message can be implemented as a POD type and have all +manipulations performed in the directive implementations, as well as +value transformations done in the accessors.

      +
      +
      +

      Directives, Modifiers, and Wrappers

      +

      In the Message Concept definition there are three basic constructs that follow a +certain pattern. These patterns are Directives, Modifiers, and Wrappers.

      +
      +

      Directives

      +

      A directive is a function object that is applied to a Message. Directives +encapsulate a set of operations that apply to messages. The general requirement +for a Directive is that it should apply these operations on a message.

      +

      A directive may dispatch on the type of the message passed to it at the point of +the function call. Typically, directives are generated using a factory function +that returns the correct directive type.

      +

      For a given directive foo_directive a generator function called foo is +typically implemented:

      +
      struct foo_directive {
      +    template <class Message>
      +    Message & operator()(Message & m) const {
      +        // do something to m
      +        return m;
      +    }
      +};
      +
      +foo_directive const foo() {
      +    return foo_directive();
      +}
      +
      +// to apply a directive, we use the << operator
      +message m;
      +m << foo();
      +
      +
      +
      +
      +

      Modifiers

      +

      A modifier is generally defined as a free function that takes a reference to a +non-const lvalue message as the first parameter, and any number of parameters. +In the concept definition of the Message Concept, a modifier follows the form:

      +
      modifier(message, ...)
      +
      +
      +

      Modifiers are meant to imply modifications on a message, which also allows for +easier dispatch based on Argument Dependent Lookup (ADL) on the type of the +message. Note that Directives can be implemented in terms of Modifiers and +vice versa, although that is not required nor specified.

      +
      +
      +

      Wrappers

      +

      A Wrapper is basically an implementation detail that ensures that a given +message, when wrapped, can be converted to the associated part of the message. A +wrapper has a type that encapsulates the conversion logic from a message to a +given type.

      +

      An example of a Wrapper would be source_wrapper which would be returned by a +call to the wrapper generator function source. An example implementation of +the source_wrapper would look like:

      +
      template <class Tag, template <class> class Message>
      +struct source_wrapper {
      +    Message<Tag> const & m;
      +    explicit source_wrapper(Message<Tag> const & m)
      +    : m(m) {}
      +    typedef typename source<Tag>::type source_type;
      +    operator source_type const & () {
      +        return m.source;
      +    }
      +    operator source_type const () {
      +        return m.source;
      +    }
      +    operator source_type () {
      +        return m.source;
      +    }
      +};
      +
      +template <class Tag, template <class> class Message>
      +source_wrapper<Tag, Message> const
      +source(Message<Tag> const & message) {
      +    return source_wrapper<Tag, Message>(message);
      +}
      +
      +
      +

      This pattern is similar to an adapter, but the specific notion of wrapping a +data type (in this case, an object of a type that models the Message Concept) +using an intermediary wrapper is what is pertained to by the Wrapper pattern. +In this case, the Wrapper is source_wrapper while source is merely a +wrapper generator function.

      +
      +
      +
      +

      basic_message

      +

      The default implementation of a simple type that models the Message +Concept is available in cpp-netlib. This default implementation is +named basic_message which supports a Tag template +parameter. The definition of basic_message looks like this:

      +
      template <class Tag>
      +class basic_message;
      +
      +
      +

      The basic_message template requires that the following +tag-dispatched metafunctions are defined for the type Tag:

      +
      template <class Tag>
      +struct string;
      +
      +template <class Tag>
      +struct headers_container;
      +
      +
      +

      All the operations defined by the message concept are implemented by +this basic message type. Other message implementations can either use +this common message type or specialize it according to whether they +want to use different containers or whether it’s going to be just a +POD type.

      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      An in-depth look at the cpp-netlib

      +

      Next topic

      +

      The URI class

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/in_depth/uri.html b/cpp-netlib/libs/network/doc/html/in_depth/uri.html new file mode 100644 index 00000000..cb896231 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/in_depth/uri.html @@ -0,0 +1,295 @@ + + + + + + + + The URI class — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      The URI class

      +

      In addition to protocol implementations, the cpp-netlib +provides a powerful URI class. The class implements a parser based +on RFC 3986 and RFC 2732.

      +
      +

      Generic URI syntax overview

      +

      A generic URI will take the form:

      +
      [scheme:]scheme-specific-part[#fragment]
      +
      +
      +

      A URI is known as absolute if it specifies the scheme. Otherwise, +it is known as a relative URI. Currently, uri supports only +absolute URIs.

      +

      URIs can be further classified according to whether they’re +hierarchical or opaque (non-hierarchical).

      +

      Some examples of non-hierarchical URIs include:

      +
      mailto:john.doe@example.com
      +news:comp.infosystems.www.servers.unix
      +tel:+1-816-555-1212
      +
      +
      +

      The data following the first ":" is said to be opaque to the URI +parser and requires no further parsing. By way of example, the +following shows how a non-hierarchical URI is processed by the parser +by defining everything after the ":" to be a part of the path:

      +../_images/mailto_uri.png +

      A hierarchical URI is identified by a double slash ("//") after +the scheme and a scheme-specific component, which RFC 3986 defines +to be:

      +
      [scheme:][//authority][path][?query][#fragment]
      +
      +
      +

      The authority component can be further broken down to:

      +
      [user_info@]host[:port]
      +
      +
      +

      Examples of hierarchical URIs include:

      +
      http://www.boost.org/
      +file:///bin/bash
      +
      +
      +

      The following example, describing a complex URI using FTP, shows how +a URI is broken down by the parser:

      +../_images/ftp_uri.png +

      Note that the authority is further subdivided into different +elements. Another example, using HTTP is given below:

      +../_images/http_uri.png +

      The difference here between the path in a hierarchical URI and that in +the example above for the non-hierarchical URI.

      +
      +
      +

      The uri class

      +

      As of version 0.9.3, uri supplies a URI parser and builder. +To use the parser, it’s as simple as supplying a string to the +constructor:

      +
      using namespace boost::network;
      +uri::uri instance("http://cpp-netlib.github.com/");
      +assert(instance.is_valid());
      +std::cout << "scheme: " << instance.scheme() << std::endl
      +          << "host: " << instance.host() << std::endl;
      +
      +
      +

      The command-line output of this program will be:

      +
      scheme: http
      +host: cpp-netlib.github.com
      +
      +
      +
      +
      +

      The uri builder

      +

      uri support a stream style syntax to create a URI from it’s +elements. For example the program:

      +
      #include <iostream>
      +#include <boost/network/uri.hpp>
      +#include <boost/network/uri/uri_io.hpp>
      +using namespace boost::network;
      +
      +int main() {
      +    uri::uri url;
      +    url << uri::scheme("http")
      +        << uri::host("www.github.com")
      +        << uri::path("/cpp-netlib");
      +    std::cout << url << std::endl;
      +    return 0;
      +}
      +
      +
      +

      will output:

      +
      http://www.github.com/cpp-netlib
      +
      +
      +
      +
      +

      URI Concept

      +

      Legend

      + +++ + + + + + + + + + + + +
      U:The URI type.
      u,u_:An instance of M.
      S:A string type.
      s,v:An instance of S.
      T:The Tag type.
      + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      ConstructResultDescription
      U(u)Instance of UCopy constructible.
      U(s)Instance of UConstructible from string.
      u = u_;Reference to uAssignable.
      u = s;Reference to uAssignable from string.
      swap(u, u_);voidSwappable.
      scheme(u);Convertible to SRetrieve the URI scheme of u.
      user_info(u);Convertible to SRetrieve the user info of u.
      host(u);Convertible to SRetrieve the host of u.
      port(u);Convertible to HRetrieve the port of u.
      path(u);Convertible to SRetrieve the path of u.
      query(u);Convertible to SRetrieve the query string of u.
      fragment(u);Convertible to SRetrieve the fragment of u.
      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      The message template

      +

      Next topic

      +

      HTTP implementation

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/index.html b/cpp-netlib/libs/network/doc/html/index.html new file mode 100644 index 00000000..e49dbc01 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/index.html @@ -0,0 +1,210 @@ + + + + + + + + Getting cpp-netlib — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +

      Straightforward network programming in modern C++

      +
      +

      Getting cpp-netlib

      +

      You can find out more about the cpp-netlib project at +http://cpp-netlib.org/.

      +

      Download

      +

      You can get the latest official version of the library from the official +project website at:

      +
      +
      +

      This version of cpp-netlib is tagged as cpp-netlib-0.11.0 in the GitHub +repository. You can find more information about the progress of the development +by checking our GitHub project page at:

      +
      +
      +

      Support

      +

      You can ask questions, join the discussion, and report issues to the +developers mailing list by joining via:

      +
      +
      +

      You can also file issues on the Github issue tracker at:

      +
      +
      +

      We are a growing community and we are happy to accept new +contributions and ideas.

      +
      +
      +

      C++ Network Library

      +

      cpp-netlib is a library collection that provides application layer +protocol support using modern C++ techniques. It is light-weight, fast, +portable and is intended to be as easy to configure as possible.

      +
      +
      +

      Hello, world!

      +

      The cpp-netlib allows developers to write fast, portable +network applications with the minimum of fuss.

      +

      An HTTP server-client example can be written in tens of lines of code. +The client is as simple as this:

      +
      using namespace boost::network;
      +using namespace boost::network::http;
      +
      +client::request request_("http://127.0.0.1:8000/");
      +request_ << header("Connection", "close");
      +client client_;
      +client::response response_ = client_.get(request_);
      +std::string body_ = body(response_);
      +
      +
      +

      And the corresponding server code is listed below:

      +
      namespace http = boost::network::http;
      +
      +struct handler;
      +typedef http::server<handler> http_server;
      +
      +struct handler {
      +    void operator() (http_server::request const &request,
      +                     http_server::response &response) {
      +        response = http_server::response::stock_reply(
      +            http_server::response::ok, "Hello, world!");
      +    }
      +
      +    void log(http_server::string_type const &info) {
      +        std::cerr << "ERROR: " << info << '\n';
      +    }
      +};
      +
      +int main(int arg, char * argv[]) {
      +    handler handler_;
      +    http_server::options options(handler_);
      +    http_server server_(
      +        options.address("0.0.0.0")
      +               .port("8000"));
      +    server_.run();
      +}
      +
      +
      +
      +
      +

      Want to learn more?

      +
      +
      +
      +

      Warning

      +

      Be aware that not all features are stable. The generic +message design is under review and the URI and HTTP +client implementation will continue to undergo +refactoring. Future versions will include support for +other network protocols.

      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      Contents

      +

      Next topic

      +

      What’s New

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/objects.inv b/cpp-netlib/libs/network/doc/html/objects.inv new file mode 100644 index 00000000..874d390f Binary files /dev/null and b/cpp-netlib/libs/network/doc/html/objects.inv differ diff --git a/cpp-netlib/libs/network/doc/html/reference.html b/cpp-netlib/libs/network/doc/html/reference.html new file mode 100644 index 00000000..4cec5fe1 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/reference.html @@ -0,0 +1,142 @@ + + + + + + + + Reference Manual — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Reference Manual

      +

      This reference manual refers to the API documentation of the public interfaces +to the different client and/or server implementations within cpp-netlib.

      + +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      Project history

      +

      Next topic

      +

      HTTP Client API

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/reference/http_client.html b/cpp-netlib/libs/network/doc/html/reference/http_client.html new file mode 100644 index 00000000..0584af81 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/reference/http_client.html @@ -0,0 +1,667 @@ + + + + + + + + HTTP Client API — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      HTTP Client API

      +
      +

      General

      +

      cpp-netlib includes and implements a number of HTTP clients that you can +use and embed in your own applications. All of the HTTP client implementations:

      +
      +
        +
      • Cannot be copied. This means you may have to store instances of the +clients in dynamic memory if you intend to use them as function parameters +or pass them around in smart pointers or by reference.
      • +
      • Assume that requests made are independent of each other. There currently +is no cookie or session management system built-in to cpp-netlib’s HTTP client +implementations.
      • +
      +
      +

      The HTTP clients all share the same API, but the internals are documented in +terms of what is different and what to expect with the different +implementations.

      +

      As of 0.9.1 the default implementation for the cpp-netlib HTTP client is +asynchronous.

      +

      As of 0.11 the Synchronous Clients are now DEPRECATED and will be removed +in subsequent releases.

      +
      +
      +

      Features

      +

      The HTTP client implementation supports requesting secure HTTP (HTTPS) content +only in the following situations:

      +
      +
        +
      • Client libraries are built with ``BOOST_NETWORK_ENABLE_HTTPS``. This +tells the implementation to use HTTPS-specific code to handle HTTPS-based +content when making connections associated with HTTPS URI’s. This requires +a dependency on OpenSSL.
      • +
      • The ``BOOST_NETWORK_ENABLE_HTTPS`` macro is set when compiling user +code. It is best to define this either at compile-time of all code using +the library, or before including any of the client headers.
      • +
      +
      +

      To use the client implementations that support HTTPS URIs, you may explicitly +do the following:

      +
      #define BOOST_NETWORK_ENABLE_HTTPS
      +#include <boost/network/include/http/client.hpp>
      +
      +
      +

      This forces HTTPS support to be enabled and forces a dependency on OpenSSL. +This dependency is imposed by Boost.Asio

      +
      +
      +

      Implementations

      +

      There is a single user-facing template class named basic_client which takes +three template parameters:

      +
      +
        +
      • Tag - which static tag you choose that defines the behavior of the client.
      • +
      • http_version_major - an unsigned int that defines the HTTP major version +number, this directly affects the HTTP messages sent by the client.
      • +
      • http_version_minor - an unsigned int that defines the HTTP minor version +number.
      • +
      +
      +

      There are two major different class of implementations of the basic_client +template that depend on which tag you choose: Synchronous Clients and +Asynchronous Clients. These two different classes are described in their own +sections following this one. What follows is a table of all tags supported by +the HTTP client implementation provided by cpp-netlib.

      +
      + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + +
      TagDescription
      http_default_8bit_tcp_resolveThis is the default HTTP implementation tag +that resolves addresses with a TCP resolver +and provides a synchronous/blocking HTTP +client interface.
      http_default_8bit_udp_resolveThis is similar to the above tag except that +it specifies the HTTP client to use a UDP +resolver. It also provides a synchronous/ +blocking HTTP client interface.
      http_keepalive_8bit_tcp_resolveThis tag specifies that the HTTP client by +default will keep connections to the server +alive. It only makes sense if the +version_major and version_minor are +both 1, to indicate HTTP 1.1. This tag +causes the HTTP client to resolve using a +TCP resolver and provides a synchronous/ +blocking HTTP client interface.
      http_keepalive_8bit_udp_resolveThis is similar to the above tag except that +it specifies the HTTP client to use a UDP +resolver. It also provides a synchronous/ +blocking HTTP client interface.
      http_async_8bit_tcp_resolveThis tag provides an active HTTP client +object implementation that uses a TCP +resolver. Response objects returned will +encapsulate a number of Boost.Thread +shared futures to hold values. Users don’t +have to see this as they are implementation +details.
      http_async_8bit_udp_resolveThis is similar to the above tag except that +specifies the HTTP client to use a UDP +resolver.
      +

      In the above table the tags follow a pattern for describing the behavior +introduced by the tags. This pattern is shown below:

      +
      +
      <protocol>_<modifier>_<character-width>_<resolve-strategy>
      +

      For example, the tag http_default_8bit_tcp_resolve indicates the protocol +http, a modifier default, a character width of 8bit, and a resolve +strategy of tcp_resolve.

      +
      +

      Synchronous Clients

      +

      Of the client tags shown in the table, the following makes the basic_client +behave as a fully synchronous client.

      +
      +
        +
      • http_default_8bit_tcp_resolve
      • +
      • http_default_8bit_udp_resolve
      • +
      • http_keepalive_8bit_tcp_resolve
      • +
      • http_keepalive_8bit_udp_resolve
      • +
      +
      +

      The synchronous client implements all the operations of the client underneath +the interface all block to wait for I/O to finish. All the member methods are +synchronous and will block until the response object is ready or throws if errors +are encountered in the performance of the HTTP requests.

      +
      +

      Warning

      +

      The synchronous clients are NOT thread safe. You will need to do +external synchronization to use synchronous client implementations.

      +
      +
      +

      Note

      +

      As of version 0.11, all the synchronous client implementations are +deprecated. They will be removed in the next version of the library.

      +
      +
      +
      +

      Asynchronous Clients

      +

      The following tags specify the basic_client to behave in an asynchronous +manner:

      +
      +
        +
      • http_async_8bit_tcp_resolve
      • +
      • http_async_8bit_udp_resolve
      • +
      +
      +

      An asynchronous client implementation means that``basic_client<...>`` is an +Active Object. This means that the client has and manages its own lifetime +thread, and returns values that are asynchronously filled in. The response +object encapsulates Boost.Thread futures which get filled in once the values +are available.

      +

      The asynchronous clients implement all operations asynchronously which are hidden +from the user. The interface is still synchronous but the fetching of data +happens on a different thread.

      +
      +

      Note

      +

      The asynchronous clients are thread safe, and can be shared across +many threads. Each request starts a sequence of asynchronous operations +dedicated to that request. The client does not re-cycle connections and uses +a one-request-one-connection model.

      +
      +

      When an asynchronous client object is destroyed, it waits for all pending +asynchronous operations to finish. Errors encountered during operations on +retrieving data from the response objects cause exceptions to be thrown – +therefore it is best that if a client object is constructed, it should outlive +the response object or be outside the try-catch block handling the errors from +operations on responses. In code, usage should look like the following:

      +
      http::client client;
      +try {
      +  http::client::response response = client.get("http://www.example.com/");
      +  std::cout << body(response);
      +} catch (std::exception& e) {
      +  // deal with exceptions here
      +}
      +
      +
      +

      A common mistake is to declare the client inside the try block which invokes +undefined behavior when errors arise from the handling of response objects. +Previous examples cited by the documentation showed the short version of the +code which didn’t bother moving the http::client object outside of the same +try block where the request/response objects are being used.

      +
      +
      +
      +

      Member Functions

      +

      In this section we assume that the following typedef is in effect:

      +
      typedef boost::network::http::basic_client<
      +    boost::network::http::tags::http_default_8bit_udp_resolve
      +    , 1
      +    , 1
      +    >
      +    client;
      +
      +
      +

      Also, that code using the HTTP client will have use the following header:

      +
      #include <boost/network/include/http/client.hpp>
      +
      +
      +
      +

      Note

      +

      Starting version 0.9, cpp-netlib clients and server implementations +by default now have an externally-linked component. This is a breaking change +for code that used to rely on cpp-netlib being a header-only library, but can +inhibited by defining the BOOST_NETWORK_NO_LIB preprocessor macro before +including any cpp-netlib header.

      +
      +
      +

      Note

      +

      Starting version 0.11, cpp-netlib clients and server implementations +no longer support the BOOST_NETWORK_NO_LIB option.

      +
      +
      +

      Constructors

      +

      The client implementation can be default constructed, or customized at +initialization.

      +
      +
      client()
      +
      Default constructor.
      +
      explicit client(client::options const &)
      +
      Constructor taking a client_options<Tag> object. The following table +shows the options you can set on a client_options<Tag> instance.
      +
      + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Parameter NameTypeDescription
      follow_redirectsboolBoolean to specify +whether the client +should follow HTTP +redirects. Default is +false.
      cache_resolvedboolBoolean to specify +whether the client +should cache resolved +endpoints. The default +is false.
      io_serviceshared_ptr<io_service>Shared pointer to a +Boost.Asio +io_service.
      openssl_certificatestringThe filename of the +certificate to load for +the SSL connection for +verification.
      openssl_verify_pathstringThe directory from +which the certificate +authority files are +located.
      always_verify_peerboolBoolean to specify +whether the client +should always verify +peers in SSL connections
      openssl_certificate_filestringFilename of the +certificate to use for +client-side SSL session +establishment.
      openssl_private_key_filestringFilename of the +private key to use for +client-side SSL session +establishment.
      timeoutintNumber of seconds to +wait for client requests +before considering a +timeout has occurred.
      +

      To use the above supported named parameters, you’ll have code that looks like +the following:

      +
      using namespace boost::network::http; // parameters are in this namespace
      +client::options options;
      +options.follow_redirects(true)
      +       .cache_resolved(true)
      +       .io_service(boost::make_shared<boost::asio::io_service>())
      +       .openssl_certificate("/tmp/my-cert")
      +       .openssl_verify_path("/tmp/ca-certs")
      +       .timeout(10);
      +client client_(options);
      +// use client_ as normal from here on out.
      +
      +
      +
      +
      +

      HTTP Methods

      +

      The client implementation supports various HTTP methods. The following +constructs assume that a client has been properly constructed named client_ +and that there is an appropriately constructed request object named request_ +and that there is an appropriately constructed response object named +response_ like the following:

      +
      using namespace boost::network::http;  // parameters are here
      +client client_();
      +client::request request_("http://cpp-netib.github.com/");
      +client::response response_;
      +
      +
      +
      +
      response_ = client_.get(request_)
      +
      Perform an HTTP GET request.
      +
      response_ = client_.get(request_, callback)
      +
      Perform an HTTP GET request, and have the body chunks be handled by the +callback parameter. The signature of callback should be the following: +void(iterator_range<char const *> const &, boost::system::error_code const +&).
      +
      response_ = client_.head(request_)
      +
      Perform an HTTP HEAD request.
      +
      response_ = client_.post(request_)
      +
      Perform an HTTP POST, use the data already set in the request object which +includes the headers, and the body.
      +
      response_ = client_.post(request_, callback)
      +
      Perform an HTTP POST request, and have the body chunks be handled by the +callback parameter. The signature of callback should be the following: +void(iterator_range<char const *> const &, boost::system::error_code const +&).
      +
      response_ = client_.post(request_, body)
      +
      Body is a string of type boost::network::string<Tag>::type where Tag +is the HTTP Client’s Tag. The default content-type used is +x-application/octet-stream.
      +
      response_ = client_.post(request_, body, callback)
      +
      Body is a string of type boost::network::string<Tag>::type where Tag +is the HTTP Client’s Tag. The default content-type used is +x-application/octet-stream. Have the response body chunks be handled by +the callback parameter. The signature of callback should be the +following: void(iterator_range<char const *> const &, +boost::system::error_code const &).
      +
      response_ = client_.post(request_, body, content_type)
      +
      The body and content_type parameters are of type +boost::network::string<Tag>::type where Tag is the HTTP Client’s +Tag. This uses the request object’s other headers.
      +
      response_ = client_.post(request_, body, content_type, callback)
      +
      The body and content_type parameters are of type +boost::network::string<Tag>::type where Tag is the HTTP Client’s +Tag. This uses the request object’s other headers. Have the response +body chunks be handled by the callback parameter. The signature of +callback should be the following: void(iterator_range<char const *> const +&, boost::system::error_code const &).
      +
      response_ = client_.post(request_, body, content_type, callback, streaming_callback)
      +
      The body and content_type parameters are of type +boost::network::string<Tag>::type where Tag is the HTTP Client’s +Tag. This uses the request object’s other headers. Have the response +body chunks be handled by the callback parameter. The signature of +callback should be the following: void(iterator_range<char const *> const +&, boost::system::error_code const &). The streaming_callback +argument should have a which has a signature of the form: +bool(string_type&). The provided string_type& will be streamed as +soon as the function returns. A return value of false signals the +client that the most recent invocation is the last chunk to be sent.
      +
      response_ = client_.post(request_, streaming_callback)
      +
      Perform and HTTP POST request, and have the request’s body chunks be +generated by the streaming_callback which has a signature of the form: +bool(string_type&). The provided string_type& will be streamed as +soon as the function returns. A return value of false signals the client +that the most recent invocation is the last chunk to be sent.
      +
      response_ = client_.post(request_, callback, streaming_callback)
      +
      Perform an HTTP POST request, and have the body chunks be handled by the +callback parameter. The signature of callback should be the +following: void(iterator_range<char const *> const &, +boost::system::error_code const &). This form also has the request’s body +chunks be generated by the streaming_callback which has a signature of +the form: bool(string_type&). The provided string_type& will be +streamed as soon as the function returns. A return value of false +signals the client that the most recent invocation is the last chunk to be +sent.
      +
      response_ = client_.put(request_)
      +
      Perform an HTTP PUT, use the data already set in the request object which +includes the headers, and the body.
      +
      response_ = client_.put(request_, callback)
      +
      Perform an HTTP PUT request, and have the body chunks be handled by the +callback parameter. The signature of callback should be the following: +void(iterator_range<char const *> const &, boost::system::error_code const +&).
      +
      response_ = client_.put(request_, body)
      +
      Body is a string of type boost::network::string<Tag>::type where Tag +is the HTTP Client’s Tag. The default content-type used is +x-application/octet-stream.
      +
      response_ = client_.put(request_, body, callback)
      +
      Body is a string of type boost::network::string<Tag>::type where Tag +is the HTTP Client’s Tag. The default content-type used is +x-application/octet-stream. Have the response body chunks be handled by +the callback parameter. The signature of callback should be the +following: void(iterator_range<char const *> const &, +boost::system::error_code const &).
      +
      response_ = client_.put(request_, body, content_type)
      +
      The body and content_type parameters are of type +boost::network::string<Tag>::type where Tag is the HTTP Client’s +Tag. This uses the request object’s other headers.
      +
      response_ = client_.put(request_, body, content_type, callback)
      +
      The body and content_type parameters are of type +boost::network::string<Tag>::type where Tag is the HTTP Client’s +Tag. This uses the request object’s other headers. Have the response +body chunks be handled by the callback parameter. The signature of +callback should be the following: void(iterator_range<char const *> const +&, boost::system::error_code const &).
      +
      response_ = client_.put(request_, body, content_type, callback, streaming_callback)
      +
      The body and content_type parameters are of type +boost::network::string<Tag>::type where Tag is the HTTP Client’s +Tag. This uses the request object’s other headers. Have the response +body chunks be handled by the callback parameter. The signature of +callback should be the following: void(iterator_range<char const *> const +&, boost::system::error_code const &). This form also has the request’s body +chunks be generated by the streaming_callback which has a signature of +the form: bool(string_type&). The provided string_type& will be +streamed as soon as the function returns. A return value of false +signals the client that the most recent invocation is the last chunk to be +sent
      +
      response_ = client_.put(request_, streaming_callback)
      +
      Perform and HTTP PUT request, and have the request’s body chunks be +generated by the streaming_callback which has a signature of the form: +bool(string_type&). The provided string_type& will be streamed as +soon as the function returns. A return value of false signals the client +that the most recent invocation is the last chunk to be sent.
      +
      response_ = client_.put(request_, callback, streaming_callback)
      +
      Perform an HTTP PUT request, and have the body chunks be handled by the +callback parameter. The signature of callback should be the +following: void(iterator_range<char const *> const &, +boost::system::error_code const &). This form also has the request’s body +chunks be generated by the streaming_callback which has a signature of +the form: bool(string_type&). The provided string_type& will be +streamed as soon as the function returns. A return value of false +signals the client that the most recent invocation is the last chunk to be +sent.
      +
      response_ = client_.delete_(request_)
      +
      Perform an HTTP DELETE request.
      +
      response_ = client_.delete_(request_, body_handler=callback)
      +
      Perform an HTTP DELETE request, and have the response body chunks be handled +by the callback parameter. The signature of callback should be the +following: void(iterator_range<char const *> const &, +boost::system::error_code const &).
      +
      +
      +
      +

      Client-Specific

      +
      +
      client_.clear_resolved_cache()
      +
      Clear the cache of resolved endpoints.
      +
      +
      +
      +

      Streaming Body Handler

      +

      As of v0.9.1 the library now offers a way to support a streaming body callback +function in all HTTP requests that expect a body part (GET, PUT, POST, DELETE). +A convenience macro is also provided to make callback handlers easier to write. +This macro is called BOOST_NETWORK_HTTP_BODY_CALLBACK which allows users to +write the following code to easily create functions or function objects that +are compatible with the callback function requirements.

      +

      An example of how to use the macro is shown below:

      +
      struct body_handler {
      +    explicit body_handler(std::string & body)
      +    : body(body) {}
      +
      +    BOOST_NETWORK_HTTP_BODY_CALLBACK(operator(), range, error) {
      +        // in here, range is the Boost.Range iterator_range, and error is
      +        // the Boost.System error code.
      +        if (!error)
      +            body.append(boost::begin(range), boost::end(range));
      +    }
      +
      +    std::string & body;
      +};
      +
      +// somewhere else
      +std::string some_string;
      +response_ = client_.get(request("http://cpp-netlib.github.com/"),
      +                        body_handler(some_string));
      +
      +
      +

      You can also use if for standalone functions instead if you don’t want or need +to create a function object.

      +
      BOOST_NETWORK_HTTP_BODY_CALLBACK(print_body, range, error) {
      +    if (!error)
      +        std::cout << "Received " << boost::distance(range) << "bytes."
      +                  << std::endl;
      +    else
      +        std::cout << "Error: " << error << std::endl;
      +}
      +
      +// somewhere else
      +response_ = client_.get(request("http://cpp-netlib.github.com/"),
      +                        print_body);
      +
      +
      +

      The BOOST_NETWORK_HTTP_BODY_CALLBACK macro is defined in +boost/network/protocol/http/client/macros.hpp.

      +
      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      Reference Manual

      +

      Next topic

      +

      HTTP Request

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/reference/http_request.html b/cpp-netlib/libs/network/doc/html/reference/http_request.html new file mode 100644 index 00000000..243edb2d --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/reference/http_request.html @@ -0,0 +1,443 @@ + + + + + + + + HTTP Request — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      HTTP Request

      +

      This part of the documentation talks about the publicly accessible API of the +HTTP Request objects. This section details the Request Concepts requirements, +the implemented and required Directives, Modifiers, and Wrappers that work +with the HTTP Request objects.

      +
      +

      Request Concepts

      +

      There are two generally supported Request Concepts implemented in the library. +The first of two is the Normal Client Request Concept and the second is the +Pod Server Request Concept.

      +

      The Normal Client Request Concept is what the HTTP Client interface requires. +All operations performed internally by the HTTP Client abide by the interface +required by this concept definition.

      +

      The Pod Server Request Concept is as the name suggests what the HTTP Server +implementation requires from Request Objects.

      +

      Switching on whether the Request concept chooses either of the Normal Client +Request Concept or the Pod Server Request Concept is done through the +nested tag type and whether that tag derives from the root tag pod. +Simply, if the Request type’s nested tag type derives from +boost::network::tags::pod then it chooses to enforce the Pod Server Request +Concept, otherwise it chooses the Normal Client Request Concept.

      +
      +

      Normal Client Request Concept

      +

      A type models the Normal Client Request Concept if it models the Message +Concept and also supports the following constructs.

      +

      Legend

      + +++ + + + + + + + + + + + + + +
      R:The request type.
      r:An instance of R.
      S:The string type.
      s:An instance of S.
      P:The port type.
      p:An instance of P.
      + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      ConstructResultDescription
      R::string_typeSThe nested string_type type.
      R::port_typePThe nested port_type type.
      R r(s)NAConstruct a Request with an s +provided. This treats s as the URI +to where the request is destined for.
      host(request)Convertible +to SReturn the host to where the request +is destined for.
      port(request)Convertible +to PReturn the port to where the request +is destined for.
      path(request)Convertible +to SReturn the path included in the URI.
      query(request)Convertible +to SReturn the query part of the URI.
      anchor(request)Convertible +to SReturn the anchor part of the URI.
      protocol(request)Convertible +to SReturn the protocol/scheme part of the +URI.
      r << uri(s)R&Set the URI of the request.
      uri(r, s)voidSet the URI of the request.
      +
      +
      +

      Pod Server Request Concept

      +

      A type models the Pod Server Request Concept if it models the Message Concept +and also supports the following constructs.

      +

      Legend

      + +++ + + + + + + + + + + + +
      R:The request type.
      r:An instance of R.
      S:The string type.
      I:An unsigned 8 bit integer.
      V:The vector type for headers.
      + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      ConstructResultDescription
      R::string_typeSThe nested string_type type.
      R::headers_container_typeVThe nested +headers_container_type type.
      r.sourceSThe nested source of the request.
      r.methodSThe method of the request.
      r.destinationSThe destination of the request. +This is normally the URI of the +request.
      r.version_majorIThe major version number part of +the request.
      r.version_minorIThe minor version number part of +the request.
      r.headersVThe vector of headers.
      r.bodySThe body of the request.
      +
      +
      +
      +

      Directives

      +

      This section details the provided directives that are provided by +cpp-netlib. The section was written to assume that an appropriately +constructed request instance is either of the following:

      +
      boost::network::http::basic_request<
      +  boost::network::http::tags::http_default_8bit_udp_resolve
      +> request;
      +
      +// or
      +
      +boost::network::http::basic_request<
      +  boost::network::http::tags::http_server
      +> request;
      +
      +
      +

      The section also assumes that there following using namespace declaration is in +effect:

      +
      using namespace boost::network;
      +
      +
      +

      Directives are meant to be used in the following manner:

      +
      request << directive(...);
      +
      +
      +
      +

      Warning

      +

      There are two versions of directives, those that are applicable to +messages that support narrow strings (std::string) and those that are +applicable to messages that support wide strings (std::wstring). The +cpp-netlib implementation still does not convert wide strings into +UTF-8 encoded narrow strings. This will be implemented in subsequent +library releases.

      +

      For now all the implemented directives are listed, even if some of them still +do not implement things correctly.

      +
      +
      +
      unspecified source(std::string const & source_)
      +
      Create a source directive with a std::string as a parameter, to be set +as the source of the request.
      +
      unspecified source(std::wstring const & source_)
      +
      Create a source directive with a std::wstring as a parameter, to be set +as the source of the request.
      +
      unspecified destination(std::string const & source_)
      +
      Create a destination directive with a std::string as a parameter, to be +set as the destination of the request.
      +
      unspecified destination(std::wstring const & source_)
      +
      Create a destination directive with a std::wstring as a parameter, to be +set as the destination of the request.
      +
      unspecified header(std::string const & name, std::string const & value)
      +
      Create a header directive that will add the given name and value pair to the +headers already associated with the request. In this case the name and +values are both std::string.
      +
      unspecified header(std::wstring const & name, std::wstring const & value)
      +
      Create a header directive that will add the given name and value pair to the +headers already associated with the request. In this case the name and +values are both std::wstring.
      +
      unspecified remove_header(std::string const & name)
      +
      Create a remove_header directive that will remove all the occurences of the +given name from the headers already associated with the request. In this +case the name of the header is of type std::string.
      +
      unspecified remove_header(std::wstring const & name)
      +
      Create a remove_header directive that will remove all the occurences of the +given name from the headers already associated with the request. In this +case the name of the header is of type std::wstring.
      +
      unspecified body(std::string const & body_)
      +
      Create a body directive that will set the request’s body to the given +parameter. In this case the type of the body is an std::string.
      +
      unspecified body(std::wstring const & body_)
      +
      Create a body directive that will set the request’s body to the given +parameter. In this case the type of the body is an std::wstring.
      +
      +
      +
      +

      Modifiers

      +

      This section details the provided modifiers that are provided by +cpp-netlib.

      +
      +
      template <class Tag> inline void source(basic_request<Tag> & request, typename string<Tag>::type const & source_)
      +
      Modifies the source of the given request. The type of source_ is +dependent on the Tag specialization of basic_request.
      +
      template <class Tag> inline void destination(basic_request<Tag> & request, typename string<Tag>::type const & destination_)
      +
      Modifies the destination of the given request. The type of destination_ is +dependent on the Tag specialization of basic_request.
      +
      template <class Tag> inline void add_header(basic_request<Tag> & request, typename string<Tag>::type const & name, typename string<Tag>::type const & value)
      +
      Adds a header to the given request. The type of the name and +value parameters are dependent on the Tag specialization of +basic_request.
      +
      template <class Tag> inline void remove_header(basic_request<Tag> & request, typename string<Tag>::type const & name)
      +
      Removes a header from the given request. The type of the name +parameter is dependent on the Tag specialization of basic_request.
      +
      template <class Tag> inline void clear_headers(basic_request<Tag> & request)
      +
      Removes all headers from the given request.
      +
      template <class Tag> inline void body(basic_request<Tag> & request, typename string<Tag>::type const & body_)
      +
      Modifies the body of the given request. The type of body_ is +dependent on the Tag specialization of basic_request.
      +
      +
      +
      +

      Wrappers

      +

      This section details the provided request wrappers that come with +cpp-netlib. Wrappers are used to convert a message into a different type, +usually providing accessor operations to retrieve just part of the message. This +section assumes that the following using namespace directives are in +effect:

      +
      using namespace boost::network;
      +using namespace boost::network::http;
      +
      +
      +
      +
      template <class Tag> unspecified source(basic_request<Tag> const & request)
      +
      Returns a wrapper convertible to typename string<Tag>::type that +provides the source of a given request.
      +
      template <class Tag> unspecified destination(basic_request<Tag> const & request)
      +
      Returns a wrapper convertible to typename string<Tag>::type that +provides the destination of a given request.
      +
      template <class Tag> unspecified headers(basic_request<Tag> const & request)
      +
      Returns a wrapper convertible to typename headers_range<basic_request<Tag> +>::type or typename basic_request<Tag>::headers_container_type that +provides the headers of a given request.
      +
      template <class Tag> unspecified body(basic_request<Tag> const & request)
      +
      Returns a wrapper convertible to typename string<Tag>::type that +provides the body of a given request.
      +
      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      HTTP Client API

      +

      Next topic

      +

      HTTP Response

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/reference/http_response.html b/cpp-netlib/libs/network/doc/html/reference/http_response.html new file mode 100644 index 00000000..884a4293 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/reference/http_response.html @@ -0,0 +1,476 @@ + + + + + + + + HTTP Response — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      HTTP Response

      +

      This part of the documentation talks about the publicly accessible API of the +HTTP Response objects. This section details the Response Concept requirements, +the implemented and required Directives, Modifiers, and Wrappers that work +with the HTTP Response objects.

      +
      +

      Note

      +

      The HTTP server response object is a POD type, which doesn’t support +any of the following details. There are only a few fields available in the +HTTP server response type, which can be seen in +boost/network/protocol/http/impl/response.ipp.

      +
      +
      +

      Response Concept

      +

      A type models the Response Concept if it models the Message Concept and also +supports the following constructs.

      +

      Legend

      + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      R:The response type.
      r:An instance of R.
      S:The string type.
      s,e,g:Instances of S.
      P:The port type.
      p:An instance of P.
      V:The version type.
      v:An instance of v.
      T:The status type.
      t:An instance of T.
      M:The status message type.
      m:An instance of M.
      U:An unsigned 16-bit int.
      u:An instance of U.
      +
      +

      Note

      +

      In the table below, the namespace traits is an alias for +boost::network::http::traits.

      +
      + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      ConstructResultDescription
      R::string_typeSThe nested string_type +type.
      traits::version<R>::typeVThe version type associated +with R.
      traits::status<R>::typeTThe status type associated +with R.
      traits::status_message<R>::typeMThe status message type +associated with R.
      r << version(v)R&Sets the version of r.
      r << status(t)R&Sets the status of r.
      r << status_message(m)R&Sets the status message of +r.
      version(r, v)voidSets the version of r.
      status(r, t)voidSets the status of r.
      status_message(r, m)voidSets the status message of +r.
      S e = version(r)NAGet the version of r.
      U u = status(r)NAGet the status of r.
      S g = status_message(r)NAGet the status message of +r.
      +
      +
      +

      Directives

      +

      This section details the provided directives that are provided by +cpp-netlib. The section was written to assume that an appropriately +constructed response instance is either of the following:

      +
      boost::network::http::basic_response<
      +  boost::network::http::tags::http_default_8bit_udp_resolve
      +> response;
      +
      +// or
      +
      +boost::network::http::basic_response<
      +  boost::network::http::tags::http_server
      +> response;
      +
      +
      +

      The section also assumes that there following using namespace declaration is in +effect:

      +
      using namespace boost::network;
      +
      +
      +

      Directives are meant to be used in the following manner:

      +
      response << directive(...);
      +
      +
      +
      +

      Warning

      +

      There are four versions of directives, those that are applicable +to messages that support narrow strings (std::string), those that are +applicable to messages that support wide strings (std::wstring), those +that are applicable to messages that support future-wrapped narrow and wide +strings (boost::shared_future<std::string> and +boost::shared_future<std::wstring>).

      +

      The cpp-netlib implementation still does not convert wide strings into +UTF-8 encoded narrow strings. This will be implemented in subsequent +library releases.

      +

      For now all the implemented directives are listed, even if some of them still +do not implement things correctly.

      +
      +
      +
      unspecified source(std::string const & source_)
      +
      Create a source directive with a std::string as a parameter, to be set +as the source of the response.
      +
      unspecified source(std::wstring const & source_)
      +
      Create a source directive with a std::wstring as a parameter, to be set +as the source of the response.
      +
      unspecified source(boost::shared_future<std::string> const & source_)
      +
      Create a source directive with a boost::shared_future<std::string> as a parameter, to be set +as the source of the response.
      +
      unspecified source(boost::shared_future<std::wstring> const & source_)
      +
      Create a source directive with a boost::shared_future<std::wstring> as a parameter, to be set +as the source of the response.
      +
      unspecified destination(std::string const & source_)
      +
      Create a destination directive with a std::string as a parameter, to be +set as the destination of the response.
      +
      unspecified destination(std::wstring const & source_)
      +
      Create a destination directive with a std::wstring as a parameter, to be +set as the destination of the response.
      +
      unspecified destination(boost::shared_future<std::string> const & destination_)
      +
      Create a destination directive with a boost::shared_future<std::string> as a parameter, to be set +as the destination of the response.
      +
      unspecified destination(boost::shared_future<std::wstring> const & destination_)
      +
      Create a destination directive with a boost::shared_future<std::wstring> as a parameter, to be set +as the destination of the response.
      +
      unspecified header(std::string const & name, std::string const & value)
      +
      Create a header directive that will add the given name and value pair to the +headers already associated with the response. In this case the name and +values are both std::string.
      +
      unspecified header(std::wstring const & name, std::wstring const & value)
      +
      Create a header directive that will add the given name and value pair to the +headers already associated with the response. In this case the name and +values are both std::wstring.
      +
      unspecified remove_header(std::string const & name)
      +
      Create a remove_header directive that will remove all the occurences of the +given name from the headers already associated with the response. In this +case the name of the header is of type std::string.
      +
      unspecified remove_header(std::wstring const & name)
      +
      Create a remove_header directive that will remove all the occurences of the +given name from the headers already associated with the response. In this +case the name of the header is of type std::wstring.
      +
      unspecified body(std::string const & body_)
      +
      Create a body directive that will set the response’s body to the given +parameter. In this case the type of the body is an std::string.
      +
      unspecified body(std::wstring const & body_)
      +
      Create a body directive that will set the response’s body to the given +parameter. In this case the type of the body is an std::wstring.
      +
      unspecified body(boost::shared_future<std::string> const & body_)
      +
      Create a body directive that will set the response’s body to the given +parameter. In this case the type of the body is an boost::shared_future<std::string>.
      +
      unspecified body(boost::shared_future<std::wstring> const & body_)
      +
      Create a body directive that will set the response’s body to the given +parameter. In this case the type of the body is an boost::shared_future<std::wstring>.
      +
      unspecified version(std::string const & version_)
      +

      Create a version directive that will set the response’s version to the given +parameter. In this case the type of the version is an std::string.

      +

      Note that this version includes the full "HTTP/" string.

      +
      +
      unspecified version(std::wstring const & version_)
      +

      Create a version directive that will set the response’s version to the given +parameter. In this case the type of the version is an std::wstring.

      +

      Note that this version includes the full "HTTP/" string.

      +
      +
      unspecified version(boost::shared_future<std::string> const & version_)
      +

      Create a version directive that will set the response’s version to the given +parameter. In this case the type of the version is an boost::shared_future<std::string>.

      +

      Note that this version includes the full "HTTP/" string.

      +
      +
      unspecified version(boost::shared_future<std::wstring> const & version_)
      +

      Create a version directive that will set the response’s version to the given +parameter. In this case the type of the version is an boost::shared_future<std::wstring>.

      +

      Note that this version includes the full "HTTP/" string.

      +
      +
      unspecified status_message(std::string const & status_message_)
      +

      Create a status_message directive that will set the response’s status_message to the given +parameter. In this case the type of the status_message is an std::string.

      +

      Note that this status_message includes the full "HTTP/" string.

      +
      +
      unspecified status_message(std::wstring const & status_message_)
      +

      Create a status_message directive that will set the response’s status_message to the given +parameter. In this case the type of the status_message is an std::wstring.

      +

      Note that this status_message includes the full "HTTP/" string.

      +
      +
      unspecified status_message(boost::shared_future<std::string> const & status_message_)
      +

      Create a status_message directive that will set the response’s status_message to the given +parameter. In this case the type of the status_message is an boost::shared_future<std::string>.

      +

      Note that this status_message includes the full "HTTP/" string.

      +
      +
      unspecified status_message(boost::shared_future<std::wstring> const & status_message_)
      +

      Create a status_message directive that will set the response’s status_message to the given +parameter. In this case the type of the status_message is an boost::shared_future<std::wstring>.

      +

      Note that this status_message includes the full "HTTP/" string.

      +
      +
      unspecified status(boost::uint16_t status_)
      +
      Create a status directive that will set the response’s status to the given +parameter. In this case the type of status_ is boost::uint16_t.
      +
      unspecified status(boost::shared_future<boost::uint16_t> const & status_)
      +
      Create a status directive that will set the response’s status to the given +parameter. In this case the type of status_ is boost::shared_future<boost::uint16_t>.
      +
      +
      +
      +

      Modifiers

      +

      This section details the provided modifiers that are provided by +cpp-netlib.

      +
      +
      template <class Tag> inline void source(basic_response<Tag> & response, typename string<Tag>::type const & source_)
      +
      Modifies the source of the given response. The type of source_ is +dependent on the Tag specialization of basic_response.
      +
      template <class Tag> inline void source(basic_response<Tag> & response, boost::shared_future<typename string<Tag>::type> const & source_)
      +
      Modifies the source of the given response. The type of source_ is +dependent on the Tag specialization of basic_response.
      +
      template <class Tag> inline void destination(basic_response<Tag> & response, typename string<Tag>::type const & destination_)
      +
      Modifies the destination of the given response. The type of destination_ is +dependent on the Tag specialization of basic_response.
      +
      template <class Tag> inline void destination(basic_response<Tag> & response, boost::shared_future<typename string<Tag>::type> const & destination_)
      +
      Modifies the destination of the given response. The type of destination_ is +dependent on the Tag specialization of basic_response.
      +
      template <class Tag> inline void add_header(basic_response<Tag> & response, typename string<Tag>::type const & name, typename string<Tag>::type const & value)
      +
      Adds a header to the given response. The type of the name and +value parameters are dependent on the Tag specialization of +basic_response.
      +
      template <class Tag> inline void remove_header(basic_response<Tag> & response, typename string<Tag>::type const & name)
      +
      Removes a header from the given response. The type of the name +parameter is dependent on the Tag specialization of basic_response.
      +
      template <class Tag> inline void headers(basic_response<Tag> & response, typename headers_container<basic_response<Tag> >::type const & headers_)
      +
      Sets the whole headers contained in response as the given parameter +headers_.
      +
      template <class Tag> inline void headers(basic_response<Tag> & response, boost::shared_future<typename headers_container<basic_response<Tag> >::type> const & headers_)
      +
      Sets the whole headers contained in response as the given parameter +headers_.
      +
      template <class Tag> inline void clear_headers(basic_response<Tag> & response)
      +
      Removes all headers from the given response.
      +
      template <class Tag> inline void body(basic_response<Tag> & response, typename string<Tag>::type const & body_)
      +
      Modifies the body of the given response. The type of body_ is +dependent on the Tag specialization of basic_response.
      +
      template <class Tag> inline void body(basic_response<Tag> & response, boost::shared_future<typename string<Tag>::type> const & body_)
      +
      Modifies the body of the given response. The type of body_ is +dependent on the Tag specialization of basic_response.
      +
      template <class Tag> inline void version(basic_response<Tag> & response, typename traits::version<basic_response<Tag> >::type const & version_)
      +
      Modifies the version of the given response. The type of version_ is +dependent on the Tag specialization of basic_response.
      +
      template <class Tag> inline void status(basic_response<Tag> & response, typename traits::status<basic_response<Tag> >::type const & status_)
      +
      Modifies the status of the given response. The type of status_ is +dependent on the Tag specialization of basic_response.
      +
      template <class Tag> inline void status_message(basic_response<Tag> & response, typename traits::status_message<basic_response<Tag> >::type const & status_message_)
      +
      Modifies the status message of the given response. The type of status_message_ is +dependent on the Tag specialization of basic_response.
      +
      +
      +
      +

      Wrappers

      +

      This section details the provided response wrappers that come with +cpp-netlib. Wrappers are used to convert a message into a different type, +usually providing accessor operations to retrieve just part of the message. This +section assumes that the following using namespace directives are in +effect:

      +
      using namespace boost::network;
      +using namespace boost::network::http;
      +
      +
      +
      +
      template <class Tag> unspecified source(basic_response<Tag> const & response)
      +
      Returns a wrapper convertible to typename string<Tag>::type that +provides the source of a given response.
      +
      template <class Tag> unspecified destination(basic_response<Tag> const & response)
      +
      Returns a wrapper convertible to typename string<Tag>::type that +provides the destination of a given response.
      +
      template <class Tag> unspecified headers(basic_response<Tag> const & response)
      +
      Returns a wrapper convertible to typename headers_range<basic_response<Tag> +>::type or typename basic_response<Tag>::headers_container_type that +provides the headers of a given response.
      +
      template <class Tag> unspecified body(basic_response<Tag> const & response)
      +
      Returns a wrapper convertible to typename string<Tag>::type that +provides the body of a given response.
      +
      template <class Tag> unspecified version(basic_response<Tag> const & response)
      +
      Returns a wrapper convertible to typename string<Tag>::type that +provides the version of the given response.
      +
      template <class Tag> unspecified status(basic_response<Tag> const & response)
      +
      Returns a wrapper convertible to typename boost::uint16_t that +provides the status of the given response.
      +
      template <class Tag> unspecified status_message(basic_response<Tag> const & response)
      +
      Returns a wrapper convertible to typename string<Tag>::type that +provides the status message of the given response.
      +
      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      HTTP Request

      +

      Next topic

      +

      HTTP Server API

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/reference/http_server.html b/cpp-netlib/libs/network/doc/html/reference/http_server.html new file mode 100644 index 00000000..eef689b9 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/reference/http_server.html @@ -0,0 +1,759 @@ + + + + + + + + HTTP Server API — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      HTTP Server API

      +
      +

      General

      +

      cpp-netlib includes and implements two distinct HTTP server +implementations that you can use and embed in your own applications. Both HTTP +Server implementations:

      +
      +
        +
      • Cannot be copied. This means you may have to store instances of the HTTP +Server in dynamic memory if you intend to use them as function parameters or +pass them around in smart pointers of by reference.
      • +
      • Assume that requests made are independent of each other. None of the +HTTP Server implementations support request pipelining (yet) so a single +connection only deals with a single request.
      • +
      • Are header-only and are compiled-into your application. Future releases +in case you want to upgrade the implementation you are using in your +application will be distributed as header-only implementations, which means +you have to re-compile your application to use a newer version of the +implementations.
      • +
      +
      +

      The HTTP Servers have different semantics, and in some cases require different +APIs from the supplied template parameters.

      +
      +
      +

      Implementations

      +

      There are two different user-facing template classes that differentiate the +Synchronous Servers from the Asynchronous Servers. Both templates take a +single template parameter named Handler which describes the type of the +Handler function object.

      +

      There are two different Handler concepts, one concept for Synchronous Servers +and another for Asynchronous Servers.

      +

      The SynchronousHandler concept for Synchronous Servers is described by the +following table:

      +
      +

      Legend:

      +
      +
      H
      +
      The Handler type.
      +
      h
      +
      An instance of H.
      +
      Req
      +
      A type that models the Request Concept.
      +
      Res
      +
      A type that models the Response Concept.
      +
      req
      +
      An instance of Req.
      +
      res
      +
      An instance of Res.
      +
      + +++++ + + + + + + + + + + + + +
      ConstructReturn TypeDescription
      h(req,res)voidHandle the request; res is passed in as a +non-const lvalue, which represents the +response to be returned to the client +performing the request.
      +

      More information about the internals of the Synchronous Servers can be found +in the following section.

      +

      The AsynchronousHandler concept for Asynchronous Servers is described by the +following table:

      +
      +

      Legend:

      +
      +
      H
      +
      The Handler type.
      +
      h
      +
      An instance of H.
      +
      Req
      +
      A type that models the Request Concept.
      +
      ConnectionPtr
      +
      A type that models the Connection Pointer Concept.
      +
      req
      +
      An instance of Req.
      +
      conn
      +
      An instance of ConncetionPtr.
      +
      + +++++ + + + + + + + + + + + + +
      ConstructReturn TypeDescription
      h(req, conn)voidHandle the request; conn is a shared +pointer which exposes functions for +writing to and reading from the connection.
      +

      More information about the internals of the Asynchronous Servers can be found +in the following section.

      +
      +
      +

      Synchronous Servers

      +

      The synchronous server implementation is represented by the template server +in namespace boost::network::http. The server template takes in a single +template parameter named Handler which models the SynchronousHandler +concept (described above).

      +

      An instance of Handler is taken in by reference to the constructor of the HTTP +server. This means the Handler is not copied around and only a single instance +of the handler is used for all connections and requests performed against the +HTTP server.

      +
      +

      Warning

      +

      It is important to note that the HTTP server does not implement any +locking upon invoking the Handler. In case you have any state in the Handler +that will be associated with the synchronous server, you would have to +implement your own synchronization internal to the Handler implementation. +This matters especially if you run the synchronous server in multiple +threads.

      +
      +

      The general pattern of usage for the HTTP Server template is shown below:

      +
      struct handler;
      +typedef boost::network::http::server<handler> http_server;
      +
      +struct handler {
      +    void operator()(
      +        http_server::request const & req,
      +        http_server::response & res
      +    ) {
      +        // do something, and then edit the res object here.
      +    }
      +};
      +
      +
      +

      More information about the actual HTTP Server API follows in the next section. +It is important to understand that the HTTP Server is actually embedded in your +application, which means you can expose almost all your application logic +through the Handler type, which you can also initialize appropriately.

      +
      +

      API Documentation

      +

      The following sections assume that the following file has been included:

      +
      #include <boost/network/include/http/server.hpp>
      +
      +
      +

      And that the following typedef’s have been put in place:

      +
      struct handler_type;
      +typedef boost::network::http::server<handler_type> http_server;
      +
      +struct handler_type {
      +    void operator()(http_server::request const & request,
      +                    http_server::response & response) {
      +        // do something here
      +    }
      +};
      +
      +
      +
      +

      Constructor

      +
      +
      explicit http_server(options)
      +
      Construct an HTTP Server instance, passing in a server_options<Tag, +Handler> object. The following table shows the supported options in +server_options<Tag, Handler>.
      +
      + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Parameter NameTypeDescription
      addressstring_typeThe hostname or IP address from which the server should be bound to. This parameter is required.
      portstring_typeThe port to which the server should bind and listen to. This parameter is required.
      thread_poolshared_ptr<thread_pool>A shared pointer to an instance of boost::network::utils::thread_pool – this is the +thread pool from where the handler is invoked. This parameter is only applicable and required +for async_server instances.
      io_serviceshared_ptr<io_service>An optional lvalue to an instance of boost::asio::io_service which allows the server to use +an already-constructed boost::asio::io_service instance instead of instantiating one that it +manages.
      reuse_addressboolA boolean that specifies whether to re-use the address and port on which the server will be +bound to. This enables or disables the socket option for listener sockets. The default is +false.
      report_abortedboolA boolean that specifies whether the listening socket should report aborted connection attempts +to the accept handler (an internal detail of cpp-netlib). This is put in place to allow for +future-proofing the code in case an optional error handler function is supported in later +releases of cpp-netlib. The default is false.
      receive_buffer_sizeintThe size of the socket’s receive buffer. The default is defined by Boost.Asio and is +platform-dependent.
      send_buffer_sizeintThe size of the socket’s send buffer. The default is defined by Boost.Asio and is +platform-dependent.
      receive_low_watermarkintThe size of the socket’s low watermark for its receive buffer. The default is defined by +Boost.Asio and is platform-dependent.
      send_buffer_sizeintThe size of the socket’s send low watermark for its send buffer. The default is defined by +Boost.Asio and is platform-dependent.
      non_blocking_ioboolAn optional bool to define whether the socket should use non-blocking I/O in case the platform +supports it. The default is true.
      lingerboolAn optional bool to determine whether the socket should linger in case there’s still data to be +sent out at the time of its closing. The default is true.
      linger_timeoutintAn optional int to define the timeout to wait for socket closes before it is set to linger. +The default is 0.
      contextshared_ptr<context>An optional shared pointer to an instance of boost::asio::ssl::context – this contains the +settings needed to support SSL. This parameter is only applicable for async_server instances.
      +

      To use the above supported named parameters, you’ll have code that looks like the following:

      +
      using namespace boost::network::http; // parameters are in this namespace
      +handler handler_instance;
      +sync_server<handler>::options options(handler_instance);
      +options.address("0.0.0.0")
      +       .port("80")
      +       .io_service(boost::make_shared<boost::asio::io_service>())
      +       .reuse_address(true);
      +sync_server<handler> instance(options);
      +instance.run();
      +
      +
      +
      +
      +

      Public Members

      +

      The following definitions assume that a properly constructed http_server +instance has been constructed in the following manner:

      +
      handler_type handler;
      +http_server::options options(handler);
      +http_server server(options.address("127.0.0.1").port("8000"));
      +
      +
      +
      +
      server.run()
      +
      Run the HTTP Server event loop. This function can be run on multiple threads +following the example:
      +
      +
      boost::thread t1(boost::bind(&http_server::run, &server));
      +boost::thread t2(boost::bind(&http_server::run, &server));
      +server.run();
      +t1.join();
      +t2.join();
      +
      +
      +
      +
      server.stop()
      +
      Stop the HTTP Server acceptor and wait for all pending requests to finish.
      +
      +
      +
      +

      Response Object

      +

      The response object has its own public member functions which can be very +helpful in certain simple situations.

      +
      +
      response = http_server::response::stock_reply(status, body)
      +
      Code like the above should go inside the handler’s operator() overload. +The body parameter is an std::string. The status parameter is any of +the following values from the http_server::response enum +status_type:
      +
      +
      enum status_type {
      +    ok = 200,
      +    created = 201,
      +    accepted = 202,
      +    no_content = 204,
      +    multiple_choices = 300,
      +    moved_permanently = 301,
      +    moved_temporarily = 302,
      +    not_modified = 304,
      +    bad_request = 400,
      +    unauthorized = 401,
      +    forbidden = 403,
      +    not_found = 404,
      +    not_supported = 405,
      +    not_acceptable = 406,
      +    internal_server_error = 500,
      +    not_implemented = 501,
      +    bad_gateway = 502,
      +    service_unavailable = 503
      +};
      +
      +
      +

      The response object also has the following publicly accessible member values +which can be directly manipulated by the handler.

      + +++++ + + + + + + + + + + + + + + + + + + + + +
      Member NameTypeDescription
      statusstatus_typeThe HTTP status of the response.
      headersvector<header>Vector of headers. [1]
      contentstring_type [2]The contents of the response.
      + + + + + +
      [1]A header is a struct of type +response_header<http::tags::http_server>. An instance always has the +members name and value both of which are of type string_type.
      + + + + + +
      [2]string_type is +boost::network::string<http::tags::http_server>::type.
      +
      +
      +
      +
      +

      Asynchronous Servers

      +

      The asynchronous server implementation is significantly different to the +synchronous server implementation in three ways:

      +
      +
        +
      1. The Handler instance is invoked asynchronously. This means the I/O +thread used to handle network-related events are free to handle only the +I/O related events. This enables the server to scale better as to the +number of concurrent connections it can handle.
      2. +
      3. The Handler is able to schedule asynchronous actions on the thread pool +associated with the server. This allows handlers to perform multiple +asynchronous computations that later on perform writes to the connection.
      4. +
      5. The Handler is able to control the (asynchronous) writes to and reads from +the HTTP connection. Because the connection is available to the Handler, +that means it can write out chunks of data at a time or stream data through +the connection continuously.
      6. +
      +
      +

      The asynchronous server is meant to allow for better scalability in terms of the +number of concurrent connections and for performing asynchronous actions within +the handlers. If your application does not need to write out information +asynchronously or perform potentially long computations, then the synchronous +server gives a generally better performance profile than the asynchronous +server.

      +

      The asynchronous server implementation is available from a single user-facing +template named async_server. This template takes in a single template +parameter which is the type of the Handler to be called once a request has been +parsed from a connection.

      +

      An instance of Handler is taken as a reference to the constructor similar to the +synchronous server implementation.

      +
      +

      Warning

      +

      The asynchronous server implementation, like the synchronous server +implementation, does not perform any synchronization on the calls to the +Handler invocation. This means if your handler contains or maintains internal +state, you are responsible for implementing your own synchronization on +accesses to the internal state of the Handler.

      +
      +

      The general pattern for using the async_server template is shown below:

      +
      struct handler;
      +typedef boost::network::http::async_server<handler> http_server;
      +
      +struct handler {
      +    void operator()(
      +        http_server::request const & req,
      +        http_server::connection_ptr connection
      +    ) {
      +        // handle the request here, and use the connection to
      +        // either read more data or write data out to the client
      +    }
      +};
      +
      +
      +
      +

      API Documentation

      +

      The following sections assume that the following file has been included:

      +
      #include <boost/network/include/http/server.hpp>
      +#include <boost/network/utils/thread_pool.hpp>
      +
      +
      +

      And that the following typedef’s have been put in place:

      +
      struct handler_type;
      +typedef boost::network::http::server<handler_type> http_server;
      +
      +struct handler_type {
      +    void operator()(http_server::request const & request,
      +                    http_server::connection_ptr connection) {
      +        // do something here
      +    }
      +};
      +
      +
      +
      +

      Constructor

      +
      +
      explicit http_server(options)
      +
      Construct an HTTP server instance passing in a server_options<Tag, +Handler> instance.
      +
      +
      +
      +

      Public Members

      +

      The following definitions assume that a properly constructed http_server +instance has been constructed in the following manner:

      +
      handler_type handler;
      +http_server::options options(handler);
      +options.thread_pool(boost::make_shared<boost::network::utils::thread_pool>(2));
      +http_server server(options.address("127.0.0.1").port("8000"));
      +
      +
      +
      +
      server.run()
      +
      Run the HTTP Server event loop. This function can be run on multiple threads +following the example:
      +
      +
      boost::thread t1(boost::bind(&http_server::run, &server));
      +boost::thread t2(boost::bind(&http_server::run, &server));
      +server.run();
      +t1.join();
      +t2.join();
      +
      +
      +
      +
      server.stop()
      +
      Stop the HTTP Server acceptor and wait for all pending requests to finish.
      +
      +
      +
      +

      Connection Object

      +

      The connection object has its own public member functions which will be the +primary means for reading from and writing to the connection.

      +
      +
      template <class Range> write(Range range)
      +

      The connection object exposes a function write that can be given a +parameter that adheres to the Boost.Range Single Pass Range Concept. +The write function, although it looks synchronous, starts of a series of +asynchronous writes to the connection as soon as the range is serialized to +appropriately sized buffers.

      +

      To use this in your handler, it would look something like this:

      +
      +
      +
      connection->write("Hello, world!");
      +std::string sample = "I have a string!";
      +connection->write(sample);
      +
      +
      +
      +
      template <class Range, class Callback> void write(Range range, Callback callback)
      +
      The connection object also exposes a function write that can be given a +parameter that adheres to the Boost.Range Single Pass Range Concept, as +well as a Callback function that returns void and takes a +boost::system::error_code as a parameter. This overload of write is +useful for writing streaming applications that send out chunks of data at a +time, or for writing data that may not all fit in memory right away.
      +
      template <class ReadCallback> void read(ReadCallback callback)
      +

      The connection object has a function read which can be used to read more +information from the connection. This read function takes in a callback +that can be assigned to a Boost.Function with the signature +void(input_range,error_code,size_t,connection_ptr). The following list +shows what the types actually mean:

      +
      +
        +
      • input_rangeboost::iterator_range<char const *> : The range +that denotes the data read from the connection.
      • +
      • error_codeboost::system::error_code : The error code if +there were any errors encountered from the read.
      • +
      • size_tstd::size_t : The number of bytes transferred.
      • +
      • connection_ptrhttp_server::connection_ptr : A handle to the +current connection, so that it is kept alive at the time of the read +callback invocation.
      • +
      +
      +

      This interface is useful when doing reads of uploaded data that can be +potentially large and may not fit in memory. The read handler is then +responsible for dealing with the chunks of data available from the +connection.

      +
      +
      void set_status(status_t new_status)
      +
      The set_status function takes a parameter of type status_t which is +an enum type nested in http_status::connection which is given in the +following code listing.
      +
      +
      enum status_t {
      +    ok = 200
      +    , created = 201
      +    , accepted = 202
      +    , no_content = 204
      +    , multiple_choices = 300
      +    , moved_permanently = 301
      +    , moved_temporarily = 302
      +    , not_modified = 304
      +    , bad_request = 400
      +    , unauthorized = 401
      +    , forbidden = 403
      +    , not_found = 404
      +    , not_supported = 405
      +    , not_acceptable = 406
      +    , internal_server_error = 500
      +    , not_implemented = 501
      +    , bad_gateway = 502
      +    , service_unavailable = 503
      +};
      +
      +
      +
      +

      Note

      +

      You may set and re-set the status several times as long as you have +not set the headers or sent data through the connection. If you do this after +data has already been set, the function will throw an instance of +std::logic_error.

      +
      +
      +
      template <class Range> void set_headers(Range range)
      +

      The set_headers function takes a Single Pass Range of +boost::network::http::response_header<http::tags::http_async_server> +instances and linearizes them to a buffer with at most +BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE and +immediately schedules an asynchronous write once that is done.

      +

      The function throws an instance of std::logic_error if you try to set +the headers for a connection more than once.

      +
      +
      +
      +
      +
      +
      +

      Adding SSL support to Asynchronous Server

      +

      In order to setup SSL support for an Asynchronous Server, it is best to start from +a regular Asynchronous Server (see above). Once this server is setup, SSL can be +enabled by adding a Boost.Asio.Ssl.Context to the options. The settings that can be +used are defined in the link.

      +
      // Initialize SSL context
      +boost::shared_ptr<boost::asio::ssl::context> ctx = boost::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
      +ctx->set_options(
      +            boost::asio::ssl::context::default_workarounds
      +            | boost::asio::ssl::context::no_sslv2
      +            | boost::asio::ssl::context::single_dh_use);
      +
      +// Set keys
      +ctx->set_password_callback(password_callback);
      +ctx->use_certificate_chain_file("server.pem");
      +ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem);
      +ctx->use_tmp_dh_file("dh512.pem");
      +
      +handler_type handler;
      +http_server::options options(handler);
      +options.thread_pool(boost::make_shared<boost::network::utils::thread_pool>(2));
      +http_server server(options.address("127.0.0.1").port("8442").context(ctx));
      +
      +std::string password_callback(std::size_t max_length, boost::asio::ssl::context_base::password_purpose purpose) {
      +    return std::string("test");
      +}
      +
      +
      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      HTTP Response

      +

      Next topic

      +

      References

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/references.html b/cpp-netlib/libs/network/doc/html/references.html new file mode 100644 index 00000000..a5a4459f --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/references.html @@ -0,0 +1,123 @@ + + + + + + + + References — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      References

      +
      +

      About cpp-netlib

      + +
      +
      +

      Other sources

      + +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      HTTP Server API

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/search.html b/cpp-netlib/libs/network/doc/html/search.html new file mode 100644 index 00000000..82b925a0 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/search.html @@ -0,0 +1,101 @@ + + + + + + + + Search — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +

      Search

      +
      + +

      + Please activate JavaScript to enable the search + functionality. +

      +
      +

      + From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list. +

      +
      + + + +
      + +
      + +
      + +
      +
      +
      +
      +
      +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/searchindex.js b/cpp-netlib/libs/network/doc/html/searchindex.js new file mode 100644 index 00000000..d4b2a75a --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({filenames:["reference/http_response","examples/http/http_client","references","examples/http/hello_world_client","reference","in_depth/http","contents","techniques/tag_metafunctions","examples/http/atom_reader","reference/http_server","reference/http_request","examples","examples/http/twitter_search","history","techniques/polymorphism","in_depth/message","in_depth","techniques","examples/http/hello_world_server","in_depth/uri","techniques/directives","index","in_depth/http_client_tags","examples/http/simple_wget","reference/http_client","whats_new","getting_started"],titles:["HTTP Response","HTTP client","References","“Hello world” HTTP client","Reference Manual","HTTP implementation","Contents","Tag metafunctions","Atom feed reader","HTTP Server API","HTTP Request","Examples","Twitter search","Project history","Static and dynamic polymorphism","The message template","An in-depth look at the cpp-netlib","Techniques","“Hello world” HTTP server","The URI class","Directives","Getting cpp-netlib","<no title>","Simple wget","HTTP Client API","What’s New","Getting Started"],envversion:43,titleterms:{http:[0,1,3,18,5,24,9,10,11],"function":24,pod:10,boost:26,linux:26,issu:26,wrapper:[15,0,10],histori:13,synchron:[9,24],other:2,todo:20,world:[21,18,3],code:[1,3,18,23,8,12],api:[9,24],ssl:9,handler:24,network:21,dive:[1,3,18,23,8,12],start:26,asynchron:[9,24],look:16,version:26,document:9,member:[9,24],motiv:13,specif:24,build:[8,18,3,26,12],method:24,develop:26,metafunct:7,respons:[0,9],syntax:19,implement:[9,5,24],about:2,client:[1,3,10,5,24],builder:19,polymorph:14,"static":14,twitter:12,stream:24,download:26,librari:21,techniqu:17,templat:[15,7],special:7,atom_read:8,offici:26,wget:23,featur:24,"public":9,learn:21,modifi:[15,0,10],cpp:[21,2,16,26,25],run:[1,3,18,23,8,12],netlib:[21,2,16,26,25],direct:[20,0,15,10],overview:19,object:[13,9],messag:15,hello:[21,18,3],get:[21,26],refer:[2,4],bodi:24,manual:4,"new":25,project:[13,26],twitter_search:12,report:26,feed:8,request:10,sourc:2,constructor:[9,24],window:26,content:6,simpl:23,gener:[9,19,24],reader:8,metaprogram:7,dynam:14,what:25,support:[9,26],search:12,"class":19,basic_messag:15,normal:10,releas:26,exampl:[1,11,23],cmake:26,concept:[15,0,10,19],depth:16,atom:8,uri:19,want:21,tag:7,server:[9,10,18,5],more:21,connect:9},objects:{},objtypes:{},terms:{structur:[7,1],filesystem:23,minim:25,next:[1,3,23,24,8,9],incompat:26,onc:[7,1,9,26,24],utils_base64_test:25,response_:[21,24],point:[15,7],explicit:[15,9,24],decod:25,deal:[9,14,18,24],ipv6:[2,25],data:[25,15,3,19,5,24,9],titl:8,destructor:[14,25],fix:25,chose:15,tel:19,instruct:[1,26],properli:[9,24],what:[],nonetheless:15,swap:[15,7,19],keep:[14,5,20,22,24,7,8],tweet:12,web:[13,26],correctli:[0,10,25],packag:26,flag:25,cellar:26,than:[7,9],virtual:14,internal_server_error:9,verifi:[24,25],origin:[7,5],find:[21,26],svn:26,member:[],"7zip":26,cross:13,reus:20,system:[20,9,26,24],log:21,metafunct:[],max_length:9,config:25,root:[7,26,10],increasingli:13,multipl:9,libcppnetlib:[26,25],visibl:5,accept:[21,20,9,25],sensit:25,didn:24,extend:[13,20,7],versa:15,avail:[13,0,14,25,15,24,9,26],outsid:[1,26,24],primari:[7,9],session:24,becom:13,user:[25,19,5,20,22,24,9,26,12],special:[],consid:24,unit:25,status_typ:9,rpc:3,constructor:[],significantli:9,migrat:13,"case":[0,14,25,15,18,5,7,9,10,26],invari:7,skeleton:7,constraint:13,cite:24,per:25,pars:[25,19,5,23,8,9,12],uint16_t:0,trivial:[20,5],notion:[20,15],afford:20,messag:[],need:[13,14,1,18,24,7,9,26,11],time:[20,24,9,26,25],talk:[0,10],http_keepalive_8bit_udp_resolv:[22,5,24],test:[9,26,25],inherit:7,unsupport:25,until:24,string:[0,25,21,15,1,3,18,5,19,23,24,7,9,10],exist:[13,8,26],compliant:23,yet:[7,9],written:[21,0,10],bash:19,simplifi:[20,25],whole:[7,0,25],continu:[13,21,9],http_async_serv:9,report:[],homebrew:26,standard:[13,20,25],along:26,defin:[14,25,15,18,19,5,20,24,7,9,26],reader:[],actual:[9,25],hex:25,myapplic:26,lack:13,abus:20,add_head:[15,0,10],thrash:26,bug:[26,25],remov:[15,0,24,10,25],account:26,boostcon:2,reli:[24,25],demand:13,consist:[13,1,26,25],liter:2,schedul:9,mode:25,tool:26,clariti:1,properti:[20,15,7,5],forward:5,"switch":[14,10],power:[26,19,12],translat:7,base_uri:12,you:[14,21,1,3,18,5,23,24,7,9,26],opt:26,least:26,http_async_8bit_tcp_resolv:[22,5,24],detail:[0,15,1,18,5,22,24,9,10],derived1:14,opaqu:[7,19],empti:[15,23,25],releas:[],instabl:25,standalon:[14,24],seen:[0,18],construct:[0,15,19,24,9,10,12],mkdir:26,truli:20,unpack:26,explicitli:24,size:[9,12],format:[20,2,25],provid:[13,0,25,21,18,19,5,22,23,24,7,10,12],below:[0,21,19,5,24,9,26,12],cppnetlib:[26,25],upon:9,wall:25,most:[15,8,9,23,24],charact:24,usr:26,"short":[24,25],address:[2,21,18,3,5,22,24,9],openssl_certificate_fil:24,although:[15,7,9,14,26],choic:26,program:[13,14,21,18,19,11],tcp_resolv:24,full:[21,0,26],pem:9,modern:21,command:[18,3,19,8,26,12],make_shar:[9,24],nest:[0,15,5,20,7,9,10],awai:9,icmp:15,like:[14,15,18,3,5,20,24,7,9,26,12],some_str:24,suppli:[9,19,5,25],softwar:13,send_buffer_s:9,propag:25,potenti:9,"class":[],builder:[],undefin:24,upload:9,underneath:[24,25],slightli:7,remain:[20,14],excel:13,version_:0,lifetim:24,servic:13,"default":[14,25,15,1,5,22,24,7,9,26],queri:[25,10,19,23,12],pend:[9,24],expos:9,previou:[26,23,24],paper:2,streaming_callback:24,if_:7,core:15,overal:7,unstabl:25,headers_contain:[15,0],cannot:[9,24],dispatch:[15,7,14,5,25],notic:[7,5],includ:[0,25,21,1,3,18,19,20,23,24,8,9,10,12],anoth:[9,19],linger_timeout:9,vice:15,review:21,back:25,effect:[0,10,24],nich:13,wai:[7,9,19,24],clrf:25,dure:24,risk:26,mani:[13,24,26,25],line:[25,21,1,3,18,19,8,26,12],offer:24,correct:[15,14,5],understand:9,percent:12,openssl:[24,26,25],host:[25,18,19,23,26,10],nor:15,second:[10,5,24],wait:[9,24],attitud:12,anymor:7,throughout:25,object:[],block:[9,22,5,24],check:[21,1,26,25],openssl_:[],clone:[26,23],under:[21,12],memori:[13,9,26,24],stuck:26,multiple_choic:9,step:26,indirect:[20,14],bodi:[],index:23,littl:[7,14],kei:[24,9,25],cert:24,studio:[26,25],wide:[0,10],status_messag:0,produc:26,invoc:[9,24],three:[15,5,16,24,9,26],proof:9,bz2:26,non:[15,9,26,19,25],everyth:19,state:[20,9],sourceforg:13,affect:24,rss:[8,25],flexibl:[20,7,1,25],udp:[22,5,24],veri:[9,23,25],io_servic:[24,9,25],basic_cli:[5,24],tcp:[14,22,5,24],natur:20,complex:[1,26,19,12],clear_resolved_cach:24,avoid:25,initi:[13,24,9,25],light:[13,21],bool:[9,24],shared_futur:0,almost:9,reuse_address:9,destination_:[0,10],cpp:[],newer:9,makefil:26,hash:12,embedd:[5,25],argv:[21,1,3,18,23,8,12],directori:[1,26,24],becaus:[20,15,9,14],locat:[26,24],dsel:20,boost_1_55_0:26,from:[0,25,21,15,1,3,18,5,19,20,23,24,7,8,9,10,26,12],platform:[13,9,26,25],behav:24,serv:7,out:[21,9,26,24],arg:21,greatli:14,progress:21,connection_ptr:9,facilit:14,find_packag:26,"char":[21,1,3,18,23,24,8,9,12],default_tag:7,"throw":[24,9,25],now:[0,25,18,24,8,26,10],"8bit":24,factori:[20,15,14],reset:14,without:[20,1,25],dcmake_c_compil:26,common:[13,15,1,11,24],unzip:26,have:[13,14,25,15,18,3,5,20,22,24,7,9,26,12],alwai:[24,9,26,25],fluid:14,invok:[24,9,18,26,25],approach:[7,14],issu:[],single_dh_us:9,show:[3,19,24,8,9,11],run:[],convers:15,simplest:1,date:26,otherwis:[14,10,19,26],safe:[18,24],send:[1,9],side:[24,14,18,25],api:[],radic:25,qualiti:13,abov:[18,19,5,22,23,24,7,9,26,12],pair:[0,10],not_accept:9,find_last_of:23,smart:[9,24],everi:[13,15],easi:[13,21,3],request:[],parallel:26,source_port:25,boost_network_default_tag:25,body_handl:24,watermark:9,ask:[21,26],close:[21,8,1,9,5],independ:[20,9,24],simpl:[],behavior:[7,14,5,24],sometim:[15,7],mostli:26,previous:18,adl:[15,7],respons:[],throught:1,unauthor:9,come:[20,0,14,10,26],req:9,place:9,netib:24,inc:25,befor:[24,9,3,25],syntact:[20,15],basic_respons:[0,5],heart:5,readcallback:9,oper:[0,25,21,15,18,5,20,24,9,10,12],lookup:15,sequenc:24,c_str:[23,12],destin:[15,0,10],fetch:24,lib:[8,1,26,25],further:[1,19],mitig:25,basic_request:[10,5],less:25,singl:[25,1,18,5,24,9],impl:[0,18],cerr:[21,18,3,5,23,8,12],iterator_rang:[9,24],"while":[13,14,15,5,20,26],via:[21,3,25],job:26,modifi:[],rudimentari:20,prolong:20,matter:9,them:[0,9,10,26,24],googl:[21,26,25],end:[13,24,5,25],set:[0,14,25,15,18,3,20,16,24,9,10,11,26,12],overload:[9,18,5],multimap:5,port:[0,25,21,18,3,19,23,9,10],flight:12,com:[21,3,19,24,8,26,12],echo:5,hello:[],caus:[7,22,5,24],inform:[21,9,26,25],get:[],clear_head:[15,0,10],include_directori:26,snmp:15,model:[0,15,20,24,9,10,26],hostnam:[9,25],directive_typ:20,twitter_search:[],should:[14,15,18,5,24,7,9,26],prescrib:26,iostream:[1,3,18,19,20,23,8,12],zip:26,area:15,detect:26,happen:24,context:[20,7,9],derived0:14,tradit:26,world:[],unavoid:14,warn:25,output:19,master:8,shell:[18,3,26],consol:[8,1],verif:[24,25],see:[25,18,5,22,24,7,9],receive_low_watermark:9,learn:[],lead:20,from_user_nam:12,portabl:[13,21],yourself:26,search:[],socket:9,third:18,list:[0,21,18,7,8,9,10,26,12],soon:[9,24],resolut:25,branch:[8,26],strategi:[14,24],instanti:9,client:[],http_keepalive_8bit_tcp_resolv:[22,5,24],fashion:20,doesn:[0,25],name:[0,25,15,5,23,24,9,10,26],directli:[9,24],your:[9,26,5,24],real:7,impli:15,tabl:[0,21,15,5,24,9],tag:[],directive2:20,chunk:[24,9,25],set_opt:9,abid:[20,10],differenti:[9,18],signatur:[9,24],heavi:[26,25],between:[26,19],undergo:21,print_bodi:24,studi:21,pod:[],simple_wget:23,slide:2,parser:[8,26,19,23,25],shared_ptr:[9,24],realli:3,ptr:14,indic:[22,5,24],client_fwd:25,forc:24,pointer:[9,24],burden:26,how:[18,3,19,24,7,26,11],extens:[20,7,5],immedi:[20,9],non_blocking_io:9,compon:[15,19,23,24,7,11],payload:[15,3],infosystem:19,applic:[13,0,21,1,3,23,24,8,9,10,11,26],cache_resolv:24,setup:9,boost_network_http_client_default_tag:25,utf:[0,10],note:[15,0,9,19,23],manner:[7,0,9,10,24],sure:18,add:[0,25,15,1,26,10],barrier:13,pull:26,fulli:[13,23,24],major:[13,10,24],upward:25,smtp:[13,15],abort:9,composit:7,tell:24,org:[21,1,19,5,23,26],functor:[18,5],situat:[20,9,14,24],chang:[25,5,20,24,7,26],date_tim:26,source_typ:15,variou:24,bind:9,directiven:20,safeti:7,hello_world:18,server:[],base64:25,self:20,outliv:24,requesthandl:5,style:[19,23],creation:20,aris:24,start:[],join:[21,9,26],let:[7,18,3,26],boost_network_http_server_connection_header_buffer_max_s:9,thing:[0,14,1,23,7,26,10],larger:11,mere:15,wire:20,typenam:[15,0,7,10],stabl:[21,26],set_password_callback:9,relev:3,introduc:[25,24,1,23,12],kept:[13,9],requir:[13,0,14,25,15,19,24,9,10,26],encapsul:[20,15,22,5,24],two:[25,18,5,24,9,10],except:[14,25,18,3,5,22,23,24,8,12],addit:[20,14,26,19],ofstream:23,wget:[],use_tmp_dh_fil:9,always_verify_p:24,publish:8,part:[0,25,15,19,24,10,12],append:24,listen:[9,18,25],intend:[21,9,26,24],connectionptr:9,specifi:[15,1,19,5,22,23,24,9,26],few:[0,26],swappabl:[15,7,19],source_:[0,10],conn:9,compulsori:26,rational:20,attempt:[9,25],especi:9,known:[26,19,25],openssl_private_key_fil:24,famili:7,modif:15,boil:20,mailto:19,fan:26,discuss:[21,26],comp:19,left:[20,7],password_callback:9,finish:[9,24],easier:[15,24],headers_rang:[0,10,5],awar:[13,21],uri:[],around:[9,24],basic:[20,15],sudo:26,made:[24,9,3,18,25],critial:25,openssl_certif:24,patch:26,want:[],interfac:[25,4,5,20,22,23,24,9,10],conveni:24,mpl:[7,25],howev:[7,26,5],resourc:[18,26,23],those:[17,0,10],path:[26,10,19,23],main:[21,1,3,18,19,23,8,26,12],namespac:[0,21,1,3,18,5,19,23,24,7,8,9,10,12],target_link_librari:26,compos:16,explos:14,support:[],access:[13,0,3,5,20,23,8,9,10],request_:[21,24],thei:[15,19,5,22,24,7,26],websit:[21,1,26,23],upgrad:[9,25],handler_inst:9,leak:25,mistak:24,incorrect:25,manag:[24,9,25],summar:15,high:13,mechan:[7,5],xzf:26,www:[24,1,19,5,23],michael:13,concept:[],receive_buffer_s:9,where:[13,14,25,15,3,5,20,24,7,9,10],cach:24,asio:[13,24,9,25],group:[13,21,26],enabl:[13,7,9,26,24],code:[],type:[13,0,14,15,19,5,20,24,7,9,10],error:[21,24,1,9,25],purpos:[9,26],distinct:9,more:[],bin:19,narrow:[0,10],boost_network_no_lib:[24,25],orient:[20,14],facad:25,disabl:9,other:[],profil:9,uri_io:19,separ:[26,25],grow:21,get_filenam:23,taken:9,histori:[],equival:7,synchron:[],fact:1,possibl:[21,8,1,14],assert:19,call:[25,15,18,5,20,24,7,9,26],overhaul:25,minimum:21,boost_root:26,pattern:[20,15,9,14,24],meant:[15,0,7,9,10],regard:25,report_abort:9,boost:[],openssl_verify_path:24,action:9,anchor:10,tar:26,jamfil:25,endl:[1,3,18,5,19,23,24,8,12],similar:[15,3,5,20,22,23,24,7,8,9],through:[21,9,10,26,5],about:[],input_rang:9,begin:[5,24],same:[13,14,18,5,20,24,7,26,12],move:[20,24],html:23,is_base_of:7,maintain:[20,9],regex:26,http_default_8bit_udp_resolv:[0,10,22,5,24],cost:25,lot:[14,26,25],deep:20,eof:25,width:24,method:[],synchronoushandl:9,dberri:26,none:9,forum:26,plain:14,asynchron:[],etc:13,hello_world_cli:3,associ:[0,15,24,7,9,10],cppnetlib_librari:26,"const":[0,21,15,18,5,20,23,24,8,9,10,12],polymorph:[],"catch":[25,18,3,23,24,8,12],configur:[21,18,26,25],save:23,rapidjson:12,repres:9,broken:19,convert:[15,0,10,19],echo_serv:5,complet:[1,26],site:26,getstr:12,fals:[9,24],tarbal:26,hpp:[25,1,3,18,19,23,24,7,8,9,12],combin:[7,14],msysgit:26,info:[21,19],offici:[],might:[7,5],reduc:26,erro:[],decis:14,artifact:26,concern:25,"public":[],travi:25,mean:[15,24,9,26,25],underli:[20,15,7,5],no_cont:9,typic:[15,26,5],substr:23,order:[20,1,9,25],hasparseerror:12,absolut:19,solut:26,inherit_linearli:7,later:9,advanc:17,runtim:14,read:[8,9,26,25],lend:20,help:9,webservic:3,ftp:[13,19],subsequ:[0,14,10,24],present:1,ado:1,remove_head:[15,0,10],reachabl:7,manual:[],suggest:10,illustr:7,copi:[25,15,19,23,24,9],make:[14,25,1,3,18,5,22,23,24,7,8,26,12],each:[15,1,24,8,9,26],weight:[13,21],acceptor:9,placehold:7,updat:25,sourc:[],take:[25,21,15,18,19,5,20,23,24,9],"void":[0,14,21,15,18,19,5,24,7,9,10],comput:[9,26],depend:[0,25,15,5,24,9,10,26],statu:[0,9,18,5,25],subvers:26,languag:13,handler_:21,hold:[22,5,24],gener:[],write:[13,25,21,3,24,9],octet:24,clear:[15,24],behaviour:12,extern:[24,14,25],instal:[26,25],"import":[9,25],aim:17,identifi:[15,19],custom:[26,24],aptli:5,foo_direct:15,"final":[1,25],discov:21,free:[15,9],thread_pool:9,mit:12,bad_gatewai:9,"long":9,"true":[9,24],parse_head:25,element:19,sake:1,git:26,establish:24,seri:[9,11],sizetyp:12,uniqu:14,static_cast:23,logic_error:9,either:[13,0,15,24,9,10],boost_network_http_body_callback:24,creativ:14,correspond:21,microsoft:26,sln:26,would:[15,18,5,7,9,26],moved_perman:9,secur:24,target:[13,20],inadvert:25,earlier:[14,3],when:[13,14,25,15,24,9,26],familiar:[8,23],choos:[15,26,10,24],alreadi:[13,0,25,24,9,10],serial:[9,25],not_impl:9,redirect:24,iter:5,wstring:[7,0,10],wrapper:[],commit:[13,8],content_typ:24,http_client:[1,5],abl:[9,26],term:[15,9,24],layer:[13,21,20,14],deriv:[14,10],overrid:25,error_cod:[9,24],exampl:[],dh512:9,ssl:[],argc:[1,3,18,23,8,12],handler:[],been:[13,9,26,24],resid:[1,5],gaga:12,localhost:3,though:[1,14,26],craft:3,ten:21,necessari:18,pool:[9,25],dive:[],directive1:20,came:5,look:[],neg:12,licens:12,els:24,phrase:12,determin:[7,9,5,23],headers_:[0,5],default_str:7,motiv:[],bzip:26,string_tag:7,use_private_key_fil:9,std:[0,21,1,3,18,5,19,23,24,7,8,9,10,12],cycl:24,file:[21,19,23,24,9,26],compat:24,use_certificate_chain_fil:9,higher:26,develop:[],deleg:5,thread:[25,18,5,22,24,9],visual:[26,25],load:24,dboost_root:26,foo:[15,7,14],embed:[9,18,11],txt:26,temporari:25,just:[0,15,18,3,5,7,26,10],logic:[20,15,1,9,5],rapidxml:8,comparison:25,callback:[24,9,25],async:25,concret:20,tree:1,reflect:25,someth:[20,15,7,9,5],distribut:[13,9,26],thi:[25,3,4,5,8,10,12,21,15,18,22,0,9,13,14,17,1,19,20,23,24,7,26],zipfil:26,togeth:[13,26],sinc:[7,1,3],whose:7,http_statu:9,experiment:25,dopenssl_root_dir:26,stock:18,event:9,usual:[20,0,10],is_valid:19,readi:[24,25],attent:20,direct:[],interact:26,valu:[0,14,15,18,5,22,24,9,10,12],valid:[15,26,25],subdivid:19,overview:[],port_typ:10,unspecifi:[0,10],stock_repli:[21,9,18,5],bad_request:9,whether:[14,25,15,19,24,9,10],instanc:[0,15,19,5,24,7,9,10],current:[9,19,24],hoc:25,sslv23:9,cmakelist:26,store:[15,9,24],preprocessor:[24,25],creat:[0,14,1,3,18,19,24,9,10,26],github:[13,21,19,24,8,26],relat:9,field:0,client_:[21,24],version_minor:[10,22,5,24],enumer:18,atom:[],multi:18,assign:[15,9,19],fragment:[19,23],status_t:9,target_typ:20,pure:[15,14],integ:10,give:9,rfc:[2,1,19,23,25],administr:18,input:[20,14],share:[9,18,22,5,24],dangl:25,"boolean":[9,24],not_modifi:9,publicli:[0,9,10],recommend:26,adapt:15,fit:9,contribut:[21,25],plenti:13,pertain:15,insid:[9,5,24],fuss:21,environ:[18,26,25],context_bas:9,sent:[9,24],foreach:8,not_found:9,"break":[24,14,25],older:25,http_async_8bit_udp_resolv:[24,22,5,25],struct:[14,21,15,18,5,20,24,7,9],larg:[7,9],basic_messag:[],numer:25,unsign:[24,0,10,5,25],somewher:24,regular:9,signal:[1,24],forbidden:9,dedic:24,adher:9,http_version_major:24,intermediari:15,fulfil:13,http:[],achiev:17,chain:20,tmp:24,hidden:[20,24],pipelin:9,moved_temporarili:9,dcmake_cxx_compil:26,alon:14,therefor:[13,5,24],simpli:[20,10,5,23],mail:[21,26],trait:[7,0],lock:9,body_:[21,0,10],usag:[25,1,3,18,23,24,8,9,12],caveat:26,text:12,assum:[0,15,1,3,24,9,10,26],section:[15,0,9,10,24],ladi:12,netlib:[],process:[19,5,25],rest:23,option:[13,25,21,24,9,26],top:[13,26],straightforward:[21,18],lvalu:[15,9],header:[0,14,25,21,15,1,18,5,20,23,24,7,8,9,10,26,12],status_message_:0,exact:[5,12],here:[14,18,1,19,5,23,24,9,12],open:13,futur:[0,21,15,5,22,24,9],realist:11,rang:[9,24],hierarch:19,design:[21,11],strictli:25,http_server:[21,0,9,10],xjf:26,suffici:26,divis:15,idea:[21,7],better:[9,26,25],clang:[26,25],problem:14,certif:[24,25],feed:[],some_xml_str:3,new_statu:9,fast:21,twitter:[],soap:13,url:[2,1,3,19,23,8,26],version:[],async_serv:[9,25],xcode:25,suit:26,fstream:23,ensur:[15,7,18],semant:[20,15,9,14],enough:[20,26],control:[7,9,26],json:12,buffer:[7,9,25],local:26,debug:26,sever:[17,9],default_wstr:7,eventu:13,goal:13,syntax:[],sync_serv:9,expect:24,shift:20,never:13,set_statu:9,also:[13,0,14,21,15,18,5,20,22,24,7,9,10,26,12],server_:[21,18],loop:9,right:[7,9],head:[1,5,24],stop:[9,25],status_:0,allow:[14,25,21,15,1,20,24,7,9,12],classifi:19,transfer:[9,25],built:[14,25,1,24,26,11],util:9,cout:[1,3,19,5,23,24,8,12],techniqu:[],templat:[],receiv:[9,24],set_head:9,ostringstream:3,typedef:[21,15,18,5,24,7,9],appli:[20,15],against:9,endpoint:24,both:[0,5,22,24,9,10,11],asynchronoushandl:9,post:[24,1,3,5,25],delete_:24,decid:[13,7,14],libc:25,destroi:24,result:[0,15,19,20,23,7,8,10,12],not_support:9,olymp:12,intent:13,chapter:17,stream:[],delet:[1,5,24],imagin:3,must:[26,25],link:[9,26,24],form:[15,19,5,20,24,7],failur:25,practic:[8,3,11],central:15,cppnetlib_include_dir:26,ani:[0,14,25,15,1,18,24,9,26,12],encod:[25,0,10,12],can:[0,14,21,15,1,3,18,5,19,20,23,24,7,9,26,11,12],follow:[0,14,15,1,3,18,5,19,20,23,24,7,9,10,11,26],"abstract":[1,14,18],dcmake_build_typ:26,src:26,download:[],aliv:[9,22,5,24],interest:26,inlin:[20,0,7,10],definit:[15,7,9,10],happi:21,retriev:[0,15,19,23,24,10],handl:[24,9,14,18,25],librari:[],broad:20,bit:[0,10],impos:24,last:24,scalabl:9,client_get_timeout_test:25,password_purpos:9,face:[9,24],http_default_8bit_tcp_resolv:[22,5,24],accord:[15,1,19],peer:[24,25],fill:24,wrap:[15,0,14],refer:[],compil:[20,24,9,26,25],service_unavail:9,str:3,number:[15,18,5,22,24,7,9,10,26],fork:26,own:[13,9,24],sstream:3,entri:[13,8],sampl:[9,26],filenam:[23,24],fail:25,cover:[15,25],base:[14,25,15,19,20,24,7,26,12],easili:[13,24],msvc:25,question:[21,26],activ:[13,22,5,24],itself:[20,7],handler_typ:9,ignor:7,certain:[20,15,7,9,5],bridg:14,variabl:[26,25],found:[13,1,18,9,26,12],were:9,mikhailberi:26,manipul:[15,9],string_typ:[0,21,24,7,9,10],tracker:21,"return":[0,14,25,15,1,3,18,5,19,20,22,23,24,8,9,10,12],berri:13,doubl:19,best:[2,9,24],cooki:24,doe:[0,15,18,19,24,9,10],resolv:[22,5,24],lower:[13,25],all:[0,14,25,21,15,1,3,18,5,20,24,8,9,10,11,26],sens:[20,22,5,24],instead:[24,7,9,25],greater:[1,18],metaprogram:[],legend:[15,0,9,10,19],"int":[0,14,21,1,3,18,19,23,24,8,9,12],connect:[],linux:[],predefin:5,server_opt:9,latest:[21,26],convent:1,contain:[0,15,18,20,7,9,11,12],had:13,timeout:[24,9,25],inhibit:24,xmpp:[13,15],repositori:[21,26],http_version_minor:24,startup:25,ipp:[0,18],ctx:9,cat:23,thrown:24,annoi:13,down:[20,14,19],cipher:25,home:[13,26],client_opt:24,window:[],onli:[0,14,25,19,5,20,22,24,7,8,9,26,12],conncetionptr:9,network:[],implement:[],flaki:25,protocol:[13,0,21,15,1,3,18,19,20,16,23,24,8,10,11,12],subdirectori:1,john:19,crash:25,our:[13,21,7,26],ultim:25,scheme:[10,19,23],document:[],range_iter:5,emb:[9,24],pass:[15,1,3,18,20,24,7,8,9],well:[20,15,9,25],hello_world_serv:[18,3],"try":[18,3,23,24,8,9,12],rel:19,boost_network_enable_http:[24,26,25],treat:10,specif:[],guid:[21,2,26],gzip:26,"function":[],level:[13,26],plai:25,linear:9,xml:[8,3],describ:[17,9,11,19,24],even:[20,0,15,10],print:[8,1,5],source_wrapp:15,descript:[0,15,19,5,22,24,9,10],deprec:[15,24,25],user_info:[19,23],normal:[],explain:1,default_workaround:9,basic_serv:5,refactor:[21,25],smarter:7,perform:[13,25,15,3,24,9,10],much:[14,26],done:[14,15,5,7,9,10,26],recent:[24,26,12],pre:18,aid:11,minor:[10,24],noth:14,edit:9,intern:[25,5,24,7,9,10],some:[0,14,25,17,21,3,19,7,8,9,10,26,12],enforc:10,said:19,bound:9,bother:24,featur:[],occur:[0,10,24],gcc:[26,25],given:[0,14,15,19,5,7,9,10,12],atom_read:[],denot:[7,9],encount:[9,24],paramet:[0,25,15,5,20,24,7,9,10,26],librt:25,cmake:[],repli:18,gnu:26,mai:[15,18,5,24,9,26],person:26,across:[18,24],vari:[15,7,14],rule:25,still:[0,25,24,7,9,10,26],compress:1,sign:25,concurr:9,breakag:25,chainabl:20,which:[0,14,25,15,1,3,18,5,19,20,24,7,8,9,26],among:7,follow_redirect:24,alia:0,collect:[13,21],cmake_prefix_path:26,response_head:[9,5],accessor:[15,0,10],"byte":[9,24],"new":[],privat:[24,25],project:[],author:[19,24],linger:9,macro:[24,26,25],dean:13,improv:25,subtitl:8,individu:26,framework:[15,18],argument:[15,1,18,5,23,24,12],unix:[26,19],headers_container_typ:[0,10],"static":[],size_t:[9,23],transform:[20,15],within:[9,26,4],programmat:25,put:[24,9,5,25],low:9,miss:13,fileserv:25,kind:[14,11],shown:[9,24],dynam:[],four:0,page:[21,26,12],submit:[13,26],longer:[24,25],no_sslv2:9,work:[0,26,10],distanc:24,scale:9,first:[14,15,1,18,19,5,8,26,10],commun:[13,21,11],version_major:[10,22,5,24],after:[1,9,19],build:[],unique_ptr:14,assumpt:5,don:[25,1,5,22,24,7,26],declar:[0,10,5,24],default_:[7,14,5],slash:19,vector:[7,9,10],depth:[],multibyt:25,boost_foreach:8,appropri:[0,9,10,26,24],unsupported_tag:7,repetit:25,differ:[0,14,25,15,4,19,20,16,23,24,7,9,10,26],repeatedli:13,packet:15,"enum":9},objnames:{}}) \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/techniques.html b/cpp-netlib/libs/network/doc/html/techniques.html new file mode 100644 index 00000000..7a68d24e --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/techniques.html @@ -0,0 +1,116 @@ + + + + + + + + Techniques — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Techniques

      +

      The cpp-netlib uses several advanced techniques to achieve it’s +aims. This chapter describes some of those techniques.

      + +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      HTTP implementation

      +

      Next topic

      +

      Tag metafunctions

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/techniques/directives.html b/cpp-netlib/libs/network/doc/html/techniques/directives.html new file mode 100644 index 00000000..c995e904 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/techniques/directives.html @@ -0,0 +1,191 @@ + + + + + + + + Directives — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Directives

      +

      The cpp-netlib uses a technique for allowing message-passing +semantics in a chainable fashion in the form of directives. The basic +concept for directives is, in a general sense, an encapsulated +transformation that can be applied to objects that abide by the +directive protocol.

      +

      Using the object-oriented notion of message passing, where an object +accepts a message (usually a function call) we define a simple DSEL in +order for the protocol to be supported by certain object types. In the +cpp-netlib the protocol implemented is similar to that of the +standard iostream formatting system:

      +
      object << directive1(...)
      +       << directive2(...)
      +       ...
      +       << directiveN(...);
      +
      +
      +

      In cpp-netlib the directives are simple function objects that +take a target object as reference and returns a reference to the same +object as a result. In code the directive pattern looks like the +following:

      +
      struct directive_type {
      +    template <class Input>
      +    Input & operator()(Input & input) const {
      +        // do something to input
      +        return input;
      +    }
      +};
      +
      +
      +

      To simplify directive creation, usually factory or generator functions +are defined to return concrete objects of the directive’s type.

      +
      inline
      +directive_type directive(...) {
      +    return directive_type();
      +}
      +
      +
      +

      The trivial implementation of the directive protocol then boils down +to the specialization of the shift-left operator on the target type.

      +
      template <class Directive>
      +inline target_type & operator<<
      +(target_type & x, Directive const & f) {
      +    return f(x);
      +}
      +
      +
      +
      +

      Todo

      +

      An example using a directive.

      +
      +

      The rationale for implementing directives include the following:

      +
      +
        +
      • Encapsulation - by moving logic into the directive types the +target object’s interface can remain rudimentary and even hidden +to the user’s immediate attention. Adding this layer of +indirection also allows for changing the underlying +implementations while maintaining the same syntactic and semantic +properties.
      • +
      • Flexibility - by allowing the creation of directives that are +independent from the target object’s type, generic operations can +be applied based on the concept being modeled by the target +type. The flexibility also afforded comes in the directive’s +generator function, which can also generate different concrete +directive specializations based on parameters to the function.
      • +
      • Extensibility - because the directives are independent of the +target object’s type, new directives can be added and supported +without having to change the target object at all.
      • +
      • Reuse - truly generic directives can then be used for a broad +set of target object types that model the same concepts supported +by the directive. Because the directives are self-contained +objects, the state and other object references it keeps are only +accessible to it and can be re-used in different contexts as well.
      • +
      +
      +

      Extending a system that uses directives is trivial in header-only +systems because new directives are simply additive. The protocol is +simple and can be applied to a broad class of situations.

      +

      In a header-only library, the static nature of the wiring and chaining +of the operations lends itself to compiler abuse. A deep enough +nesting of the directives can lead to prolonged compilation times.

      +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      Tag metafunctions

      +

      Next topic

      +

      Static and dynamic polymorphism

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/techniques/polymorphism.html b/cpp-netlib/libs/network/doc/html/techniques/polymorphism.html new file mode 100644 index 00000000..04bcbe00 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/techniques/polymorphism.html @@ -0,0 +1,189 @@ + + + + + + + + Static and dynamic polymorphism — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Static and dynamic polymorphism

      +

      With a header only library, you can only do so much with static +polymorphism alone. There are some situations where you have to handle +dynamic polymorphism because of unavoidable runtime-based decision +making. Although you can deal with the base types that remain static, +behavior can vary greatly which derived type should be handling the +situation based on runtime values.

      +

      This situation comes up in the cpp-netlib when we decide what +kind of connection handler to use for a given HTTP URI – whether it’s +plain HTTP or HTTPS. Although the HTTP semantics are the same for +HTTP and HTTPS the implementation of the connection handler greatly +varies on whether to use a plain TCP connection or an SSL-wrapped TCP +connection.

      +

      The general pattern or technique is to combine tag-based dispatch with +a strategy factory, all while not requiring any externally built +libraries. Doing it in a header-only library requires a little +creativity and additional layers of indirection that you otherwise +will not need for a library with externally built static/dynamic +libraries.

      +

      First we define the base type which we want to support dynamic +behavior with. There’s nothing special with the base type, except +that it supports the tag dispatch earlier defined and has a virtual +destructor. In code it looks like this:

      +
      template <class Tag>
      +struct base {
      +    virtual void foo() = 0; // make this an abstract base
      +    virtual ~base() {
      +        // do the base destructor thing here.
      +    }
      +};
      +
      +
      +

      We then define a set of derived types that specialize the +implementation of the foo member function. To facilitate the +dispatch of the correct type based on an input, we create a strategy +factory function:

      +
      template <class Tag>
      +unique_ptr<base<Tag> > strategy(int input, Tag) {
      +    unique_ptr<base<Tag> > ptr;
      +    switch(input) {
      +        case 0: ptr.reset(new derived0()); break;
      +        case 1: ptr.reset(new derived1()); break;
      +        // ...
      +        default: ptr.reset(0); break;
      +    }
      +    return ptr;
      +}
      +
      +unique_ptr<base<default_> > ptr =
      +    strategy(input, default_()); // input is a runtime value
      +
      +
      +

      The strategy factory can be a standalone function, or a static member +of a factory class that is specialized by tag dispatch. This can be +done like the following:

      +
      template <class Tag>
      +struct strategy;
      +
      +template <>
      +struct strategy<default_> {
      +    static unique_ptr<base<default_> > create(int input) {
      +        unique_ptr<base<default_> > ptr;
      +        switch(input) {
      +            case 0: ptr.reset(new derived0()); break;
      +            case 1: ptr.reset(new derived1()); break;
      +            //...
      +            default: ptr.reset(0); break;
      +        }
      +        return ptr;
      +    }
      +};
      +
      +
      +

      This approach allows the header-only libraries to define new dynamic +types in subsequent versions of the library while keeping the +static-dynamic bridge fluid. The only down-side to this is the +possibility of derived type explosion in case there are a lot of +different strategies or specializations available – this though is +not unique to static-dynamic bridging, but is also a problem with pure +object oriented programming with dynamic polymorphism.

      +
      + + +
      +
      +
      +
      +
      +

      Previous topic

      +

      Directives

      +

      Next topic

      +

      Project history

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/techniques/tag_metafunctions.html b/cpp-netlib/libs/network/doc/html/techniques/tag_metafunctions.html new file mode 100644 index 00000000..eabf0cd0 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/techniques/tag_metafunctions.html @@ -0,0 +1,265 @@ + + + + + + + + Tag metafunctions — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      Tag metafunctions

      +

      Sometimes you want to vary a function or a type’s behavior based on a +static parameter. In the cpp-netlib there are a number of +things you might want to change based on some such parameter – like +what the underlying string type should be and how large a buffer +should be, among other things. The primary way to define this in a +header-only manner is to use tag-based metafunctions.

      +

      The skeleton of the approach is based on a similar technique for +defining type traits. In the cpp-netlib however the type traits +are defined on opaque tag types which serve to associate results to a +family of metafunctions.

      +
      +

      Template Specialization

      +

      To illustrate this point, let’s define a tag default_ which we use +to denote the default implementation of a certain type foo. For +instance we decide that the default string type we will use for +default_ tagged foo specializations will be an +std::string.

      +

      In the cpp-netlib this is done by defining a string +metafunction type that is specialized on the tag default_ whose +nested type result is the type std::string. In code this would +translate to:

      +
      template <class Tag>
      +struct string {
      +    typedef void type;
      +};
      +
      +struct default_;
      +
      +template <>
      +struct string<default_> {
      +    typedef std::string type;
      +};
      +
      +
      +
      +
      +

      Template Metaprogramming

      +

      Starting with version 0.7, the tag dispatch mechanism changed slightly to use +Boost.MPL. The idea is still the same, although we can get a little smarter +than just using template specializations. Instead of just defining an opaque +type default_, we use the Boost.MPL equivalent of a vector to define which +root types of properties this default_ tag supports. The idea is to make the +opaque type default_ inherit property tags which the library supports +internally as definite extension points.

      +

      Our definition of the default_ tag will then look something like the +following:

      +
      typedef mpl::vector<default_string> default_tags;
      +
      +template <class Tag>
      +struct components;
      +
      +typedef mpl::inherit_linearly<
      +    default_tags,
      +    mpl::inherit<mpl::placeholders::_1, mpl::placeholders::_2>
      +    >::type default_;
      +
      +template <class Tag>
      +struct components<default_> {
      +    typedef default_tags type;
      +};
      +
      +
      +

      In the above listing, default_string is what we call a “root” tag which is +meant to be combined with other “root” tags to form composite tags. In this case +our composite tag is the tag default_. There are a number of these “root” +tags that cpp-netlib provides. These are in the namespace +boost::network::tags and are defined in boost/network/tags.hpp.

      +

      Using this technique we change slightly our definition of the string +metafunction class into this:

      +
      template <class Tag>
      +struct unsupported_tag;
      +
      +template <class Tag>
      +struct string :
      +    mpl::if_<
      +        is_base_of<
      +            tags::default_string,
      +            Tag
      +        >,
      +        std::string,
      +        unsupported_tag<Tag>
      +    >
      +{};
      +
      +
      +

      Notice that we don’t have the typedef for type in the body of string +anymore, but we do inherit from mpl::if_. Since mpl::if_ is a template +metafunction itself, it contains a definition of the resulting type which +string inherits.

      +

      You can see the real definition of the string metafunction in +boost/network/traits/string.hpp.

      +
      +
      +

      Using Tags

      +

      Once we have the defined tag, we can then use this in the definition of our +types. In the definition of the type foo we use this type function +string and pass the tag type parameter to determine what to use as +the string type in the context of the type foo. In code this would +translate into:

      +
      template <class Tag>
      +struct foo {
      +    typedef typename string<Tag>::type string_type;
      +
      +    // .. use string_type where you need a string.
      +};
      +
      +
      +

      Using this approach we can support different types of strings for +different tags on the type foo. In case we want to use a different +type of string for the tag default_ we only change the +composition of the string_tags MPL vector. For example, in cpp-netlib +there is a root tag default_wstring which causes the string metafunction +to define std::wstring as the resulting type.

      +

      The approach also allows for the control of the structure and features +of types like foo based on the specialization of the tag. Whole +type function families can be defined on tags where they are supported +and ignored in cases where they are not.

      +

      To illustrate let’s define a new tag swappable. Given the above +definition of foo, we want to make the swappable-tagged +foo define a swap function that extends the original +default_-tagged foo. In code this would look like:

      +
      struct swappable;
      +
      +template <>
      +struct foo<swappable> : foo<default_> {
      +    void swap(foo<swappable> & other) {
      +        // ...
      +    }
      +};
      +
      +
      +

      We also for example want to enable an ADL-reachable swap function:

      +
      struct swappable;
      +
      +inline
      +void swap(foo<swappable> & left, foo<swappable> & right) {
      +    left.swap(right);
      +}
      +
      +
      +

      Overall what the tag-based definition approach allows is for static +definition of extension points that ensures type-safety and +invariants. This keeps the whole extension mechanism static and yet +flexible.

      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      Techniques

      +

      Next topic

      +

      Directives

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/html/whats_new.html b/cpp-netlib/libs/network/doc/html/whats_new.html new file mode 100644 index 00000000..57e827e9 --- /dev/null +++ b/cpp-netlib/libs/network/doc/html/whats_new.html @@ -0,0 +1,342 @@ + + + + + + + + What’s New — cpp-netlib v0.11.2 + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +

      What’s New

      +
      +

      cpp-netlib 0.11

      +
      +

      v0.11.2

      +
        +
      • Support a source_port setting for connections made by the client per-request.
      • +
      • Allow using cpp-netlib without OpenSSL.
      • +
      • Fix build breakage for Visual Studio 2015.
      • +
      • Add more options for HTTP client use of SSL/TLS options/ciphers.
      • +
      • Made client_get_timeout_test less flaky.
      • +
      • Fixes to URI encoding issues with multibyte strings.
      • +
      • Make cpp-netlib not crash on unstable networks.
      • +
      • Allow parsing empty query parameters (#499).
      • +
      • CMake build changes to simplify dependencies on cppnetlib-client-connections.
      • +
      • Handle EOF correctly (#496).
      • +
      • Fix fileserver example to chunk data correctly.
      • +
      • Copy hostname to avoid dangling reference to a temporary request object. (#482)
      • +
      • Catch exceptions in parse_headers to avoid propagating issues in parsing upwards.
      • +
      • Fix some GCC warnings on signed/unsigned comparison.
      • +
      • Support environment variable-based peer verification (via OpenSSL).
      • +
      • Support IPv6 connections.
      • +
      • Support certificate-based verification, and option to always verify hosts.
      • +
      +
      +
      +

      v0.11.1

      +
        +
      • Add support for request timeouts.
      • +
      • Build configuration fixes.
      • +
      • Support for Travis CI in-project config.
      • +
      • Make the response parser more flexible to support older/ad-hoc servers that don’t have standard format responses.
      • +
      • Fix some instability in the client destructor.
      • +
      • MSVC 2010 specific fixes.
      • +
      +
      +
      +

      v0.11.0

      +
        +
      • Fix thread leak in DNS resolution failure (#245)
      • +
      • Remove unsupported client_fwd.hpp header (#277)
      • +
      • Remove support for header-only usage (#129) – this means that the BOOST_NETWORK_NO_LIB option is no longer actually supported.
      • +
      • Deprecate Synchronous Client implementations (#279)
      • +
      • Support streaming body chunks for PUT/POST client requests (#27)
      • +
      • Fix non-case-sensitive header parsing for some client tags (#313)
      • +
      • Remove unsupported Jamfiles from the whole project (#316)
      • +
      • Add make install for Linux and OS X (#285)
      • +
      • Fix incorrect Body processing (#69)
      • +
      • Support chunked transfer encoding from HTTP responses (#86)
      • +
      • Make OS X Clang builds use C++11 and libc++.
      • +
      • Update Boost requirement to 1.54.0.
      • +
      • Experimental Base64 encoding/decoding library (#287)
      • +
      • Known test failure: OS X Xcode Clang 5.0 + Boost 1.54.0 + libc++ don’t play +well with Boost.Serialization issues, mitigate test breakage but +cpp-netlib-utils_base64_test still fails in this platform. (#287)
      • +
      • Provide a client option to always validate peers for HTTPS requests made by +the client. (#349)
      • +
      • Back-port fix for #163 for improved URI parsing.
      • +
      • Added support for client-side certificates and private keys (#361).
      • +
      +
      +
      +
      +

      cpp-netlib 0.10

      +
      +

      v0.10.1

      +
        +
      • Documentation updates (#182, #265, #194, #233, #255)
      • +
      • Fix issue with async server inadvertently stopping from listening when +accepting a connection fails. (#172)
      • +
      • Allow overriding and ultimately removing defaulted headers from HTTP +requests. (#263)
      • +
      • Add -Wall to the base rule for GCC builds. (#264)
      • +
      • Make the server implementation throw on startup errors. (#166)
      • +
      +
      +
      +

      v0.10.0

      +
        +
      • Added support for more HTTP status codes (206, 408, 412, 416, 507).
      • +
      • Refactored the parser for chunked encoding.
      • +
      • Fixed parsing chunked encoding if the response body has <chunk>CLRF<hex>CLRF<data>.
      • +
      • Added librt dependency on Linux.
      • +
      • Check the callback in the asynchronous client before calling it.
      • +
      • Fixed issues #110, #168, #213.
      • +
      +
      +
      +
      +

      cpp-netlib 0.9

      +
      +

      v0.9.5

      +
        +
      • Removed dependency on Boost.Parameter from HTTP client and server.
      • +
      • Fixed for Clang error on Twitter example.
      • +
      • Added source port to the request (HTTP server).
      • +
      • Updated CMake config for MSVC 2010/2012.
      • +
      • Now support chunked content encoding in client response parsing.
      • +
      • Fixed bug with client not invoking callback when a request fails.
      • +
      +
      +
      +

      v0.9.4

      +
        +
      • Lots of URI fixes.
      • +
      • Fixed async_server’s request handler so it doesn’t make copies of the supplied handler.
      • +
      • Fix for issue #73 regarding SSL connections ending in short read errors.
      • +
      • Final C++03-only release.
      • +
      +
      +
      +

      v0.9.3

      +
        +
      • URI, HTTP client and HTTP server are now built as static libraries (libcppnetlib-uri.a, libcppnetlib-client-connections.a and libcppnetlib-server-parsers.a on Linux and cppnetlib-uri.lib, cppnetlib-client-connections.lib and cppnetlib-server-parsers.lib on Windows).
      • +
      • Updated URI parser.
      • +
      • A new URI builder.
      • +
      • URI support for IPv6 RFC 2732.
      • +
      • Fixed issues #67, #72, #78, #79, #80, #81, #82, #83.
      • +
      • New examples for the HTTP client, including an Atom feed, an RSS feed and a +very simple client that uses the Twitter Search API.
      • +
      +
      +
      +

      v0.9.2

      +
        +
      • Critial bug fixes to v0.9.1.
      • +
      +
      +
      +

      v0.9.1

      +
        +
      • Introduced macro BOOST_NETWORK_DEFAULT_TAG to allow for programmatically +defining the default flag to use throughout the compilation unit.
      • +
      • Support for streaming body handlers when performing HTTP client operations. +See documentation for HTTP client interface for more information.
      • +
      • Numerous bug fixes from v0.9.0.
      • +
      • Google, Inc. contributions.
      • +
      +
      +
      +

      v0.9.0

      +
        +
      • IMPORTANT BREAKING CHANGE: By default all compile-time heavy parser +implementations are now compiled to external static libraries. In order to use +cpp-netlib in header-only mode, users must define the preprocessor +macro BOOST_NETWORK_NO_LIB before including any cpp-netlib header. +This breaks code that relied on the version 0.8.x line where the library is +strictly header-only.
      • +
      • Fix issue #41: Introduce a macro BOOST_NETWORK_HTTP_CLIENT_DEFAULT_TAG +which makes the default HTTP client use tags::http_async_8bit_udp_resolve +as the tag.
      • +
      • Fix issue #40: Write the status line and headers in a single buffer write +instead of two writes.
      • +
      • More consistent message API for client and server messages (request and +response objects).
      • +
      • Refactoring of internal implementations to allow better separation of concerns +and more manageable coding/documentation.
      • +
      • Client and server constructors that support Boost.Parameter named parameters.
      • +
      • Client and server constructors now take in an optional reference to a Boost.Asio +io_service to use internally.
      • +
      • Documentation updates to reflect new APIs.
      • +
      +
      +
      +
      +

      cpp-netlib 0.8

      +
        +
      • Updates to URI unit tests and documentation.
      • +
      • More documentation, covering the HTTP Client and HTTP Server APIs
      • +
      • Asynchronous HTTP Server that now supports running request handlers on a +different thread pool.
      • +
      • An initial thread pool implementation, using Boost.Asio underneath.
      • +
      • Adding a ready(...) wrapper to check whether a response object returned by +the asynchronous client in 0.7 already has all the parts available.
      • +
      • Some attempts at lowering compile time costs.
      • +
      +
      +
      +

      cpp-netlib 0.7

      +
        +
      • Radical documentation overhaul
      • +
      • Asynchronous HTTP client
      • +
      • Tag dispatch overhaul, using Boost.MPL
      • +
      • HTTP Client Facade refactoring
      • +
      • Bug fixes for HTTP 1.1 response parsing
      • +
      • Minimized code repetition with some header macro’s
      • +
      • Configurable HTTPS support in the library with BOOST_NETWORK_ENABLE_HTTPS
      • +
      +
      +
      +

      cpp-netlib 0.6

      +
        +
      • Many fixes for MSVC compiler
      • +
      +
      +
      +

      cpp-netlib 0.5

      +
        +
      • An embeddable HTTP 1.1 server
      • +
      • An HTTP 1.1 client upgraded to support HTTPS
      • +
      • An updated URI parser implementation
      • +
      • An asynchronous HTTP 1.1 client
      • +
      • An HTTP 1.1 client that supports streaming function handlers
      • +
      +
      +
      + + +
      +
      +
      +
      +
      +

      Table Of Contents

      + + +

      Previous topic

      +

      Getting cpp-netlib

      +

      Next topic

      +

      Getting Started

      + + +
      +
      +
      +
      + + + + \ No newline at end of file diff --git a/cpp-netlib/libs/network/doc/in_depth.rst b/cpp-netlib/libs/network/doc/in_depth.rst new file mode 100644 index 00000000..39af9a4f --- /dev/null +++ b/cpp-netlib/libs/network/doc/in_depth.rst @@ -0,0 +1,15 @@ +.. _in_depth: + +An in-depth look at the :mod:`cpp-netlib` +========================================= + +The :mod:`cpp-netlib` is composed of three different sets of +functionality: a **message** template, a **URI** template and +different **protocol** implementations. + +.. toctree:: + :maxdepth: 2 + + in_depth/message + in_depth/uri + in_depth/http diff --git a/cpp-netlib/libs/network/doc/in_depth/http.rst b/cpp-netlib/libs/network/doc/in_depth/http.rst new file mode 100644 index 00000000..711bf6b3 --- /dev/null +++ b/cpp-netlib/libs/network/doc/in_depth/http.rst @@ -0,0 +1,180 @@ +HTTP implementation +=================== + +HTTP client +``````````` + +At the heart of the HTTP client implementation is a single class aptly named +``basic_client``, which is also a template. The template ``basic_client`` takes +three template parameters: + +.. code-block:: c++ + + namespace boost { namespace http { + + template + struct basic_client; + + } // namespace http + + } // namespace boost + +The ``Tag`` template parameter follows the same tag-dispatch mechanism to +determine the behavior of the ``basic_client``. The interface of +``basic_client`` may change depending on certain properties defined for the tag +you provide. Below is a table of predefined supported tags you can use in your +overload of the ``basic_client``: + +------------ + +.. include:: http_client_tags.rst + +.. _Boost.Thread: http://www.boost.org/libs/thread + + +The default typedef for the HTTP client that is provided uses the +``http_async_8bit_udp_resolve`` tag, and implements HTTP 1.1. The exact +typedef is in the ``boost::network::http`` namespace as the following: + +.. code-block:: c++ + + namespace boost { namespace network { namespace http { + + typedef basic_client + client; + + }}} + + +This type has nested typedefs for the correct types for the ``basic_request`` +and ``basic_response`` templates. To use the correct types for ``basic_request`` +or ``basic_response`` you can use these nested typedefs like so: + + +.. code-block:: c++ + + boost::network::http::client::request request; + boost::network::http::client::response response; + + // or... + using namespace boost::network; + http::client::request request; + http::client::response response; + + +Typical use cases for the HTTP client would look something like the following: + + +.. code-block:: c++ + + using namespace boost::network; + http::request request("http://www.boost.org/"); + request << header("Connection", "close"); + + +The ``basic_client`` implements all HTTP methods as member functions +(HEAD, GET, POST, PUT, DELETE). Therefore, the code to make an HTTP +request looks trivially simple: + + +.. code-block:: c++ + + using namespace boost::network; + http::client client; + http::client::request request("http://www.boost.org/"); + http::client::response response = client.get(request); + + +Accessing data from ``http::response`` is done using wrappers. +To get the response headers, we use the ``headers`` wrapper which +returns, in the default case, a multimap of strings to strings: + + +.. code-block:: c++ + + using namespace boost::network; + typedef headers_range::type response_headers; + boost::range_iterator::type iterator; + + response_headers headers_ = headers(response); + for (iterator it = headers_.begin(); it != headers_.end(); ++it) { + std::cout << it->first << ": " << it->second << std::endl; + } + std::cout << std::endl; + + +HTTP server +``````````` + +As with the HTTP client, the HTTP server that is provided with +cpp-netlib is extensible through the tag mechanism and is embeddable. +The template class declaration of ``basic_server`` is given below: + + +.. code-block:: c++ + + namespace boost { namespace network { namespace http { + + template basic_server; + + }}} + + +The second template argument is used to specify the request handler +type. The request handler type is a functor type which should overload +the function call operator (``RequestHandler::operator()`` should be +overloaded) that takes two parameters: the first one being a reference +to a ``const basic_request`` and the second being a reference to +a ``basic_response`` instance. + +All the logic for parsing the HTTP request and building the ``const +basic_request`` object resides internally in the ``basic_server`` +template. Processing the request is delegated to the +``RequestHandler`` type, and the assumption of which would be that the +response is formed inside the ``RequestHandler`` function call +operator overload. + +The ``basic_server`` template however is only an underlying +implementation while the user-visible implementation is the +``http::server`` template. This simply specializes the +``basic_server`` template to use the ``default_`` tag and forwards the +``RequestHandler`` parameter: + +.. code-block:: c++ + + namespace boost { namespace network { namespace http { + + template + class server : + public basic_server {}; + + }}} + +To use the forwarding server type you just supply the request handler +implementation as the parameter. For example, an "echo" server example +might look something like this: + + +.. code-block:: c++ + + using namespace boost::network; + struct echo; + typedef http::server echo_server; + + struct echo { + void operator () (const echo_server::request &request, + echo_server::response &response) const { + std::string ip = source(request); + response = echo_server::response::stock_reply( + echo_server::response::ok, + body(request)); + std::cerr << "[" << ip << "]: " << request.uri << + " status = " << echo_server::response::ok << '\n'; + } + }; + + +Here, all we're doing is returning the original request body with an +HTTP OK response (200). We are also printing the IP address from where the +request came from. Notice that we are using a wrapper to access the source of +the request. diff --git a/cpp-netlib/libs/network/doc/in_depth/http_client_tags.rst b/cpp-netlib/libs/network/doc/in_depth/http_client_tags.rst new file mode 100644 index 00000000..5d79ed1e --- /dev/null +++ b/cpp-netlib/libs/network/doc/in_depth/http_client_tags.rst @@ -0,0 +1,42 @@ ++---------------------------------+---------------------------------------------+ +| Tag | Description | ++=================================+=============================================+ +| http_default_8bit_tcp_resolve | This is the default HTTP implementation tag | +| | that resolves addresses with a TCP resolver | +| | and provides a synchronous/blocking HTTP | +| | client interface. | ++---------------------------------+---------------------------------------------+ +| http_default_8bit_udp_resolve | This is similar to the above tag except that| +| | it specifies the HTTP client to use a UDP | +| | resolver. It also provides a synchronous/ | +| | blocking HTTP client interface. | ++---------------------------------+---------------------------------------------+ +| http_keepalive_8bit_tcp_resolve | This tag specifies that the HTTP client by | +| | default will keep connections to the server | +| | alive. It only makes sense if the | +| | ``version_major`` and ``version_minor`` are | +| | both ``1``, to indicate HTTP 1.1. This tag | +| | causes the HTTP client to resolve using a | +| | TCP resolver and provides a synchronous/ | +| | blocking HTTP client interface. | ++---------------------------------+---------------------------------------------+ +| http_keepalive_8bit_udp_resolve | This is similar to the above tag except that| +| | it specifies the HTTP client to use a UDP | +| | resolver. It also provides a synchronous/ | +| | blocking HTTP client interface. | ++---------------------------------+---------------------------------------------+ +| http_async_8bit_tcp_resolve | This tag provides an active HTTP client | +| | object implementation that uses a TCP | +| | resolver. Response objects returned will | +| | encapsulate a number of Boost.Thread_ | +| | shared futures to hold values. Users don't | +| | have to see this as they are implementation | +| | details. | ++---------------------------------+---------------------------------------------+ +| http_async_8bit_udp_resolve | This is similar to the above tag except that| +| | specifies the HTTP client to use a UDP | +| | resolver. | ++---------------------------------+---------------------------------------------+ + +.. _Boost.Thread: http://www.boost.org/libs/thread + diff --git a/cpp-netlib/libs/network/doc/in_depth/message.rst b/cpp-netlib/libs/network/doc/in_depth/message.rst new file mode 100644 index 00000000..51512314 --- /dev/null +++ b/cpp-netlib/libs/network/doc/in_depth/message.rst @@ -0,0 +1,233 @@ +The message template +==================== + +One of the core components in the library is the concept and the +implementation of a common message type. In most (not all) network +protocols, the concept of a message is central to the definition of +the protocol. In HTTP, SMTP, XMPP, and even other protocols like SNMP +and ICMP, there is a common notion of a "packet" or a message. In +cpp-netlib we chose to implement the concept of a message that has the +following common parts: + + * **Source** - every message has a source identifier which varies + from protocol to protocol. + + * **Destination** - every message has a destination identifier which + varies from protocol to protocol. + + * **Headers** - each message is assumed to contain headers, which + may be empty in cases where the protocol does not support it, but + is nonetheless supported by cpp-netlib messages. + + * **Body** - the content area of a message which varies from + protocol to protocol (also sometimes referred to as payload). + +This division is purely logical -- in the underlying implementation, +the message type can choose to have different means of storing the +data, depending on the type used to tag the message. This section +covers the `Message Concept`_ as well as the `basic_message`_ +implementation. + +Message Concept +``````````````` + +.. warning:: The Message framework is deprecated in the 0.11 release, and will + be removed in future versions of the library. + +The Message Concept specifies what the valid operations on a message +are as well as what messages look like semantically. The following +table summarize the operations and syntactic as well as semantic +properties of messages. + +**Legend** + +:M: The message type. +:H: A headers container type. +:m,n: An instance of **M**. +:S: A string type. +:s,k,v: An instance of **S**. +:O: The source type. +:D: The destination type. +:B: The body type. +:T: The Tag type. + ++----------------------------+----------------------+-----------------------------------------+ +| Construct | Result | Description | ++============================+======================+=========================================+ +| ``typename M::tag`` | T | The nested tag type. | ++----------------------------+----------------------+-----------------------------------------+ +| ``M()`` | Instance of M | Default constructible. | ++----------------------------+----------------------+-----------------------------------------+ +| ``M(m)`` | Instance of M | Copy constructible. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m = n;`` | Reference to m | Assignable. | ++----------------------------+----------------------+-----------------------------------------+ +| ``swap(m, n);`` | ``void`` | Swappable. | ++----------------------------+----------------------+-----------------------------------------+ +| ``source(m);`` | Convertible to O | Retrieve the source of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``destination(m);`` | Convertible to D | Retrieve the destination of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``headers(m);`` | Convertible to H | Retrieve the headers of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``body(m);`` | Convertible to B | Retrieve the body of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m << source(s);`` | ``M &`` | Set the source of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m << destination(s);`` | ``M &`` | Set the destination of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m << header(k, v);`` | ``M &`` | Add a header to ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m << remove_header(k);`` | ``M &`` | Remove a header from ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``m << body(s);`` | ``M &`` | Set the body of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``source(m,s);`` | ``void`` | Set the source of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``destination(m,s);`` | ``void`` | Set the destination of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``add_header(m, k, v);`` | ``void`` | Add a header to ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``remove_header(m, k);`` | ``void`` | Remove a header from ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``clear_headers(m);`` | ``void`` | Clear the headers of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``body(m,s);`` | ``M &`` | Set the body of ``m``. | ++----------------------------+----------------------+-----------------------------------------+ + +Types that model the Message Concept are meant to encapsulate data +that has a source, a destination, one or more named headers, and a +body/payload. Because the accessors and the directives are not +required to be part of the message type that models the Message +Concept, a message can be implemented as a POD type and have all +manipulations performed in the directive implementations, as well as +value transformations done in the accessors. + +Directives, Modifiers, and Wrappers +``````````````````````````````````` + +In the Message Concept definition there are three basic constructs that follow a +certain pattern. These patterns are Directives_, Modifiers_, and Wrappers_. + +Directives +~~~~~~~~~~ + +A directive is a function object that is applied to a Message. Directives +encapsulate a set of operations that apply to messages. The general requirement +for a Directive is that it should apply these operations on a message. + +A directive may dispatch on the type of the message passed to it at the point of +the function call. Typically, directives are generated using a factory function +that returns the correct directive type. + +For a given directive ``foo_directive`` a generator function called ``foo`` is +typically implemented: + +.. code-block:: c++ + + struct foo_directive { + template + Message & operator()(Message & m) const { + // do something to m + return m; + } + }; + + foo_directive const foo() { + return foo_directive(); + } + + // to apply a directive, we use the << operator + message m; + m << foo(); + +Modifiers +~~~~~~~~~ + +A modifier is generally defined as a free function that takes a reference to a +non-const lvalue message as the first parameter, and any number of parameters. +In the concept definition of the Message Concept, a modifier follows the form: + +.. code-block:: c++ + + modifier(message, ...) + +Modifiers are meant to imply modifications on a message, which also allows for +easier dispatch based on Argument Dependent Lookup (ADL_) on the type of the +message. Note that Directives_ can be implemented in terms of Modifiers and +vice versa, although that is not required nor specified. + +.. _ADL: http://en.wikipedia.org/wiki/Argument-dependent_name_lookup + +Wrappers +~~~~~~~~ + +A Wrapper is basically an implementation detail that ensures that a given +message, when wrapped, can be converted to the associated part of the message. A +wrapper has a type that encapsulates the conversion logic from a message to a +given type. + +An example of a Wrapper would be ``source_wrapper`` which would be returned by a +call to the wrapper generator function ``source``. An example implementation of +the ``source_wrapper`` would look like: + +.. code-block:: c++ + + template class Message> + struct source_wrapper { + Message const & m; + explicit source_wrapper(Message const & m) + : m(m) {} + typedef typename source::type source_type; + operator source_type const & () { + return m.source; + } + operator source_type const () { + return m.source; + } + operator source_type () { + return m.source; + } + }; + + template class Message> + source_wrapper const + source(Message const & message) { + return source_wrapper(message); + } + +This pattern is similar to an adapter, but the specific notion of wrapping a +data type (in this case, an object of a type that models the Message Concept) +using an intermediary wrapper is what is pertained to by the Wrapper pattern. +In this case, the Wrapper is ``source_wrapper`` while ``source`` is merely a +wrapper generator function. + +``basic_message`` +````````````````` + +The default implementation of a simple type that models the Message +Concept is available in cpp-netlib. This default implementation is +named ``basic_message`` which supports a ``Tag`` template +parameter. The definition of ``basic_message`` looks like this: + +.. code-block:: c++ + + template + class basic_message; + +The ``basic_message`` template requires that the following +tag-dispatched metafunctions are defined for the type ``Tag``: + +.. code-block:: c++ + + template + struct string; + + template + struct headers_container; + +All the operations defined by the message concept are implemented by +this basic message type. Other message implementations can either use +this common message type or specialize it according to whether they +want to use different containers or whether it's going to be just a +POD type. diff --git a/cpp-netlib/libs/network/doc/in_depth/uri.rst b/cpp-netlib/libs/network/doc/in_depth/uri.rst new file mode 100644 index 00000000..84eca62e --- /dev/null +++ b/cpp-netlib/libs/network/doc/in_depth/uri.rst @@ -0,0 +1,151 @@ +The URI class +============= + +In addition to protocol implementations, the :mod:`cpp-netlib` +provides a powerful URI class. The class implements a parser based +on `RFC 3986`_ and `RFC 2732`_. + +Generic URI syntax overview +``````````````````````````` + +A generic URI will take the form:: + + [scheme:]scheme-specific-part[#fragment] + +A URI is known as `absolute` if it specifies the scheme. Otherwise, +it is known as a relative URI. Currently, ``uri`` supports only +absolute URIs. + +URIs can be further classified according to whether they're +hierarchical or opaque (non-hierarchical). + +Some examples of non-hierarchical URIs include:: + + mailto:john.doe@example.com + news:comp.infosystems.www.servers.unix + tel:+1-816-555-1212 + +The data following the first ``":"`` is said to be opaque to the URI +parser and requires no further parsing. By way of example, the +following shows how a non-hierarchical URI is processed by the parser +by defining everything after the ``":"`` to be a part of the path: + +.. image:: ../_static/mailto_uri.png + +A hierarchical URI is identified by a double slash (``"//"``) after +the scheme and a scheme-specific component, which `RFC 3986`_ defines +to be:: + + [scheme:][//authority][path][?query][#fragment] + +The authority component can be further broken down to:: + + [user_info@]host[:port] + +Examples of hierarchical URIs include:: + + http://www.boost.org/ + file:///bin/bash + +The following example, describing a complex URI using FTP, shows how +a URI is broken down by the parser: + +.. image:: ../_static/ftp_uri.png + +Note that the ``authority`` is further subdivided into different +elements. Another example, using HTTP is given below: + +.. image:: ../_static/http_uri.png + +The difference here between the path in a hierarchical URI and that in +the example above for the non-hierarchical URI. + +The ``uri`` class +````````````````` + +As of version 0.9.3, ``uri`` supplies a URI parser and builder. +To use the parser, it's as simple as supplying a string to the +constructor: + +.. code-block:: c++ + + using namespace boost::network; + uri::uri instance("http://cpp-netlib.github.com/"); + assert(instance.is_valid()); + std::cout << "scheme: " << instance.scheme() << std::endl + << "host: " << instance.host() << std::endl; + +The command-line output of this program will be:: + + scheme: http + host: cpp-netlib.github.com + +The ``uri`` builder +``````````````````` + +``uri`` support a stream style syntax to create a URI from it's +elements. For example the program: + +.. code-block:: c++ + + #include + #include + #include + using namespace boost::network; + + int main() { + uri::uri url; + url << uri::scheme("http") + << uri::host("www.github.com") + << uri::path("/cpp-netlib"); + std::cout << url << std::endl; + return 0; + } + +will output:: + + http://www.github.com/cpp-netlib + +``URI Concept`` +``````````````` + +**Legend** + +:U: The URI type. +:u,u_: An instance of **M**. +:S: A string type. +:s,v: An instance of **S**. +:T: The Tag type. + ++----------------------------+----------------------+-----------------------------------------+ +| Construct | Result | Description | ++============================+======================+=========================================+ +| ``U(u)`` | Instance of U | Copy constructible. | ++----------------------------+----------------------+-----------------------------------------+ +| ``U(s)`` | Instance of U | Constructible from string. | ++----------------------------+----------------------+-----------------------------------------+ +| ``u = u_;`` | Reference to u | Assignable. | ++----------------------------+----------------------+-----------------------------------------+ +| ``u = s;`` | Reference to u | Assignable from string. | ++----------------------------+----------------------+-----------------------------------------+ +| ``swap(u, u_);`` | ``void`` | Swappable. | ++----------------------------+----------------------+-----------------------------------------+ +| ``scheme(u);`` | Convertible to S | Retrieve the URI scheme of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``user_info(u);`` | Convertible to S | Retrieve the user info of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``host(u);`` | Convertible to S | Retrieve the host of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``port(u);`` | Convertible to H | Retrieve the port of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``path(u);`` | Convertible to S | Retrieve the path of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``query(u);`` | Convertible to S | Retrieve the query string of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ +| ``fragment(u);`` | Convertible to S | Retrieve the fragment of ``u``. | ++----------------------------+----------------------+-----------------------------------------+ + +.. _`RFC 3986`: http://tools.ietf.org/html/rfc3986 +.. _`RFC 2368`: http://tools.ietf.org/html/rfc2368 +.. _`RFC 3513`: http://tools.ietf.org/html/rfc3513 +.. _`RFC 2732`: http://tools.ietf.org/html/rfc2732 diff --git a/cpp-netlib/libs/network/doc/index.rst b/cpp-netlib/libs/network/doc/index.rst new file mode 100644 index 00000000..fc9e6540 --- /dev/null +++ b/cpp-netlib/libs/network/doc/index.rst @@ -0,0 +1,124 @@ +.. _index: +.. rubric:: Straightforward network programming in modern C++ + +.. :Authors: Glyn Matthews +.. Dean Michael Berris +.. :Date: 2014-10-01 +.. :Version: 0.11.0 +.. :Description: Complete user documentation, with examples, for the :mod:`cpp-netlib`. +.. :Copyright: Copyright Glyn Matthews, Dean Michael Berris 2008-2013. +.. Copyrigh 2013 Google, Inc. +.. 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) + +Getting cpp-netlib +================== + +You can find out more about the :mod:`cpp-netlib` project at +http://cpp-netlib.org/. + +**Download** + +You can get the latest official version of the library from the official +project website at: + + http://cpp-netlib.org/ + +This version of :mod:`cpp-netlib` is tagged as cpp-netlib-0.11.0 in the GitHub_ +repository. You can find more information about the progress of the development +by checking our GitHub_ project page at: + + http://github.com/cpp-netlib/cpp-netlib + +**Support** + +You can ask questions, join the discussion, and report issues to the +developers mailing list by joining via: + + https://groups.google.com/group/cpp-netlib + +You can also file issues on the Github_ issue tracker at: + + http://github.com/cpp-netlib/cpp-netlib/issues + +We are a growing community and we are happy to accept new +contributions and ideas. + +C++ Network Library +=================== + +:mod:`cpp-netlib` is a library collection that provides application layer +protocol support using modern C++ techniques. It is light-weight, fast, +portable and is intended to be as easy to configure as possible. + +Hello, world! +============= + +The :mod:`cpp-netlib` allows developers to write fast, portable +network applications with the minimum of fuss. + +An HTTP server-client example can be written in tens of lines of code. +The client is as simple as this: + +.. code-block:: cpp + + using namespace boost::network; + using namespace boost::network::http; + + client::request request_("http://127.0.0.1:8000/"); + request_ << header("Connection", "close"); + client client_; + client::response response_ = client_.get(request_); + std::string body_ = body(response_); + +And the corresponding server code is listed below: + +.. code-block:: cpp + + namespace http = boost::network::http; + + struct handler; + typedef http::server http_server; + + struct handler { + void operator() (http_server::request const &request, + http_server::response &response) { + response = http_server::response::stock_reply( + http_server::response::ok, "Hello, world!"); + } + + void log(http_server::string_type const &info) { + std::cerr << "ERROR: " << info << '\n'; + } + }; + + int main(int arg, char * argv[]) { + handler handler_; + http_server::options options(handler_); + http_server server_( + options.address("0.0.0.0") + .port("8000")); + server_.run(); + } + +Want to learn more? +=================== + + * :ref:`Take a look at the getting started guide ` + * :ref:`Learn from some simple examples ` + * :ref:`Find out what's new ` + * :ref:`Study the library in more depth ` + * :ref:`Discover more through the full reference ` + * :ref:`Full table of contents ` + +.. warning:: Be aware that not all features are stable. The generic + message design is under review and the URI and HTTP + client implementation will continue to undergo + refactoring. Future versions will include support for + other network protocols. + + +.. _Boost: http://www.boost.org/ +.. _GitHub: http://github.com/ + diff --git a/cpp-netlib/libs/network/doc/make.bat b/cpp-netlib/libs/network/doc/make.bat new file mode 100644 index 00000000..e79deefd --- /dev/null +++ b/cpp-netlib/libs/network/doc/make.bat @@ -0,0 +1,113 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +set SPHINXBUILD=sphinx-build +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\cpp-netlib.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\cpp-netlib.ghc + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end diff --git a/cpp-netlib/libs/network/doc/reference.rst b/cpp-netlib/libs/network/doc/reference.rst new file mode 100644 index 00000000..d4cbf99d --- /dev/null +++ b/cpp-netlib/libs/network/doc/reference.rst @@ -0,0 +1,16 @@ +.. _reference: + +Reference Manual +================ + +This reference manual refers to the API documentation of the public interfaces +to the different client and/or server implementations within :mod:`cpp-netlib`. + +.. toctree:: + :maxdepth: 2 + + reference/http_client + reference/http_request + reference/http_response + reference/http_server + diff --git a/cpp-netlib/libs/network/doc/reference/http_client.rst b/cpp-netlib/libs/network/doc/reference/http_client.rst new file mode 100644 index 00000000..1277c83e --- /dev/null +++ b/cpp-netlib/libs/network/doc/reference/http_client.rst @@ -0,0 +1,475 @@ + +HTTP Client API +=============== + +General +------- + +:mod:`cpp-netlib` includes and implements a number of HTTP clients that you can +use and embed in your own applications. All of the HTTP client implementations: + + * **Cannot be copied.** This means you may have to store instances of the + clients in dynamic memory if you intend to use them as function parameters + or pass them around in smart pointers or by reference. + * **Assume that requests made are independent of each other.** There currently + is no cookie or session management system built-in to cpp-netlib's HTTP client + implementations. + +The HTTP clients all share the same API, but the internals are documented in +terms of what is different and what to expect with the different +implementations. + +As of 0.9.1 the default implementation for the :mod:`cpp-netlib` HTTP client is +asynchronous. + +As of 0.11 the `Synchronous Clients`_ are now *DEPRECATED* and will be removed +in subsequent releases. + +Features +-------- + +The HTTP client implementation supports requesting secure HTTP (HTTPS) content +only in the following situations: + + * **Client libraries are built with ``BOOST_NETWORK_ENABLE_HTTPS``.** This + tells the implementation to use HTTPS-specific code to handle HTTPS-based + content when making connections associated with HTTPS URI's. This requires + a dependency on OpenSSL_. + * **The ``BOOST_NETWORK_ENABLE_HTTPS`` macro is set when compiling user + code.** It is best to define this either at compile-time of all code using + the library, or before including any of the client headers. + +To use the client implementations that support HTTPS URIs, you may explicitly +do the following: + +.. code-block:: c++ + + #define BOOST_NETWORK_ENABLE_HTTPS + #include + +This forces HTTPS support to be enabled and forces a dependency on OpenSSL_. +This dependency is imposed by `Boost.Asio`_ + +.. _OpenSSL: http://www.openssl.org/ +.. _`Boost.Asio`: http://www.boost.org/libs/asio + +Implementations +--------------- + +There is a single user-facing template class named ``basic_client`` which takes +three template parameters: + + * **Tag** - which static tag you choose that defines the behavior of the client. + + * **http_version_major** - an unsigned int that defines the HTTP major version + number, this directly affects the HTTP messages sent by the client. + + * **http_version_minor** - an unsigned int that defines the HTTP minor version + number. + +There are two major different class of implementations of the ``basic_client`` +template that depend on which tag you choose: `Synchronous Clients`_ and +`Asynchronous Clients`_. These two different classes are described in their own +sections following this one. What follows is a table of all tags supported by +the HTTP client implementation provided by :mod:`cpp-netlib`. + +--------------- + +.. include:: ../in_depth/http_client_tags.rst + +In the above table the tags follow a pattern for describing the behavior +introduced by the tags. This pattern is shown below: + + ___ + +For example, the tag ``http_default_8bit_tcp_resolve`` indicates the protocol +``http``, a modifier ``default``, a character width of ``8bit``, and a resolve +strategy of ``tcp_resolve``. + +Synchronous Clients +~~~~~~~~~~~~~~~~~~~ + +Of the client tags shown in the table, the following makes the ``basic_client`` +behave as a fully synchronous client. + + * **http_default_8bit_tcp_resolve** + * **http_default_8bit_udp_resolve** + * **http_keepalive_8bit_tcp_resolve** + * **http_keepalive_8bit_udp_resolve** + +The synchronous client implements all the operations of the client underneath +the interface all block to wait for I/O to finish. All the member methods are +synchronous and will block until the response object is ready or throws if errors +are encountered in the performance of the HTTP requests. + +.. warning:: The synchronous clients are **NOT** thread safe. You will need to do + external synchronization to use synchronous client implementations. + +.. note:: As of version 0.11, all the synchronous client implementations are + deprecated. They will be removed in the next version of the library. + +Asynchronous Clients +~~~~~~~~~~~~~~~~~~~~ + +The following tags specify the ``basic_client`` to behave in an asynchronous +manner: + + * **http_async_8bit_tcp_resolve** + * **http_async_8bit_udp_resolve** + +An asynchronous client implementation means that``basic_client<...>`` is an +`Active Object`_. This means that the client has and manages its own lifetime +thread, and returns values that are asynchronously filled in. The response +object encapsulates Boost.Thread_ futures which get filled in once the values +are available. + +.. _Boost.Thread: http://www.boost.org/libs/thread +.. _`Active Object`: http://en.wikipedia.org/wiki/Active_object + +The asynchronous clients implement all operations asynchronously which are hidden +from the user. The interface is still synchronous but the fetching of data +happens on a different thread. + +.. note:: The asynchronous clients are thread safe, and can be shared across + many threads. Each request starts a sequence of asynchronous operations + dedicated to that request. The client does not re-cycle connections and uses + a one-request-one-connection model. + +When an asynchronous client object is destroyed, it waits for all pending +asynchronous operations to finish. Errors encountered during operations on +retrieving data from the response objects cause exceptions to be thrown -- +therefore it is best that if a client object is constructed, it should outlive +the response object or be outside the try-catch block handling the errors from +operations on responses. In code, usage should look like the following: + +.. code-block:: c++ + + http::client client; + try { + http::client::response response = client.get("http://www.example.com/"); + std::cout << body(response); + } catch (std::exception& e) { + // deal with exceptions here + } + +A common mistake is to declare the client inside the try block which invokes +undefined behavior when errors arise from the handling of response objects. +Previous examples cited by the documentation showed the short version of the +code which didn't bother moving the ``http::client`` object outside of the same +``try`` block where the request/response objects are being used. + +Member Functions +---------------- + +In this section we assume that the following typedef is in effect: + +.. code-block:: c++ + + typedef boost::network::http::basic_client< + boost::network::http::tags::http_default_8bit_udp_resolve + , 1 + , 1 + > + client; + +Also, that code using the HTTP client will have use the following header: + +.. code-block:: c++ + + #include + +.. note:: Starting version 0.9, cpp-netlib clients and server implementations + by default now have an externally-linked component. This is a breaking change + for code that used to rely on cpp-netlib being a header-only library, but can + inhibited by defining the ``BOOST_NETWORK_NO_LIB`` preprocessor macro before + including any cpp-netlib header. + +.. note:: Starting version 0.11, cpp-netlib clients and server implementations + no longer support the ``BOOST_NETWORK_NO_LIB`` option. + +Constructors +~~~~~~~~~~~~ + +The client implementation can be default constructed, or customized at +initialization. + +``client()`` + Default constructor. +``explicit client(client::options const &)`` + Constructor taking a ``client_options`` object. The following table + shows the options you can set on a ``client_options`` instance. + ++--------------------------+----------------------------+--------------------------+ +| Parameter Name | Type | Description | ++==========================+============================+==========================+ +| follow_redirects | ``bool`` | Boolean to specify | +| | | whether the client | +| | | should follow HTTP | +| | | redirects. Default is | +| | | ``false``. | ++--------------------------+----------------------------+--------------------------+ +| cache_resolved | ``bool`` | Boolean to specify | +| | | whether the client | +| | | should cache resolved | +| | | endpoints. The default | +| | | is ``false``. | ++--------------------------+----------------------------+--------------------------+ +| io_service | ``shared_ptr`` | Shared pointer to a | +| | | Boost.Asio | +| | | ``io_service``. | ++--------------------------+----------------------------+--------------------------+ +| openssl_certificate | ``string`` | The filename of the | +| | | certificate to load for | +| | | the SSL connection for | +| | | verification. | ++--------------------------+----------------------------+--------------------------+ +| openssl_verify_path | ``string`` | The directory from | +| | | which the certificate | +| | | authority files are | +| | | located. | ++--------------------------+----------------------------+--------------------------+ +| always_verify_peer | ``bool`` | Boolean to specify | +| | | whether the client | +| | | should always verify | +| | | peers in SSL connections | ++--------------------------+----------------------------+--------------------------+ +| openssl_certificate_file | ``string`` | Filename of the | +| | | certificate to use for | +| | | client-side SSL session | +| | | establishment. | ++--------------------------+----------------------------+--------------------------+ +| openssl_private_key_file | ``string`` | Filename of the | +| | | private key to use for | +| | | client-side SSL session | +| | | establishment. | ++--------------------------+----------------------------+--------------------------+ +| timeout | ``int`` | Number of seconds to | +| | | wait for client requests | +| | | before considering a | +| | | timeout has occurred. | ++--------------------------+----------------------------+--------------------------+ + + +To use the above supported named parameters, you'll have code that looks like +the following: + +.. code-block:: c++ + + using namespace boost::network::http; // parameters are in this namespace + client::options options; + options.follow_redirects(true) + .cache_resolved(true) + .io_service(boost::make_shared()) + .openssl_certificate("/tmp/my-cert") + .openssl_verify_path("/tmp/ca-certs") + .timeout(10); + client client_(options); + // use client_ as normal from here on out. + +HTTP Methods +~~~~~~~~~~~~ + +The client implementation supports various HTTP methods. The following +constructs assume that a client has been properly constructed named ``client_`` +and that there is an appropriately constructed request object named ``request_`` +and that there is an appropriately constructed response object named +``response_`` like the following: + +.. code-block:: c++ + + using namespace boost::network::http; // parameters are here + client client_(); + client::request request_("http://cpp-netib.github.com/"); + client::response response_; + +``response_ = client_.get(request_)`` + Perform an HTTP GET request. +``response_ = client_.get(request_, callback)`` + Perform an HTTP GET request, and have the body chunks be handled by the + ``callback`` parameter. The signature of ``callback`` should be the following: + ``void(iterator_range const &, boost::system::error_code const + &)``. +``response_ = client_.head(request_)`` + Perform an HTTP HEAD request. +``response_ = client_.post(request_)`` + Perform an HTTP POST, use the data already set in the request object which + includes the headers, and the body. +``response_ = client_.post(request_, callback)`` + Perform an HTTP POST request, and have the body chunks be handled by the + ``callback`` parameter. The signature of ``callback`` should be the following: + ``void(iterator_range const &, boost::system::error_code const + &)``. +``response_ = client_.post(request_, body)`` + Body is a string of type ``boost::network::string::type`` where ``Tag`` + is the HTTP Client's ``Tag``. The default content-type used is + ``x-application/octet-stream``. +``response_ = client_.post(request_, body, callback)`` + Body is a string of type ``boost::network::string::type`` where ``Tag`` + is the HTTP Client's ``Tag``. The default content-type used is + ``x-application/octet-stream``. Have the response body chunks be handled by + the ``callback`` parameter. The signature of ``callback`` should be the + following: ``void(iterator_range const &, + boost::system::error_code const &)``. +``response_ = client_.post(request_, body, content_type)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. +``response_ = client_.post(request_, body, content_type, callback)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. Have the response + body chunks be handled by the ``callback`` parameter. The signature of + ``callback`` should be the following: ``void(iterator_range const + &, boost::system::error_code const &)``. +``response_ = client_.post(request_, body, content_type, callback, streaming_callback)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. Have the response + body chunks be handled by the ``callback`` parameter. The signature of + ``callback`` should be the following: ``void(iterator_range const + &, boost::system::error_code const &)``. The ``streaming_callback`` + argument should have a which has a signature of the form: + ``bool(string_type&)``. The provided ``string_type&`` will be streamed as + soon as the function returns. A return value of ``false`` signals the + client that the most recent invocation is the last chunk to be sent. +``response_ = client_.post(request_, streaming_callback)`` + Perform and HTTP POST request, and have the request's body chunks be + generated by the ``streaming_callback`` which has a signature of the form: + ``bool(string_type&)``. The provided ``string_type&`` will be streamed as + soon as the function returns. A return value of ``false`` signals the client + that the most recent invocation is the last chunk to be sent. +``response_ = client_.post(request_, callback, streaming_callback)`` + Perform an HTTP POST request, and have the body chunks be handled by the + ``callback`` parameter. The signature of ``callback`` should be the + following: ``void(iterator_range const &, + boost::system::error_code const &)``. This form also has the request's body + chunks be generated by the ``streaming_callback`` which has a signature of + the form: ``bool(string_type&)``. The provided ``string_type&`` will be + streamed as soon as the function returns. A return value of ``false`` + signals the client that the most recent invocation is the last chunk to be + sent. +``response_ = client_.put(request_)`` + Perform an HTTP PUT, use the data already set in the request object which + includes the headers, and the body. +``response_ = client_.put(request_, callback)`` + Perform an HTTP PUT request, and have the body chunks be handled by the + ``callback`` parameter. The signature of ``callback`` should be the following: + ``void(iterator_range const &, boost::system::error_code const + &)``. +``response_ = client_.put(request_, body)`` + Body is a string of type ``boost::network::string::type`` where ``Tag`` + is the HTTP Client's ``Tag``. The default content-type used is + ``x-application/octet-stream``. +``response_ = client_.put(request_, body, callback)`` + Body is a string of type ``boost::network::string::type`` where ``Tag`` + is the HTTP Client's ``Tag``. The default content-type used is + ``x-application/octet-stream``. Have the response body chunks be handled by + the ``callback`` parameter. The signature of ``callback`` should be the + following: ``void(iterator_range const &, + boost::system::error_code const &)``. +``response_ = client_.put(request_, body, content_type)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. +``response_ = client_.put(request_, body, content_type, callback)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. Have the response + body chunks be handled by the ``callback`` parameter. The signature of + ``callback`` should be the following: ``void(iterator_range const + &, boost::system::error_code const &)``. +``response_ = client_.put(request_, body, content_type, callback, streaming_callback)`` + The body and content_type parameters are of type + ``boost::network::string::type`` where ``Tag`` is the HTTP Client's + ``Tag``. This uses the request object's other headers. Have the response + body chunks be handled by the ``callback`` parameter. The signature of + ``callback`` should be the following: ``void(iterator_range const + &, boost::system::error_code const &)``. This form also has the request's body + chunks be generated by the ``streaming_callback`` which has a signature of + the form: ``bool(string_type&)``. The provided ``string_type&`` will be + streamed as soon as the function returns. A return value of ``false`` + signals the client that the most recent invocation is the last chunk to be + sent +``response_ = client_.put(request_, streaming_callback)`` + Perform and HTTP PUT request, and have the request's body chunks be + generated by the ``streaming_callback`` which has a signature of the form: + ``bool(string_type&)``. The provided ``string_type&`` will be streamed as + soon as the function returns. A return value of ``false`` signals the client + that the most recent invocation is the last chunk to be sent. +``response_ = client_.put(request_, callback, streaming_callback)`` + Perform an HTTP PUT request, and have the body chunks be handled by the + ``callback`` parameter. The signature of ``callback`` should be the + following: ``void(iterator_range const &, + boost::system::error_code const &)``. This form also has the request's body + chunks be generated by the ``streaming_callback`` which has a signature of + the form: ``bool(string_type&)``. The provided ``string_type&`` will be + streamed as soon as the function returns. A return value of ``false`` + signals the client that the most recent invocation is the last chunk to be + sent. +``response_ = client_.delete_(request_)`` + Perform an HTTP DELETE request. +``response_ = client_.delete_(request_, body_handler=callback)`` + Perform an HTTP DELETE request, and have the response body chunks be handled + by the ``callback`` parameter. The signature of ``callback`` should be the + following: ``void(iterator_range const &, + boost::system::error_code const &)``. + +Client-Specific +~~~~~~~~~~~~~~~ + +``client_.clear_resolved_cache()`` + Clear the cache of resolved endpoints. + + +Streaming Body Handler +~~~~~~~~~~~~~~~~~~~~~~ + +As of v0.9.1 the library now offers a way to support a streaming body callback +function in all HTTP requests that expect a body part (GET, PUT, POST, DELETE). +A convenience macro is also provided to make callback handlers easier to write. +This macro is called ``BOOST_NETWORK_HTTP_BODY_CALLBACK`` which allows users to +write the following code to easily create functions or function objects that +are compatible with the callback function requirements. + +An example of how to use the macro is shown below: + +.. code-block:: c++ + + struct body_handler { + explicit body_handler(std::string & body) + : body(body) {} + + BOOST_NETWORK_HTTP_BODY_CALLBACK(operator(), range, error) { + // in here, range is the Boost.Range iterator_range, and error is + // the Boost.System error code. + if (!error) + body.append(boost::begin(range), boost::end(range)); + } + + std::string & body; + }; + + // somewhere else + std::string some_string; + response_ = client_.get(request("http://cpp-netlib.github.com/"), + body_handler(some_string)); + +You can also use if for standalone functions instead if you don't want or need +to create a function object. + +.. code-block:: c++ + + BOOST_NETWORK_HTTP_BODY_CALLBACK(print_body, range, error) { + if (!error) + std::cout << "Received " << boost::distance(range) << "bytes." + << std::endl; + else + std::cout << "Error: " << error << std::endl; + } + + // somewhere else + response_ = client_.get(request("http://cpp-netlib.github.com/"), + print_body); + +The ``BOOST_NETWORK_HTTP_BODY_CALLBACK`` macro is defined in +``boost/network/protocol/http/client/macros.hpp``. diff --git a/cpp-netlib/libs/network/doc/reference/http_request.rst b/cpp-netlib/libs/network/doc/reference/http_request.rst new file mode 100644 index 00000000..cbef6e18 --- /dev/null +++ b/cpp-netlib/libs/network/doc/reference/http_request.rst @@ -0,0 +1,254 @@ + +HTTP Request +============ + +This part of the documentation talks about the publicly accessible API of the +HTTP Request objects. This section details the `Request Concepts`_ requirements, +the implemented and required Directives_, Modifiers_, and Wrappers_ that work +with the HTTP Request objects. + +Request Concepts +---------------- + +There are two generally supported Request Concepts implemented in the library. +The first of two is the `Normal Client Request Concept`_ and the second is the +`Pod Server Request Concept`_. + +The `Normal Client Request Concept`_ is what the HTTP Client interface requires. +All operations performed internally by the HTTP Client abide by the interface +required by this concept definition. + +The `Pod Server Request Concept`_ is as the name suggests what the HTTP Server +implementation requires from Request Objects. + +Switching on whether the `Request` concept chooses either of the `Normal Client +Request Concept`_ or the `Pod Server Request Concept`_ is done through the +nested ``tag`` type and whether that tag derives from the root tag ``pod``. +Simply, if the Request type's nested ``tag`` type derives from +``boost::network::tags::pod`` then it chooses to enforce the `Pod Server Request +Concept`_, otherwise it chooses the `Normal Client Request Concept`_. + +Normal Client Request Concept +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A type models the Normal Client Request Concept if it models the `Message +Concept`_ and also supports the following constructs. + +**Legend** + +:R: The request type. +:r: An instance of R. +:S: The string type. +:s: An instance of S. +:P: The port type. +:p: An instance of P. + ++-----------------------+-------------+----------------------------------------+ +| Construct | Result | Description | ++=======================+=============+========================================+ +| ``R::string_type`` | ``S`` | The nested ``string_type`` type. | ++-----------------------+-------------+----------------------------------------+ +| ``R::port_type`` | ``P`` | The nested ``port_type`` type. | ++-----------------------+-------------+----------------------------------------+ +| ``R r(s)`` | **NA** | Construct a Request with an ``s`` | +| | | provided. This treats ``s`` as the URI | +| | | to where the request is destined for. | ++-----------------------+-------------+----------------------------------------+ +| ``host(request)`` | Convertible | Return the host to where the request | +| | to ``S`` | is destined for. | ++-----------------------+-------------+----------------------------------------+ +| ``port(request)`` | Convertible | Return the port to where the request | +| | to ``P`` | is destined for. | ++-----------------------+-------------+----------------------------------------+ +| ``path(request)`` | Convertible | Return the path included in the URI. | +| | to ``S`` | | ++-----------------------+-------------+----------------------------------------+ +| ``query(request)`` | Convertible | Return the query part of the URI. | +| | to ``S`` | | ++-----------------------+-------------+----------------------------------------+ +| ``anchor(request)`` | Convertible | Return the anchor part of the URI. | +| | to ``S`` | | ++-----------------------+-------------+----------------------------------------+ +| ``protocol(request)`` | Convertible | Return the protocol/scheme part of the | +| | to ``S`` | URI. | ++-----------------------+-------------+----------------------------------------+ +| ``r << uri(s)`` | ``R&`` | Set the URI of the request. | ++-----------------------+-------------+----------------------------------------+ +| ``uri(r, s)`` | ``void`` | Set the URI of the request. | ++-----------------------+-------------+----------------------------------------+ + +Pod Server Request Concept +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A type models the Pod Server Request Concept if it models the `Message Concept`_ +and also supports the following constructs. + +**Legend** + +:R: The request type. +:r: An instance of R. +:S: The string type. +:I: An unsigned 8 bit integer. +:V: The vector type for headers. + ++-------------------------------+--------+-------------------------------------+ +| Construct | Result | Description | ++===============================+========+=====================================+ +| ``R::string_type`` | ``S`` | The nested ``string_type`` type. | ++-------------------------------+--------+-------------------------------------+ +| ``R::headers_container_type`` | ``V`` | The nested | +| | | ``headers_container_type`` type. | ++-------------------------------+--------+-------------------------------------+ +| ``r.source`` | ``S`` | The nested source of the request. | ++-------------------------------+--------+-------------------------------------+ +| ``r.method`` | ``S`` | The method of the request. | ++-------------------------------+--------+-------------------------------------+ +| ``r.destination`` | ``S`` | The destination of the request. | +| | | This is normally the URI of the | +| | | request. | ++-------------------------------+--------+-------------------------------------+ +| ``r.version_major`` | ``I`` | The major version number part of | +| | | the request. | ++-------------------------------+--------+-------------------------------------+ +| ``r.version_minor`` | ``I`` | The minor version number part of | +| | | the request. | ++-------------------------------+--------+-------------------------------------+ +| ``r.headers`` | ``V`` | The vector of headers. | ++-------------------------------+--------+-------------------------------------+ +| ``r.body`` | ``S`` | The body of the request. | ++-------------------------------+--------+-------------------------------------+ + +.. _Message Concept: ../in_depth/message.html#message-concept + +Directives +---------- + +This section details the provided directives that are provided by +:mod:`cpp-netlib`. The section was written to assume that an appropriately +constructed request instance is either of the following: + +.. code-block:: c++ + + boost::network::http::basic_request< + boost::network::http::tags::http_default_8bit_udp_resolve + > request; + + // or + + boost::network::http::basic_request< + boost::network::http::tags::http_server + > request; + +The section also assumes that there following using namespace declaration is in +effect: + +.. code-block:: c++ + + using namespace boost::network; + +Directives are meant to be used in the following manner: + +.. code-block:: c++ + + request << directive(...); + +.. warning:: + + There are two versions of directives, those that are applicable to + messages that support narrow strings (``std::string``) and those that are + applicable to messages that support wide strings (``std::wstring``). The + :mod:`cpp-netlib` implementation still does not convert wide strings into + UTF-8 encoded narrow strings. This will be implemented in subsequent + library releases. + + For now all the implemented directives are listed, even if some of them still + do not implement things correctly. + +*unspecified* ``source(std::string const & source_)`` + Create a source directive with a ``std::string`` as a parameter, to be set + as the source of the request. +*unspecified* ``source(std::wstring const & source_)`` + Create a source directive with a ``std::wstring`` as a parameter, to be set + as the source of the request. +*unspecified* ``destination(std::string const & source_)`` + Create a destination directive with a ``std::string`` as a parameter, to be + set as the destination of the request. +*unspecified* ``destination(std::wstring const & source_)`` + Create a destination directive with a ``std::wstring`` as a parameter, to be + set as the destination of the request. +*unspecified* ``header(std::string const & name, std::string const & value)`` + Create a header directive that will add the given name and value pair to the + headers already associated with the request. In this case the name and + values are both ``std::string``. +*unspecified* ``header(std::wstring const & name, std::wstring const & value)`` + Create a header directive that will add the given name and value pair to the + headers already associated with the request. In this case the name and + values are both ``std::wstring``. +*unspecified* ``remove_header(std::string const & name)`` + Create a remove_header directive that will remove all the occurences of the + given name from the headers already associated with the request. In this + case the name of the header is of type ``std::string``. +*unspecified* ``remove_header(std::wstring const & name)`` + Create a remove_header directive that will remove all the occurences of the + given name from the headers already associated with the request. In this + case the name of the header is of type ``std::wstring``. +*unspecified* ``body(std::string const & body_)`` + Create a body directive that will set the request's body to the given + parameter. In this case the type of the body is an ``std::string``. +*unspecified* ``body(std::wstring const & body_)`` + Create a body directive that will set the request's body to the given + parameter. In this case the type of the body is an ``std::wstring``. + +Modifiers +--------- + +This section details the provided modifiers that are provided by +:mod:`cpp-netlib`. + +``template inline void source(basic_request & request, typename string::type const & source_)`` + Modifies the source of the given ``request``. The type of ``source_`` is + dependent on the ``Tag`` specialization of ``basic_request``. +``template inline void destination(basic_request & request, typename string::type const & destination_)`` + Modifies the destination of the given ``request``. The type of ``destination_`` is + dependent on the ``Tag`` specialization of ``basic_request``. +``template inline void add_header(basic_request & request, typename string::type const & name, typename string::type const & value)`` + Adds a header to the given ``request``. The type of the ``name`` and + ``value`` parameters are dependent on the ``Tag`` specialization of + ``basic_request``. +``template inline void remove_header(basic_request & request, typename string::type const & name)`` + Removes a header from the given ``request``. The type of the ``name`` + parameter is dependent on the ``Tag`` specialization of ``basic_request``. +``template inline void clear_headers(basic_request & request)`` + Removes all headers from the given ``request``. +``template inline void body(basic_request & request, typename string::type const & body_)`` + Modifies the body of the given ``request``. The type of ``body_`` is + dependent on the ``Tag`` specialization of ``basic_request``. + +Wrappers +-------- + +This section details the provided request wrappers that come with +:mod:`cpp-netlib`. Wrappers are used to convert a message into a different type, +usually providing accessor operations to retrieve just part of the message. This +section assumes that the following using namespace directives are in +effect: + +.. code-block:: c++ + + using namespace boost::network; + using namespace boost::network::http; + +``template `` *unspecified* ``source(basic_request const & request)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the source of a given request. +``template `` *unspecified* ``destination(basic_request const & request)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the destination of a given request. +``template `` *unspecified* ``headers(basic_request const & request)`` + Returns a wrapper convertible to ``typename headers_range + >::type`` or ``typename basic_request::headers_container_type`` that + provides the headers of a given request. +``template `` *unspecified* ``body(basic_request const & request)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the body of a given request. + diff --git a/cpp-netlib/libs/network/doc/reference/http_response.rst b/cpp-netlib/libs/network/doc/reference/http_response.rst new file mode 100644 index 00000000..d0a97399 --- /dev/null +++ b/cpp-netlib/libs/network/doc/reference/http_response.rst @@ -0,0 +1,309 @@ + +HTTP Response +============= + +This part of the documentation talks about the publicly accessible API of the +HTTP Response objects. This section details the `Response Concept`_ requirements, +the implemented and required Directives_, Modifiers_, and Wrappers_ that work +with the HTTP Response objects. + +.. note:: The HTTP server response object is a POD type, which doesn't support + any of the following details. There are only a few fields available in the + HTTP server response type, which can be seen in + ``boost/network/protocol/http/impl/response.ipp``. + +Response Concept +---------------- + +A type models the Response Concept if it models the `Message Concept`_ and also +supports the following constructs. + +**Legend** + +:R: The response type. +:r: An instance of R. +:S: The string type. +:s,e,g: Instances of S. +:P: The port type. +:p: An instance of P. +:V: The version type. +:v: An instance of v. +:T: The status type. +:t: An instance of T. +:M: The status message type. +:m: An instance of M. +:U: An unsigned 16-bit int. +:u: An instance of U. + +.. note:: In the table below, the namespace ``traits`` is an alias for + ``boost::network::http::traits``. + ++-------------------------------------+----------+-----------------------------+ +| Construct | Result | Description | ++=====================================+==========+=============================+ +| ``R::string_type`` | ``S`` | The nested ``string_type`` | +| | | type. | ++-------------------------------------+----------+-----------------------------+ +| ``traits::version::type`` | ``V`` | The version type associated | +| | | with R. | ++-------------------------------------+----------+-----------------------------+ +| ``traits::status::type`` | ``T`` | The status type associated | +| | | with R. | ++-------------------------------------+----------+-----------------------------+ +| ``traits::status_message::type`` | ``M`` | The status message type | +| | | associated with R. | ++-------------------------------------+----------+-----------------------------+ +| ``r << version(v)`` | ``R&`` | Sets the version of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``r << status(t)`` | ``R&`` | Sets the status of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``r << status_message(m)`` | ``R&`` | Sets the status message of | +| | | ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``version(r, v)`` | ``void`` | Sets the version of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``status(r, t)`` | ``void`` | Sets the status of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``status_message(r, m)`` | ``void`` | Sets the status message of | +| | | ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``S e = version(r)`` | **NA** | Get the version of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``U u = status(r)`` | **NA** | Get the status of ``r``. | ++-------------------------------------+----------+-----------------------------+ +| ``S g = status_message(r)`` | **NA** | Get the status message of | +| | | ``r``. | ++-------------------------------------+----------+-----------------------------+ + +.. _Message Concept: ../in_depth/message.html#message-concept + +Directives +---------- + +This section details the provided directives that are provided by +:mod:`cpp-netlib`. The section was written to assume that an appropriately +constructed response instance is either of the following: + +.. code-block:: c++ + + boost::network::http::basic_response< + boost::network::http::tags::http_default_8bit_udp_resolve + > response; + + // or + + boost::network::http::basic_response< + boost::network::http::tags::http_server + > response; + +The section also assumes that there following using namespace declaration is in +effect: + +.. code-block:: c++ + + using namespace boost::network; + +Directives are meant to be used in the following manner: + +.. code-block:: c++ + + response << directive(...); + +.. warning:: There are four versions of directives, those that are applicable + to messages that support narrow strings (``std::string``), those that are + applicable to messages that support wide strings (``std::wstring``), those + that are applicable to messages that support future-wrapped narrow and wide + strings (``boost::shared_future`` and + ``boost::shared_future``). + + The :mod:`cpp-netlib` implementation still does not convert wide strings into + UTF-8 encoded narrow strings. This will be implemented in subsequent + library releases. + + For now all the implemented directives are listed, even if some of them still + do not implement things correctly. + +*unspecified* ``source(std::string const & source_)`` + Create a source directive with a ``std::string`` as a parameter, to be set + as the source of the response. +*unspecified* ``source(std::wstring const & source_)`` + Create a source directive with a ``std::wstring`` as a parameter, to be set + as the source of the response. +*unspecified* ``source(boost::shared_future const & source_)`` + Create a source directive with a ``boost::shared_future`` as a parameter, to be set + as the source of the response. +*unspecified* ``source(boost::shared_future const & source_)`` + Create a source directive with a ``boost::shared_future`` as a parameter, to be set + as the source of the response. +*unspecified* ``destination(std::string const & source_)`` + Create a destination directive with a ``std::string`` as a parameter, to be + set as the destination of the response. +*unspecified* ``destination(std::wstring const & source_)`` + Create a destination directive with a ``std::wstring`` as a parameter, to be + set as the destination of the response. +*unspecified* ``destination(boost::shared_future const & destination_)`` + Create a destination directive with a ``boost::shared_future`` as a parameter, to be set + as the destination of the response. +*unspecified* ``destination(boost::shared_future const & destination_)`` + Create a destination directive with a ``boost::shared_future`` as a parameter, to be set + as the destination of the response. +*unspecified* ``header(std::string const & name, std::string const & value)`` + Create a header directive that will add the given name and value pair to the + headers already associated with the response. In this case the name and + values are both ``std::string``. +*unspecified* ``header(std::wstring const & name, std::wstring const & value)`` + Create a header directive that will add the given name and value pair to the + headers already associated with the response. In this case the name and + values are both ``std::wstring``. +*unspecified* ``remove_header(std::string const & name)`` + Create a remove_header directive that will remove all the occurences of the + given name from the headers already associated with the response. In this + case the name of the header is of type ``std::string``. +*unspecified* ``remove_header(std::wstring const & name)`` + Create a remove_header directive that will remove all the occurences of the + given name from the headers already associated with the response. In this + case the name of the header is of type ``std::wstring``. +*unspecified* ``body(std::string const & body_)`` + Create a body directive that will set the response's body to the given + parameter. In this case the type of the body is an ``std::string``. +*unspecified* ``body(std::wstring const & body_)`` + Create a body directive that will set the response's body to the given + parameter. In this case the type of the body is an ``std::wstring``. +*unspecified* ``body(boost::shared_future const & body_)`` + Create a body directive that will set the response's body to the given + parameter. In this case the type of the body is an ``boost::shared_future``. +*unspecified* ``body(boost::shared_future const & body_)`` + Create a body directive that will set the response's body to the given + parameter. In this case the type of the body is an ``boost::shared_future``. +*unspecified* ``version(std::string const & version_)`` + Create a version directive that will set the response's version to the given + parameter. In this case the type of the version is an ``std::string``. + + Note that this version includes the full ``"HTTP/"`` string. +*unspecified* ``version(std::wstring const & version_)`` + Create a version directive that will set the response's version to the given + parameter. In this case the type of the version is an ``std::wstring``. + + Note that this version includes the full ``"HTTP/"`` string. +*unspecified* ``version(boost::shared_future const & version_)`` + Create a version directive that will set the response's version to the given + parameter. In this case the type of the version is an ``boost::shared_future``. + + Note that this version includes the full ``"HTTP/"`` string. +*unspecified* ``version(boost::shared_future const & version_)`` + Create a version directive that will set the response's version to the given + parameter. In this case the type of the version is an ``boost::shared_future``. + + Note that this version includes the full ``"HTTP/"`` string. +*unspecified* ``status_message(std::string const & status_message_)`` + Create a status_message directive that will set the response's status_message to the given + parameter. In this case the type of the status_message is an ``std::string``. + + Note that this status_message includes the full ``"HTTP/"`` string. +*unspecified* ``status_message(std::wstring const & status_message_)`` + Create a status_message directive that will set the response's status_message to the given + parameter. In this case the type of the status_message is an ``std::wstring``. + + Note that this status_message includes the full ``"HTTP/"`` string. +*unspecified* ``status_message(boost::shared_future const & status_message_)`` + Create a status_message directive that will set the response's status_message to the given + parameter. In this case the type of the status_message is an ``boost::shared_future``. + + Note that this status_message includes the full ``"HTTP/"`` string. +*unspecified* ``status_message(boost::shared_future const & status_message_)`` + Create a status_message directive that will set the response's status_message to the given + parameter. In this case the type of the status_message is an ``boost::shared_future``. + + Note that this status_message includes the full ``"HTTP/"`` string. +*unspecified* ``status(boost::uint16_t status_)`` + Create a status directive that will set the response's status to the given + parameter. In this case the type of ``status_`` is ``boost::uint16_t``. +*unspecified* ``status(boost::shared_future const & status_)`` + Create a status directive that will set the response's status to the given + parameter. In this case the type of ``status_`` is ``boost::shared_future``. + +Modifiers +--------- + +This section details the provided modifiers that are provided by +:mod:`cpp-netlib`. + +``template inline void source(basic_response & response, typename string::type const & source_)`` + Modifies the source of the given ``response``. The type of ``source_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void source(basic_response & response, boost::shared_future::type> const & source_)`` + Modifies the source of the given ``response``. The type of ``source_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void destination(basic_response & response, typename string::type const & destination_)`` + Modifies the destination of the given ``response``. The type of ``destination_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void destination(basic_response & response, boost::shared_future::type> const & destination_)`` + Modifies the destination of the given ``response``. The type of ``destination_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void add_header(basic_response & response, typename string::type const & name, typename string::type const & value)`` + Adds a header to the given ``response``. The type of the ``name`` and + ``value`` parameters are dependent on the ``Tag`` specialization of + ``basic_response``. +``template inline void remove_header(basic_response & response, typename string::type const & name)`` + Removes a header from the given ``response``. The type of the ``name`` + parameter is dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void headers(basic_response & response, typename headers_container >::type const & headers_)`` + Sets the whole headers contained in ``response`` as the given parameter + ``headers_``. +``template inline void headers(basic_response & response, boost::shared_future >::type> const & headers_)`` + Sets the whole headers contained in ``response`` as the given parameter + ``headers_``. +``template inline void clear_headers(basic_response & response)`` + Removes all headers from the given ``response``. +``template inline void body(basic_response & response, typename string::type const & body_)`` + Modifies the body of the given ``response``. The type of ``body_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void body(basic_response & response, boost::shared_future::type> const & body_)`` + Modifies the body of the given ``response``. The type of ``body_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void version(basic_response & response, typename traits::version >::type const & version_)`` + Modifies the version of the given ``response``. The type of ``version_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void status(basic_response & response, typename traits::status >::type const & status_)`` + Modifies the status of the given ``response``. The type of ``status_`` is + dependent on the ``Tag`` specialization of ``basic_response``. +``template inline void status_message(basic_response & response, typename traits::status_message >::type const & status_message_)`` + Modifies the status message of the given ``response``. The type of ``status_message_`` is + dependent on the ``Tag`` specialization of ``basic_response``. + +Wrappers +-------- + +This section details the provided response wrappers that come with +:mod:`cpp-netlib`. Wrappers are used to convert a message into a different type, +usually providing accessor operations to retrieve just part of the message. This +section assumes that the following using namespace directives are in +effect: + +.. code-block:: c++ + + using namespace boost::network; + using namespace boost::network::http; + +``template `` *unspecified* ``source(basic_response const & response)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the source of a given response. +``template `` *unspecified* ``destination(basic_response const & response)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the destination of a given response. +``template `` *unspecified* ``headers(basic_response const & response)`` + Returns a wrapper convertible to ``typename headers_range + >::type`` or ``typename basic_response::headers_container_type`` that + provides the headers of a given response. +``template `` *unspecified* ``body(basic_response const & response)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the body of a given response. +``template `` *unspecified* ``version(basic_response const & response)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the version of the given response. +``template `` *unspecified* ``status(basic_response const & response)`` + Returns a wrapper convertible to ``typename boost::uint16_t`` that + provides the status of the given response. +``template `` *unspecified* ``status_message(basic_response const & response)`` + Returns a wrapper convertible to ``typename string::type`` that + provides the status message of the given response. diff --git a/cpp-netlib/libs/network/doc/reference/http_server.rst b/cpp-netlib/libs/network/doc/reference/http_server.rst new file mode 100644 index 00000000..26ceb9b6 --- /dev/null +++ b/cpp-netlib/libs/network/doc/reference/http_server.rst @@ -0,0 +1,559 @@ + +HTTP Server API +=============== + +General +------- + +:mod:`cpp-netlib` includes and implements two distinct HTTP server +implementations that you can use and embed in your own applications. Both HTTP +Server implementations: + + * **Cannot be copied.** This means you may have to store instances of the HTTP + Server in dynamic memory if you intend to use them as function parameters or + pass them around in smart pointers of by reference. + * **Assume that requests made are independent of each other.** None of the + HTTP Server implementations support request pipelining (yet) so a single + connection only deals with a single request. + * **Are header-only and are compiled-into your application.** Future releases + in case you want to upgrade the implementation you are using in your + application will be distributed as header-only implementations, which means + you have to re-compile your application to use a newer version of the + implementations. + +The HTTP Servers have different semantics, and in some cases require different +APIs from the supplied template parameters. + +Implementations +--------------- + +There are two different user-facing template classes that differentiate the +`Synchronous Servers`_ from the `Asynchronous Servers`_. Both templates take a +single template parameter named ``Handler`` which describes the type of the +Handler function object. + +There are two different Handler concepts, one concept for `Synchronous Servers`_ +and another for `Asynchronous Servers`. + +The SynchronousHandler concept for `Synchronous Servers`_ is described by the +following table: + +--------------- + +**Legend:** + +H + The Handler type. +h + An instance of H. +Req + A type that models the Request Concept. +Res + A type that models the Response Concept. +req + An instance of Req. +res + An instance of Res. + ++----------------+-------------+----------------------------------------------+ +| Construct | Return Type | Description | ++================+=============+==============================================+ +| ``h(req,res)`` | ``void`` | Handle the request; res is passed in as a | +| | | non-const lvalue, which represents the | +| | | response to be returned to the client | +| | | performing the request. | ++----------------+-------------+----------------------------------------------+ + +More information about the internals of the `Synchronous Servers`_ can be found +in the following section. + +The AsynchronousHandler concept for `Asynchronous Servers`_ is described by the +following table: + +--------------- + +**Legend:** + +H + The Handler type. +h + An instance of H. +Req + A type that models the Request Concept. +ConnectionPtr + A type that models the Connection Pointer Concept. +req + An instance of Req. +conn + An instance of ConncetionPtr. + ++------------------+-------------+--------------------------------------------+ +| Construct | Return Type | Description | ++==================+=============+============================================+ +| ``h(req, conn)`` | ``void`` | Handle the request; conn is a shared | +| | | pointer which exposes functions for | +| | | writing to and reading from the connection.| ++------------------+-------------+--------------------------------------------+ + +More information about the internals of the `Asynchronous Servers`_ can be found +in the following section. + +Synchronous Servers +------------------- + +The synchronous server implementation is represented by the template ``server`` +in namespace ``boost::network::http``. The ``server`` template takes in a single +template parameter named ``Handler`` which models the SynchronousHandler +concept (described above). + +An instance of Handler is taken in by reference to the constructor of the HTTP +server. This means the Handler is not copied around and only a single instance +of the handler is used for all connections and requests performed against the +HTTP server. + +.. warning:: It is important to note that the HTTP server does not implement any + locking upon invoking the Handler. In case you have any state in the Handler + that will be associated with the synchronous server, you would have to + implement your own synchronization internal to the Handler implementation. + This matters especially if you run the synchronous server in multiple + threads. + +The general pattern of usage for the HTTP Server template is shown below: + +.. code-block:: c++ + + struct handler; + typedef boost::network::http::server http_server; + + struct handler { + void operator()( + http_server::request const & req, + http_server::response & res + ) { + // do something, and then edit the res object here. + } + }; + +More information about the actual HTTP Server API follows in the next section. +It is important to understand that the HTTP Server is actually embedded in your +application, which means you can expose almost all your application logic +through the Handler type, which you can also initialize appropriately. + +API Documentation +~~~~~~~~~~~~~~~~~ + +The following sections assume that the following file has been included: + +.. code-block:: c++ + + #include + +And that the following typedef's have been put in place: + +.. code-block:: c++ + + struct handler_type; + typedef boost::network::http::server http_server; + + struct handler_type { + void operator()(http_server::request const & request, + http_server::response & response) { + // do something here + } + }; + +Constructor +``````````` + +``explicit http_server(options)`` + Construct an HTTP Server instance, passing in a ``server_options`` object. The following table shows the supported options in + ``server_options``. + ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| Parameter Name | Type | Description | ++=======================+==========================================+==================================================================================================+ +| address | string_type | The hostname or IP address from which the server should be bound to. This parameter is required. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| port | string_type | The port to which the server should bind and listen to. This parameter is required. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| thread_pool | ``shared_ptr`` | A shared pointer to an instance of ``boost::network::utils::thread_pool`` -- this is the | +| | | thread pool from where the handler is invoked. This parameter is only applicable and required | +| | | for ``async_server`` instances. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| io_service | ``shared_ptr`` | An optional lvalue to an instance of ``boost::asio::io_service`` which allows the server to use | +| | | an already-constructed ``boost::asio::io_service`` instance instead of instantiating one that it | +| | | manages. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| reuse_address | ``bool`` | A boolean that specifies whether to re-use the address and port on which the server will be | +| | | bound to. This enables or disables the socket option for listener sockets. The default is | +| | | ``false``. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| report_aborted | ``bool`` | A boolean that specifies whether the listening socket should report aborted connection attempts | +| | | to the accept handler (an internal detail of cpp-netlib). This is put in place to allow for | +| | | future-proofing the code in case an optional error handler function is supported in later | +| | | releases of cpp-netlib. The default is ``false``. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| receive_buffer_size | ``int`` | The size of the socket's receive buffer. The default is defined by Boost.Asio and is | +| | | platform-dependent. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| send_buffer_size | ``int`` | The size of the socket's send buffer. The default is defined by Boost.Asio and is | +| | | platform-dependent. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| receive_low_watermark | ``int`` | The size of the socket's low watermark for its receive buffer. The default is defined by | +| | | Boost.Asio and is platform-dependent. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| send_buffer_size | ``int`` | The size of the socket's send low watermark for its send buffer. The default is defined by | +| | | Boost.Asio and is platform-dependent. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| non_blocking_io | ``bool`` | An optional bool to define whether the socket should use non-blocking I/O in case the platform | +| | | supports it. The default is ``true``. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| linger | ``bool`` | An optional bool to determine whether the socket should linger in case there's still data to be | +| | | sent out at the time of its closing. The default is ``true``. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| linger_timeout | ``int`` | An optional int to define the timeout to wait for socket closes before it is set to linger. | +| | | The default is ``0``. | ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ +| context | ``shared_ptr`` | An optional shared pointer to an instance of ``boost::asio::ssl::context`` -- this contains the | +| | | settings needed to support SSL. This parameter is only applicable for ``async_server`` instances.| ++-----------------------+------------------------------------------+--------------------------------------------------------------------------------------------------+ + +To use the above supported named parameters, you'll have code that looks like the following: + +.. code-block:: c++ + + using namespace boost::network::http; // parameters are in this namespace + handler handler_instance; + sync_server::options options(handler_instance); + options.address("0.0.0.0") + .port("80") + .io_service(boost::make_shared()) + .reuse_address(true); + sync_server instance(options); + instance.run(); + +Public Members +`````````````` + +The following definitions assume that a properly constructed ``http_server`` +instance has been constructed in the following manner: + +.. code-block:: c++ + + handler_type handler; + http_server::options options(handler); + http_server server(options.address("127.0.0.1").port("8000")); + +``server.run()`` + Run the HTTP Server event loop. This function can be run on multiple threads + following the example: + +.. code-block:: c++ + + boost::thread t1(boost::bind(&http_server::run, &server)); + boost::thread t2(boost::bind(&http_server::run, &server)); + server.run(); + t1.join(); + t2.join(); + +``server.stop()`` + Stop the HTTP Server acceptor and wait for all pending requests to finish. + +Response Object +``````````````` + +The response object has its own public member functions which can be very +helpful in certain simple situations. + +``response = http_server::response::stock_reply(status, body)`` + Code like the above should go inside the handler's ``operator()`` overload. + The body parameter is an ``std::string``. The status parameter is any of + the following values from the ``http_server::response`` enum + ``status_type``: + +.. code-block:: c++ + + enum status_type { + ok = 200, + created = 201, + accepted = 202, + no_content = 204, + multiple_choices = 300, + moved_permanently = 301, + moved_temporarily = 302, + not_modified = 304, + bad_request = 400, + unauthorized = 401, + forbidden = 403, + not_found = 404, + not_supported = 405, + not_acceptable = 406, + internal_server_error = 500, + not_implemented = 501, + bad_gateway = 502, + service_unavailable = 503 + }; + +The response object also has the following publicly accessible member values +which can be directly manipulated by the handler. + ++------------------+----------------------+------------------------------------+ +| Member Name | Type | Description | ++==================+======================+====================================+ +| status | ``status_type`` | The HTTP status of the response. | ++------------------+----------------------+------------------------------------+ +| headers | ``vector
      `` | Vector of headers. [#]_ | ++------------------+----------------------+------------------------------------+ +| content | ``string_type`` [#]_ | The contents of the response. | ++------------------+----------------------+------------------------------------+ + +.. [#] A header is a struct of type + ``response_header``. An instance always has the + members ``name`` and ``value`` both of which are of type ``string_type``. +.. [#] ``string_type`` is + ``boost::network::string::type``. + +Asynchronous Servers +-------------------- + +The asynchronous server implementation is significantly different to the +synchronous server implementation in three ways: + + #. **The Handler instance is invoked asynchronously**. This means the I/O + thread used to handle network-related events are free to handle only the + I/O related events. This enables the server to scale better as to the + number of concurrent connections it can handle. + #. **The Handler is able to schedule asynchronous actions on the thread pool + associated with the server.** This allows handlers to perform multiple + asynchronous computations that later on perform writes to the connection. + #. **The Handler is able to control the (asynchronous) writes to and reads from + the HTTP connection.** Because the connection is available to the Handler, + that means it can write out chunks of data at a time or stream data through + the connection continuously. + +The asynchronous server is meant to allow for better scalability in terms of the +number of concurrent connections and for performing asynchronous actions within +the handlers. If your application does not need to write out information +asynchronously or perform potentially long computations, then the synchronous +server gives a generally better performance profile than the asynchronous +server. + +The asynchronous server implementation is available from a single user-facing +template named ``async_server``. This template takes in a single template +parameter which is the type of the Handler to be called once a request has been +parsed from a connection. + +An instance of Handler is taken as a reference to the constructor similar to the +synchronous server implementation. + +.. warning:: The asynchronous server implementation, like the synchronous server + implementation, does not perform any synchronization on the calls to the + Handler invocation. This means if your handler contains or maintains internal + state, you are responsible for implementing your own synchronization on + accesses to the internal state of the Handler. + +The general pattern for using the ``async_server`` template is shown below: + +.. code-block:: c++ + + struct handler; + typedef boost::network::http::async_server http_server; + + struct handler { + void operator()( + http_server::request const & req, + http_server::connection_ptr connection + ) { + // handle the request here, and use the connection to + // either read more data or write data out to the client + } + }; + +API Documentation +~~~~~~~~~~~~~~~~~ + +The following sections assume that the following file has been included: + +.. code-block:: c++ + + #include + #include + +And that the following typedef's have been put in place: + +.. code-block:: c++ + + struct handler_type; + typedef boost::network::http::server http_server; + + struct handler_type { + void operator()(http_server::request const & request, + http_server::connection_ptr connection) { + // do something here + } + }; + +Constructor +``````````` + +``explicit http_server(options)`` + Construct an HTTP server instance passing in a ``server_options`` instance. + +Public Members +`````````````` + +The following definitions assume that a properly constructed ``http_server`` +instance has been constructed in the following manner: + +.. code-block:: c++ + + handler_type handler; + http_server::options options(handler); + options.thread_pool(boost::make_shared(2)); + http_server server(options.address("127.0.0.1").port("8000")); + +``server.run()`` + Run the HTTP Server event loop. This function can be run on multiple threads + following the example: + +.. code-block:: c++ + + boost::thread t1(boost::bind(&http_server::run, &server)); + boost::thread t2(boost::bind(&http_server::run, &server)); + server.run(); + t1.join(); + t2.join(); + +``server.stop()`` + Stop the HTTP Server acceptor and wait for all pending requests to finish. + +Connection Object +````````````````` + +The connection object has its own public member functions which will be the +primary means for reading from and writing to the connection. + +``template write(Range range)`` + The connection object exposes a function ``write`` that can be given a + parameter that adheres to the Boost.Range_ ``Single Pass Range`` Concept. + The write function, although it looks synchronous, starts of a series of + asynchronous writes to the connection as soon as the range is serialized to + appropriately sized buffers. + + To use this in your handler, it would look something like this: + +.. code-block:: c++ + + connection->write("Hello, world!"); + std::string sample = "I have a string!"; + connection->write(sample); + +``template void write(Range range, Callback callback)`` + The connection object also exposes a function ``write`` that can be given a + parameter that adheres to the Boost.Range_ ``Single Pass Range`` Concept, as + well as a Callback function that returns ``void`` and takes a + ``boost::system::error_code`` as a parameter. This overload of ``write`` is + useful for writing streaming applications that send out chunks of data at a + time, or for writing data that may not all fit in memory right away. + +``template void read(ReadCallback callback)`` + The connection object has a function ``read`` which can be used to read more + information from the connection. This ``read`` function takes in a callback + that can be assigned to a Boost.Function_ with the signature + ``void(input_range,error_code,size_t,connection_ptr)``. The following list + shows what the types actually mean: + + * **input_range** -- ``boost::iterator_range`` : The range + that denotes the data read from the connection. + * **error_code** -- ``boost::system::error_code`` : The error code if + there were any errors encountered from the read. + * **size_t** -- ``std::size_t`` : The number of bytes transferred. + * **connection_ptr** -- ``http_server::connection_ptr`` : A handle to the + current connection, so that it is kept alive at the time of the read + callback invocation. + + This interface is useful when doing reads of uploaded data that can be + potentially large and may not fit in memory. The read handler is then + responsible for dealing with the chunks of data available from the + connection. + +``void set_status(status_t new_status)`` + The ``set_status`` function takes a parameter of type ``status_t`` which is + an enum type nested in ``http_status::connection`` which is given in the + following code listing. + +.. code-block:: c++ + + enum status_t { + ok = 200 + , created = 201 + , accepted = 202 + , no_content = 204 + , multiple_choices = 300 + , moved_permanently = 301 + , moved_temporarily = 302 + , not_modified = 304 + , bad_request = 400 + , unauthorized = 401 + , forbidden = 403 + , not_found = 404 + , not_supported = 405 + , not_acceptable = 406 + , internal_server_error = 500 + , not_implemented = 501 + , bad_gateway = 502 + , service_unavailable = 503 + }; + +.. note:: You may set and re-set the status several times as long as you have + not set the headers or sent data through the connection. If you do this after + data has already been set, the function will throw an instance of + ``std::logic_error``. + +``template void set_headers(Range range)`` + The ``set_headers`` function takes a Single Pass Range of + ``boost::network::http::response_header`` + instances and linearizes them to a buffer with at most + ``BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE`` and + immediately schedules an asynchronous write once that is done. + + The function throws an instance of ``std::logic_error`` if you try to set + the headers for a connection more than once. + +Adding SSL support to Asynchronous Server +----------------------------------------- + +In order to setup SSL support for an Asynchronous Server, it is best to start from +a regular Asynchronous Server (see above). Once this server is setup, SSL can be +enabled by adding a Boost.Asio.Ssl.Context_ to the options. The settings that can be +used are defined in the link. + +.. code-block:: c++ + + // Initialize SSL context + boost::shared_ptr ctx = boost::make_shared(boost::asio::ssl::context::sslv23); + ctx->set_options( + boost::asio::ssl::context::default_workarounds + | boost::asio::ssl::context::no_sslv2 + | boost::asio::ssl::context::single_dh_use); + + // Set keys + ctx->set_password_callback(password_callback); + ctx->use_certificate_chain_file("server.pem"); + ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem); + ctx->use_tmp_dh_file("dh512.pem"); + + handler_type handler; + http_server::options options(handler); + options.thread_pool(boost::make_shared(2)); + http_server server(options.address("127.0.0.1").port("8442").context(ctx)); + + std::string password_callback(std::size_t max_length, boost::asio::ssl::context_base::password_purpose purpose) { + return std::string("test"); + } + +.. _Boost.Range: http://www.boost.org/libs/range +.. _Boost.Function: http://www.boost.org/libs/function +.. _Boost.Asio.SSL.Context: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/ssl__context.html diff --git a/cpp-netlib/libs/network/doc/references.rst b/cpp-netlib/libs/network/doc/references.rst new file mode 100644 index 00000000..7f2c97d4 --- /dev/null +++ b/cpp-netlib/libs/network/doc/references.rst @@ -0,0 +1,25 @@ +References +========== + +About :mod:`cpp-netlib` +~~~~~~~~~~~~~~~~~~~~~~~ + +* `BoostCon 2010 Slides`_ +* `BoostCon 2010 Paper`_ + +Other sources +~~~~~~~~~~~~~ + +* `Template Metaprogramming`_: The best guide to C++ template metaprogramming. +* `HTTP 1.0`_: The HTTP 1.0 specification. +* `HTTP 1.1 (RFC 2616)`_: The HTTP 1.1 specification. +* `URI Generic Syntax (RFC 3986)`_: Generic URI syntax specification. +* `Format for Literal IPv6 Addresses in URLs (RFC 2732)`_: Literal IPv6 Addresses in URLs. + +.. _`BoostCon 2010 Slides`: http://www.filetolink.com/b0e89d06 +.. _`BoostCon 2010 Paper`: http://github.com/downloads/mikhailberis/cpp-netlib-boostcon-paper/cpp-netlib.pdf +.. _`Template Metaprogramming`: http://www.boostpro.com/mplbook/ +.. _`HTTP 1.0`: http://www.w3.org/Protocols/HTTP/1.0/spec.html +.. _`HTTP 1.1 (RFC 2616)`: http://www.w3.org/Protocols/rfc2616/rfc2616.html +.. _`URI Generic Syntax (RFC 3986)`: http://www.ietf.org/rfc/rfc3986.txt +.. _`Format for Literal IPv6 Addresses in URLs (RFC 2732)`: http://www.ietf.org/rfc/rfc2732.txt diff --git a/cpp-netlib/libs/network/doc/techniques.rst b/cpp-netlib/libs/network/doc/techniques.rst new file mode 100644 index 00000000..b52bf7e3 --- /dev/null +++ b/cpp-netlib/libs/network/doc/techniques.rst @@ -0,0 +1,12 @@ +Techniques +========== + +The :mod:`cpp-netlib` uses several advanced techniques to achieve it's +aims. This chapter describes some of those techniques. + +.. toctree:: + :maxdepth: 1 + + techniques/tag_metafunctions + techniques/directives + techniques/polymorphism diff --git a/cpp-netlib/libs/network/doc/techniques/directives.rst b/cpp-netlib/libs/network/doc/techniques/directives.rst new file mode 100644 index 00000000..e40882d9 --- /dev/null +++ b/cpp-netlib/libs/network/doc/techniques/directives.rst @@ -0,0 +1,92 @@ +Directives +========== + +The :mod:`cpp-netlib` uses a technique for allowing message-passing +semantics in a chainable fashion in the form of directives. The basic +concept for directives is, in a general sense, an encapsulated +transformation that can be applied to objects that abide by the +directive protocol. + +Using the object-oriented notion of message passing, where an object +accepts a message (usually a function call) we define a simple DSEL in +order for the protocol to be supported by certain object types. In the +:mod:`cpp-netlib` the protocol implemented is similar to that of the +standard iostream formatting system: + +.. code-block:: c++ + + object << directive1(...) + << directive2(...) + ... + << directiveN(...); + +In :mod:`cpp-netlib` the directives are simple function objects that +take a target object as reference and returns a reference to the same +object as a result. In code the directive pattern looks like the +following: + +.. code-block:: c++ + + struct directive_type { + template + Input & operator()(Input & input) const { + // do something to input + return input; + } + }; + +To simplify directive creation, usually factory or generator functions +are defined to return concrete objects of the directive's type. + +.. code-block:: c++ + + inline + directive_type directive(...) { + return directive_type(); + } + +The trivial implementation of the directive protocol then boils down +to the specialization of the shift-left operator on the target type. + +.. code-block:: c++ + + template + inline target_type & operator<< + (target_type & x, Directive const & f) { + return f(x); + } + +.. todo:: + + An example using a directive. + +The rationale for implementing directives include the following: + + * **Encapsulation** - by moving logic into the directive types the + target object's interface can remain rudimentary and even hidden + to the user's immediate attention. Adding this layer of + indirection also allows for changing the underlying + implementations while maintaining the same syntactic and semantic + properties. + * **Flexibility** - by allowing the creation of directives that are + independent from the target object's type, generic operations can + be applied based on the concept being modeled by the target + type. The flexibility also afforded comes in the directive's + generator function, which can also generate different concrete + directive specializations based on parameters to the function. + * **Extensibility** - because the directives are independent of the + target object's type, new directives can be added and supported + without having to change the target object at all. + * **Reuse** - truly generic directives can then be used for a broad + set of target object types that model the same concepts supported + by the directive. Because the directives are self-contained + objects, the state and other object references it keeps are only + accessible to it and can be re-used in different contexts as well. + +Extending a system that uses directives is trivial in header-only +systems because new directives are simply additive. The protocol is +simple and can be applied to a broad class of situations. + +In a header-only library, the static nature of the wiring and chaining +of the operations lends itself to compiler abuse. A deep enough +nesting of the directives can lead to prolonged compilation times. diff --git a/cpp-netlib/libs/network/doc/techniques/polymorphism.rst b/cpp-netlib/libs/network/doc/techniques/polymorphism.rst new file mode 100644 index 00000000..d5e42f8c --- /dev/null +++ b/cpp-netlib/libs/network/doc/techniques/polymorphism.rst @@ -0,0 +1,92 @@ +Static and dynamic polymorphism +=============================== + + +With a header only library, you can only do so much with static +polymorphism alone. There are some situations where you have to handle +dynamic polymorphism because of unavoidable runtime-based decision +making. Although you can deal with the base types that remain static, +behavior can vary greatly which derived type should be handling the +situation based on runtime values. + +This situation comes up in the :mod:`cpp-netlib` when we decide what +kind of connection handler to use for a given HTTP URI -- whether it's +plain HTTP or HTTPS. Although the HTTP semantics are the same for +HTTP and HTTPS the implementation of the connection handler greatly +varies on whether to use a plain TCP connection or an SSL-wrapped TCP +connection. + +The general pattern or technique is to combine tag-based dispatch with +a strategy factory, all while not requiring any externally built +libraries. Doing it in a header-only library requires a little +creativity and additional layers of indirection that you otherwise +will not need for a library with externally built static/dynamic +libraries. + +First we define the base type which we want to support dynamic +behavior with. There's nothing special with the base type, except +that it supports the tag dispatch earlier defined and has a virtual +destructor. In code it looks like this: + +.. code-block:: c++ + + template + struct base { + virtual void foo() = 0; // make this an abstract base + virtual ~base() { + // do the base destructor thing here. + } + }; + +We then define a set of derived types that specialize the +implementation of the ``foo`` member function. To facilitate the +dispatch of the correct type based on an input, we create a strategy +factory function: + +.. code-block:: c++ + + template + unique_ptr > strategy(int input, Tag) { + unique_ptr > ptr; + switch(input) { + case 0: ptr.reset(new derived0()); break; + case 1: ptr.reset(new derived1()); break; + // ... + default: ptr.reset(0); break; + } + return ptr; + } + + unique_ptr > ptr = + strategy(input, default_()); // input is a runtime value + +The strategy factory can be a standalone function, or a static member +of a factory class that is specialized by tag dispatch. This can be +done like the following: + +.. code-block:: c++ + + template + struct strategy; + + template <> + struct strategy { + static unique_ptr > create(int input) { + unique_ptr > ptr; + switch(input) { + case 0: ptr.reset(new derived0()); break; + case 1: ptr.reset(new derived1()); break; + //... + default: ptr.reset(0); break; + } + return ptr; + } + }; + +This approach allows the header-only libraries to define new dynamic +types in subsequent versions of the library while keeping the +static-dynamic bridge fluid. The only down-side to this is the +possibility of derived type explosion in case there are a lot of +different strategies or specializations available -- this though is +not unique to static-dynamic bridging, but is also a problem with pure +object oriented programming with dynamic polymorphism. diff --git a/cpp-netlib/libs/network/doc/techniques/tag_metafunctions.rst b/cpp-netlib/libs/network/doc/techniques/tag_metafunctions.rst new file mode 100644 index 00000000..68edd144 --- /dev/null +++ b/cpp-netlib/libs/network/doc/techniques/tag_metafunctions.rst @@ -0,0 +1,172 @@ +Tag metafunctions +================= + +Sometimes you want to vary a function or a type's behavior based on a +static parameter. In the :mod:`cpp-netlib` there are a number of +things you might want to change based on some such parameter -- like +what the underlying string type should be and how large a buffer +should be, among other things. The primary way to define this in a +header-only manner is to use tag-based metafunctions. + +The skeleton of the approach is based on a similar technique for +defining type traits. In the :mod:`cpp-netlib` however the type traits +are defined on opaque tag types which serve to associate results to a +family of metafunctions. + +Template Specialization +----------------------- + +To illustrate this point, let's define a tag ``default_`` which we use +to denote the default implementation of a certain type ``foo``. For +instance we decide that the default string type we will use for +``default_`` tagged ``foo`` specializations will be an +``std::string``. + +In the :mod:`cpp-netlib` this is done by defining a ``string`` +metafunction type that is specialized on the tag ``default_`` whose +nested ``type`` result is the type ``std::string``. In code this would +translate to: + +.. code-block:: c++ + + template + struct string { + typedef void type; + }; + + struct default_; + + template <> + struct string { + typedef std::string type; + }; + +Template Metaprogramming +------------------------ + +Starting with version 0.7, the tag dispatch mechanism changed slightly to use +Boost.MPL_. The idea is still the same, although we can get a little smarter +than just using template specializations. Instead of just defining an opaque +type ``default_``, we use the Boost.MPL equivalent of a vector to define which +root types of properties this ``default_`` tag supports. The idea is to make the +opaque type ``default_`` inherit property tags which the library supports +internally as definite extension points. + +.. _Boost.MPL: http://www.boost.org/libs/mpl/index.html + +Our definition of the ``default_`` tag will then look something like the +following: + +.. code-block:: c++ + + typedef mpl::vector default_tags; + + template + struct components; + + typedef mpl::inherit_linearly< + default_tags, + mpl::inherit + >::type default_; + + template + struct components { + typedef default_tags type; + }; + +In the above listing, ``default_string`` is what we call a "root" tag which is +meant to be combined with other "root" tags to form composite tags. In this case +our composite tag is the tag ``default_``. There are a number of these "root" +tags that :mod:`cpp-netlib` provides. These are in the namespace +``boost::network::tags`` and are defined in ``boost/network/tags.hpp``. + +Using this technique we change slightly our definition of the ``string`` +metafunction class into this: + +.. code-block:: c++ + + template + struct unsupported_tag; + + template + struct string : + mpl::if_< + is_base_of< + tags::default_string, + Tag + >, + std::string, + unsupported_tag + > + {}; + +Notice that we don't have the typedef for ``type`` in the body of ``string`` +anymore, but we do inherit from ``mpl::if_``. Since ``mpl::if_`` is a template +metafunction itself, it contains a definition of the resulting ``type`` which +``string`` inherits. + +You can see the real definition of the ``string`` metafunction in +``boost/network/traits/string.hpp``. + +Using Tags +---------- + +Once we have the defined tag, we can then use this in the definition of our +types. In the definition of the type ``foo`` we use this type function +``string`` and pass the tag type parameter to determine what to use as +the string type in the context of the type ``foo``. In code this would +translate into: + +.. code-block:: c++ + + template + struct foo { + typedef typename string::type string_type; + + // .. use string_type where you need a string. + }; + +Using this approach we can support different types of strings for +different tags on the type ``foo``. In case we want to use a different +type of string for the tag ``default_`` we only change the +composition of the ``string_tags`` MPL vector. For example, in :mod:`cpp-netlib` +there is a root tag ``default_wstring`` which causes the ``string`` metafunction +to define ``std::wstring`` as the resulting type. + +The approach also allows for the control of the structure and features +of types like ``foo`` based on the specialization of the tag. Whole +type function families can be defined on tags where they are supported +and ignored in cases where they are not. + +To illustrate let's define a new tag ``swappable``. Given the above +definition of ``foo``, we want to make the ``swappable``-tagged +``foo`` define a ``swap`` function that extends the original +``default_``-tagged ``foo``. In code this would look like: + +.. code-block:: c++ + + struct swappable; + + template <> + struct foo : foo { + void swap(foo & other) { + // ... + } + }; + +We also for example want to enable an ADL-reachable ``swap`` function: + +.. code-block:: c++ + + struct swappable; + + inline + void swap(foo & left, foo & right) { + left.swap(right); + } + +Overall what the tag-based definition approach allows is for static +definition of extension points that ensures type-safety and +invariants. This keeps the whole extension mechanism static and yet +flexible. + diff --git a/cpp-netlib/libs/network/doc/whats_new.rst b/cpp-netlib/libs/network/doc/whats_new.rst new file mode 100644 index 00000000..e09530a2 --- /dev/null +++ b/cpp-netlib/libs/network/doc/whats_new.rst @@ -0,0 +1,229 @@ +.. _whats_new: + +************ + What's New +************ + +:mod:`cpp-netlib` 0.11 +---------------------- + +v0.11.2 +~~~~~~~ +* Support a source_port setting for connections made by the client per-request. +* Allow using cpp-netlib without OpenSSL. +* Fix build breakage for Visual Studio 2015. +* Add more options for HTTP client use of SSL/TLS options/ciphers. +* Made client_get_timeout_test less flaky. +* Fixes to URI encoding issues with multibyte strings. +* Make cpp-netlib not crash on unstable networks. +* Allow parsing empty query parameters (`#499`_). +* CMake build changes to simplify dependencies on cppnetlib-client-connections. +* Handle EOF correctly (`#496`_). +* Fix fileserver example to chunk data correctly. +* Copy hostname to avoid dangling reference to a temporary request object. (`#482`_) +* Catch exceptions in parse_headers to avoid propagating issues in parsing upwards. +* Fix some GCC warnings on signed/unsigned comparison. +* Support environment variable-based peer verification (via OpenSSL). +* Support IPv6 connections. +* Support certificate-based verification, and option to always verify hosts. + +.. _`#499`: https://github.com/cpp-netlib/cpp-netlib/issues/499 +.. _`#496`: https://github.com/cpp-netlib/cpp-netlib/issues/496 +.. _`#482`: https://github.com/cpp-netlib/cpp-netlib/issues/482 + + +v0.11.1 +~~~~~~~ +* Add support for request timeouts. +* Build configuration fixes. +* Support for Travis CI in-project config. +* Make the response parser more flexible to support older/ad-hoc servers that don't have standard format responses. +* Fix some instability in the client destructor. +* MSVC 2010 specific fixes. + +v0.11.0 +~~~~~~~ +* Fix thread leak in DNS resolution failure (`#245`_) +* Remove unsupported `client_fwd.hpp` header (`#277`_) +* Remove support for header-only usage (`#129`_) -- this means that the BOOST_NETWORK_NO_LIB option is no longer actually supported. +* Deprecate Synchronous Client implementations (`#279`_) +* Support streaming body chunks for PUT/POST client requests (`#27`_) +* Fix non-case-sensitive header parsing for some client tags (`#313`_) +* Remove unsupported Jamfiles from the whole project (`#316`_) +* Add ``make install`` for Linux and OS X (`#285`_) +* Fix incorrect Body processing (`#69`_) +* Support chunked transfer encoding from HTTP responses (`#86`_) +* Make OS X Clang builds use C++11 and libc++. +* Update Boost requirement to 1.54.0. +* Experimental Base64 encoding/decoding library (`#287`_) +* *Known test failure:* OS X Xcode Clang 5.0 + Boost 1.54.0 + libc++ don't play + well with Boost.Serialization issues, mitigate test breakage but + ``cpp-netlib-utils_base64_test`` still fails in this platform. (`#287`_) +* Provide a client option to always validate peers for HTTPS requests made by + the client. (`#349`_) +* Back-port fix for `#163`_ for improved URI parsing. +* Added support for client-side certificates and private keys (`#361`_). + +.. _`#129`: https://github.com/cpp-netlib/cpp-netlib/issues/129 +.. _`#163`: https://github.com/cpp-netlib/cpp-netlib/issues/163 +.. _`#245`: https://github.com/cpp-netlib/cpp-netlib/issues/245 +.. _`#277`: https://github.com/cpp-netlib/cpp-netlib/issues/277 +.. _`#279`: https://github.com/cpp-netlib/cpp-netlib/issues/279 +.. _`#27`: https://github.com/cpp-netlib/cpp-netlib/issues/27 +.. _`#285`: https://github.com/cpp-netlib/cpp-netlib/issues/285 +.. _`#287`: https://github.com/cpp-netlib/cpp-netlib/issues/287 +.. _`#313`: https://github.com/cpp-netlib/cpp-netlib/issues/313 +.. _`#316`: https://github.com/cpp-netlib/cpp-netlib/issues/316 +.. _`#349`: https://github.com/cpp-netlib/cpp-netlib/issues/349 +.. _`#69`: https://github.com/cpp-netlib/cpp-netlib/issues/69 +.. _`#86`: https://github.com/cpp-netlib/cpp-netlib/issues/86 +.. _`#361`: https://github.com/cpp-netlib/cpp-netlib/pull/361 + +:mod:`cpp-netlib` 0.10 +---------------------- + +v0.10.1 +~~~~~~~ +* Documentation updates (`#182`_, `#265`_, `#194`_, `#233`_, `#255`_) +* Fix issue with async server inadvertently stopping from listening when + accepting a connection fails. (`#172`_) +* Allow overriding and ultimately removing defaulted headers from HTTP + requests. (`#263`_) +* Add `-Wall` to the base rule for GCC builds. (`#264`_) +* Make the server implementation throw on startup errors. (`#166`_) + +.. _`#182`: https://github.com/cpp-netlib/cpp-netlib/issues/182 +.. _`#265`: https://github.com/cpp-netlib/cpp-netlib/issues/265 +.. _`#194`: https://github.com/cpp-netlib/cpp-netlib/issues/194 +.. _`#172`: https://github.com/cpp-netlib/cpp-netlib/issues/172 +.. _`#263`: https://github.com/cpp-netlib/cpp-netlib/issues/263 +.. _`#233`: https://github.com/cpp-netlib/cpp-netlib/issues/233 +.. _`#264`: https://github.com/cpp-netlib/cpp-netlib/issues/264 +.. _`#255`: https://github.com/cpp-netlib/cpp-netlib/issues/255 +.. _`#166`: https://github.com/cpp-netlib/cpp-netlib/issues/166 + +v0.10.0 +~~~~~~~ +* Added support for more HTTP status codes (206, 408, 412, 416, 507). +* Refactored the parser for chunked encoding. +* Fixed parsing chunked encoding if the response body has ``CLRFCLRF``. +* Added librt dependency on Linux. +* Check the callback in the asynchronous client before calling it. +* Fixed issues `#110`_, `#168`_, `#213`_. + +.. _`#110`: https://github.com/cpp-netlib/cpp-netlib/issues/110 +.. _`#168`: https://github.com/cpp-netlib/cpp-netlib/issues/168 +.. _`#213`: https://github.com/cpp-netlib/cpp-netlib/issues/213 + +:mod:`cpp-netlib` 0.9 +--------------------- + +v0.9.5 +~~~~~~ +* Removed dependency on Boost.Parameter from HTTP client and server. +* Fixed for Clang error on Twitter example. +* Added source port to the request (HTTP server). +* Updated CMake config for MSVC 2010/2012. +* Now support chunked content encoding in client response parsing. +* Fixed bug with client not invoking callback when a request fails. + +v0.9.4 +~~~~~~ +* Lots of URI fixes. +* Fixed async_server's request handler so it doesn't make copies of the supplied handler. +* Fix for issue `#73`_ regarding SSL connections ending in short read errors. +* Final C++03-only release. + +.. _`#73`: https://github.com/cpp-netlib/cpp-netlib/issues/73 + +v0.9.3 +~~~~~~ +* URI, HTTP client and HTTP server are now built as static libraries (``libcppnetlib-uri.a``, ``libcppnetlib-client-connections.a`` and ``libcppnetlib-server-parsers.a`` on Linux and ``cppnetlib-uri.lib``, ``cppnetlib-client-connections.lib`` and ``cppnetlib-server-parsers.lib`` on Windows). +* Updated URI parser. +* A new URI builder. +* URI support for IPv6 RFC 2732. +* Fixed issues `#67`_, `#72`_, `#78`_, `#79`_, `#80`_, `#81`_, `#82`_, `#83`_. +* New examples for the HTTP client, including an Atom feed, an RSS feed and a + very simple client that uses the Twitter Search API. + +.. _`#67`: https://github.com/cpp-netlib/cpp-netlib/issues/67 +.. _`#72`: https://github.com/cpp-netlib/cpp-netlib/issues/72 +.. _`#78`: https://github.com/cpp-netlib/cpp-netlib/issues/78 +.. _`#79`: https://github.com/cpp-netlib/cpp-netlib/issues/79 +.. _`#80`: https://github.com/cpp-netlib/cpp-netlib/issues/80 +.. _`#81`: https://github.com/cpp-netlib/cpp-netlib/issues/81 +.. _`#82`: https://github.com/cpp-netlib/cpp-netlib/issues/82 +.. _`#83`: https://github.com/cpp-netlib/cpp-netlib/issues/83 + +v0.9.2 +~~~~~~ +* Critial bug fixes to v0.9.1. + +v0.9.1 +~~~~~~ +* Introduced macro ``BOOST_NETWORK_DEFAULT_TAG`` to allow for programmatically + defining the default flag to use throughout the compilation unit. +* Support for streaming body handlers when performing HTTP client operations. + See documentation for HTTP client interface for more information. +* Numerous bug fixes from v0.9.0. +* Google, Inc. contributions. + +v0.9.0 +~~~~~~ +* **IMPORTANT BREAKING CHANGE**: By default all compile-time heavy parser + implementations are now compiled to external static libraries. In order to use + :mod:`cpp-netlib` in header-only mode, users must define the preprocessor + macro ``BOOST_NETWORK_NO_LIB`` before including any :mod:`cpp-netlib` header. + This breaks code that relied on the version 0.8.x line where the library is + strictly header-only. +* Fix issue #41: Introduce a macro ``BOOST_NETWORK_HTTP_CLIENT_DEFAULT_TAG`` + which makes the default HTTP client use ``tags::http_async_8bit_udp_resolve`` + as the tag. +* Fix issue #40: Write the status line and headers in a single buffer write + instead of two writes. +* More consistent message API for client and server messages (request and + response objects). +* Refactoring of internal implementations to allow better separation of concerns + and more manageable coding/documentation. +* Client and server constructors that support Boost.Parameter named parameters. +* Client and server constructors now take in an optional reference to a Boost.Asio + ``io_service`` to use internally. +* Documentation updates to reflect new APIs. + +:mod:`cpp-netlib` 0.8 +--------------------- + +* Updates to URI unit tests and documentation. +* More documentation, covering the HTTP Client and HTTP Server APIs +* Asynchronous HTTP Server that now supports running request handlers on a + different thread pool. +* An initial thread pool implementation, using Boost.Asio underneath. +* Adding a ready(...) wrapper to check whether a response object returned by + the asynchronous client in 0.7 already has all the parts available. +* Some attempts at lowering compile time costs. + +:mod:`cpp-netlib` 0.7 +--------------------- + +* Radical documentation overhaul +* Asynchronous HTTP client +* Tag dispatch overhaul, using Boost.MPL +* HTTP Client Facade refactoring +* Bug fixes for HTTP 1.1 response parsing +* Minimized code repetition with some header macro's +* Configurable HTTPS support in the library with ``BOOST_NETWORK_ENABLE_HTTPS`` + + +:mod:`cpp-netlib` 0.6 +--------------------- + +* Many fixes for MSVC compiler + +:mod:`cpp-netlib` 0.5 +--------------------- + +* An embeddable HTTP 1.1 server +* An HTTP 1.1 client upgraded to support HTTPS +* An updated URI parser implementation +* An asynchronous HTTP 1.1 client +* An HTTP 1.1 client that supports streaming function handlers diff --git a/cpp-netlib/libs/network/example/CMakeLists.txt b/cpp-netlib/libs/network/example/CMakeLists.txt new file mode 100644 index 00000000..2828e97f --- /dev/null +++ b/cpp-netlib/libs/network/example/CMakeLists.txt @@ -0,0 +1,162 @@ +# Copyright (c) Dean Michael Berris 2010. +# 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_directories(${CPP-NETLIB_SOURCE_DIR}) +if (OPENSSL_FOUND) + include_directories(${OPENSSL_INCLUDE_DIR}) +endif (OPENSSL_FOUND) + +add_executable(http_client http_client.cpp) +add_executable(simple_wget simple_wget.cpp) +add_executable(atom_reader atom/atom.cpp atom/main.cpp) +add_executable(rss_reader rss/rss.cpp rss/main.cpp) +add_executable(twitter_search twitter/search.cpp) +add_executable(hello_world_server http/hello_world_server.cpp) +add_executable(hello_world_client http/hello_world_client.cpp) +add_executable(hello_world_async_server_with_work_queue http/hello_world_async_server_with_work_queue.cpp) +add_executable(trivial_google trivial_google.cpp) +if (UNIX) + add_executable(fileserver http/fileserver.cpp) +endif (UNIX) +add_dependencies(http_client cppnetlib-uri cppnetlib-client-connections) +add_dependencies(simple_wget cppnetlib-uri cppnetlib-client-connections) +add_dependencies(atom_reader cppnetlib-uri cppnetlib-client-connections) +add_dependencies(rss_reader cppnetlib-uri cppnetlib-client-connections) +add_dependencies(twitter_search cppnetlib-uri cppnetlib-client-connections) +add_dependencies(trivial_google cppnetlib-uri cppnetlib-client-connections) +set(BOOST_CLIENT_LIBS + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_DATE_TIME_LIBRARY} + ${Boost_REGEX_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_CHRONO_LIBRARY}) + +set(BOOST_SERVER_LIBS + ${Boost_THREAD_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${Boost_DATE_TIME_LIBRARY} + ${Boost_REGEX_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_CHRONO_LIBRARY}) + +target_link_libraries(http_client + ${BOOST_CLIENT_LIBS} + ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-uri + cppnetlib-client-connections) + +target_link_libraries(simple_wget + ${BOOST_CLIENT_LIBS} + ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-uri + cppnetlib-client-connections) + +target_link_libraries(atom_reader + ${BOOST_CLIENT_LIBS} + ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-uri + cppnetlib-client-connections) + +target_link_libraries(rss_reader + ${BOOST_CLIENT_LIBS} + ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-uri + cppnetlib-client-connections) + +target_link_libraries(twitter_search + ${BOOST_CLIENT_LIBS} + ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-uri + cppnetlib-client-connections) + +target_link_libraries(trivial_google + ${BOOST_CLIENT_LIBS} + ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-uri + cppnetlib-client-connections) + +target_link_libraries(hello_world_server + ${BOOST_SERVER_LIBS} + ${CMAKE_THREAD_LIBS_INIT}) + +target_link_libraries(hello_world_client + ${BOOST_CLIENT_LIBS} + ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-uri + cppnetlib-client-connections) + +target_link_libraries(hello_world_async_server_with_work_queue + ${BOOST_CLIENT_LIBS} + ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-uri + cppnetlib-client-connections + cppnetlib-server-parsers) + +if (OPENSSL_FOUND) + target_link_libraries(http_client ${OPENSSL_LIBRARIES}) + target_link_libraries(simple_wget ${OPENSSL_LIBRARIES}) + target_link_libraries(atom_reader ${OPENSSL_LIBRARIES}) + target_link_libraries(rss_reader ${OPENSSL_LIBRARIES}) + target_link_libraries(twitter_search ${OPENSSL_LIBRARIES}) + target_link_libraries(hello_world_server ${OPENSSL_LIBRARIES}) + target_link_libraries(hello_world_client ${OPENSSL_LIBRARIES}) + target_link_libraries(hello_world_async_server_with_work_queue ${OPENSSL_LIBRARIES}) + target_link_libraries(trivial_google ${OPENSSL_LIBRARIES}) +endif (OPENSSL_FOUND) + +if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU AND ${CMAKE_SYSTEM_NAME} MATCHES "Windows") + target_link_libraries(http_client ws2_32) + target_link_libraries(simple_wget ws2_32) + target_link_libraries(atom_reader ws2_32) + target_link_libraries(rss_reader ws2_32) + target_link_libraries(twitter_search ws2_32) + target_link_libraries(hello_world_server ws2_32 wsock32) + target_link_libraries(hello_world_client ws2_32) + target_link_libraries(hello_world_async_server_with_work_queue ws2_32 wsock32) + target_link_libraries(trivial_google ws2_32) +endif() + +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_link_libraries(http_client rt) + target_link_libraries(simple_wget rt) + target_link_libraries(atom_reader rt) + target_link_libraries(rss_reader rt) + target_link_libraries(twitter_search rt) + target_link_libraries(hello_world_server rt) + target_link_libraries(hello_world_client rt) + target_link_libraries(hello_world_async_server_with_work_queue rt) + target_link_libraries(trivial_google rt) +endif() + +if (UNIX) + target_link_libraries(fileserver + ${BOOST_SERVER_LIBS} + ${Boost_FILESYSTEM_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-server-parsers) + if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_link_libraries(fileserver rt) + endif() + if (OPENSSL_FOUND) + target_link_libraries(fileserver ${OPENSSL_LIBRARIES}) + endif(OPENSSL_FOUND) +endif (UNIX) + +set_target_properties(http_client PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example) +set_target_properties(simple_wget PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example) +set_target_properties(atom_reader PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example) +set_target_properties(rss_reader PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example) +set_target_properties(twitter_search PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example) +set_target_properties(trivial_google PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example) +set_target_properties(hello_world_server PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example) +set_target_properties(hello_world_client PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example) +set_target_properties(hello_world_async_server_with_work_queue PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example) + +if (UNIX) + set_target_properties(fileserver PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example) +endif (UNIX) diff --git a/cpp-netlib/libs/network/example/atom/atom.cpp b/cpp-netlib/libs/network/example/atom/atom.cpp new file mode 100644 index 00000000..a823ed93 --- /dev/null +++ b/cpp-netlib/libs/network/example/atom/atom.cpp @@ -0,0 +1,95 @@ +// Copyright (c) Glyn Matthews 2011. +// 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 "atom.hpp" +#include "../rapidxml/rapidxml.hpp" +#include +#include + +namespace boost { +namespace network { +namespace atom { +feed::feed(const http::client::response &response) { + std::string response_body = body(response); + rapidxml::xml_document<> doc; + doc.parse<0>(const_cast(response_body.c_str())); + + rapidxml::xml_node<> *feed = doc.first_node("feed"); + if (!feed) { + throw std::runtime_error("Invalid atom feed."); + } + + rapidxml::xml_node<> *title = feed->first_node("title"); + if (title) { + title_ = title->first_node()->value(); + } + + rapidxml::xml_node<> *subtitle = feed->first_node("subtitle"); + if (subtitle) { + subtitle_ = subtitle->first_node()->value(); + } + + rapidxml::xml_node<> *id = feed->first_node("id"); + if (id) { + id_ = id->first_node()->value(); + } + + rapidxml::xml_node<> *updated = feed->first_node("updated"); + if (updated) { + updated_ = updated->first_node()->value(); + } + + rapidxml::xml_node<> *author = feed->first_node("author"); + if (author) { + rapidxml::xml_node<> *name = author->first_node("name"); + rapidxml::xml_node<> *email = author->first_node("email"); + if (name && email) { + author_ = atom::author(name->first_node()->value(), + email->first_node()->value()); + } else if (name) { + author_ = atom::author(name->first_node()->value()); + } + } + + rapidxml::xml_node<> *entry = feed->first_node("entry"); + while (entry) { + entries_.push_back(atom::entry()); + + rapidxml::xml_node<> *title = entry->first_node("title"); + if (title) { + entries_.back().set_title(title->first_node()->value()); + } + + rapidxml::xml_node<> *id = entry->first_node("id"); + if (id) { + entries_.back().set_id(id->first_node()->value()); + } + + rapidxml::xml_node<> *published = entry->first_node("published"); + if (published) { + entries_.back().set_published(published->first_node()->value()); + } + + rapidxml::xml_node<> *updated = entry->first_node("updated"); + if (updated) { + entries_.back().set_updated(updated->first_node()->value()); + } + + rapidxml::xml_node<> *summary = entry->first_node("summary"); + if (summary) { + entries_.back().set_summary(summary->first_node()->value()); + } + + rapidxml::xml_node<> *content = entry->first_node("content"); + if (content) { + entries_.back().set_content(content->first_node()->value()); + } + + entry = entry->next_sibling(); + } +} +} // namespace atom +} // namespace network +} // namespace boost diff --git a/cpp-netlib/libs/network/example/atom/atom.hpp b/cpp-netlib/libs/network/example/atom/atom.hpp new file mode 100644 index 00000000..0d96109e --- /dev/null +++ b/cpp-netlib/libs/network/example/atom/atom.hpp @@ -0,0 +1,112 @@ +// Copyright (c) Glyn Matthews 2011. +// 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 ___ATOM_INC__ +#define ___ATOM_INC__ + +#include +#include +#include + +namespace boost { +namespace network { +namespace atom { +class entry { + + public: + void set_title(const std::string &title) { title_ = title; } + + std::string title() const { return title_; } + + void set_id(const std::string &id) { id_ = id; } + + std::string id() const { return id_; } + + void set_published(const std::string &published) { published_ = published; } + + std::string published() const { return published_; } + + void set_updated(const std::string &updated) { updated_ = updated; } + + std::string updated() const { return updated_; } + + void set_summary(const std::string &summary) { summary_ = summary; } + + std::string summary() const { return summary_; } + + void set_content(const std::string &content) { content_ = content; } + + std::string content() const { return content_; } + + private: + std::string title_; + std::string id_; + std::string published_; + std::string updated_; + std::string summary_; + std::string content_; +}; + +class author { + + public: + author() {} + + author(const std::string &name) : name_(name) {} + + author(const std::string &name, const std::string &email) + : name_(name), email_(email) {} + + std::string name() const { return name_; } + + std::string email() const { return email_; } + + private: + std::string name_; + std::string email_; +}; + +class feed { + + public: + typedef entry value_type; + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + feed(const http::client::response &response); + + std::string title() const { return title_; } + + std::string subtitle() const { return subtitle_; } + + std::string id() const { return id_; } + + std::string updated() const { return updated_; } + + atom::author author() const { return author_; } + + unsigned int entry_count() const { return entries_.size(); } + + iterator begin() { return entries_.begin(); } + + iterator end() { return entries_.end(); } + + const_iterator begin() const { return entries_.begin(); } + + const_iterator end() const { return entries_.end(); } + + private: + std::string title_; + std::string subtitle_; + std::string id_; + std::string updated_; + atom::author author_; + std::vector entries_; +}; +} // namespace atom +} // namespace network +} // namespace boost + +#endif // ___ATOM_INC__ diff --git a/cpp-netlib/libs/network/example/atom/main.cpp b/cpp-netlib/libs/network/example/atom/main.cpp new file mode 100644 index 00000000..8d9a8b8d --- /dev/null +++ b/cpp-netlib/libs/network/example/atom/main.cpp @@ -0,0 +1,38 @@ +// Copyright (c) Glyn Matthews 2011. +// 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 "atom.hpp" +#include +#include +#include + +int main(int argc, char *argv[]) { + using namespace boost::network; + + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + try { + http::client client; + http::client::request request(argv[1]); + request << header("Connection", "close"); + http::client::response response = client.get(request); + atom::feed feed(response); + + std::cout << "Feed: " << feed.title() << " (" << feed.subtitle() << ")" + << std::endl; + BOOST_FOREACH(const atom::entry & entry, feed) { + std::cout << entry.title() << " (" << entry.published() << ")" + << std::endl; + } + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/cpp-netlib/libs/network/example/http/fileserver.cpp b/cpp-netlib/libs/network/example/http/fileserver.cpp new file mode 100644 index 00000000..9951d695 --- /dev/null +++ b/cpp-netlib/libs/network/example/http/fileserver.cpp @@ -0,0 +1,187 @@ +// Copyright 2010 Dean Michael Berris. +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace http = boost::network::http; +namespace utils = boost::network::utils; + +struct file_server; +typedef http::async_server server; + +struct file_cache { + + typedef std::map > region_map; + typedef std::map > meta_map; + + std::string doc_root_; + region_map regions; + meta_map file_headers; + boost::shared_mutex cache_mutex; + + explicit file_cache(std::string const &doc_root) : doc_root_(doc_root) {} + + ~file_cache() throw() { + BOOST_FOREACH(region_map::value_type const & region, regions) { + munmap(region.second.first, region.second.second); + } + } + + bool has(std::string const &path) { + boost::shared_lock lock(cache_mutex); + return regions.find(doc_root_ + path) != regions.end(); + } + + bool add(std::string const &path) { + boost::upgrade_lock lock(cache_mutex); + std::string real_filename = doc_root_ + path; + if (regions.find(real_filename) != regions.end()) return true; +#ifdef O_NOATIME + int fd = open(real_filename.c_str(), O_RDONLY | O_NOATIME | O_NONBLOCK); +#else + int fd = open(real_filename.c_str(), O_RDONLY | O_NONBLOCK); +#endif + if (fd == -1) return false; + std::size_t size = lseek(fd, 0, SEEK_END); + void *region = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (region == MAP_FAILED) { + close(fd); + return false; + } + + boost::upgrade_to_unique_lock unique_lock(lock); + regions.insert(std::make_pair(real_filename, std::make_pair(region, size))); + static server::response_header common_headers[] = { + {"Connection", "close"}, {"Content-Type", "x-application/octet-stream"}, + {"Content-Length", "0"}}; + std::vector headers(common_headers, + common_headers + 3); + headers[2].value = boost::lexical_cast(size); + file_headers.insert(std::make_pair(real_filename, headers)); + return true; + } + + std::pair get(std::string const &path) { + boost::shared_lock lock(cache_mutex); + region_map::const_iterator region = regions.find(doc_root_ + path); + if (region != regions.end()) + return region->second; + else + return std::pair(0, 0); + } + + boost::iterator_range::iterator> meta( + std::string const &path) { + boost::shared_lock lock(cache_mutex); + static std::vector empty_vector; + meta_map::iterator headers = file_headers.find(doc_root_ + path); + if (headers != file_headers.end()) { + std::vector::iterator begin = headers->second + .begin(), + end = + headers->second.end(); + return boost::make_iterator_range(begin, end); + } else + return boost::make_iterator_range(empty_vector); + } +}; + +struct connection_handler : boost::enable_shared_from_this { + explicit connection_handler(file_cache &cache) : file_cache_(cache) {} + + void operator()(std::string const &path, server::connection_ptr connection, + bool serve_body) { + bool ok = file_cache_.has(path); + if (!ok) ok = file_cache_.add(path); + if (ok) { + send_headers(file_cache_.meta(path), connection); + if (serve_body) send_file(file_cache_.get(path), 0, connection); + } else { + not_found(path, connection); + } + } + + void not_found(std::string const &path, server::connection_ptr connection) { + static server::response_header headers[] = {{"Connection", "close"}, + {"Content-Type", "text/plain"}}; + connection->set_status(server::connection::not_found); + connection->set_headers(boost::make_iterator_range(headers, headers + 2)); + connection->write("File Not Found!"); + } + + template + void send_headers(Range const &headers, server::connection_ptr connection) { + connection->set_status(server::connection::ok); + connection->set_headers(headers); + } + + void send_file(std::pair mmaped_region, off_t offset, + server::connection_ptr connection) { + // chunk it up page by page + std::size_t adjusted_offset = offset + 4096; + off_t rightmost_bound = std::min(mmaped_region.second, adjusted_offset); + connection->write( + boost::asio::const_buffers_1( + static_cast(mmaped_region.first) + offset, + rightmost_bound - offset), + boost::bind(&connection_handler::handle_chunk, + connection_handler::shared_from_this(), mmaped_region, + rightmost_bound, connection, _1)); + } + + void handle_chunk(std::pair mmaped_region, off_t offset, + server::connection_ptr connection, + boost::system::error_code const &ec) { + assert(offset>=0); + if (!ec && static_cast(offset) < mmaped_region.second) + send_file(mmaped_region, offset, connection); + } + + file_cache &file_cache_; +}; + +struct file_server { + explicit file_server(file_cache &cache) : cache_(cache) {} + + void operator()(server::request const &request, + server::connection_ptr connection) { + if (request.method == "HEAD") { + boost::shared_ptr h(new connection_handler(cache_)); + (*h)(request.destination, connection, false); + } else if (request.method == "GET") { + boost::shared_ptr h(new connection_handler(cache_)); + (*h)(request.destination, connection, true); + } else { + static server::response_header error_headers[] = { + {"Connection", "close"}}; + connection->set_status(server::connection::not_supported); + connection->set_headers( + boost::make_iterator_range(error_headers, error_headers + 1)); + connection->write("Method not supported."); + } + } + + file_cache &cache_; +}; + +int main(int argc, char *argv[]) { + file_cache cache("."); + file_server handler(cache); + server::options options(handler); + server instance(options.thread_pool(boost::make_shared(4)) + .address("0.0.0.0") + .port("8000")); + instance.run(); + return 0; +} diff --git a/cpp-netlib/libs/network/example/http/hello_world_async_server_with_work_queue.cpp b/cpp-netlib/libs/network/example/http/hello_world_async_server_with_work_queue.cpp new file mode 100644 index 00000000..dc3c0224 --- /dev/null +++ b/cpp-netlib/libs/network/example/http/hello_world_async_server_with_work_queue.cpp @@ -0,0 +1,187 @@ +/* + * sample application to show the usage of work queues along with async http + *server + * + * (C) Copyright Dino Korah 2013. + * Distributed under the Boost Software License, Version 1.0. (See copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define Log(line) \ + do { \ + std::cout << line << std::endl; \ + } while (false) + +struct handler; +typedef boost::network::http::async_server server; + +/** + * request + connection encapsulation (work item) + */ +struct request_data { + const server::request req; + server::connection_ptr conn; + + typedef boost::shared_ptr pointer; + + request_data(server::request const& req, const server::connection_ptr& conn) + : req(req), conn(conn) {} +}; + +/** + * A basic work queue + */ +struct work_queue { + typedef std::list list; + + list requests; + boost::mutex mutex; + + inline void put(const request_data::pointer& p_rd) { + boost::unique_lock lock(mutex); + requests.push_back(p_rd); + (void)lock; + } + + inline request_data::pointer get() { + boost::unique_lock lock(mutex); + + request_data::pointer p_ret; + if (!requests.empty()) { + p_ret = requests.front(); + requests.pop_front(); + } + + (void)lock; + + return p_ret; + } +}; + +struct handler { + work_queue& queue; + + handler(work_queue& queue) : queue(queue) {} + + /** + * Feed the work queue + * + * @param req + * @param conn + */ + void operator()(server::request const& req, + const server::connection_ptr& conn) { + queue.put(boost::make_shared(req, conn)); + } +}; + +/** + * Clean shutdown signal handler + * + * @param error + * @param signal + * @param p_server_instance + */ +void shut_me_down(const boost::system::error_code& error, int signal, + boost::shared_ptr p_server_instance) { + if (!error) p_server_instance->stop(); +} + +/** + * Process request; worker (thread) + * + * @param queue + */ +void process_request(work_queue& queue) { + while (!boost::this_thread::interruption_requested()) { + request_data::pointer p_req(queue.get()); + if (p_req) { + + // some heavy work! + boost::this_thread::sleep(boost::posix_time::seconds(10)); + + p_req->conn->set_status(server::connection::ok); + p_req->conn->write("Hello, world!"); + } + + boost::this_thread::sleep(boost::posix_time::microseconds(1000)); + } +} + +int main(void) try { + // the thread group + boost::shared_ptr p_threads( + boost::make_shared()); + + // setup asio::io_service + boost::shared_ptr p_io_service( + boost::make_shared()); + boost::shared_ptr p_work( + boost::make_shared( + boost::ref(*p_io_service))); + + // io_service threads + { + int n_threads = 5; + while (0 < n_threads--) { + p_threads->create_thread( + boost::bind(&boost::asio::io_service::run, p_io_service)); + } + } + + // the shared work queue + work_queue queue; + + // worker threads that will process the request; off the queue + { + int n_threads = 5; + while (0 < n_threads--) { + p_threads->create_thread(boost::bind(process_request, boost::ref(queue))); + } + } + + // setup the async server + handler request_handler(queue); + boost::shared_ptr p_server_instance(boost::make_shared( + server::options(request_handler) + .address("0.0.0.0") + .port("8800") + .io_service(p_io_service) + .reuse_address(true) + .thread_pool(boost::make_shared( + 2, p_io_service, p_threads)))); + + // setup clean shutdown + boost::asio::signal_set signals(*p_io_service, SIGINT, SIGTERM); + signals.async_wait(boost::bind(shut_me_down, _1, _2, p_server_instance)); + + // run the async server + p_server_instance->run(); + + // we are stopped - shutting down + + p_threads->interrupt_all(); + + p_work.reset(); + p_io_service->stop(); + + p_threads->join_all(); + + Log("Terminated normally"); + exit(EXIT_SUCCESS); +} +catch (const std::exception& e) { + Log("Abnormal termination - exception:" << e.what()); + exit(EXIT_FAILURE); +} diff --git a/cpp-netlib/libs/network/example/http/hello_world_client.cpp b/cpp-netlib/libs/network/example/http/hello_world_client.cpp new file mode 100644 index 00000000..039e471f --- /dev/null +++ b/cpp-netlib/libs/network/example/http/hello_world_client.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Glyn Matthews 2010. +// 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) + +//[ hello_world_client_main +/*` + This is a part of the 'Hello World' example. We create a client + object and make a single HTTP request. If we use make this request + to the `hello_world_server`, then the output is simply "Hello, + World!". + */ +#include +#include + +namespace http = boost::network::http; + +int main(int argc, char *argv[]) { + + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " url" << std::endl; + return 1; + } + + try { + /*<< Creates the client. >>*/ + http::client client; + /*<< Creates a request using a URI supplied on the command + line. >>*/ + http::client::request request(argv[1]); + /*<< Gets a response from the HTTP server. >>*/ + http::client::response response = client.get(request); + /*<< Prints the response body to the console. >>*/ + std::cout << body(response) << std::endl; + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + return 1; + } + + return 0; +} +//] diff --git a/cpp-netlib/libs/network/example/http/hello_world_server.cpp b/cpp-netlib/libs/network/example/http/hello_world_server.cpp new file mode 100644 index 00000000..84882442 --- /dev/null +++ b/cpp-netlib/libs/network/example/http/hello_world_server.cpp @@ -0,0 +1,64 @@ +// Copyright 2009 (c) Tarro, Inc. +// Copyright 2009 (c) Dean Michael Berris +// 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) +// + +//[ hello_world_server_main +/*` + This is a part of the 'Hello World' example. It's used to + demonstrate how easy it is to set up an HTTP server. All we do in + this example is create a request handler and run the server. + */ +#include +#include + +namespace http = boost::network::http; + +/*<< Defines the server. >>*/ +struct hello_world; +typedef http::server server; + +/*<< Defines the request handler. It's a class that defines two + functions, `operator()` and `log()` >>*/ +struct hello_world { + /*<< This is the function that handles the incoming request. >>*/ + void operator()(server::request const &request, server::response &response) { + server::string_type ip = source(request); + unsigned int port = request.source_port; + std::ostringstream data; + data << "Hello, " << ip << ':' << port << '!'; + response = server::response::stock_reply(server::response::ok, data.str()); + } + /*<< It's necessary to define a log function, but it's ignored in + this example. >>*/ + void log(...) { + // do nothing + } +}; + +int main(int argc, char *argv[]) { + + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " address port" << std::endl; + return 1; + } + + try { + /*<< Creates the request handler. >>*/ + hello_world handler; + /*<< Creates the server. >>*/ + server::options options(handler); + server server_(options.address(argv[1]).port(argv[2])); + /*<< Runs the server. >>*/ + server_.run(); + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + return 1; + } + + return 0; +} +//] diff --git a/cpp-netlib/libs/network/example/http/one_liner.cpp b/cpp-netlib/libs/network/example/http/one_liner.cpp new file mode 100644 index 00000000..82efd77b --- /dev/null +++ b/cpp-netlib/libs/network/example/http/one_liner.cpp @@ -0,0 +1,22 @@ + +// Copyright Dean Michael Berris 2010. +// 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) + +//[ http_one_liner_main +/*` + + */ +#include + +using namespace std; +using namespace boost::network; +using namespace boost::network::http; + +int main(int argc, const char *argv[]) { + /*<< The client sends an HTTP request to the server, and the output + is printed to the console. >>*/ + cout << body(client().get(client::request("http://www.boost.org/"))); + return 0; +} diff --git a/cpp-netlib/libs/network/example/http/ssl/dh512.pem b/cpp-netlib/libs/network/example/http/ssl/dh512.pem new file mode 100644 index 00000000..c316cb99 --- /dev/null +++ b/cpp-netlib/libs/network/example/http/ssl/dh512.pem @@ -0,0 +1,12 @@ +Diffie-Hellman-Parameters: (512 bit) + prime: + 00:f8:57:8f:79:09:08:95:c9:0a:74:2c:85:b5:75: + ff:07:67:c0:d2:94:4f:a2:45:77:7e:e1:f4:b6:86: + 60:9a:33:80:7b:31:75:f3:fc:8e:c3:0b:d0:8d:77: + a4:ed:3a:e8:e4:35:69:3e:ce:63:49:26:a4:64:38: + 55:41:51:de:13 + generator: 5 (0x5) +-----BEGIN DH PARAMETERS----- +MEYCQQD4V495CQiVyQp0LIW1df8HZ8DSlE+iRXd+4fS2hmCaM4B7MXXz/I7DC9CN +d6TtOujkNWk+zmNJJqRkOFVBUd4TAgEF +-----END DH PARAMETERS----- diff --git a/cpp-netlib/libs/network/example/http/ssl/server.pem b/cpp-netlib/libs/network/example/http/ssl/server.pem new file mode 100644 index 00000000..0d7c7d65 --- /dev/null +++ b/cpp-netlib/libs/network/example/http/ssl/server.pem @@ -0,0 +1,53 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,0ED70FE151E3399B + ++0JpEbgYMyIdEE7yKdosnNzzwGffSe6UIOf/8RgWg5N1f6obqYVRPaO53R1Fdhx2 +08q5acaNNCZcoCs1X0s0F/dr4L5XOorz2W5qUKnlDiZqBVBfpW8vIKMiZxOBePO7 +/h4LGtuX843k5sCmXnONtDJrpklsds0/vvZbuln6VHNf3mCWdLc8d5yJq/nPUKSm +hBd8uXPF0VUSSmTre2P0pTACz2WWI7N2uWKJqBJgGbqTfR5ciufXVR/n9leICjWM +LiipPMdp4ZNGDQcP3eW7/pSgxGzGvxP9e1vTEkmv0/fRGgClOdQbs+uEyDemOA+V +KHJYGhdhSCDM4VJQTO40dDhsn0glp9IjchYrxjI6jyziG1Jg7YMhoeQBMYm1zSsY +vqB0i7gtjVBKzltWN9fNvZ1kOJWhOsHuPocP4L4sqaQEqWCMtcKnm8ECGYXtu8E2 +QmDokiWqO1+MORf+naU0nOTtnXSpsysBn1ns+8TeUzaLAy8Dd/mhX2+SWnwGs0RI +VEYP+mef96SnqOKy2mDl/uzwcKUdKw4wnXrb2s8039gXBDZL09YlJxu/b/h67Dzn +LSRft4JjdojTmT0Ji4eJFiew9L3bbbUyIhA9M/cdoNEnXMmOcO+XDMxemaaX4rLf +nmEUcz0xpe8CVqTgx/TuOv06PX/iLyCYPnz5nczeVIw0a1/9g4WRghtoO/ezGJia +jpJRmXI7Mcw4z4GgW1AbVEeIPSXQD6sqnuNcY4h/62XkVI29FjsVgU1ZRx5fu68L +EIPuEri087Eep1NdRHOWwN03ppRdNxQQqB4uMNL2ruX3LzRKa0p7OQ3iL7e2V6el +2srv/5AYtFCq/adukhNcpU/otSZ5Re5B6C1zLAEUSKcgYHjCOUluq8HnCijnVCMh +pEQPaSM0P36DlNFjAWFlK8/N80LOfiYekLyZLbHjczSOS3EyVyvuF3pbtSHzpgtF +W4EJD8siMTXcE5hL8Ws1FwWHfviAq/mI4NUcNNz6S/4IcHS6teQOE5/uFcicJxXl +2wgZgYzBUeQlSqyI6XKoyfdJXducbLQqSWLEHL++Ek0ZaUKOiF+iGKPE0azKwMCc +QumPY+R2BhJbuiTQE36hBpte//XPQS5dWwXW5RTJm8ARNl1vNR/DESfhWX+wmKqx +2UBDRoEBa5HvrU82tWeGgm9CvTg6EOSNkap/BSdd3np631NnVm1tYz/flQvw4+5t +AH0X9C1QsGFwP6y/pAZ+YB+U65iN1UE3D3U1pC5JL+56ETc3GsPKnsWhAftIMm4r +l7zJ4BsrvfVnRaZFH4W+ITGy5q7iLD6Tuhpq574DxCINHtiENr00ZfPw08pMpvjG +5qhuE7Vgx5MGcVhUkz+Dtsm7bDRNsRxGAO5MSiIl70oahB5q247HF2ZElVT6+LbU +rQlIL4OdTdSXplW84NcoLTRy1HmLPf8B0Dt5f9Es0fAeWMiOmrrzM+spOgGXQhwv +VnqQrDeSDk6TOjN5z+BuwFfR7kImO+/As9NnG8D0l0PCRMW79mED2iOTnyHT8g8b +JLOjK/u2RxXFtbRwhERl4pei3NHfX4yXz2mcFjFLEOKin909WqObwedMsOUYoiN9 +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIJAI84QTgzQ+NXMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV +BAYTAkJFMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQKEwljcHBuZXRsaWIx +DDAKBgNVBAsTA3NzbDEPMA0GA1UEAxMGc2VydmVyMB4XDTE0MDUyMTA4MzI1OFoX +DTI0MDUxODA4MzI1OFowVTELMAkGA1UEBhMCQkUxEzARBgNVBAgTClNvbWUtU3Rh +dGUxEjAQBgNVBAoTCWNwcG5ldGxpYjEMMAoGA1UECxMDc3NsMQ8wDQYDVQQDEwZz +ZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZdnFuC9w3Jmdh +nQkeCD3rJ3LbmopRJkBFeAdHXvF2zPedsCjQ2J9XNcrGoejQuWNzEfmhs8pPSve3 ++Hn5AmqByGzN6aylJnD4qZZqpV1JrWvhReswLJktUTKtu+gh2a3gZjvXAdkGi0QX +LoXyAFuhILmivE9bQB6unUpMhGiAfX9AxDINgBt/+oi2V8bkXdJl45BNUY9IqgaJ +9WeDC37DmORb/IDHjmancIMyirDG2SBBGOVv/wuI0a/QUmjtBKUMEiX8PtyKSORA +PnOd2Fe0LL70thBD1WtlMNoU3upIrlLUE0F4bb+Ibn+iuSyu6dWp7rr9kR3uigQ6 +gspTVX4RAgMBAAGjgbgwgbUwHQYDVR0OBBYEFHZpVctJQmv6ixP7PmHcFUa+7+Dy +MIGFBgNVHSMEfjB8gBR2aVXLSUJr+osT+z5h3BVGvu/g8qFZpFcwVTELMAkGA1UE +BhMCQkUxEzARBgNVBAgTClNvbWUtU3RhdGUxEjAQBgNVBAoTCWNwcG5ldGxpYjEM +MAoGA1UECxMDc3NsMQ8wDQYDVQQDEwZzZXJ2ZXKCCQCPOEE4M0PjVzAMBgNVHRME +BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCd70N4MzxI7jKdyFXNQtHLh74hALd5 +p2PconV+3dE3yge88Z9IkgIx8MtVl6jm7dlggwJLGTBUD5fI0iL+KWqLl7/QxbwS +82J28ScsXlEf7pygowEsUYPM8j6O42JhIGQqMWOnmqnBVDxszHvYkO12/JupbEeK +p5RYS3GkyxQm5MmX0pX0H6wdfCkOdSZrHaXTx2wq2lKeQgN3mECUH51jXzB1G3nI +y1dCMD+AF3eUqS2UxgPbF14U6V2vsk4DvbgyzjYFjF+ttFdnIgGwAJJWet+orhW/ +k+h3ZaviXhOyqjpXHXGkVUj+/AvKWArjl7D6Xh03iUp0xt1Bn28CxQ90 +-----END CERTIFICATE----- diff --git a/cpp-netlib/libs/network/example/http/ssl/ssl_server.cpp b/cpp-netlib/libs/network/example/http/ssl/ssl_server.cpp new file mode 100644 index 00000000..51a151b7 --- /dev/null +++ b/cpp-netlib/libs/network/example/http/ssl/ssl_server.cpp @@ -0,0 +1,112 @@ +/* + * Sample application based loosely on existing async server sample to + *demonstrate ssl + * + * Requires openssl lib to run (https://www.openssl.org/) + * + * (C) Copyright Jelle Van den Driessche 2014. + * + * Distributed under the Boost Software License, Version 1.0. (See copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include + +#include +#include +#include +#include +#include + +struct handler; +typedef boost::network::http::async_server server; + +std::string password_callback( + std::size_t max_length, + boost::asio::ssl::context_base::password_purpose purpose) { + return std::string("test"); +} + +/** + * request + connection encapsulation (work item) + */ +struct request_data { + const server::request req; + server::connection_ptr conn; + + typedef boost::shared_ptr pointer; + + request_data(server::request const& req, const server::connection_ptr& conn) + : req(req), conn(conn) {} +}; + +struct handler { + void operator()(server::request const& req, + const server::connection_ptr& conn) { + conn->set_status(server::connection::ok); + conn->write(std::string("Hello World!!")); + } +}; + +/** + * Clean shutdown signal handler + * + * @param error + * @param signal + * @param p_server_instance + */ +void shut_me_down(const boost::system::error_code& error, int signal, + boost::shared_ptr p_server_instance) { + if (!error) p_server_instance->stop(); +} + +int main(void) try { + + // setup asio::io_service + boost::shared_ptr p_io_service( + boost::make_shared()); + + // Initialize SSL context + boost::shared_ptr ctx = + boost::make_shared( + boost::asio::ssl::context::sslv23); + ctx->set_options(boost::asio::ssl::context::default_workarounds | + boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::single_dh_use); + + // Set keys + ctx->set_password_callback(password_callback); + ctx->use_certificate_chain_file("server.pem"); + ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem); + ctx->use_tmp_dh_file("dh512.pem"); + + // setup the async server + handler request_handler; + boost::shared_ptr p_server_instance(boost::make_shared( + server::options(request_handler) + .address("0.0.0.0") + .port("8442") + .io_service(p_io_service) + .reuse_address(true) + .thread_pool( + boost::make_shared(2)) + .context(ctx))); + + // setup clean shutdown + boost::asio::signal_set signals(*p_io_service, SIGINT, SIGTERM); + signals.async_wait(boost::bind(shut_me_down, _1, _2, p_server_instance)); + + // run the async server + p_server_instance->run(); + + // we are stopped - shutting down + + p_io_service->stop(); + + std::cout << "Terminated normally" << std::endl; + exit(EXIT_SUCCESS); +} +catch (const std::exception& e) { + std::cout << "Abnormal termination - exception:" << e.what() << std::endl; + exit(EXIT_FAILURE); +} diff --git a/cpp-netlib/libs/network/example/http_client.cpp b/cpp-netlib/libs/network/example/http_client.cpp new file mode 100644 index 00000000..a2ea1f27 --- /dev/null +++ b/cpp-netlib/libs/network/example/http_client.cpp @@ -0,0 +1,86 @@ + +// Copyright 2008, 2014 Dean Michael Berris +// Copyright 2014 Google, Inc. +// 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) + +//[ http_client_main +/*` + This application takes a URL as a command line argument and prints + the resource to the console. +*/ +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +int main(int argc, char* argv[]) { + using namespace boost::network; + po::options_description options("Allowed options"); + std::string output_filename, source; + bool show_headers; + options.add_options()("help,h", "produce help message")( + "headers,H", "print headers")("status,S", "print status and message")( + "source,s", po::value(&source), "source URL"); + + po::positional_options_description positional_options; + positional_options.add("source", 1); + po::variables_map vm; + try { + po::store(po::command_line_parser(argc, argv) + .options(options) + .positional(positional_options) + .run(), + vm); + po::notify(vm); + } + catch (std::exception& e) { + std::cout << "Error: " << e.what() << std::endl; + std::cout << options << std::endl; + return EXIT_FAILURE; + } + + if (vm.count("help")) { + std::cout << options << std::endl; + return EXIT_SUCCESS; + } + + if (vm.count("source") < 1) { + std::cout << "Error: Source URL required." << std::endl; + std::cout << options << std::endl; + return EXIT_FAILURE; + } + + show_headers = vm.count("headers") ? true : false; + bool show_status = vm.count("status") ? true : false; + + http::client::request request(source); + http::client::string_type destination_ = host(request); + + request << ::boost::network::header("Connection", "close"); + http::client::options client_options; + client_options.follow_redirects(true); + http::client client(client_options); + http::client::response response = client.get(request); + + if (show_status) + std::cout << status(response) << " " << status_message(response) + << std::endl; + + if (show_headers) { + headers_range::type headers_ = response.headers(); + typedef std::pair header_type; + BOOST_FOREACH(header_type const & header, headers_) { + std::cout << header.first << ": " << header.second << std::endl; + } + std::cout << std::endl; + } + + std::cout << body(response); + return EXIT_SUCCESS; +} +//] diff --git a/cpp-netlib/libs/network/example/http_client1.cpp b/cpp-netlib/libs/network/example/http_client1.cpp new file mode 100644 index 00000000..61a96117 --- /dev/null +++ b/cpp-netlib/libs/network/example/http_client1.cpp @@ -0,0 +1,24 @@ +// Copyright Dean Michael Berris 2011. +// 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 +#include + +int main(int argc, char* argv[]) { + using namespace boost::network; + + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + http::client client; + http::client::request request(argv[1]); + request << header("Connection", "close"); + http::client::response response = client.get(request); + std::cout << body(response) << std::endl; + + return 0; +} diff --git a/cpp-netlib/libs/network/example/rapidxml/license.txt b/cpp-netlib/libs/network/example/rapidxml/license.txt new file mode 100644 index 00000000..14098318 --- /dev/null +++ b/cpp-netlib/libs/network/example/rapidxml/license.txt @@ -0,0 +1,52 @@ +Use of this software is granted under one of the following two licenses, +to be chosen freely by the user. + +1. Boost Software License - Version 1.0 - August 17th, 2003 +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +2. The MIT License +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/cpp-netlib/libs/network/example/rapidxml/manual.html b/cpp-netlib/libs/network/example/rapidxml/manual.html new file mode 100644 index 00000000..2c422703 --- /dev/null +++ b/cpp-netlib/libs/network/example/rapidxml/manual.html @@ -0,0 +1,406 @@ +

      RAPIDXML Manual

      Version 1.13

      Copyright (C) 2006, 2009 Marcin Kalicinski
      See accompanying file license.txt for license information.

      Table of Contents

      1. What is RapidXml?
      1.1 Dependencies And Compatibility
      1.2 Character Types And Encodings
      1.3 Error Handling
      1.4 Memory Allocation
      1.5 W3C Compliance
      1.6 API Design
      1.7 Reliability
      1.8 Acknowledgements
      2. Two Minute Tutorial
      2.1 Parsing
      2.2 Accessing The DOM Tree
      2.3 Modifying The DOM Tree
      2.4 Printing XML
      3. Differences From Regular XML Parsers
      3.1 Lifetime Of Source Text
      3.2 Ownership Of Strings
      3.3 Destructive Vs Non-Destructive Mode
      4. Performance
      4.1 Comparison With Other Parsers
      5. Reference

      1. What is RapidXml?

      RapidXml is an attempt to create the fastest XML DOM parser possible, while retaining useability, portability and reasonable W3C compatibility. It is an in-situ parser written in C++, with parsing speed approaching that of strlen() function executed on the same data.

      + Entire parser is contained in a single header file, so no building or linking is neccesary. To use it you just need to copy rapidxml.hpp file to a convenient place (such as your project directory), and include it where needed. You may also want to use printing functions contained in header rapidxml_print.hpp.

      1.1 Dependencies And Compatibility

      RapidXml has no dependencies other than a very small subset of standard C++ library (<cassert>, <cstdlib>, <new> and <exception>, unless exceptions are disabled). It should compile on any reasonably conformant compiler, and was tested on Visual C++ 2003, Visual C++ 2005, Visual C++ 2008, gcc 3, gcc 4, and Comeau 4.3.3. Care was taken that no warnings are produced on these compilers, even with highest warning levels enabled.

      1.2 Character Types And Encodings

      RapidXml is character type agnostic, and can work both with narrow and wide characters. Current version does not fully support UTF-16 or UTF-32, so use of wide characters is somewhat incapacitated. However, it should succesfully parse wchar_t strings containing UTF-16 or UTF-32 if endianness of the data matches that of the machine. UTF-8 is fully supported, including all numeric character references, which are expanded into appropriate UTF-8 byte sequences (unless you enable parse_no_utf8 flag).

      + Note that RapidXml performs no decoding - strings returned by name() and value() functions will contain text encoded using the same encoding as source file. Rapidxml understands and expands the following character references: &apos; &amp; &quot; &lt; &gt; &#...; Other character references are not expanded.

      1.3 Error Handling

      By default, RapidXml uses C++ exceptions to report errors. If this behaviour is undesirable, RAPIDXML_NO_EXCEPTIONS can be defined to suppress exception code. See parse_error class and parse_error_handler() function for more information.

      1.4 Memory Allocation

      RapidXml uses a special memory pool object to allocate nodes and attributes, because direct allocation using new operator would be far too slow. Underlying memory allocations performed by the pool can be customized by use of memory_pool::set_allocator() function. See class memory_pool for more information.

      1.5 W3C Compliance

      RapidXml is not a W3C compliant parser, primarily because it ignores DOCTYPE declarations. There is a number of other, minor incompatibilities as well. Still, it can successfully parse and produce complete trees of all valid XML files in W3C conformance suite (over 1000 files specially designed to find flaws in XML processors). In destructive mode it performs whitespace normalization and character entity substitution for a small set of built-in entities.

      1.6 API Design

      RapidXml API is minimalistic, to reduce code size as much as possible, and facilitate use in embedded environments. Additional convenience functions are provided in separate headers: rapidxml_utils.hpp and rapidxml_print.hpp. Contents of these headers is not an essential part of the library, and is currently not documented (otherwise than with comments in code).

      1.7 Reliability

      RapidXml is very robust and comes with a large harness of unit tests. Special care has been taken to ensure stability of the parser no matter what source text is thrown at it. One of the unit tests produces 100,000 randomly corrupted variants of XML document, which (when uncorrupted) contains all constructs recognized by RapidXml. RapidXml passes this test when it correctly recognizes that errors have been introduced, and does not crash or loop indefinitely.

      + Another unit test puts RapidXml head-to-head with another, well estabilished XML parser, and verifies that their outputs match across a wide variety of small and large documents.

      + Yet another test feeds RapidXml with over 1000 test files from W3C compliance suite, and verifies that correct results are obtained. There are also additional tests that verify each API function separately, and test that various parsing modes work as expected.

      1.8 Acknowledgements

      I would like to thank Arseny Kapoulkine for his work on pugixml, which was an inspiration for this project. Additional thanks go to Kristen Wegner for creating pugxml, from which pugixml was derived. Janusz Wohlfeil kindly ran RapidXml speed tests on hardware that I did not have access to, allowing me to expand performance comparison table.

      2. Two Minute Tutorial

      2.1 Parsing

      The following code causes RapidXml to parse a zero-terminated string named text:
      using namespace rapidxml;
      +xml_document<> doc;    // character type defaults to char
      +doc.parse<0>(text);    // 0 means default parse flags
      +
      doc object is now a root of DOM tree containing representation of the parsed XML. Because all RapidXml interface is contained inside namespace rapidxml, users must either bring contents of this namespace into scope, or fully qualify all the names. Class xml_document represents a root of the DOM hierarchy. By means of public inheritance, it is also an xml_node and a memory_pool. Template parameter of xml_document::parse() function is used to specify parsing flags, with which you can fine-tune behaviour of the parser. Note that flags must be a compile-time constant.

      2.2 Accessing The DOM Tree

      To access the DOM tree, use methods of xml_node and xml_attribute classes:
      cout << "Name of my first node is: " << doc.first_node()->name() << "\n";
      +xml_node<> *node = doc.first_node("foobar");
      +cout << "Node foobar has value " << node->value() << "\n";
      +for (xml_attribute<> *attr = node->first_attribute();
      +     attr; attr = attr->next_attribute())
      +{
      +    cout << "Node foobar has attribute " << attr->name() << " ";
      +    cout << "with value " << attr->value() << "\n";
      +}
      +

      2.3 Modifying The DOM Tree

      DOM tree produced by the parser is fully modifiable. Nodes and attributes can be added/removed, and their contents changed. The below example creates a HTML document, whose sole contents is a link to google.com website:
      xml_document<> doc;
      +xml_node<> *node = doc.allocate_node(node_element, "a", "Google");
      +doc.append_node(node);
      +xml_attribute<> *attr = doc.allocate_attribute("href", "google.com");
      +node->append_attribute(attr);
      +
      One quirk is that nodes and attributes do not own the text of their names and values. This is because normally they only store pointers to the source text. So, when assigning a new name or value to the node, care must be taken to ensure proper lifetime of the string. The easiest way to achieve it is to allocate the string from the xml_document memory pool. In the above example this is not necessary, because we are only assigning character constants. But the code below uses memory_pool::allocate_string() function to allocate node name (which will have the same lifetime as the document), and assigns it to a new node:
      xml_document<> doc;
      +char *node_name = doc.allocate_string(name);        // Allocate string and copy name into it
      +xml_node<> *node = doc.allocate_node(node_element, node_name);  // Set node name to node_name
      +
      Check Reference section for description of the entire interface.

      2.4 Printing XML

      You can print xml_document and xml_node objects into an XML string. Use print() function or operator <<, which are defined in rapidxml_print.hpp header.
      using namespace rapidxml;
      +xml_document<> doc;    // character type defaults to char
      +// ... some code to fill the document
      +
      +// Print to stream using operator <<
      +std::cout << doc;   
      +
      +// Print to stream using print function, specifying printing flags
      +print(std::cout, doc, 0);   // 0 means default printing flags
      +
      +// Print to string using output iterator
      +std::string s;
      +print(std::back_inserter(s), doc, 0);
      +
      +// Print to memory buffer using output iterator
      +char buffer[4096];                      // You are responsible for making the buffer large enough!
      +char *end = print(buffer, doc, 0);      // end contains pointer to character after last printed character
      +*end = 0;                               // Add string terminator after XML
      +

      3. Differences From Regular XML Parsers

      RapidXml is an in-situ parser, which allows it to achieve very high parsing speed. In-situ means that parser does not make copies of strings. Instead, it places pointers to the source text in the DOM hierarchy.

      3.1 Lifetime Of Source Text

      In-situ parsing requires that source text lives at least as long as the document object. If source text is destroyed, names and values of nodes in DOM tree will become destroyed as well. Additionally, whitespace processing, character entity translation, and zero-termination of strings require that source text be modified during parsing (but see non-destructive mode). This makes the text useless for further processing once it was parsed by RapidXml.

      + In many cases however, these are not serious issues.

      3.2 Ownership Of Strings

      Nodes and attributes produced by RapidXml do not own their name and value strings. They merely hold the pointers to them. This means you have to be careful when setting these values manually, by using xml_base::name(const Ch *) or xml_base::value(const Ch *) functions. Care must be taken to ensure that lifetime of the string passed is at least as long as lifetime of the node/attribute. The easiest way to achieve it is to allocate the string from memory_pool owned by the document. Use memory_pool::allocate_string() function for this purpose.

      3.3 Destructive Vs Non-Destructive Mode

      By default, the parser modifies source text during the parsing process. This is required to achieve character entity translation, whitespace normalization, and zero-termination of strings.

      + In some cases this behaviour may be undesirable, for example if source text resides in read only memory, or is mapped to memory directly from file. By using appropriate parser flags (parse_non_destructive), source text modifications can be disabled. However, because RapidXml does in-situ parsing, it obviously has the following side-effects:

      4. Performance

      RapidXml achieves its speed through use of several techniques:
      • In-situ parsing. When building DOM tree, RapidXml does not make copies of string data, such as node names and values. Instead, it stores pointers to interior of the source text.
      • Use of template metaprogramming techniques. This allows it to move much of the work to compile time. Through magic of the templates, C++ compiler generates a separate copy of parsing code for any combination of parser flags you use. In each copy, all possible decisions are made at compile time and all unused code is omitted.
      • Extensive use of lookup tables for parsing.
      • Hand-tuned C++ with profiling done on several most popular CPUs.
      This results in a very small and fast code: a parser which is custom tailored to exact needs with each invocation.

      4.1 Comparison With Other Parsers

      The table below compares speed of RapidXml to some other parsers, and to strlen() function executed on the same data. On a modern CPU (as of 2007), you can expect parsing throughput to be close to 1 GB/s. As a rule of thumb, parsing speed is about 50-100x faster than Xerces DOM, 30-60x faster than TinyXml, 3-12x faster than pugxml, and about 5% - 30% faster than pugixml, the fastest XML parser I know of.
      • The test file is a real-world, 50kB large, moderately dense XML file.
      • All timing is done by using RDTSC instruction present in Pentium-compatible CPUs.
      • No profile-guided optimizations are used.
      • All parsers are running in their fastest modes.
      • The results are given in CPU cycles per character, so frequency of CPUs is irrelevant.
      • The results are minimum values from a large number of runs, to minimize effects of operating system activity, task switching, interrupt handling etc.
      • A single parse of the test file takes about 1/10th of a millisecond, so with large number of runs there is a good chance of hitting at least one no-interrupt streak, and obtaining undisturbed results.
      Platform
      Compiler
      strlen() RapidXml pugixml 0.3 pugxml TinyXml
      Pentium 4
      MSVC 8.0
      2.5
      5.4
      7.0
      61.7
      298.8
      Pentium 4
      gcc 4.1.1
      0.8
      6.1
      9.5
      67.0
      413.2
      Core 2
      MSVC 8.0
      1.0
      4.5
      5.0
      24.6
      154.8
      Core 2
      gcc 4.1.1
      0.6
      4.6
      5.4
      28.3
      229.3
      Athlon XP
      MSVC 8.0
      3.1
      7.7
      8.0
      25.5
      182.6
      Athlon XP
      gcc 4.1.1
      0.9
      8.2
      9.2
      33.7
      265.2
      Pentium 3
      MSVC 8.0
      2.0
      6.3
      7.0
      30.9
      211.9
      Pentium 3
      gcc 4.1.1
      1.0
      6.7
      8.9
      35.3
      316.0
      (*) All results are in CPU cycles per character of source text

      5. Reference

      This section lists all classes, functions, constants etc. and describes them in detail.
      class + template + rapidxml::memory_pool
      + constructor + memory_pool()
      + destructor + ~memory_pool()
      function allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
      function allocate_attribute(const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
      function allocate_string(const Ch *source=0, std::size_t size=0)
      function clone_node(const xml_node< Ch > *source, xml_node< Ch > *result=0)
      function clear()
      function set_allocator(alloc_func *af, free_func *ff)

      class rapidxml::parse_error
      + constructor + parse_error(const char *what, void *where)
      function what() const
      function where() const

      class + template + rapidxml::xml_attribute
      + constructor + xml_attribute()
      function document() const
      function previous_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
      function next_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const

      class + template + rapidxml::xml_base
      + constructor + xml_base()
      function name() const
      function name_size() const
      function value() const
      function value_size() const
      function name(const Ch *name, std::size_t size)
      function name(const Ch *name)
      function value(const Ch *value, std::size_t size)
      function value(const Ch *value)
      function parent() const

      class + template + rapidxml::xml_document
      + constructor + xml_document()
      function parse(Ch *text)
      function clear()

      class + template + rapidxml::xml_node
      + constructor + xml_node(node_type type)
      function type() const
      function document() const
      function first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
      function last_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
      function previous_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
      function next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
      function first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
      function last_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
      function type(node_type type)
      function prepend_node(xml_node< Ch > *child)
      function append_node(xml_node< Ch > *child)
      function insert_node(xml_node< Ch > *where, xml_node< Ch > *child)
      function remove_first_node()
      function remove_last_node()
      function remove_node(xml_node< Ch > *where)
      function remove_all_nodes()
      function prepend_attribute(xml_attribute< Ch > *attribute)
      function append_attribute(xml_attribute< Ch > *attribute)
      function insert_attribute(xml_attribute< Ch > *where, xml_attribute< Ch > *attribute)
      function remove_first_attribute()
      function remove_last_attribute()
      function remove_attribute(xml_attribute< Ch > *where)
      function remove_all_attributes()

      namespace rapidxml
      enum node_type
      function parse_error_handler(const char *what, void *where)
      function print(OutIt out, const xml_node< Ch > &node, int flags=0)
      function print(std::basic_ostream< Ch > &out, const xml_node< Ch > &node, int flags=0)
      function operator<<(std::basic_ostream< Ch > &out, const xml_node< Ch > &node)
      + constant + parse_no_data_nodes
      + constant + parse_no_element_values
      + constant + parse_no_string_terminators
      + constant + parse_no_entity_translation
      + constant + parse_no_utf8
      + constant + parse_declaration_node
      + constant + parse_comment_nodes
      + constant + parse_doctype_node
      + constant + parse_pi_nodes
      + constant + parse_validate_closing_tags
      + constant + parse_trim_whitespace
      + constant + parse_normalize_whitespace
      + constant + parse_default
      + constant + parse_non_destructive
      + constant + parse_fastest
      + constant + parse_full
      + constant + print_no_indenting


      class + template + rapidxml::memory_pool

      + + Defined in rapidxml.hpp
      + Base class for + xml_document

      Description

      This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. In most cases, you will not need to use this class directly. However, if you need to create nodes manually or modify names/values of nodes, you are encouraged to use memory_pool of relevant xml_document to allocate the memory. Not only is this faster than allocating them by using new operator, but also their lifetime will be tied to the lifetime of document, possibly simplyfing memory management.

      + Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. You can also call allocate_string() function to allocate strings. Such strings can then be used as names or values of nodes without worrying about their lifetime. Note that there is no free() function -- all allocations are freed at once when clear() function is called, or when the pool is destroyed.

      + It is also possible to create a standalone memory_pool, and use it to allocate nodes, whose lifetime will not be tied to any document.

      + Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. Until static memory is exhausted, no dynamic memory allocations are done. When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, by using global new[] and delete[] operators. This behaviour can be changed by setting custom allocation routines. Use set_allocator() function to set them.

      + Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. This value defaults to the size of pointer on target architecture.

      + To obtain absolutely top performance from the parser, it is important that all nodes are allocated from a single, contiguous block of memory. Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT to obtain best wasted memory to performance compromise. To do it, define their values before rapidxml.hpp file is included.

      Parameters

      Ch
      Character type of created nodes.

      + constructor + memory_pool::memory_pool

      Synopsis

      memory_pool(); +

      Description

      Constructs empty pool with default allocator functions.

      + destructor + memory_pool::~memory_pool

      Synopsis

      ~memory_pool(); +

      Description

      Destroys pool and frees all the memory. This causes memory occupied by nodes allocated by the pool to be freed. Nodes allocated from the pool are no longer valid.

      function memory_pool::allocate_node

      Synopsis

      xml_node<Ch>* allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0); +

      Description

      Allocates a new node from the pool, and optionally assigns name and value to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

      Parameters

      type
      Type of node to create.
      name
      Name to assign to the node, or 0 to assign no name.
      value
      Value to assign to the node, or 0 to assign no value.
      name_size
      Size of name to assign, or 0 to automatically calculate size from name string.
      value_size
      Size of value to assign, or 0 to automatically calculate size from value string.

      Returns

      Pointer to allocated node. This pointer will never be NULL.

      function memory_pool::allocate_attribute

      Synopsis

      xml_attribute<Ch>* allocate_attribute(const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0); +

      Description

      Allocates a new attribute from the pool, and optionally assigns name and value to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

      Parameters

      name
      Name to assign to the attribute, or 0 to assign no name.
      value
      Value to assign to the attribute, or 0 to assign no value.
      name_size
      Size of name to assign, or 0 to automatically calculate size from name string.
      value_size
      Size of value to assign, or 0 to automatically calculate size from value string.

      Returns

      Pointer to allocated attribute. This pointer will never be NULL.

      function memory_pool::allocate_string

      Synopsis

      Ch* allocate_string(const Ch *source=0, std::size_t size=0); +

      Description

      Allocates a char array of given size from the pool, and optionally copies a given string to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

      Parameters

      source
      String to initialize the allocated memory with, or 0 to not initialize it.
      size
      Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated.

      Returns

      Pointer to allocated char array. This pointer will never be NULL.

      function memory_pool::clone_node

      Synopsis

      xml_node<Ch>* clone_node(const xml_node< Ch > *source, xml_node< Ch > *result=0); +

      Description

      Clones an xml_node and its hierarchy of child nodes and attributes. Nodes and attributes are allocated from this memory pool. Names and values are not cloned, they are shared between the clone and the source. Result node can be optionally specified as a second parameter, in which case its contents will be replaced with cloned source node. This is useful when you want to clone entire document.

      Parameters

      source
      Node to clone.
      result
      Node to put results in, or 0 to automatically allocate result node

      Returns

      Pointer to cloned node. This pointer will never be NULL.

      function memory_pool::clear

      Synopsis

      void clear(); +

      Description

      Clears the pool. This causes memory occupied by nodes allocated by the pool to be freed. Any nodes or strings allocated from the pool will no longer be valid.

      function memory_pool::set_allocator

      Synopsis

      void set_allocator(alloc_func *af, free_func *ff); +

      Description

      Sets or resets the user-defined memory allocation functions for the pool. This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. Allocation function must not return invalid pointer on failure. It should either throw, stop the program, or use longjmp() function to pass control to other place of program. If it returns invalid pointer, results are undefined.

      + User defined allocation functions must have the following forms:

      +void *allocate(std::size_t size);
      +void free(void *pointer);

      Parameters

      af
      Allocation function, or 0 to restore default function
      ff
      Free function, or 0 to restore default function

      class rapidxml::parse_error

      + + Defined in rapidxml.hpp

      Description

      Parse error exception. This exception is thrown by the parser when an error occurs. Use what() function to get human-readable error message. Use where() function to get a pointer to position within source text where error was detected.

      + If throwing exceptions by the parser is undesirable, it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. This function must be defined by the user.

      + This class derives from std::exception class.

      + constructor + parse_error::parse_error

      Synopsis

      parse_error(const char *what, void *where); +

      Description

      Constructs parse error.

      function parse_error::what

      Synopsis

      virtual const char* what() const; +

      Description

      Gets human readable description of error.

      Returns

      Pointer to null terminated description of the error.

      function parse_error::where

      Synopsis

      Ch* where() const; +

      Description

      Gets pointer to character data where error happened. Ch should be the same as char type of xml_document that produced the error.

      Returns

      Pointer to location within the parsed string where error occured.

      class + template + rapidxml::xml_attribute

      + + Defined in rapidxml.hpp
      + Inherits from + xml_base

      Description

      Class representing attribute node of XML document. Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). Note that after parse, both name and value of attribute will point to interior of source text used for parsing. Thus, this text must persist in memory for the lifetime of attribute.

      Parameters

      Ch
      Character type to use.

      + constructor + xml_attribute::xml_attribute

      Synopsis

      xml_attribute(); +

      Description

      Constructs an empty attribute with the specified type. Consider using memory_pool of appropriate xml_document if allocating attributes manually.

      function xml_attribute::document

      Synopsis

      xml_document<Ch>* document() const; +

      Description

      Gets document of which attribute is a child.

      Returns

      Pointer to document that contains this attribute, or 0 if there is no parent document.

      function xml_attribute::previous_attribute

      Synopsis

      xml_attribute<Ch>* previous_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

      Description

      Gets previous attribute, optionally matching attribute name.

      Parameters

      name
      Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
      name_size
      Size of name, in characters, or 0 to have size calculated automatically from string
      case_sensitive
      Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

      Returns

      Pointer to found attribute, or 0 if not found.

      function xml_attribute::next_attribute

      Synopsis

      xml_attribute<Ch>* next_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

      Description

      Gets next attribute, optionally matching attribute name.

      Parameters

      name
      Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
      name_size
      Size of name, in characters, or 0 to have size calculated automatically from string
      case_sensitive
      Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

      Returns

      Pointer to found attribute, or 0 if not found.

      class + template + rapidxml::xml_base

      + + Defined in rapidxml.hpp
      + Base class for + xml_attribute xml_node

      Description

      Base class for xml_node and xml_attribute implementing common functions: name(), name_size(), value(), value_size() and parent().

      Parameters

      Ch
      Character type to use

      + constructor + xml_base::xml_base

      Synopsis

      xml_base(); +

      function xml_base::name

      Synopsis

      Ch* name() const; +

      Description

      Gets name of the node. Interpretation of name depends on type of node. Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.

      + Use name_size() function to determine length of the name.

      Returns

      Name of node, or empty string if node has no name.

      function xml_base::name_size

      Synopsis

      std::size_t name_size() const; +

      Description

      Gets size of node name, not including terminator character. This function works correctly irrespective of whether name is or is not zero terminated.

      Returns

      Size of node name, in characters.

      function xml_base::value

      Synopsis

      Ch* value() const; +

      Description

      Gets value of node. Interpretation of value depends on type of node. Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.

      + Use value_size() function to determine length of the value.

      Returns

      Value of node, or empty string if node has no value.

      function xml_base::value_size

      Synopsis

      std::size_t value_size() const; +

      Description

      Gets size of node value, not including terminator character. This function works correctly irrespective of whether value is or is not zero terminated.

      Returns

      Size of node value, in characters.

      function xml_base::name

      Synopsis

      void name(const Ch *name, std::size_t size); +

      Description

      Sets name of node to a non zero-terminated string. See Ownership Of Strings .

      + Note that node does not own its name or value, it only stores a pointer to it. It will not delete or otherwise free the pointer on destruction. It is reponsibility of the user to properly manage lifetime of the string. The easiest way to achieve it is to use memory_pool of the document to allocate the string - on destruction of the document the string will be automatically freed.

      + Size of name must be specified separately, because name does not have to be zero terminated. Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).

      Parameters

      name
      Name of node to set. Does not have to be zero terminated.
      size
      Size of name, in characters. This does not include zero terminator, if one is present.

      function xml_base::name

      Synopsis

      void name(const Ch *name); +

      Description

      Sets name of node to a zero-terminated string. See also Ownership Of Strings and xml_node::name(const Ch *, std::size_t).

      Parameters

      name
      Name of node to set. Must be zero terminated.

      function xml_base::value

      Synopsis

      void value(const Ch *value, std::size_t size); +

      Description

      Sets value of node to a non zero-terminated string. See Ownership Of Strings .

      + Note that node does not own its name or value, it only stores a pointer to it. It will not delete or otherwise free the pointer on destruction. It is reponsibility of the user to properly manage lifetime of the string. The easiest way to achieve it is to use memory_pool of the document to allocate the string - on destruction of the document the string will be automatically freed.

      + Size of value must be specified separately, because it does not have to be zero terminated. Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated).

      + If an element has a child node of type node_data, it will take precedence over element value when printing. If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser.

      Parameters

      value
      value of node to set. Does not have to be zero terminated.
      size
      Size of value, in characters. This does not include zero terminator, if one is present.

      function xml_base::value

      Synopsis

      void value(const Ch *value); +

      Description

      Sets value of node to a zero-terminated string. See also Ownership Of Strings and xml_node::value(const Ch *, std::size_t).

      Parameters

      value
      Vame of node to set. Must be zero terminated.

      function xml_base::parent

      Synopsis

      xml_node<Ch>* parent() const; +

      Description

      Gets node parent.

      Returns

      Pointer to parent node, or 0 if there is no parent.

      class + template + rapidxml::xml_document

      + + Defined in rapidxml.hpp
      + Inherits from + xml_node memory_pool

      Description

      This class represents root of the DOM hierarchy. It is also an xml_node and a memory_pool through public inheritance. Use parse() function to build a DOM tree from a zero-terminated XML text string. parse() function allocates memory for nodes and attributes by using functions of xml_document, which are inherited from memory_pool. To access root node of the document, use the document itself, as if it was an xml_node.

      Parameters

      Ch
      Character type to use.

      + constructor + xml_document::xml_document

      Synopsis

      xml_document(); +

      Description

      Constructs empty XML document.

      function xml_document::parse

      Synopsis

      void parse(Ch *text); +

      Description

      Parses zero-terminated XML string according to given flags. Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. The string must persist for the lifetime of the document. In case of error, rapidxml::parse_error exception will be thrown.

      + If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. Make sure that data is zero-terminated.

      + Document can be parsed into multiple times. Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool.

      Parameters

      text
      XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser.

      function xml_document::clear

      Synopsis

      void clear(); +

      Description

      Clears the document by deleting all nodes and clearing the memory pool. All nodes owned by document pool are destroyed.

      class + template + rapidxml::xml_node

      + + Defined in rapidxml.hpp
      + Inherits from + xml_base
      + Base class for + xml_document

      Description

      Class representing a node of XML document. Each node may have associated name and value strings, which are available through name() and value() functions. Interpretation of name and value depends on type of the node. Type of node can be determined by using type() function.

      + Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. Thus, this text must persist in the memory for the lifetime of node.

      Parameters

      Ch
      Character type to use.

      + constructor + xml_node::xml_node

      Synopsis

      xml_node(node_type type); +

      Description

      Constructs an empty node with the specified type. Consider using memory_pool of appropriate document to allocate nodes manually.

      Parameters

      type
      Type of node to construct.

      function xml_node::type

      Synopsis

      node_type type() const; +

      Description

      Gets type of node.

      Returns

      Type of node.

      function xml_node::document

      Synopsis

      xml_document<Ch>* document() const; +

      Description

      Gets document of which node is a child.

      Returns

      Pointer to document that contains this node, or 0 if there is no parent document.

      function xml_node::first_node

      Synopsis

      xml_node<Ch>* first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

      Description

      Gets first child node, optionally matching node name.

      Parameters

      name
      Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
      name_size
      Size of name, in characters, or 0 to have size calculated automatically from string
      case_sensitive
      Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

      Returns

      Pointer to found child, or 0 if not found.

      function xml_node::last_node

      Synopsis

      xml_node<Ch>* last_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

      Description

      Gets last child node, optionally matching node name. Behaviour is undefined if node has no children. Use first_node() to test if node has children.

      Parameters

      name
      Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
      name_size
      Size of name, in characters, or 0 to have size calculated automatically from string
      case_sensitive
      Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

      Returns

      Pointer to found child, or 0 if not found.

      function xml_node::previous_sibling

      Synopsis

      xml_node<Ch>* previous_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

      Description

      Gets previous sibling node, optionally matching node name. Behaviour is undefined if node has no parent. Use parent() to test if node has a parent.

      Parameters

      name
      Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
      name_size
      Size of name, in characters, or 0 to have size calculated automatically from string
      case_sensitive
      Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

      Returns

      Pointer to found sibling, or 0 if not found.

      function xml_node::next_sibling

      Synopsis

      xml_node<Ch>* next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

      Description

      Gets next sibling node, optionally matching node name. Behaviour is undefined if node has no parent. Use parent() to test if node has a parent.

      Parameters

      name
      Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
      name_size
      Size of name, in characters, or 0 to have size calculated automatically from string
      case_sensitive
      Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

      Returns

      Pointer to found sibling, or 0 if not found.

      function xml_node::first_attribute

      Synopsis

      xml_attribute<Ch>* first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

      Description

      Gets first attribute of node, optionally matching attribute name.

      Parameters

      name
      Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
      name_size
      Size of name, in characters, or 0 to have size calculated automatically from string
      case_sensitive
      Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

      Returns

      Pointer to found attribute, or 0 if not found.

      function xml_node::last_attribute

      Synopsis

      xml_attribute<Ch>* last_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

      Description

      Gets last attribute of node, optionally matching attribute name.

      Parameters

      name
      Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
      name_size
      Size of name, in characters, or 0 to have size calculated automatically from string
      case_sensitive
      Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

      Returns

      Pointer to found attribute, or 0 if not found.

      function xml_node::type

      Synopsis

      void type(node_type type); +

      Description

      Sets type of node.

      Parameters

      type
      Type of node to set.

      function xml_node::prepend_node

      Synopsis

      void prepend_node(xml_node< Ch > *child); +

      Description

      Prepends a new child node. The prepended child becomes the first child, and all existing children are moved one position back.

      Parameters

      child
      Node to prepend.

      function xml_node::append_node

      Synopsis

      void append_node(xml_node< Ch > *child); +

      Description

      Appends a new child node. The appended child becomes the last child.

      Parameters

      child
      Node to append.

      function xml_node::insert_node

      Synopsis

      void insert_node(xml_node< Ch > *where, xml_node< Ch > *child); +

      Description

      Inserts a new child node at specified place inside the node. All children after and including the specified node are moved one position back.

      Parameters

      where
      Place where to insert the child, or 0 to insert at the back.
      child
      Node to insert.

      function xml_node::remove_first_node

      Synopsis

      void remove_first_node(); +

      Description

      Removes first child node. If node has no children, behaviour is undefined. Use first_node() to test if node has children.

      function xml_node::remove_last_node

      Synopsis

      void remove_last_node(); +

      Description

      Removes last child of the node. If node has no children, behaviour is undefined. Use first_node() to test if node has children.

      function xml_node::remove_node

      Synopsis

      void remove_node(xml_node< Ch > *where); +

      Description

      Removes specified child from the node.

      function xml_node::remove_all_nodes

      Synopsis

      void remove_all_nodes(); +

      Description

      Removes all child nodes (but not attributes).

      function xml_node::prepend_attribute

      Synopsis

      void prepend_attribute(xml_attribute< Ch > *attribute); +

      Description

      Prepends a new attribute to the node.

      Parameters

      attribute
      Attribute to prepend.

      function xml_node::append_attribute

      Synopsis

      void append_attribute(xml_attribute< Ch > *attribute); +

      Description

      Appends a new attribute to the node.

      Parameters

      attribute
      Attribute to append.

      function xml_node::insert_attribute

      Synopsis

      void insert_attribute(xml_attribute< Ch > *where, xml_attribute< Ch > *attribute); +

      Description

      Inserts a new attribute at specified place inside the node. All attributes after and including the specified attribute are moved one position back.

      Parameters

      where
      Place where to insert the attribute, or 0 to insert at the back.
      attribute
      Attribute to insert.

      function xml_node::remove_first_attribute

      Synopsis

      void remove_first_attribute(); +

      Description

      Removes first attribute of the node. If node has no attributes, behaviour is undefined. Use first_attribute() to test if node has attributes.

      function xml_node::remove_last_attribute

      Synopsis

      void remove_last_attribute(); +

      Description

      Removes last attribute of the node. If node has no attributes, behaviour is undefined. Use first_attribute() to test if node has attributes.

      function xml_node::remove_attribute

      Synopsis

      void remove_attribute(xml_attribute< Ch > *where); +

      Description

      Removes specified attribute from node.

      Parameters

      where
      Pointer to attribute to be removed.

      function xml_node::remove_all_attributes

      Synopsis

      void remove_all_attributes(); +

      Description

      Removes all attributes of node.

      enum node_type

      Description

      Enumeration listing all node types produced by the parser. Use xml_node::type() function to query node type.

      Values

      node_document
      A document node. Name and value are empty.
      node_element
      An element node. Name contains element name. Value contains text of first data node.
      node_data
      A data node. Name is empty. Value contains data text.
      node_cdata
      A CDATA node. Name is empty. Value contains data text.
      node_comment
      A comment node. Name is empty. Value contains comment text.
      node_declaration
      A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes.
      node_doctype
      A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
      node_pi
      A PI node. Name contains target. Value contains instructions.

      function parse_error_handler

      Synopsis

      void rapidxml::parse_error_handler(const char *what, void *where); +

      Description

      When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function is called to notify user about the error. It must be defined by the user.

      + This function cannot return. If it does, the results are undefined.

      + A very simple definition might look like that: + void rapidxml::parse_error_handler(const char *what, void *where) + { + std::cout << "Parse error: " << what << "\n"; + std::abort(); + } +

      Parameters

      what
      Human readable description of the error.
      where
      Pointer to character data where error was detected.

      function print

      Synopsis

      OutIt rapidxml::print(OutIt out, const xml_node< Ch > &node, int flags=0); +

      Description

      Prints XML to given output iterator.

      Parameters

      out
      Output iterator to print to.
      node
      Node to be printed. Pass xml_document to print entire document.
      flags
      Flags controlling how XML is printed.

      Returns

      Output iterator pointing to position immediately after last character of printed text.

      function print

      Synopsis

      std::basic_ostream<Ch>& rapidxml::print(std::basic_ostream< Ch > &out, const xml_node< Ch > &node, int flags=0); +

      Description

      Prints XML to given output stream.

      Parameters

      out
      Output stream to print to.
      node
      Node to be printed. Pass xml_document to print entire document.
      flags
      Flags controlling how XML is printed.

      Returns

      Output stream.

      function operator<<

      Synopsis

      std::basic_ostream<Ch>& rapidxml::operator<<(std::basic_ostream< Ch > &out, const xml_node< Ch > &node); +

      Description

      Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.

      Parameters

      out
      Output stream to print to.
      node
      Node to be printed.

      Returns

      Output stream.

      + constant + parse_no_data_nodes

      Synopsis

      const int parse_no_data_nodes + = 0x1; +

      Description

      Parse flag instructing the parser to not create data nodes. Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_no_element_values

      Synopsis

      const int parse_no_element_values + = 0x2; +

      Description

      Parse flag instructing the parser to not use text of first data node as a value of parent element. Can be combined with other flags by use of | operator. Note that child data nodes of element node take precendence over its value when printing. That is, if element has one or more child data nodes and a value, the value will be ignored. Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements.

      + See xml_document::parse() function.

      + constant + parse_no_string_terminators

      Synopsis

      const int parse_no_string_terminators + = 0x4; +

      Description

      Parse flag instructing the parser to not place zero terminators after strings in the source text. By default zero terminators are placed, modifying source text. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_no_entity_translation

      Synopsis

      const int parse_no_entity_translation + = 0x8; +

      Description

      Parse flag instructing the parser to not translate entities in the source text. By default entities are translated, modifying source text. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_no_utf8

      Synopsis

      const int parse_no_utf8 + = 0x10; +

      Description

      Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. By default, UTF-8 handling is enabled. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_declaration_node

      Synopsis

      const int parse_declaration_node + = 0x20; +

      Description

      Parse flag instructing the parser to create XML declaration node. By default, declaration node is not created. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_comment_nodes

      Synopsis

      const int parse_comment_nodes + = 0x40; +

      Description

      Parse flag instructing the parser to create comments nodes. By default, comment nodes are not created. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_doctype_node

      Synopsis

      const int parse_doctype_node + = 0x80; +

      Description

      Parse flag instructing the parser to create DOCTYPE node. By default, doctype node is not created. Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_pi_nodes

      Synopsis

      const int parse_pi_nodes + = 0x100; +

      Description

      Parse flag instructing the parser to create PI nodes. By default, PI nodes are not created. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_validate_closing_tags

      Synopsis

      const int parse_validate_closing_tags + = 0x200; +

      Description

      Parse flag instructing the parser to validate closing tag names. If not set, name inside closing tag is irrelevant to the parser. By default, closing tags are not validated. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_trim_whitespace

      Synopsis

      const int parse_trim_whitespace + = 0x400; +

      Description

      Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. By default, whitespace is not trimmed. This flag does not cause the parser to modify source text. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_normalize_whitespace

      Synopsis

      const int parse_normalize_whitespace + = 0x800; +

      Description

      Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. By default, whitespace is not normalized. If this flag is specified, source text will be modified. Can be combined with other flags by use of | operator.

      + See xml_document::parse() function.

      + constant + parse_default

      Synopsis

      const int parse_default + = 0; +

      Description

      Parse flags which represent default behaviour of the parser. This is always equal to 0, so that all other flags can be simply ored together. Normally there is no need to inconveniently disable flags by anding with their negated (~) values. This also means that meaning of each flag is a negation of the default setting. For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, and using the flag will disable it.

      + See xml_document::parse() function.

      + constant + parse_non_destructive

      Synopsis

      const int parse_non_destructive + = parse_no_string_terminators | parse_no_entity_translation; +

      Description

      A combination of parse flags that forbids any modifications of the source text. This also results in faster parsing. However, note that the following will occur:
      • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
      • entities will not be translated
      • whitespace will not be normalized
      +See xml_document::parse() function.

      + constant + parse_fastest

      Synopsis

      const int parse_fastest + = parse_non_destructive | parse_no_data_nodes; +

      Description

      A combination of parse flags resulting in fastest possible parsing, without sacrificing important data.

      + See xml_document::parse() function.

      + constant + parse_full

      Synopsis

      const int parse_full + = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; +

      Description

      A combination of parse flags resulting in largest amount of data being extracted. This usually results in slowest parsing.

      + See xml_document::parse() function.

      + constant + print_no_indenting

      Synopsis

      const int print_no_indenting + = 0x1; +

      Description

      Printer flag instructing the printer to suppress indenting of XML. See print() function.

      \ No newline at end of file diff --git a/cpp-netlib/libs/network/example/rapidxml/rapidxml.hpp b/cpp-netlib/libs/network/example/rapidxml/rapidxml.hpp new file mode 100644 index 00000000..bb05ffb1 --- /dev/null +++ b/cpp-netlib/libs/network/example/rapidxml/rapidxml.hpp @@ -0,0 +1,2746 @@ +#ifndef RAPIDXML_HPP_INCLUDED +#define RAPIDXML_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +// If standard library is disabled, user must provide implementations of +// required functions and typedefs +#if !defined(RAPIDXML_NO_STDLIB) +#include // For std::size_t +#include // For assert +#include // For placement new +#endif + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated +// code +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// RAPIDXML_PARSE_ERROR + +#if defined(RAPIDXML_NO_EXCEPTIONS) + +#define RAPIDXML_PARSE_ERROR(what, where) \ + { \ + parse_error_handler(what, where); \ + assert(0); \ + } + +namespace rapidxml { +//! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, +//! this function is called to notify user about the error. +//! It must be defined by the user. +//!

      +//! This function cannot return. If it does, the results are undefined. +//!

      +//! A very simple definition might look like that: +//!

      +//! void %rapidxml::%parse_error_handler(const char *what, void *where)
      +//! {
      +//!     std::cout << "Parse error: " << what << "\n";
      +//!     std::abort();
      +//! }
      +//! 
      +//! \param what Human readable description of the error. +//! \param where Pointer to character data where error was detected. +void parse_error_handler(const char *what, void *where); +} + +#else + +#include // For std::exception + +#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) + +namespace rapidxml { + +//! Parse error exception. +//! This exception is thrown by the parser when an error occurs. +//! Use what() function to get human-readable error message. +//! Use where() function to get a pointer to position within source text where +// error was detected. +//!

      +//! If throwing exceptions by the parser is undesirable, +//! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before +// rapidxml.hpp is included. +//! This will cause the parser to call rapidxml::parse_error_handler() +// function instead of throwing an exception. +//! This function must be defined by the user. +//!

      +//! This class derives from std::exception class. +class parse_error : public std::exception { + + public: + //! Constructs parse error + parse_error(const char *what, void *where) : m_what(what), m_where(where) {} + + //! Gets human readable description of error. + //! \return Pointer to null terminated description of the error. + virtual const char *what() const throw() { return m_what; } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the + // error. + //! \return Pointer to location within the parsed string where error + // occured. + template + Ch *where() const { + return reinterpret_cast(m_where); + } + + private: + const char *m_what; + void *m_where; +}; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef RAPIDXML_STATIC_POOL_SIZE +// Size of static memory block of memory_pool. +// Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to +// override the default value. +// No dynamic memory allocations are performed by memory_pool until static +// memory is exhausted. +#define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_DYNAMIC_POOL_SIZE +// Size of dynamic memory block of memory_pool. +// Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want +// to override the default value. +// After the static block is exhausted, dynamic blocks with approximately this +// size are allocated by memory_pool. +#define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_ALIGNMENT +// Memory allocation alignment. +// Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to +// override the default value, which is the size of pointer. +// All memory allocations for nodes, attributes and strings will be aligned to +// this value. +// This must be a power of 2 and at least 1, otherwise memory_pool will not +// work. +#define RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace rapidxml { +// Forward declarations +template +class xml_node; +template +class xml_attribute; +template +class xml_document; + +//! Enumeration listing all node types produced by the parser. +//! Use xml_node::type() function to query node type. +enum node_type { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value + // contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment + // text. + node_declaration, //!< A declaration node. Name and value are empty. + // Declaration parameters (version, encoding and + // standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE + // text. + node_pi //!< A PI node. Name contains target. Value contains instructions. +}; + +/////////////////////////////////////////////////////////////////////// +// Parsing flags + +//! Parse flag instructing the parser to not create data nodes. +//! Text of first data node will still be placed in value of parent element, +// unless rapidxml::parse_no_element_values flag is also specified. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_no_data_nodes = 0x1; + +//! Parse flag instructing the parser to not use text of first data node as a +// value of parent element. +//! Can be combined with other flags by use of | operator. +//! Note that child data nodes of element node take precendence over its value +// when printing. +//! That is, if element has one or more child data nodes and a value, +// the value will be ignored. +//! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes +// if you want to manipulate data using values of elements. +//!

      +//! See xml_document::parse() function. +const int parse_no_element_values = 0x2; + +//! Parse flag instructing the parser to not place zero terminators after +// strings in the source text. +//! By default zero terminators are placed, modifying source text. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_no_string_terminators = 0x4; + +//! Parse flag instructing the parser to not translate entities in the source +// text. +//! By default entities are translated, modifying source text. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_no_entity_translation = 0x8; + +//! Parse flag instructing the parser to disable UTF-8 handling and assume +// plain 8 bit characters. +//! By default, UTF-8 handling is enabled. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_no_utf8 = 0x10; + +//! Parse flag instructing the parser to create XML declaration node. +//! By default, declaration node is not created. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_declaration_node = 0x20; + +//! Parse flag instructing the parser to create comments nodes. +//! By default, comment nodes are not created. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_comment_nodes = 0x40; + +//! Parse flag instructing the parser to create DOCTYPE node. +//! By default, doctype node is not created. +//! Although W3C specification allows at most one DOCTYPE node, RapidXml will +// silently accept documents with more than one. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_doctype_node = 0x80; + +//! Parse flag instructing the parser to create PI nodes. +//! By default, PI nodes are not created. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_pi_nodes = 0x100; + +//! Parse flag instructing the parser to validate closing tag names. +//! If not set, name inside closing tag is irrelevant to the parser. +//! By default, closing tags are not validated. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_validate_closing_tags = 0x200; + +//! Parse flag instructing the parser to trim all leading and trailing +// whitespace of data nodes. +//! By default, whitespace is not trimmed. +//! This flag does not cause the parser to modify source text. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_trim_whitespace = 0x400; + +//! Parse flag instructing the parser to condense all whitespace runs of data +// nodes to a single space character. +//! Trimming of leading and trailing whitespace of data is controlled by +// rapidxml::parse_trim_whitespace flag. +//! By default, whitespace is not normalized. +//! If this flag is specified, source text will be modified. +//! Can be combined with other flags by use of | operator. +//!

      +//! See xml_document::parse() function. +const int parse_normalize_whitespace = 0x800; + +// Compound flags + +//! Parse flags which represent default behaviour of the parser. +//! This is always equal to 0, so that all other flags can be simply ored +// together. +//! Normally there is no need to inconveniently disable flags by anding with +// their negated (~) values. +//! This also means that meaning of each flag is a negation of the +// default setting. +//! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 +// is enabled by default, +//! and using the flag will disable it. +//!

      +//! See xml_document::parse() function. +const int parse_default = 0; + +//! A combination of parse flags that forbids any modifications of the source +// text. +//! This also results in faster parsing. However, note that the following will +// occur: +//!
        +//!
      • names and values of nodes will not be zero terminated, you have to use +// xml_base::name_size() and xml_base::value_size() functions to determine +// where name and value ends
      • +//!
      • entities will not be translated
      • +//!
      • whitespace will not be normalized
      • +//!
      +//! See xml_document::parse() function. +const int parse_non_destructive = + parse_no_string_terminators | parse_no_entity_translation; + +//! A combination of parse flags resulting in fastest possible parsing, +// without sacrificing important data. +//!

      +//! See xml_document::parse() function. +const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + +//! A combination of parse flags resulting in largest amount of data being +// extracted. +//! This usually results in slowest parsing. +//!

      +//! See xml_document::parse() function. +const int parse_full = parse_declaration_node | parse_comment_nodes | + parse_doctype_node | parse_pi_nodes | + parse_validate_closing_tags; + +/////////////////////////////////////////////////////////////////////// +// Internals + +//! \cond internal +namespace internal { + +// Struct that contains lookup tables for the parser +// It must be a template to allow correct linking (because it has static +// data members, which are defined in a header file). +template +struct lookup_tables { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name + // table + static const unsigned char lookup_attribute_data_1[256]; // Attribute + // data table + // with single + // quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute + // data table + // with single + // quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute + // data table + // with double + // quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute + // data table + // with double + // quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion + // table for ASCII + // characters +}; + +// Find length of the string +template +inline std::size_t measure(const Ch *p) { + const Ch *tmp = p; + while (*tmp) ++tmp; + return tmp - p; +} + +// Compare strings for equality +template +inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, + std::size_t size2, bool case_sensitive) { + if (size1 != size2) return false; + if (case_sensitive) { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) return false; + } else { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != + lookup_tables<0>::lookup_upcase[static_cast(*p2)]) + return false; + } + return true; +} +} +//! \endcond + +/////////////////////////////////////////////////////////////////////// +// Memory pool + +//! This class is used by the parser to create new nodes and attributes, +// without overheads of dynamic memory allocation. +//! In most cases, you will not need to use this class directly. +//! However, if you need to create nodes manually or modify names/values of +// nodes, +//! you are encouraged to use memory_pool of relevant xml_document to allocate +// the memory. +//! Not only is this faster than allocating them by using new +// operator, +//! but also their lifetime will be tied to the lifetime of document, +//! possibly simplyfing memory management. +//!

      +//! Call allocate_node() or allocate_attribute() functions to obtain new nodes +// or attributes from the pool. +//! You can also call allocate_string() function to allocate strings. +//! Such strings can then be used as names or values of nodes without worrying +// about their lifetime. +//! Note that there is no free() function -- all allocations are +// freed at once when clear() function is called, +//! or when the pool is destroyed. +//!

      +//! It is also possible to create a standalone memory_pool, and use it +//! to allocate nodes, whose lifetime will not be tied to any document. +//!

      +//! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically +// allocated memory. +//! Until static memory is exhausted, no dynamic memory allocations are done. +//! When static memory is exhausted, pool allocates additional blocks of +// memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, +//! by using global new[] and delete[] operators. +//! This behaviour can be changed by setting custom allocation routines. +//! Use set_allocator() function to set them. +//!

      +//! Allocations for nodes, attributes and strings are aligned at +//RAPIDXML_ALIGNMENT bytes. +//! This value defaults to the size of pointer on target architecture. +//!

      +//! To obtain absolutely top performance from the parser, +//! it is important that all nodes are allocated from a single, contiguous +// block of memory. +//! Otherwise, cache misses when jumping between two (or more) disjoint blocks +// of memory can slow down parsing quite considerably. +//! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, +//RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT +//! to obtain best wasted memory to performance compromise. +//! To do it, define their values before rapidxml.hpp file is included. +//! \param Ch Character type of created nodes. +template +class memory_pool { + + public: + //! \cond internal + typedef void *(alloc_func)(std::size_t); // Type of user-defined function + // used to allocate memory + typedef void(free_func)(void *); // Type of user-defined function used to + // free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool() : m_alloc_func(0), m_free_func(0) { init(); } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() { clear(); } + + //! Allocates a new node from the pool, and optionally assigns name and + // value to it. + //! If the allocation request cannot be accomodated, this function will + // throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this + // function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate + // size from name string. + //! \param value_size Size of value to assign, or 0 to automatically + // calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node *allocate_node(node_type type, const Ch *name = 0, + const Ch *value = 0, std::size_t name_size = 0, + std::size_t value_size = 0) { + void *memory = allocate_aligned(sizeof(xml_node)); + xml_node *node = new (memory) xml_node(type); + if (name) { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + if (value) { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and + // value to it. + //! If the allocation request cannot be accomodated, this function will + // throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this + // function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate + // size from name string. + //! \param value_size Size of value to assign, or 0 to automatically + // calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, + std::size_t value_size = 0) { + void *memory = allocate_aligned(sizeof(xml_attribute)); + xml_attribute *attribute = new (memory) xml_attribute; + if (name) { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally + // copies a given string to it. + //! If the allocation request cannot be accomodated, this function will + // throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this + // function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to + // not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it + // automatically from source string length; if size is 0, source string must + // be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be + // NULL. + Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) { + assert(source || + size); // Either source or size (or both) must be specified + if (size == 0) size = internal::measure(source) + 1; + Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); + if (source) + for (std::size_t i = 0; i < size; ++i) result[i] = source[i]; + return result; + } + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and + // the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate + // result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node *clone_node(const xml_node *source, + xml_node *result = 0) { + // Prepare result node + if (result) { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } else + result = allocate_node(source->type()); + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node *child = source->first_node(); child; + child = child->next_sibling()) + result->append_node(clone_node(child)); + for (xml_attribute *attr = source->first_attribute(); attr; + attr = attr->next_attribute()) + result->append_attribute(allocate_attribute( + attr->name(), attr->value(), attr->name_size(), attr->value_size())); + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() { + while (m_begin != m_static_memory) { + char *previous_begin = + reinterpret_cast
      (align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the + // pool. + //! This can only be called when no memory is allocated from the pool yet, + // otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It + // should either throw, + //! stop the program, or use longjmp() function to pass control + // to other place of program. + //! If it returns invalid pointer, results are undefined. + //!

      + //! User defined allocation functions must have the following forms: + //!
      + //!
      void *allocate(std::size_t size); + //!
      void free(void *pointer); + //!

      + //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(alloc_func *af, free_func *ff) { + assert(m_begin == m_static_memory && + m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + struct header { + char *previous_begin; + }; + + void init() { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + } + + char *align(char *ptr) { + std::size_t alignment = + ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & + (RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified + // allocation function or global operator new[] + { + memory = m_alloc_func(size); + assert(memory); // Allocator is not allowed to return 0, on failure it + // must either throw, stop the program or use longjmp + } else { + memory = new char[size]; +#ifdef RAPIDXML_NO_EXCEPTIONS + if (!memory) // If exceptions are disabled, verify memory allocation, + // because new will not be able to throw bad_alloc + RAPIDXML_PARSE_ERROR("out of memory", 0); +#endif + } + return static_cast(memory); + } + + void *allocate_aligned(std::size_t size) { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) { + // Calculate required pool size (may be bigger than + // RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + + pool_size; // 2 alignments required in worst + // case: one for header, one for + // actual allocation + char *raw_memory = allocate_raw(alloc_size); + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast
      (pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be + // used + free_func *m_free_func; // Free function, or 0 if default is to be used +}; + +/////////////////////////////////////////////////////////////////////////// +// XML base + +//! Base class for xml_node and xml_attribute implementing common functions: +//! name(), name_size(), value(), value_size() and parent(). +//! \param Ch Character type to use +template +class xml_base { + + public: + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() : m_name(0), m_value(0), m_parent(0) {} + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if + // rapidxml::parse_no_string_terminators option was selected during parse. + //!

      + //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const { return m_name ? m_name : nullstr(); } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not + // zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const { return m_name ? m_name_size : 0; } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if + // rapidxml::parse_no_string_terminators option was selected during parse. + //!

      + //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const { return m_value ? m_value : nullstr(); } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not + // zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const { return m_value ? m_value_size : 0; } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

      + //! Note that node does not own its name or value, it only stores a pointer + // to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the + // string. + //! The easiest way to achieve it is to use memory_pool of the document to + // allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

      + //! Size of name must be specified separately, because name does not have to + // be zero terminated. + //! Use name(const Ch *) function to have the length automatically + // calculated (string must be zero terminated). + //! \param name Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero + // terminator, if one is present. + void name(const Ch *name, std::size_t size) { + m_name = const_cast(name); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, + // std::size_t). + //! \param name Name of node to set. Must be zero terminated. + void name(const Ch *name) { this->name(name, internal::measure(name)); } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

      + //! Note that node does not own its name or value, it only stores a pointer + // to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the + // string. + //! The easiest way to achieve it is to use memory_pool of the document to + // allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

      + //! Size of value must be specified separately, because it does not have to + // be zero terminated. + //! Use value(const Ch *) function to have the length automatically + // calculated (string must be zero terminated). + //!

      + //! If an element has a child node of type node_data, it will take + // precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag + // rapidxml::parse_no_data_nodes to prevent creation of data nodes by the + // parser. + //! \param value value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero + // terminator, if one is present. + void value(const Ch *value, std::size_t size) { + m_value = const_cast(value); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, + // std::size_t). + //! \param value Vame of node to set. Must be zero terminated. + void value(const Ch *value) { this->value(value, internal::measure(value)); } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node *parent() const { return m_parent; } + + protected: + // Return empty string + static Ch *nullstr() { + static Ch zero = Ch('\0'); + return &zero; + } + + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node *m_parent; // Pointer to parent node, or 0 if none +}; + +//! Class representing attribute node of XML document. +//! Each attribute has name and value strings, which are available through +// name() and value() functions (inherited from xml_base). +//! Note that after parse, both name and value of attribute will point to +// interior of source text used for parsing. +//! Thus, this text must persist in memory for the lifetime of attribute. +//! \param Ch Character type to use. +template +class xml_attribute : public xml_base { + + friend class xml_node; + + public: + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating + // attributes manually. + xml_attribute() {} + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there + // is no parent document. + xml_document *document() const { + if (xml_node *node = this->parent()) { + while (node->parent()) node = node->parent(); + return node->type() == node_document + ? static_cast *>(node) + : 0; + } else + return 0; + } + + //! Gets previous attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return previous attribute + // regardless of its name; this string doesn't have to be zero-terminated if + // name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size + // calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non + // case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *previous_attribute(const Ch *name = 0, + std::size_t name_size = 0, + bool case_sensitive = true) const { + if (name) { + if (name_size == 0) name_size = internal::measure(name); + for (xml_attribute *attribute = m_prev_attribute; attribute; + attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, + name_size, case_sensitive)) + return attribute; + return 0; + } else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return next attribute + // regardless of its name; this string doesn't have to be zero-terminated if + // name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size + // calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non + // case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *next_attribute(const Ch *name = 0, + std::size_t name_size = 0, + bool case_sensitive = true) const { + if (name) { + if (name_size == 0) name_size = internal::measure(name); + for (xml_attribute *attribute = m_next_attribute; attribute; + attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, + name_size, case_sensitive)) + return attribute; + return 0; + } else + return this->m_parent ? m_next_attribute : 0; + } + + private: + xml_attribute *m_prev_attribute; // Pointer to previous sibling of + // attribute, or 0 if none; only valid + // if parent is non-zero + xml_attribute *m_next_attribute; // Pointer to next sibling of + // attribute, or 0 if none; only valid + // if parent is non-zero +}; + +/////////////////////////////////////////////////////////////////////////// +// XML node + +//! Class representing a node of XML document. +//! Each node may have associated name and value strings, which are available +// through name() and value() functions. +//! Interpretation of name and value depends on type of the node. +//! Type of node can be determined by using type() function. +//!

      +//! Note that after parse, both name and value of node, if any, will point +// interior of source text used for parsing. +//! Thus, this text must persist in the memory for the lifetime of node. +//! \param Ch Character type to use. +template +class xml_node : public xml_base { + + public: + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes + // manually. + //! \param type Type of node to construct. + xml_node(node_type type) + : m_type(type), m_first_node(0), m_first_attribute(0) {} + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const { return m_type; } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no + // parent document. + xml_document *document() const { + xml_node *node = const_cast *>(this); + while (node->parent()) node = node->parent(); + return node->type() == node_document ? static_cast *>(node) + : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param name Name of child to find, or 0 to return first child regardless + // of its name; this string doesn't have to be zero-terminated if name_size + // is non-zero + //! \param name_size Size of name, in characters, or 0 to have size + // calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non + // case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *first_node(const Ch *name = 0, std::size_t name_size = 0, + bool case_sensitive = true) const { + if (name) { + if (name_size == 0) name_size = internal::measure(name); + for (xml_node *child = m_first_node; child; + child = child->next_sibling()) + if (internal::compare(child->name(), child->name_size(), name, + name_size, case_sensitive)) + return child; + return 0; + } else + return m_first_node; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param name Name of child to find, or 0 to return last child regardless + // of its name; this string doesn't have to be zero-terminated if name_size + // is non-zero + //! \param name_size Size of name, in characters, or 0 to have size + // calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non + // case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *last_node(const Ch *name = 0, std::size_t name_size = 0, + bool case_sensitive = true) const { + assert( + m_first_node); // Cannot query for last child if node has no children + if (name) { + if (name_size == 0) name_size = internal::measure(name); + for (xml_node *child = m_last_node; child; + child = child->previous_sibling()) + if (internal::compare(child->name(), child->name_size(), name, + name_size, case_sensitive)) + return child; + return 0; + } else + return m_last_node; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return previous sibling + // regardless of its name; this string doesn't have to be zero-terminated if + // name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size + // calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non + // case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, + bool case_sensitive = true) const { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) { + if (name_size == 0) name_size = internal::measure(name); + for (xml_node *sibling = m_prev_sibling; sibling; + sibling = sibling->m_prev_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, + name_size, case_sensitive)) + return sibling; + return 0; + } else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return next sibling + // regardless of its name; this string doesn't have to be zero-terminated if + // name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size + // calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non + // case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *next_sibling(const Ch *name = 0, std::size_t name_size = 0, + bool case_sensitive = true) const { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) { + if (name_size == 0) name_size = internal::measure(name); + for (xml_node *sibling = m_next_sibling; sibling; + sibling = sibling->m_next_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, + name_size, case_sensitive)) + return sibling; + return 0; + } else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return first attribute + // regardless of its name; this string doesn't have to be zero-terminated if + // name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size + // calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non + // case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *first_attribute(const Ch *name = 0, + std::size_t name_size = 0, + bool case_sensitive = true) const { + if (name) { + if (name_size == 0) name_size = internal::measure(name); + for (xml_attribute *attribute = m_first_attribute; attribute; + attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, + name_size, case_sensitive)) + return attribute; + return 0; + } else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return last attribute + // regardless of its name; this string doesn't have to be zero-terminated if + // name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size + // calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non + // case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *last_attribute(const Ch *name = 0, + std::size_t name_size = 0, + bool case_sensitive = true) const { + if (name) { + if (name_size == 0) name_size = internal::measure(name); + for (xml_attribute *attribute = m_last_attribute; attribute; + attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, + name_size, case_sensitive)) + return attribute; + return 0; + } else + return m_first_attribute ? m_last_attribute : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param type Type of node to set. + void type(node_type type) { m_type = type; } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children + // are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node *child) { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } else { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node *child) { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } else { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one + // position back. + //! \param where Place where to insert the child, or 0 to insert at the + // back. + //! \param child Node to insert. + void insert_node(xml_node *where, xml_node *child) { + assert(!where || where->parent() == this); + assert(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() { + assert(first_node()); + xml_node *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() { + assert(first_node()); + xml_node *child = m_last_node; + if (child->m_prev_sibling) { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node *where) { + assert(where && where->parent() == this); + assert(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() { + for (xml_node *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute *attribute) { + assert(attribute && !attribute->parent()); + if (first_attribute()) { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } else { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute *attribute) { + assert(attribute && !attribute->parent()); + if (first_attribute()) { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } else { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one + // position back. + //! \param where Place where to insert the attribute, or 0 to insert at the + // back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute *where, + xml_attribute *attribute) { + assert(!where || where->parent() == this); + assert(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() { + assert(first_attribute()); + xml_attribute *attribute = m_first_attribute; + if (attribute->m_next_attribute) { + attribute->m_next_attribute->m_prev_attribute = 0; + } else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() { + assert(first_attribute()); + xml_attribute *attribute = m_last_attribute; + if (attribute->m_prev_attribute) { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute *where) { + assert(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() { + for (xml_attribute *attribute = first_attribute(); attribute; + attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + private: + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator=(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain + // other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit + // initialization of + // unneded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node + // has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one + // child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, + // otherwise they contain garbage + + node_type m_type; // Type of node; always valid + xml_node *m_first_node; // Pointer to first child node, or 0 if none; + // always valid + xml_node *m_last_node; // Pointer to last child node, or 0 if none; + // this value is only valid if m_first_node is + // non-zero + xml_attribute *m_first_attribute; // Pointer to first attribute of + // node, or 0 if none; always valid + xml_attribute *m_last_attribute; // Pointer to last attribute of node, + // or 0 if none; this value is only + // valid if m_first_attribute is + // non-zero + xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 + // if none; this value is only valid if + // m_parent is non-zero + xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if + // none; this value is only valid if m_parent + // is non-zero +}; + +/////////////////////////////////////////////////////////////////////////// +// XML document + +//! This class represents root of the DOM hierarchy. +//! It is also an xml_node and a memory_pool through public inheritance. +//! Use parse() function to build a DOM tree from a zero-terminated XML text +// string. +//! parse() function allocates memory for nodes and attributes by using +// functions of xml_document, +//! which are inherited from memory_pool. +//! To access root node of the document, use the document itself, as if it was +// an xml_node. +//! \param Ch Character type to use. +template +class xml_document : public xml_node, public memory_pool { + + public: + //! Constructs empty XML document + xml_document() : xml_node(node_document) {} + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless + // rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //!

      + //! If you want to parse contents of a file, you must first load the file + // into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //!

      + //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), + // but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that + // this data may be modified by the parser. + template + void parse(Ch *text) { + assert(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + + // Parse BOM, if any + parse_bom(text); + + // Parse children + while (1) { + // Skip whitespace before node + skip(text); + if (*text == 0) break; + + // Parse and append new child + if (*text == Ch('<')) { + ++text; // Skip '<' + if (xml_node *node = parse_node(text)) + this->append_node(node); + } else + RAPIDXML_PARSE_ERROR("expected <", text); + } + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool::clear(); + } + + private: + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred { + static unsigned char test(Ch ch) { + return internal::lookup_tables<0>::lookup_whitespace + [static_cast(ch)]; + } + }; + + // Detect node name character + struct node_name_pred { + static unsigned char test(Ch ch) { + return internal::lookup_tables<0>::lookup_node_name + [static_cast(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred { + static unsigned char test(Ch ch) { + return internal::lookup_tables<0>::lookup_attribute_name + [static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred { + static unsigned char test(Ch ch) { + return internal::lookup_tables<0>::lookup_text + [static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred { + static unsigned char test(Ch ch) { + return internal::lookup_tables<0>::lookup_text_pure_no_ws + [static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred { + static unsigned char test(Ch ch) { + return internal::lookup_tables<0>::lookup_text_pure_with_ws + [static_cast(ch)]; + } + }; + + // Detect attribute value character + template + struct attribute_value_pred { + static unsigned char test(Ch ch) { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1 + [static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2 + [static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template + struct attribute_value_pure_pred { + static unsigned char test(Ch ch) { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure + [static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure + [static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template + static void insert_coded_character(Ch *&text, unsigned long code) { + if (Flags & parse_no_utf8) { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement + // char otherwise? + text[0] = static_cast(code); + text += 1; + } else { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast(code); + text += 1; + } else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast((code | 0x80) & 0xBF); + code >>= 6; + text[0] = static_cast(code | 0xC0); + text += 2; + } else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast((code | 0x80) & 0xBF); + code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); + code >>= 6; + text[0] = static_cast(code | 0xE0); + text += 3; + } else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast((code | 0x80) & 0xBF); + code >>= 6; + text[2] = static_cast((code | 0x80) & 0xBF); + code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); + code >>= 6; + text[0] = static_cast(code | 0xF0); + text += 4; + } else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); + } + } + } + + // Skip characters until predicate evaluates to true + template + static void skip(Ch *&text) { + Ch *tmp = text; + while (StopPred::test(*tmp)) ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the + // following: + // - replacing XML character entity references with proper characters + // (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template + static Ch *skip_and_expand_character_refs(Ch *&text) { + // If entity translation, whitespace condense and whitespace trimming is + // disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) { + skip(text); + return text; + } + + // Use simple skip until first modification is detected + skip(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) { + // Test if replacement is needed + if (src[0] == Ch('&')) { + switch (src[1]) { + + // & ' + case Ch('a') : + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && + src[5] == Ch(';')) { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q') : + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && + src[5] == Ch(';')) { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g') : + if (src[2] == Ch('t') && src[3] == Ch(';')) { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l') : + if (src[2] == Ch('t') && src[3] == Ch(';')) { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#') : + if (src[2] == Ch('x')) { + unsigned long code = 0; + src += 3; // Skip &#x + while (1) { + unsigned char digit = + internal::lookup_tables<0>::lookup_digits + [static_cast(*src)]; + if (digit == 0xFF) break; + code = code * 16 + digit; + ++src; + } + insert_coded_character(dest, + code); // Put character in output + } else { + unsigned long code = 0; + src += 2; // Skip &# + while (1) { + unsigned char digit = + internal::lookup_tables<0>::lookup_digits + [static_cast(*src)]; + if (digit == 0xFF) break; + code = code * 10 + digit; + ++src; + } + insert_coded_character(dest, + code); // Put character in output + } + if (*src == Ch(';')) + ++src; + else + RAPIDXML_PARSE_ERROR("expected ;", src); + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) { + // Test if condensing is needed + if (whitespace_pred::test(*src)) { + *dest = Ch(' '); + ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + } + + // Return new end + text = src; + return dest; + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse BOM, if any + template + void parse_bom(Ch *&text) { + // UTF-8? + if (static_cast(text[0]) == 0xEF && + static_cast(text[1]) == 0xBB && + static_cast(text[2]) == 0xBF) { + text += 3; // Skup utf-8 bom + } + } + + // Parse XML declaration ( + xml_node *parse_xml_declaration(Ch *&text) { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) { + if (!text[0]) RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + + // Create declaration + xml_node *declaration = this->allocate_node(node_declaration); + + // Skip whitespace before attributes or ?> + skip(text); + + // Parse declaration attributes + parse_node_attributes(text, declaration); + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) + RAPIDXML_PARSE_ERROR("expected ?>", text); + text += 2; + + return declaration; + } + + // Parse XML comment (' + return 0; // Do not produce comment node + } + + // Remember value start + Ch *value = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) { + if (!text[0]) RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create comment node + xml_node *comment = this->allocate_node(node_comment); + comment->value(value, text - value); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template + xml_node *parse_doctype(Ch *&text) { + // Remember value start + Ch *value = text; + + // Skip to > + while (*text != Ch('>')) { + // Determine character type + switch (*text) { + + // If '[' encountered, scan for matching ending ']' using naive + // algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('[') : { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) { + switch (*text) { + case Ch('[') : + ++depth; + break; + case Ch(']') : + --depth; + break; + case 0: + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0') : + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Other character, skip it + default: + ++text; + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) { + // Create a new doctype node + xml_node *doctype = this->allocate_node(node_doctype); + doctype->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } else { + text += 1; // skip '>' + return 0; + } + } + + // Parse PI + template + xml_node *parse_pi(Ch *&text) { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) { + // Create pi node + xml_node *pi = this->allocate_node(node_pi); + + // Extract PI target name + Ch *name = text; + skip(text); + if (text == name) RAPIDXML_PARSE_ERROR("expected PI target", text); + pi->name(name, text - name); + + // Skip whitespace between pi target and pi + skip(text); + + // Remember start of pi + Ch *value = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace + // normalization) + pi->value(value, text - value); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } else { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + } + + // Parse and append data + // Return character that ends data. + // This is necessary because this character might have been overwritten by a + // terminating 0 + template + Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) text = contents_start; + + // Skip until end of data + Ch *value = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs(text); + else + end = skip_and_expand_character_refs(text); + + // Trim trailing whitespace if flag is set; leading was already trimmed by + // whitespace skip after > + if (Flags & parse_trim_whitespace) { + if (Flags & parse_normalize_whitespace) { + // Whitespace is already condensed to single space characters by + // skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) --end; + } else { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) --end; + } + } + + // If characters are still left between end and value (this test is only + // necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) { + xml_node *data = this->allocate_node(node_data); + data->value(value, end - value); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) node->value(value, end - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) { + Ch ch = *text; + *end = Ch('\0'); + return ch; // Return character that ends data; this is required because + // zero terminator overwritten it + } + + // Return character that ends data + return *text; + } + + // Parse CDATA + template + xml_node *parse_cdata(Ch *&text) { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) { + if (!text[0]) RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip ]]> + return 0; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *value = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) { + if (!text[0]) RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create new cdata node + xml_node *cdata = this->allocate_node(node_cdata); + cdata->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template + xml_node *parse_element(Ch *&text) { + // Create element node + xml_node *element = this->allocate_node(node_element); + + // Extract element name + Ch *name = text; + skip(text); + if (text == name) RAPIDXML_PARSE_ERROR("expected element name", text); + element->name(name, text - name); + + // Skip whitespace between element name and attributes or > + skip(text); + + // Parse attributes, if any + parse_node_attributes(text, element); + + // Determine ending type + if (*text == Ch('>')) { + ++text; + parse_node_contents(text, element); + } else if (*text == Ch('/')) { + ++text; + if (*text != Ch('>')) RAPIDXML_PARSE_ERROR("expected >", text); + ++text; + } else + RAPIDXML_PARSE_ERROR("expected >", text); + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = Ch('\0'); + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template + xml_node *parse_node(Ch *&text) { + // Parse proper node type + switch (text[0]) { + + // <... + default: + // Parse and append element node + return parse_element(text); + + // (text); + } else { + // Parse PI + return parse_pi(text); + } + + // (text); + } + break; + + // (text); + } + break; + + // (text); + } + + } // switch + + // Attempt to skip other, unrecognized node types starting with ')) { + if (*text == 0) RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + ++text; // Skip '>' + return 0; // No node recognized + } + } + + // Parse contents of the node - children, data etc. + template + void parse_node_contents(Ch *&text, xml_node *node) { + // For all children and text + while (1) { + // Skip whitespace between > and node contents + Ch *contents_start = + text; // Store start of node contents before whitespace is skipped + skip(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() + // function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) { + + // Node closing or child node + case Ch('<') : + if (text[1] == Ch('/')) { + // Node closing + text += 2; // Skip '(text); + if (!internal::compare(node->name(), node->name_size(), + closing_name, text - closing_name, true)) + RAPIDXML_PARSE_ERROR("invalid closing tag name", text); + } else { + // No validation, just skip name + skip(text); + } + // Skip remaining whitespace after node name + skip(text); + if (*text != Ch('>')) RAPIDXML_PARSE_ERROR("expected >", text); + ++text; // Skip '>' + return; // Node closed, finished parsing contents + } else { + // Child node + ++text; // Skip '<' + if (xml_node *child = parse_node(text)) + node->append_node(child); + } + break; + + // End of data - error + case Ch('\0') : + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Data node + default: + next_char = parse_and_append_data(node, text, contents_start); + goto after_data_node; // Bypass regular processing after data nodes + } + } + } + + // Parse XML attributes of the node + template + void parse_node_attributes(Ch *&text, xml_node *node) { + // For all attributes + while (attribute_name_pred::test(*text)) { + // Extract attribute name + Ch *name = text; + ++text; // Skip first character of attribute name + skip(text); + if (text == name) RAPIDXML_PARSE_ERROR("expected attribute name", name); + + // Create new attribute + xml_attribute *attribute = this->allocate_attribute(); + attribute->name(name, text - name); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip(text); + + // Skip = + if (*text != Ch('=')) RAPIDXML_PARSE_ERROR("expected =", text); + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; + + // Extract attribute value and expand char refs in it + Ch *value = text, *end; + const int AttFlags = + Flags & ~parse_normalize_whitespace; // No whitespace normalization + // in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs< + attribute_value_pred, attribute_value_pure_pred, + AttFlags>(text); + else + end = skip_and_expand_character_refs, + attribute_value_pure_pred, + AttFlags>(text); + + // Set attribute value + attribute->value(value, end - value); + + // Make sure that end quote is present + if (*text != quote) RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip(text); + } + } +}; + +//! \cond internal +namespace internal { + +// Whitespace (space \n \r \t) +template +const unsigned char lookup_tables::lookup_whitespace[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 // F +}; + +// Node name (anything but space \n \r \t / > ? \0) +template +const unsigned char lookup_tables::lookup_node_name[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 // F +}; + +// Text (i.e. PCDATA) (anything but < \0) +template +const unsigned char lookup_tables::lookup_text[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 // F +}; + +// Text (i.e. PCDATA) that does not require processing when ws normalization +// is disabled +// (anything but < \0 &) +template +const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 // F +}; + +// Text (i.e. PCDATA) that does not require processing when ws +// normalizationis is enabled +// (anything but < \0 & space \n \r \t) +template +const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 // F +}; + +// Attribute name (anything but space \n \r \t / < > = ? ! \0) +template +const unsigned char lookup_tables::lookup_attribute_name[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 // F +}; + +// Attribute data with single quote (anything but ' \0) +template +const unsigned char lookup_tables::lookup_attribute_data_1[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 // F +}; + +// Attribute data with single quote that does not require processing +// (anything but ' \0 &) +template +const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 // F +}; + +// Attribute data with double quote (anything but " \0) +template +const unsigned char lookup_tables::lookup_attribute_data_2[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 // F +}; + +// Attribute data with double quote that does not require processing +// (anything but " \0 &) +template +const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 // F +}; + +// Digits (dec and hex, 255 denotes end of numeric character reference) +template +const unsigned char lookup_tables::lookup_digits[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // 0 + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // 1 + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 255, 255, 255, 255, 255, 255, // 3 + 255, 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // 4 + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // 5 + 255, 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // 6 + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // 7 + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // 8 + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // 9 + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // A + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // B + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // C + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // D + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, // E + 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255 // F +}; + +// Upper case conversion +template +const unsigned char lookup_tables::lookup_upcase[256] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 123, 124, 125, 126, 127, // 7 + 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, // 8 + 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, // 9 + 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, // A + 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, // B + 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, // C + 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, // D + 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, // E + 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255 // F +}; +} +//! \endcond +} + +// Undefine internal macros +#undef RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif diff --git a/cpp-netlib/libs/network/example/rapidxml/rapidxml_iterators.hpp b/cpp-netlib/libs/network/example/rapidxml/rapidxml_iterators.hpp new file mode 100644 index 00000000..c43b509c --- /dev/null +++ b/cpp-netlib/libs/network/example/rapidxml/rapidxml_iterators.hpp @@ -0,0 +1,133 @@ +#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED +#define RAPIDXML_ITERATORS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_iterators.hpp This file contains rapidxml iterators + +#include "rapidxml.hpp" + +namespace rapidxml { + +//! Iterator of child nodes of xml_node +template +class node_iterator { + + public: + typedef typename xml_node value_type; + typedef typename xml_node &reference; + typedef typename xml_node *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + node_iterator() : m_node(0) {} + + node_iterator(xml_node *node) : m_node(node->first_node()) {} + + reference operator*() const { + assert(m_node); + return *m_node; + } + + pointer operator->() const { + assert(m_node); + return m_node; + } + + node_iterator &operator++() { + assert(m_node); + m_node = m_node->next_sibling(); + return *this; + } + + node_iterator operator++(int) { + node_iterator tmp = *this; + ++this; + return tmp; + } + + node_iterator &operator--() { + assert(m_node && m_node->previous_sibling()); + m_node = m_node->previous_sibling(); + return *this; + } + + node_iterator operator--(int) { + node_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator==(const node_iterator &rhs) { return m_node == rhs.m_node; } + + bool operator!=(const node_iterator &rhs) { return m_node != rhs.m_node; } + + private: + xml_node *m_node; +}; + +//! Iterator of child attributes of xml_node +template +class attribute_iterator { + + public: + typedef typename xml_attribute value_type; + typedef typename xml_attribute &reference; + typedef typename xml_attribute *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + attribute_iterator() : m_attribute(0) {} + + attribute_iterator(xml_node *node) + : m_attribute(node->first_attribute()) {} + + reference operator*() const { + assert(m_attribute); + return *m_attribute; + } + + pointer operator->() const { + assert(m_attribute); + return m_attribute; + } + + attribute_iterator &operator++() { + assert(m_attribute); + m_attribute = m_attribute->next_attribute(); + return *this; + } + + attribute_iterator operator++(int) { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + attribute_iterator &operator--() { + assert(m_attribute && m_attribute->previous_attribute()); + m_attribute = m_attribute->previous_attribute(); + return *this; + } + + attribute_iterator operator--(int) { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator==(const attribute_iterator &rhs) { + return m_attribute == rhs.m_attribute; + } + + bool operator!=(const attribute_iterator &rhs) { + return m_attribute != rhs.m_attribute; + } + + private: + xml_attribute *m_attribute; +}; +} + +#endif diff --git a/cpp-netlib/libs/network/example/rapidxml/rapidxml_print.hpp b/cpp-netlib/libs/network/example/rapidxml/rapidxml_print.hpp new file mode 100644 index 00000000..08125487 --- /dev/null +++ b/cpp-netlib/libs/network/example/rapidxml/rapidxml_print.hpp @@ -0,0 +1,432 @@ +#ifndef RAPIDXML_PRINT_HPP_INCLUDED +#define RAPIDXML_PRINT_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_print.hpp This file contains rapidxml printer implementation + +#include "rapidxml.hpp" + +// Only include streams if not disabled +#ifndef RAPIDXML_NO_STREAMS +#include +#include +#endif + +namespace rapidxml { + +/////////////////////////////////////////////////////////////////////// +// Printing flags + +const int print_no_indenting = 0x1; //!< Printer flag instructing the printer +// to suppress indenting of XML. See +// print() function. + +/////////////////////////////////////////////////////////////////////// +// Internal + +//! \cond internal +namespace internal { + +/////////////////////////////////////////////////////////////////////////// +// Internal character operations + +// Copy characters from given range to given output iterator +template +inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) { + while (begin != end) *out++ = *begin++; + return out; +} + +// Copy characters from given range to given output iterator and expand +// characters into references (< > ' " &) +template +inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, + OutIt out) { + while (begin != end) { + if (*begin == noexpand) { + *out++ = *begin; // No expansion, copy character + } else { + switch (*begin) { + case Ch('<') : + *out++ = Ch('&'); + *out++ = Ch('l'); + *out++ = Ch('t'); + *out++ = Ch(';'); + break; + case Ch('>') : + *out++ = Ch('&'); + *out++ = Ch('g'); + *out++ = Ch('t'); + *out++ = Ch(';'); + break; + case Ch('\'') : + *out++ = Ch('&'); + *out++ = Ch('a'); + *out++ = Ch('p'); + *out++ = Ch('o'); + *out++ = Ch('s'); + *out++ = Ch(';'); + break; + case Ch('"') : + *out++ = Ch('&'); + *out++ = Ch('q'); + *out++ = Ch('u'); + *out++ = Ch('o'); + *out++ = Ch('t'); + *out++ = Ch(';'); + break; + case Ch('&') : + *out++ = Ch('&'); + *out++ = Ch('a'); + *out++ = Ch('m'); + *out++ = Ch('p'); + *out++ = Ch(';'); + break; + default: + *out++ = *begin; // No expansion, copy character + } + } + ++begin; // Step to next character + } + return out; +} + +// Fill given output iterator with repetitions of the same character +template +inline OutIt fill_chars(OutIt out, int n, Ch ch) { + for (int i = 0; i < n; ++i) *out++ = ch; + return out; +} + +// Find character +template +inline bool find_char(const Ch *begin, const Ch *end) { + while (begin != end) + if (*begin++ == ch) return true; + return false; +} + +/////////////////////////////////////////////////////////////////////////// +// Internal printing operations + +// Print node +template +inline OutIt print_node(OutIt out, const xml_node *node, int flags, + int indent) { + // Print proper node type + switch (node->type()) { + + // Document + case node_document: + out = print_children(out, node, flags, indent); + break; + + // Element + case node_element: + out = print_element_node(out, node, flags, indent); + break; + + // Data + case node_data: + out = print_data_node(out, node, flags, indent); + break; + + // CDATA + case node_cdata: + out = print_cdata_node(out, node, flags, indent); + break; + + // Declaration + case node_declaration: + out = print_declaration_node(out, node, flags, indent); + break; + + // Comment + case node_comment: + out = print_comment_node(out, node, flags, indent); + break; + + // Doctype + case node_doctype: + out = print_doctype_node(out, node, flags, indent); + break; + + // Pi + case node_pi: + out = print_pi_node(out, node, flags, indent); + break; + + // Unknown + default: + assert(0); + break; + } + + // If indenting not disabled, add line break after node + if (!(flags & print_no_indenting)) *out = Ch('\n'), ++out; + + // Return modified iterator + return out; +} + +// Print children of the node +template +inline OutIt print_children(OutIt out, const xml_node *node, int flags, + int indent) { + for (xml_node *child = node->first_node(); child; + child = child->next_sibling()) + out = print_node(out, child, flags, indent); + return out; +} + +// Print attributes of the node +template +inline OutIt print_attributes(OutIt out, const xml_node *node, int flags) { + for (xml_attribute *attribute = node->first_attribute(); attribute; + attribute = attribute->next_attribute()) { + if (attribute->name() && attribute->value()) { + // Print attribute name + *out = Ch(' '), ++out; + out = copy_chars(attribute->name(), + attribute->name() + attribute->name_size(), out); + *out = Ch('='), ++out; + // Print attribute value using appropriate quote type + if (find_char( + attribute->value(), + attribute->value() + attribute->value_size())) { + *out = Ch('\''), ++out; + out = copy_and_expand_chars( + attribute->value(), attribute->value() + attribute->value_size(), + Ch('"'), out); + *out = Ch('\''), ++out; + } else { + *out = Ch('"'), ++out; + out = copy_and_expand_chars( + attribute->value(), attribute->value() + attribute->value_size(), + Ch('\''), out); + *out = Ch('"'), ++out; + } + } + } + return out; +} + +// Print data node +template +inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, + int indent) { + assert(node->type() == node_data); + if (!(flags & print_no_indenting)) out = fill_chars(out, indent, Ch('\t')); + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), + Ch(0), out); + return out; +} + +// Print data node +template +inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, + int indent) { + assert(node->type() == node_cdata); + if (!(flags & print_no_indenting)) out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'); + ++out; + *out = Ch('!'); + ++out; + *out = Ch('['); + ++out; + *out = Ch('C'); + ++out; + *out = Ch('D'); + ++out; + *out = Ch('A'); + ++out; + *out = Ch('T'); + ++out; + *out = Ch('A'); + ++out; + *out = Ch('['); + ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch(']'); + ++out; + *out = Ch(']'); + ++out; + *out = Ch('>'); + ++out; + return out; +} + +// Print element node +template +inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, + int indent) { + assert(node->type() == node_element); + + // Print element name and attributes, if any + if (!(flags & print_no_indenting)) out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + out = print_attributes(out, node, flags); + + // If node is childless + if (node->value_size() == 0 && !node->first_node()) { + // Print childless node tag ending + *out = Ch('/'), ++out; + *out = Ch('>'), ++out; + } else { + // Print normal node tag ending + *out = Ch('>'), ++out; + + // Test if node contains a single data node only (and no other nodes) + xml_node *child = node->first_node(); + if (!child) { + // If node has no children, only print its value without indenting + out = copy_and_expand_chars( + node->value(), node->value() + node->value_size(), Ch(0), out); + } else if (child->next_sibling() == 0 && child->type() == node_data) { + // If node has a sole data child, only print its value without + // indenting + out = copy_and_expand_chars( + child->value(), child->value() + child->value_size(), Ch(0), out); + } else { + // Print all children with full indenting + if (!(flags & print_no_indenting)) *out = Ch('\n'), ++out; + out = print_children(out, node, flags, indent + 1); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + } + + // Print node end + *out = Ch('<'), ++out; + *out = Ch('/'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch('>'), ++out; + } + return out; +} + +// Print declaration node +template +inline OutIt print_declaration_node(OutIt out, const xml_node *node, + int flags, int indent) { + // Print declaration start + if (!(flags & print_no_indenting)) out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + *out = Ch('x'), ++out; + *out = Ch('m'), ++out; + *out = Ch('l'), ++out; + + // Print attributes + out = print_attributes(out, node, flags); + + // Print declaration end + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + + return out; +} + +// Print comment node +template +inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, + int indent) { + assert(node->type() == node_comment); + if (!(flags & print_no_indenting)) out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + *out = Ch('>'), ++out; + return out; +} + +// Print doctype node +template +inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, + int indent) { + assert(node->type() == node_doctype); + if (!(flags & print_no_indenting)) out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('D'), ++out; + *out = Ch('O'), ++out; + *out = Ch('C'), ++out; + *out = Ch('T'), ++out; + *out = Ch('Y'), ++out; + *out = Ch('P'), ++out; + *out = Ch('E'), ++out; + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('>'), ++out; + return out; +} + +// Print pi node +template +inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, + int indent) { + assert(node->type() == node_pi); + if (!(flags & print_no_indenting)) out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + return out; +} +} +//! \endcond + +/////////////////////////////////////////////////////////////////////////// +// Printing + +//! Prints XML to given output iterator. +//! \param out Output iterator to print to. +//! \param node Node to be printed. Pass xml_document to print entire +// document. +//! \param flags Flags controlling how XML is printed. +//! \return Output iterator pointing to position immediately after last +// character of printed text. +template +inline OutIt print(OutIt out, const xml_node &node, int flags = 0) { + return internal::print_node(out, &node, flags, 0); +} + +#ifndef RAPIDXML_NO_STREAMS + +//! Prints XML to given output stream. +//! \param out Output stream to print to. +//! \param node Node to be printed. Pass xml_document to print entire +// document. +//! \param flags Flags controlling how XML is printed. +//! \return Output stream. +template +inline std::basic_ostream &print(std::basic_ostream &out, + const xml_node &node, int flags = 0) { + print(std::ostream_iterator(out), node, flags); + return out; +} + +//! Prints formatted XML to given output stream. Uses default printing flags. +// Use print() function to customize printing process. +//! \param out Output stream to print to. +//! \param node Node to be printed. +//! \return Output stream. +template +inline std::basic_ostream &operator<<(std::basic_ostream &out, + const xml_node &node) { + return print(out, node); +} + +#endif +} + +#endif diff --git a/cpp-netlib/libs/network/example/rapidxml/rapidxml_utils.hpp b/cpp-netlib/libs/network/example/rapidxml/rapidxml_utils.hpp new file mode 100644 index 00000000..4ca963c7 --- /dev/null +++ b/cpp-netlib/libs/network/example/rapidxml/rapidxml_utils.hpp @@ -0,0 +1,104 @@ +#ifndef RAPIDXML_UTILS_HPP_INCLUDED +#define RAPIDXML_UTILS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities +// that can be useful +//! in certain simple scenarios. They should probably not be used if maximizing +// performance is the main objective. + +#include "rapidxml.hpp" +#include +#include +#include +#include + +namespace rapidxml { + +//! Represents data loaded from a file +template +class file { + + public: + //! Loads file into the memory. Data will be automatically destroyed by the + // destructor. + //! \param filename Filename to load. + file(const char *filename) { + using namespace std; + + // Open stream + basic_ifstream stream(filename, ios::binary); + if (!stream) throw runtime_error(string("cannot open file ") + filename); + stream.unsetf(ios::skipws); + + // Determine stream size + stream.seekg(0, ios::end); + size_t size = stream.tellg(); + stream.seekg(0); + + // Load data and add terminating 0 + m_data.resize(size + 1); + stream.read(&m_data.front(), static_cast(size)); + m_data[size] = 0; + } + + //! Loads file into the memory. Data will be automatically destroyed by the + // destructor + //! \param stream Stream to load from + file(std::basic_istream &stream) { + using namespace std; + + // Load data and add terminating 0 + stream.unsetf(ios::skipws); + m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); + if (stream.fail() || stream.bad()) + throw runtime_error("error reading stream"); + m_data.push_back(0); + } + + //! Gets file data. + //! \return Pointer to data of file. + Ch *data() { return &m_data.front(); } + + //! Gets file data. + //! \return Pointer to data of file. + const Ch *data() const { return &m_data.front(); } + + //! Gets file data size. + //! \return Size of file data, in characters. + std::size_t size() const { return m_data.size(); } + + private: + std::vector m_data; // File data +}; + +//! Counts children of node. Time complexity is O(n). +//! \return Number of children of node +template +inline std::size_t count_children(xml_node *node) { + xml_node *child = node->first_node(); + std::size_t count = 0; + while (child) { + ++count; + child = child->next_sibling(); + } + return count; +} + +//! Counts attributes of node. Time complexity is O(n). +//! \return Number of attributes of node +template +inline std::size_t count_attributes(xml_node *node) { + xml_attribute *attr = node->first_attribute(); + std::size_t count = 0; + while (attr) { + ++count; + attr = attr->next_attribute(); + } + return count; +} +} + +#endif diff --git a/cpp-netlib/libs/network/example/rss/main.cpp b/cpp-netlib/libs/network/example/rss/main.cpp new file mode 100644 index 00000000..72a25ef1 --- /dev/null +++ b/cpp-netlib/libs/network/example/rss/main.cpp @@ -0,0 +1,37 @@ +// Copyright (c) Glyn Matthews 2011. +// 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 "rss.hpp" +#include +#include +#include + +int main(int argc, char *argv[]) { + using namespace boost::network; + + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + try { + http::client client; + http::client::request request(argv[1]); + request << header("Connection", "close"); + http::client::response response = client.get(request); + rss::channel channel(response); + + std::cout << "Channel: " << channel.title() << " (" << channel.description() + << ")" << std::endl; + BOOST_FOREACH(const rss::item & item, channel) { + std::cout << item.title() << " (" << item.author() << ")" << std::endl; + } + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/cpp-netlib/libs/network/example/rss/rss.cpp b/cpp-netlib/libs/network/example/rss/rss.cpp new file mode 100644 index 00000000..e76685ff --- /dev/null +++ b/cpp-netlib/libs/network/example/rss/rss.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Glyn Matthews 2011. +// 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 "rss.hpp" +#include "../rapidxml/rapidxml.hpp" +#include +#include + +namespace boost { +namespace network { +namespace rss { +channel::channel(const http::client::response &response) { + std::string response_body = body(response); + rapidxml::xml_document<> doc; + doc.parse<0>(const_cast(response_body.c_str())); + + rapidxml::xml_node<> *rss = doc.first_node("rss"); + if (!rss) { + throw std::runtime_error("Invalid RSS feed."); + } + + rapidxml::xml_node<> *channel = rss->first_node("channel"); + if (!channel) { + throw std::runtime_error("Invalid RSS channel."); + } + + rapidxml::xml_node<> *title = channel->first_node("title"); + if (title) { + title_ = title->first_node()->value(); + } + + rapidxml::xml_node<> *description = channel->first_node("description"); + if (description) { + description_ = description->first_node()->value(); + } + + rapidxml::xml_node<> *link = channel->first_node("link"); + if (link) { + link_ = link->first_node()->value(); + } + + rapidxml::xml_node<> *author = channel->first_node("author"); + if (author) { + author_ = author->first_node()->value(); + } + + rapidxml::xml_node<> *item = channel->first_node("item"); + while (item) { + items_.push_back(rss::item()); + + rapidxml::xml_node<> *title = item->first_node("title"); + if (title) { + items_.back().set_title(title->first_node()->value()); + } + + rapidxml::xml_node<> *author = item->first_node("author"); + if (author) { + items_.back().set_author(author->first_node()->value()); + } + + rapidxml::xml_node<> *description = item->first_node("description"); + if (description) { + items_.back().set_description(description->first_node()->value()); + } + + item = item->next_sibling(); + } +} +} // namespace rss +} // namespace network +} // namespace boost diff --git a/cpp-netlib/libs/network/example/rss/rss.hpp b/cpp-netlib/libs/network/example/rss/rss.hpp new file mode 100644 index 00000000..5daa1b1b --- /dev/null +++ b/cpp-netlib/libs/network/example/rss/rss.hpp @@ -0,0 +1,77 @@ +// Copyright (c) Glyn Matthews 2011. +// 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 ___RSS_INC__ +#define ___RSS_INC__ + +#include +#include +#include + +namespace boost { +namespace network { +namespace rss { +class item { + + public: + void set_title(const std::string &title) { title_ = title; } + + std::string title() const { return title_; } + + void set_author(const std::string &author) { author_ = author; } + + std::string author() const { return author_; } + + void set_description(const std::string &description) { + description_ = description; + } + + std::string description() const { return description_; } + + private: + std::string title_; + std::string author_; + std::string description_; +}; + +class channel { + + public: + typedef item value_type; + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + channel(const http::client::response &response); + + std::string title() const { return title_; } + + std::string description() const { return description_; } + + std::string link() const { return link_; } + + std::string author() const { return author_; } + + unsigned int item_count() const { return items_.size(); } + + iterator begin() { return items_.begin(); } + + iterator end() { return items_.end(); } + + const_iterator begin() const { return items_.begin(); } + + const_iterator end() const { return items_.end(); } + + private: + std::string title_; + std::string description_; + std::string link_; + std::string author_; + std::vector items_; +}; +} // namespace rss +} // namespace network +} // namespace boost + +#endif // ___RSS_INC__ diff --git a/cpp-netlib/libs/network/example/simple_wget.cpp b/cpp-netlib/libs/network/example/simple_wget.cpp new file mode 100644 index 00000000..261022b8 --- /dev/null +++ b/cpp-netlib/libs/network/example/simple_wget.cpp @@ -0,0 +1,57 @@ +// Copyright (c) Glyn Matthews 2009, 2010. +// 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) + +//[ simple_wget_main +/*` + This is a very basic clone of wget. It's missing a lot of + features, such as content-type detection, but it does the + fundamental things the same. + + It demonstrates the use the `uri` and the `http::client`. +*/ + +#include +#include +#include +#include +#include + +namespace http = boost::network::http; +namespace uri = boost::network::uri; + +namespace { +std::string get_filename(const uri::uri &url) { + std::string path = uri::path(url); + std::size_t index = path.find_last_of('/'); + std::string filename = path.substr(index + 1); + return filename.empty() ? "index.html" : filename; +} +} // namespace + +int main(int argc, char *argv[]) { + + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " url" << std::endl; + return 1; + } + + http::client client; + try { + http::client::request request(argv[1]); + http::client::response response = client.get(request); + + std::string filename = get_filename(request.uri()); + std::cout << "Saving to: " << filename << std::endl; + std::ofstream ofs(filename.c_str()); + ofs << static_cast(body(response)) << std::endl; + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + return 1; + } + + return 0; +} +//] diff --git a/cpp-netlib/libs/network/example/trivial_google.cpp b/cpp-netlib/libs/network/example/trivial_google.cpp new file mode 100644 index 00000000..800c90b2 --- /dev/null +++ b/cpp-netlib/libs/network/example/trivial_google.cpp @@ -0,0 +1,18 @@ +// Copyright 2014 Dean Michael Berris +// Copyright 2014 Google, Inc. +// 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 + +#include + +namespace http = boost::network::http; + +int main(int, char * []) { + http::client client; + http::client::request request("https://www.google.com/"); + http::client::response response = client.get(request); + std::cout << body(response) << std::endl; +} diff --git a/cpp-netlib/libs/network/example/twitter/rapidjson/document.h b/cpp-netlib/libs/network/example/twitter/rapidjson/document.h new file mode 100644 index 00000000..4062bd84 --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/rapidjson/document.h @@ -0,0 +1,806 @@ +#ifndef RAPIDJSON_DOCUMENT_H_ +#define RAPIDJSON_DOCUMENT_H_ + +#include "reader.h" +#include "internal/strfunc.h" + +namespace rapidjson { + +/////////////////////////////////////////////////////////////////////////////// +// GenericValue + +//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. +/*! + A JSON value can be one of 7 types. This class is a variant type supporting + these types. + + Use the Value if UTF8 and default allocator + + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. +*/ +#pragma pack (push, 4) +template > +class GenericValue { +public: + //! Name-value pair in an object. + struct Member { + GenericValue name; //!< name of member (must be a string) + GenericValue value; //!< value of member. + }; + + typedef Encoding EncodingType; //!< Encoding type from template parameter. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef Member* MemberIterator; //!< Member iterator for iterating in object. + typedef const Member* ConstMemberIterator; //!< Constant member iterator for iterating in object. + typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. + typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. + + //!@name Constructors and destructor. + //@{ + + //! Default constructor creates a null value. + GenericValue() : flags_(kNullFlag) {} + + //! Copy constructor is not permitted. +private: + GenericValue(const GenericValue& rhs); + +public: + + //! Constructor with JSON value type. + /*! This creates a Value of specified type with default content. + \param type Type of the value. + \note Default content for number is zero. + */ + GenericValue(Type type) { + static const unsigned defaultFlags[7] = { + kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag, + kNumberFlag | kIntFlag | kUintFlag | kInt64Flag | kUint64Flag | kDoubleFlag + }; + RAPIDJSON_ASSERT(type <= kNumberType); + flags_ = defaultFlags[type]; + memset(&data_, 0, sizeof(data_)); + } + + //! Constructor for boolean value. + GenericValue(bool b) : flags_(b ? kTrueFlag : kFalseFlag) {} + + //! Constructor for int value. + GenericValue(int i) : flags_(kNumberIntFlag) { + data_.n.i64 = i; + if (i >= 0) + flags_ |= kUintFlag | kUint64Flag; + } + + //! Constructor for unsigned value. + GenericValue(unsigned u) : flags_(kNumberUintFlag) { + data_.n.u64 = u; + if (!(u & 0x80000000)) + flags_ |= kIntFlag | kInt64Flag; + } + + //! Constructor for int64_t value. + GenericValue(int64_t i64) : flags_(kNumberInt64Flag) { + data_.n.i64 = i64; + if (i64 >= 0) { + flags_ |= kNumberUint64Flag; + if (!(i64 & 0xFFFFFFFF00000000LL)) + flags_ |= kUintFlag; + if (!(i64 & 0xFFFFFFFF80000000LL)) + flags_ |= kIntFlag; + } + else if (i64 >= -2147483648LL) + flags_ |= kIntFlag; + } + + //! Constructor for uint64_t value. + GenericValue(uint64_t u64) : flags_(kNumberUint64Flag) { + data_.n.u64 = u64; + if (!(u64 & 0x8000000000000000L)) + flags_ |= kInt64Flag; + if (!(u64 & 0xFFFFFFFF00000000L)) + flags_ |= kUintFlag; + if (!(u64 & 0xFFFFFFFF80000000L)) + flags_ |= kIntFlag; + } + + //! Constructor for double value. + GenericValue(double d) : flags_(kNumberDoubleFlag) { data_.n.d = d; } + + //! Constructor for constant string (i.e. do not make a copy of string) + GenericValue(const Ch* s, SizeType length) { + RAPIDJSON_ASSERT(s != NULL); + flags_ = kConstStringFlag; + data_.s.str = s; + data_.s.length = length; + } + + //! Constructor for constant string (i.e. do not make a copy of string) + GenericValue(const Ch* s) { SetStringRaw(s, internal::StrLen(s)); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch* s, SizeType length, Allocator& allocator) { SetStringRaw(s, length, allocator); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch*s, Allocator& allocator) { SetStringRaw(s, internal::StrLen(s), allocator); } + + //! Destructor. + /*! Need to destruct elements of array, members of object, or copy-string. + */ + ~GenericValue() { + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + switch(flags_) { + case kArrayFlag: + for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) + v->~GenericValue(); + Allocator::Free(data_.a.elements); + break; + + case kObjectFlag: + for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) { + m->name.~GenericValue(); + m->value.~GenericValue(); + } + Allocator::Free(data_.o.members); + break; + + case kCopyStringFlag: + Allocator::Free((void*)data_.s.str); + break; + } + } + } + + //@} + + //!@name Assignment operators + //@{ + + //! Assignment with move semantics. + /*! \param rhs Source of the assignment. It will become a null value after assignment. + */ + GenericValue& operator=(GenericValue& rhs) { + RAPIDJSON_ASSERT(this != &rhs); + this->~GenericValue(); + memcpy(this, &rhs, sizeof(GenericValue)); + rhs.flags_ = kNullFlag; + return *this; + } + + //! Assignment with primitive types. + /*! \tparam T Either Type, int, unsigned, int64_t, uint64_t, const Ch* + \param value The value to be assigned. + */ + template + GenericValue& operator=(T value) { + this->~GenericValue(); + new (this) GenericValue(value); + return *this; + } + //@} + + //!@name Type + //@{ + + Type GetType() const { return static_cast(flags_ & kTypeMask); } + bool IsNull() const { return flags_ == kNullFlag; } + bool IsFalse() const { return flags_ == kFalseFlag; } + bool IsTrue() const { return flags_ == kTrueFlag; } + bool IsBool() const { return (flags_ & kBoolFlag) != 0; } + bool IsObject() const { return flags_ == kObjectFlag; } + bool IsArray() const { return flags_ == kArrayFlag; } + bool IsNumber() const { return (flags_ & kNumberFlag) != 0; } + bool IsInt() const { return (flags_ & kIntFlag) != 0; } + bool IsUint() const { return (flags_ & kUintFlag) != 0; } + bool IsInt64() const { return (flags_ & kInt64Flag) != 0; } + bool IsUint64() const { return (flags_ & kUint64Flag) != 0; } + bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; } + bool IsString() const { return (flags_ & kStringFlag) != 0; } + + //@} + + //!@name Null + //@{ + + GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } + + //@} + + //!@name Bool + //@{ + + bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; } + GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } + + //@} + + //!@name Object + //@{ + + //! Set this value as an empty object. + GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } + + //! Get the value associated with the object's name. + GenericValue& operator[](const Ch* name) { + if (Member* member = FindMember(name)) + return member->value; + else { + static GenericValue NullValue; + return NullValue; + } + } + const GenericValue& operator[](const Ch* name) const { return const_cast(*this)[name]; } + + //! Member iterators. + ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; } + ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; } + MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; } + MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; } + + //! Check whether a member exists in the object. + bool HasMember(const Ch* name) const { return FindMember(name) != 0; } + + //! Add a member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. + \return The value itself for fluent API. + \note The ownership of name and value will be transfered to this object if success. + */ + GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + Object& o = data_.o; + if (o.size >= o.capacity) { + if (o.capacity == 0) { + o.capacity = kDefaultObjectCapacity; + o.members = (Member*)allocator.Malloc(o.capacity * sizeof(Member)); + } + else { + SizeType oldCapacity = o.capacity; + o.capacity *= 2; + o.members = (Member*)allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)); + } + } + o.members[o.size].name = name; + o.members[o.size].value = value; + o.size++; + return *this; + } + + GenericValue& AddMember(const char* name, Allocator& nameAllocator, GenericValue& value, Allocator& allocator) { + GenericValue n(name, internal::StrLen(name), nameAllocator); + return AddMember(n, value, allocator); + } + + GenericValue& AddMember(const char* name, GenericValue& value, Allocator& allocator) { + GenericValue n(name, internal::StrLen(name)); + return AddMember(n, value, allocator); + } + + template + GenericValue& AddMember(const char* name, T value, Allocator& allocator) { + GenericValue n(name, internal::StrLen(name)); + GenericValue v(value); + return AddMember(n, v, allocator); + } + + //! Remove a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note Removing member is implemented by moving the last member. So the ordering of members is changed. + */ + bool RemoveMember(const Ch* name) { + RAPIDJSON_ASSERT(IsObject()); + if (Member* m = FindMember(name)) { + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(data_.o.members != 0); + + if (data_.o.size > 1) { + // Move the last one to this place + Member* last = data_.o.members + (data_.o.size - 1); + m->name = last->name; + m->value = last->value; + } + else { + // Only one left, just destroy + m->name.~GenericValue(); + m->value.~GenericValue(); + } + --data_.o.size; + return true; + } + return false; + } + + //@} + + //!@name Array + //@{ + + //! Set this value as an empty array. + GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } + + //! Get the number of elements in array. + SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } + + //! Get the capacity of array. + SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } + + //! Check whether the array is empty. + bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } + + //! Remove all elements in the array. + /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. + */ + void Clear() { + RAPIDJSON_ASSERT(IsArray()); + for (SizeType i = 0; i < data_.a.size; ++i) + data_.a.elements[i].~GenericValue(); + data_.a.size = 0; + } + + //! Get an element from array by index. + /*! \param index Zero-based index of element. + \note +\code +Value a(kArrayType); +a.PushBack(123); +int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type. +int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work. +int z = a[0u].GetInt(); // This works too. +\endcode + */ + GenericValue& operator[](SizeType index) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(index < data_.a.size); + return data_.a.elements[index]; + } + const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } + + //! Element iterator + ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; } + ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; } + ConstValueIterator Begin() const { return const_cast(*this).Begin(); } + ConstValueIterator End() const { return const_cast(*this).End(); } + + //! Request the array to have enough capacity to store elements. + /*! \param newCapacity The capacity that the array at least need to have. + \param allocator The allocator for allocating memory. It must be the same one use previously. + \return The value itself for fluent API. + */ + GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (newCapacity > data_.a.capacity) { + data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); + data_.a.capacity = newCapacity; + } + return *this; + } + + //! Append a value at the end of the array. + /*! \param value The value to be appended. + \param allocator The allocator for allocating memory. It must be the same one use previously. + \return The value itself for fluent API. + \note The ownership of the value will be transfered to this object if success. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + */ + GenericValue& PushBack(GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (data_.a.size >= data_.a.capacity) + Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity * 2, allocator); + data_.a.elements[data_.a.size++] = value; + return *this; + } + + template + GenericValue& PushBack(T value, Allocator& allocator) { + GenericValue v(value); + return PushBack(v, allocator); + } + + //! Remove the last element in the array. + GenericValue& PopBack() { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(!Empty()); + data_.a.elements[--data_.a.size].~GenericValue(); + return *this; + } + //@} + + //!@name Number + //@{ + + int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i; } + unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u; } + int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; } + int64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.u64; } + + double GetDouble() const { + RAPIDJSON_ASSERT(IsNumber()); + if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. + if ((flags_ & kIntFlag) != 0) return data_.n.i; // int -> double + if ((flags_ & kUintFlag) != 0) return data_.n.u; // unsigned -> double + if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision) + RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision) + } + + GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } + GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } + GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } + GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } + GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } + + //@} + + //!@name String + //@{ + + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; } + + //! Get the length of string. + /*! Since rapidjson permits "\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). + */ + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; } + + //! Set this value as a string without copying source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string pointer. + \param length The length of source string, excluding the trailing null terminator. + \return The value itself for fluent API. + */ + GenericValue& SetString(const Ch* s, SizeType length) { this->~GenericValue(); SetStringRaw(s, length); return *this; } + + //! Set this value as a string without copying source string. + /*! \param s source string pointer. + \return The value itself for fluent API. + */ + GenericValue& SetString(const Ch* s) { return SetString(s, internal::StrLen(s)); } + + //! Set this value as a string by copying from source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string. + \param length The length of source string, excluding the trailing null terminator. + \param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator(). + \return The value itself for fluent API. + */ + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, length, allocator); return *this; } + + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator(). + \return The value itself for fluent API. + */ + GenericValue& SetString(const Ch* s, Allocator& allocator) { SetString(s, internal::StrLen(s), allocator); return *this; } + + //@} + + //! Generate events of this value to a Handler. + /*! This function adopts the GoF visitor pattern. + Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. + It can also be used to deep clone this value via GenericDocument, which is also a Handler. + \tparam Handler type of handler. + \param handler An object implementing concept Handler. + */ + template + GenericValue& Accept(Handler& handler) { + switch(GetType()) { + case kNullType: handler.Null(); break; + case kFalseType: handler.Bool(false); break; + case kTrueType: handler.Bool(true); break; + + case kObjectType: + handler.StartObject(); + for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) { + handler.String(m->name.data_.s.str, m->name.data_.s.length, false); + m->value.Accept(handler); + } + handler.EndObject(data_.o.size); + break; + + case kArrayType: + handler.StartArray(); + for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) + v->Accept(handler); + handler.EndArray(data_.a.size); + break; + + case kStringType: + handler.String(data_.s.str, data_.s.length, false); + break; + + case kNumberType: + if (IsInt()) handler.Int(data_.n.i); + else if (IsUint()) handler.Uint(data_.n.u); + else if (IsInt64()) handler.Int64(data_.n.i64); + else if (IsUint64()) handler.Uint64(data_.n.i64); + else handler.Double(data_.n.d); + break; + } + return *this; + } + +private: + template + friend class GenericDocument; + + enum { + kBoolFlag = 0x100, + kNumberFlag = 0x200, + kIntFlag = 0x400, + kUintFlag = 0x800, + kInt64Flag = 0x1000, + kUint64Flag = 0x2000, + kDoubleFlag = 0x4000, + kStringFlag = 0x100000, + kCopyFlag = 0x200000, + + // Initial flags of different types. + kNullFlag = kNullType, + kTrueFlag = kTrueType | kBoolFlag, + kFalseFlag = kFalseType | kBoolFlag, + kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, + kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag, + kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, + kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, + kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, + kConstStringFlag = kStringType | kStringFlag, + kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, + kObjectFlag = kObjectType, + kArrayFlag = kArrayType, + + kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler + }; + + static const SizeType kDefaultArrayCapacity = 16; + static const SizeType kDefaultObjectCapacity = 16; + + struct String { + const Ch* str; + SizeType length; + unsigned hashcode; //!< reserved + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + // By using proper binary layout, retrieval of different integer types do not need conversions. + union Number { +#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN + struct { + int i; + char padding[4]; + }; + struct { + unsigned u; + char padding2[4]; + }; +#else + struct { + char padding[4]; + int i; + }; + struct { + char padding2[4]; + unsigned u; + }; +#endif + int64_t i64; + uint64_t u64; + double d; + }; // 8 bytes + + struct Object { + Member* members; + SizeType size; + SizeType capacity; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + struct Array { + GenericValue* elements; + SizeType size; + SizeType capacity; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + union Data { + String s; + Number n; + Object o; + Array a; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + //! Find member by name. + Member* FindMember(const Ch* name) { + RAPIDJSON_ASSERT(name); + RAPIDJSON_ASSERT(IsObject()); + + Object& o = data_.o; + for (Member* member = o.members; member != data_.o.members + data_.o.size; ++member) + if (name[member->name.data_.s.length] == '\0' && memcmp(member->name.data_.s.str, name, member->name.data_.s.length * sizeof(Ch)) == 0) + return member; + + return 0; + } + const Member* FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } + + // Initialize this value as array with initial data, without calling destructor. + void SetArrayRaw(GenericValue* values, SizeType count, Allocator& alloctaor) { + flags_ = kArrayFlag; + data_.a.elements = (GenericValue*)alloctaor.Malloc(count * sizeof(GenericValue)); + memcpy(data_.a.elements, values, count * sizeof(GenericValue)); + data_.a.size = data_.a.capacity = count; + } + + //! Initialize this value as object with initial data, without calling destructor. + void SetObjectRaw(Member* members, SizeType count, Allocator& alloctaor) { + flags_ = kObjectFlag; + data_.o.members = (Member*)alloctaor.Malloc(count * sizeof(Member)); + memcpy(data_.o.members, members, count * sizeof(Member)); + data_.o.size = data_.o.capacity = count; + } + + //! Initialize this value as constant string, without calling destructor. + void SetStringRaw(const Ch* s, SizeType length) { + RAPIDJSON_ASSERT(s != NULL); + flags_ = kConstStringFlag; + data_.s.str = s; + data_.s.length = length; + } + + //! Initialize this value as copy string with initial data, without calling destructor. + void SetStringRaw(const Ch* s, SizeType length, Allocator& allocator) { + RAPIDJSON_ASSERT(s != NULL); + flags_ = kCopyStringFlag; + data_.s.str = (char *)allocator.Malloc(length + 1); + data_.s.length = length; + memcpy((void*)data_.s.str, s, length); + ((char*)data_.s.str)[length] = '\0'; + } + + //! Assignment without calling destructor + void RawAssign(GenericValue& rhs) { + memcpy(this, &rhs, sizeof(GenericValue)); + rhs.flags_ = kNullFlag; + } + + Data data_; + unsigned flags_; +}; +#pragma pack (pop) + +//! Value with UTF8 encoding. +typedef GenericValue > Value; + +/////////////////////////////////////////////////////////////////////////////// +// GenericDocument + +//! A document for parsing JSON text as DOM. +/*! + \implements Handler + \tparam Encoding encoding for both parsing and string storage. + \tparam Alloactor allocator for allocating memory for the DOM, and the stack during parsing. +*/ +template > +class GenericDocument : public GenericValue { +public: + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericValue ValueType; //!< Value type of the document. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + + //! Constructor + /*! \param allocator Optional allocator for allocating stack memory. + \param stackCapacity Initial capacity of stack in bytes. + */ + GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {} + + //! Parse JSON text from an input stream. + /*! \tparam parseFlags Combination of ParseFlag. + \param stream Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(Stream& stream) { + ValueType::SetNull(); // Remove existing root if exist + GenericReader reader; + if (reader.template Parse(stream, *this)) { + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + this->RawAssign(*stack_.template Pop(1)); + parseError_ = 0; + errorOffset_ = 0; + } + else { + parseError_ = reader.GetParseError(); + errorOffset_ = reader.GetErrorOffset(); + ClearStack(); + } + return *this; + } + + //! Parse JSON text from a mutable string. + /*! \tparam parseFlags Combination of ParseFlag. + \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseInsitu(Ch* str) { + GenericInsituStringStream s(str); + return ParseStream(s); + } + + //! Parse JSON text from a read-only string. + /*! \tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag). + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const Ch* str) { + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + GenericStringStream s(str); + return ParseStream(s); + } + + //! Whether a parse error was occured in the last parsing. + bool HasParseError() const { return parseError_ != 0; } + + //! Get the message of parsing error. + const char* GetParseError() const { return parseError_; } + + //! Get the offset in character of the parsing error. + size_t GetErrorOffset() const { return errorOffset_; } + + //! Get the allocator of this document. + Allocator& GetAllocator() { return stack_.GetAllocator(); } + + //! Get the capacity of stack in bytes. + size_t GetStackCapacity() const { return stack_.GetCapacity(); } + +private: + friend class GenericReader; // for Reader to call the following private handler functions + + // Implementation of Handler + void Null() { new (stack_.template Push()) ValueType(); } + void Bool(bool b) { new (stack_.template Push()) ValueType(b); } + void Int(int i) { new (stack_.template Push()) ValueType(i); } + void Uint(unsigned i) { new (stack_.template Push()) ValueType(i); } + void Int64(int64_t i) { new (stack_.template Push()) ValueType(i); } + void Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); } + void Double(double d) { new (stack_.template Push()) ValueType(d); } + + void String(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + } + + void StartObject() { new (stack_.template Push()) ValueType(kObjectType); } + + void EndObject(SizeType memberCount) { + typename ValueType::Member* members = stack_.template Pop(memberCount); + stack_.template Top()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); + } + + void StartArray() { new (stack_.template Push()) ValueType(kArrayType); } + + void EndArray(SizeType elementCount) { + ValueType* elements = stack_.template Pop(elementCount); + stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); + } + + void ClearStack() { + if (Allocator::kNeedFree) + while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) + (stack_.template Pop(1))->~ValueType(); + else + stack_.Clear(); + } + + static const size_t kDefaultStackCapacity = 1024; + internal::Stack stack_; + const char* parseError_; + size_t errorOffset_; +}; + +typedef GenericDocument > Document; + +} // namespace rapidjson + +#endif // RAPIDJSON_DOCUMENT_H_ diff --git a/cpp-netlib/libs/network/example/twitter/rapidjson/filestream.h b/cpp-netlib/libs/network/example/twitter/rapidjson/filestream.h new file mode 100644 index 00000000..24573aa4 --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/rapidjson/filestream.h @@ -0,0 +1,46 @@ +#ifndef RAPIDJSON_FILESTREAM_H_ +#define RAPIDJSON_FILESTREAM_H_ + +#include + +namespace rapidjson { + +//! Wrapper of C file stream for input or output. +/*! + This simple wrapper does not check the validity of the stream. + \implements Stream +*/ +class FileStream { +public: + typedef char Ch; //!< Character type. Only support char. + + FileStream(FILE* fp) : fp_(fp), count_(0) { Read(); } + char Peek() const { return current_; } + char Take() { char c = current_; Read(); return c; } + size_t Tell() const { return count_; } + void Put(char c) { fputc(c, fp_); } + + // Not implemented + char* PutBegin() { return 0; } + size_t PutEnd(char*) { return 0; } + +private: + void Read() { + RAPIDJSON_ASSERT(fp_ != 0); + int c = fgetc(fp_); + if (c != EOF) { + current_ = (char)c; + count_++; + } + else + current_ = '\0'; + } + + FILE* fp_; + char current_; + size_t count_; +}; + +} // namespace rapidjson + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/cpp-netlib/libs/network/example/twitter/rapidjson/internal/pow10.h b/cpp-netlib/libs/network/example/twitter/rapidjson/internal/pow10.h new file mode 100644 index 00000000..0852539e --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/rapidjson/internal/pow10.h @@ -0,0 +1,54 @@ +#ifndef RAPIDJSON_POW10_ +#define RAPIDJSON_POW10_ + +namespace rapidjson { +namespace internal { + +//! Computes integer powers of 10 in double (10.0^n). +/*! This function uses lookup table for fast and accurate results. + \param n positive/negative exponent. Must <= 308. + \return 10.0^n +*/ +inline double Pow10(int n) { + static const double e[] = { // 1e-308...1e308: 617 * 8 bytes = 4936 bytes + 1e-308,1e-307,1e-306,1e-305,1e-304,1e-303,1e-302,1e-301,1e-300, + 1e-299,1e-298,1e-297,1e-296,1e-295,1e-294,1e-293,1e-292,1e-291,1e-290,1e-289,1e-288,1e-287,1e-286,1e-285,1e-284,1e-283,1e-282,1e-281,1e-280, + 1e-279,1e-278,1e-277,1e-276,1e-275,1e-274,1e-273,1e-272,1e-271,1e-270,1e-269,1e-268,1e-267,1e-266,1e-265,1e-264,1e-263,1e-262,1e-261,1e-260, + 1e-259,1e-258,1e-257,1e-256,1e-255,1e-254,1e-253,1e-252,1e-251,1e-250,1e-249,1e-248,1e-247,1e-246,1e-245,1e-244,1e-243,1e-242,1e-241,1e-240, + 1e-239,1e-238,1e-237,1e-236,1e-235,1e-234,1e-233,1e-232,1e-231,1e-230,1e-229,1e-228,1e-227,1e-226,1e-225,1e-224,1e-223,1e-222,1e-221,1e-220, + 1e-219,1e-218,1e-217,1e-216,1e-215,1e-214,1e-213,1e-212,1e-211,1e-210,1e-209,1e-208,1e-207,1e-206,1e-205,1e-204,1e-203,1e-202,1e-201,1e-200, + 1e-199,1e-198,1e-197,1e-196,1e-195,1e-194,1e-193,1e-192,1e-191,1e-190,1e-189,1e-188,1e-187,1e-186,1e-185,1e-184,1e-183,1e-182,1e-181,1e-180, + 1e-179,1e-178,1e-177,1e-176,1e-175,1e-174,1e-173,1e-172,1e-171,1e-170,1e-169,1e-168,1e-167,1e-166,1e-165,1e-164,1e-163,1e-162,1e-161,1e-160, + 1e-159,1e-158,1e-157,1e-156,1e-155,1e-154,1e-153,1e-152,1e-151,1e-150,1e-149,1e-148,1e-147,1e-146,1e-145,1e-144,1e-143,1e-142,1e-141,1e-140, + 1e-139,1e-138,1e-137,1e-136,1e-135,1e-134,1e-133,1e-132,1e-131,1e-130,1e-129,1e-128,1e-127,1e-126,1e-125,1e-124,1e-123,1e-122,1e-121,1e-120, + 1e-119,1e-118,1e-117,1e-116,1e-115,1e-114,1e-113,1e-112,1e-111,1e-110,1e-109,1e-108,1e-107,1e-106,1e-105,1e-104,1e-103,1e-102,1e-101,1e-100, + 1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80, + 1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62, 1e-61, 1e-60, + 1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, + 1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20, + 1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e+0, + 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, + 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, + 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, + 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, + 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, + 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, + 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, + 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, + 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, + 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, + 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, + 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, + 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, + 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, + 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, + 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 + }; + RAPIDJSON_ASSERT(n <= 308); + return n < -308 ? 0.0 : e[n + 308]; +} + +} // namespace internal +} // namespace rapidjson + +#endif // RAPIDJSON_POW10_ diff --git a/cpp-netlib/libs/network/example/twitter/rapidjson/internal/stack.h b/cpp-netlib/libs/network/example/twitter/rapidjson/internal/stack.h new file mode 100644 index 00000000..6faefdee --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/rapidjson/internal/stack.h @@ -0,0 +1,82 @@ +#ifndef RAPIDJSON_INTERNAL_STACK_H_ +#define RAPIDJSON_INTERNAL_STACK_H_ + +namespace rapidjson { +namespace internal { + +/////////////////////////////////////////////////////////////////////////////// +// Stack + +//! A type-unsafe stack for storing different types of data. +/*! \tparam Allocator Allocator for allocating stack memory. +*/ +template +class Stack { +public: + Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) { + RAPIDJSON_ASSERT(stack_capacity_ > 0); + if (!allocator_) + own_allocator_ = allocator_ = new Allocator(); + stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_); + stack_end_ = stack_ + stack_capacity_; + } + + ~Stack() { + Allocator::Free(stack_); + delete own_allocator_; // Only delete if it is owned by the stack + } + + void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; } + + template + T* Push(size_t count = 1) { + // Expand the stack if needed + if (stack_top_ + sizeof(T) * count >= stack_end_) { + size_t new_capacity = stack_capacity_ * 2; + size_t size = GetSize(); + size_t new_size = GetSize() + sizeof(T) * count; + if (new_capacity < new_size) + new_capacity = new_size; + stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity); + stack_capacity_ = new_capacity; + stack_top_ = stack_ + size; + stack_end_ = stack_ + stack_capacity_; + } + T* ret = (T*)stack_top_; + stack_top_ += sizeof(T) * count; + return ret; + } + + template + T* Pop(size_t count) { + RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); + stack_top_ -= count * sizeof(T); + return (T*)stack_top_; + } + + template + T* Top() { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return (T*)(stack_top_ - sizeof(T)); + } + + template + T* Bottom() { return (T*)stack_; } + + Allocator& GetAllocator() { return *allocator_; } + size_t GetSize() const { /*return stack_top_;*/ return stack_top_ - stack_; } + size_t GetCapacity() const { return stack_capacity_; } + +private: + Allocator* allocator_; + Allocator* own_allocator_; + char *stack_; + char *stack_top_; + char *stack_end_; + size_t stack_capacity_; +}; + +} // namespace internal +} // namespace rapidjson + +#endif // RAPIDJSON_STACK_H_ diff --git a/cpp-netlib/libs/network/example/twitter/rapidjson/internal/strfunc.h b/cpp-netlib/libs/network/example/twitter/rapidjson/internal/strfunc.h new file mode 100644 index 00000000..47b8ac07 --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/rapidjson/internal/strfunc.h @@ -0,0 +1,24 @@ +#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ +#define RAPIDJSON_INTERNAL_STRFUNC_H_ + +namespace rapidjson { +namespace internal { + +//! Custom strlen() which works on different character types. +/*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s Null-terminated input string. + \return Number of characters in the string. + \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. +*/ +template +inline SizeType StrLen(const Ch* s) { + const Ch* p = s; + while (*p != '\0') + ++p; + return SizeType(p - s); +} + +} // namespace internal +} // namespace rapidjson + +#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/cpp-netlib/libs/network/example/twitter/rapidjson/prettywriter.h b/cpp-netlib/libs/network/example/twitter/rapidjson/prettywriter.h new file mode 100644 index 00000000..6f282933 --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/rapidjson/prettywriter.h @@ -0,0 +1,152 @@ +#ifndef RAPIDJSON_PRETTYWRITER_H_ +#define RAPIDJSON_PRETTYWRITER_H_ + +#include "writer.h" + +namespace rapidjson { + +//! Writer with indentation and spacing. +/*! + \tparam Stream Type of ouptut stream. + \tparam Encoding Encoding of both source strings and output. + \tparam Allocator Type of allocator for allocating memory of stack. +*/ +template, typename Allocator = MemoryPoolAllocator<> > +class PrettyWriter : public Writer { +public: + typedef Writer Base; + typedef typename Base::Ch Ch; + + //! Constructor + /*! \param stream Output stream. + \param allocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of + */ + PrettyWriter(Stream& stream, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(stream, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + + //! Set custom indentation. + /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r'). + \param indentCharCount Number of indent characters for each indentation level. + \note The default indentation is 4 spaces. + */ + PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { + RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); + indentChar_ = indentChar; + indentCharCount_ = indentCharCount; + return *this; + } + + //@name Implementation of Handler. + //@{ + + PrettyWriter& Null() { PrettyPrefix(kNullType); Base::WriteNull(); return *this; } + PrettyWriter& Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool(b); return *this; } + PrettyWriter& Int(int i) { PrettyPrefix(kNumberType); Base::WriteInt(i); return *this; } + PrettyWriter& Uint(unsigned u) { PrettyPrefix(kNumberType); Base::WriteUint(u); return *this; } + PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; } + PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; } + PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; } + + PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) { + PrettyPrefix(kStringType); + Base::WriteString(str, length); + return *this; + } + + PrettyWriter& StartObject() { + PrettyPrefix(kObjectType); + new (Base::level_stack_.template Push()) typename Base::Level(false); + Base::WriteStartObject(); + return *this; + } + + PrettyWriter& EndObject(SizeType memberCount = 0) { + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty) { + Base::stream_.Put('\n'); + WriteIndent(); + } + Base::WriteEndObject(); + return *this; + } + + PrettyWriter& StartArray() { + PrettyPrefix(kArrayType); + new (Base::level_stack_.template Push()) typename Base::Level(true); + Base::WriteStartArray(); + return *this; + } + + PrettyWriter& EndArray(SizeType memberCount = 0) { + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty) { + Base::stream_.Put('\n'); + WriteIndent(); + } + Base::WriteEndArray(); + return *this; + } + + //@} + + //! Simpler but slower overload. + PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); } + +protected: + void PrettyPrefix(Type type) { + if (Base::level_stack_.GetSize() != 0) { // this value is not at root + typename Base::Level* level = Base::level_stack_.template Top(); + + if (level->inArray) { + if (level->valueCount > 0) { + Base::stream_.Put(','); // add comma if it is not the first element in array + Base::stream_.Put('\n'); + } + else + Base::stream_.Put('\n'); + WriteIndent(); + } + else { // in object + if (level->valueCount > 0) { + if (level->valueCount % 2 == 0) { + Base::stream_.Put(','); + Base::stream_.Put('\n'); + } + else { + Base::stream_.Put(':'); + Base::stream_.Put(' '); + } + } + else + Base::stream_.Put('\n'); + + if (level->valueCount % 2 == 0) + WriteIndent(); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else + RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); + } + + void WriteIndent() { + size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; + PutN(Base::stream_, indentChar_, count); + } + + Ch indentChar_; + unsigned indentCharCount_; +}; + +} // namespace rapidjson + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/cpp-netlib/libs/network/example/twitter/rapidjson/rapidjson.h b/cpp-netlib/libs/network/example/twitter/rapidjson/rapidjson.h new file mode 100644 index 00000000..14b0c3a3 --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/rapidjson/rapidjson.h @@ -0,0 +1,512 @@ +#ifndef RAPIDJSON_RAPIDJSON_H_ +#define RAPIDJSON_RAPIDJSON_H_ + +// Copyright (c) 2011 Milo Yip (miloyip@gmail.com) +// Version 0.1 + +#include // malloc(), realloc(), free() +#include // memcpy() + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_INT64DEFINE + +// Here defines int64_t and uint64_t types in global namespace. +// If user have their own definition, can define RAPIDJSON_NO_INT64DEFINE to disable this. +#ifndef RAPIDJSON_NO_INT64DEFINE +#ifdef _MSC_VER +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif +#endif // RAPIDJSON_NO_INT64TYPEDEF + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ENDIAN +#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine +#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine + +//! Endianness of the machine. +/*! GCC provided macro for detecting endianness of the target machine. But other + compilers may not have this. User can define RAPIDJSON_ENDIAN to either + RAPIDJSON_LITTLEENDIAN or RAPIDJSON_BIGENDIAN. +*/ +#ifndef RAPIDJSON_ENDIAN +#ifdef __BYTE_ORDER__ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +#else +#define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +#endif // __BYTE_ORDER__ +#else +#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN // Assumes little endian otherwise. +#endif +#endif // RAPIDJSON_ENDIAN + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD + +// Enable SSE2 optimization. +//#define RAPIDJSON_SSE2 + +// Enable SSE4.2 optimization. +//#define RAPIDJSON_SSE42 + +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) +#define RAPIDJSON_SIMD +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_SIZETYPEDEFINE + +#ifndef RAPIDJSON_NO_SIZETYPEDEFINE +namespace rapidjson { +//! Use 32-bit array/string indices even for 64-bit platform, instead of using size_t. +/*! User may override the SizeType by defining RAPIDJSON_NO_SIZETYPEDEFINE. +*/ +typedef unsigned SizeType; +} // namespace rapidjson +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ASSERT + +//! Assertion. +/*! By default, rapidjson uses C assert() for assertion. + User can override it by defining RAPIDJSON_ASSERT(x) macro. +*/ +#ifndef RAPIDJSON_ASSERT +#include +#define RAPIDJSON_ASSERT(x) assert(x) +#endif // RAPIDJSON_ASSERT + +namespace rapidjson { + +/////////////////////////////////////////////////////////////////////////////// +// Allocator + +/*! \class rapidjson::Allocator + \brief Concept for allocating, resizing and freeing memory block. + + Note that Malloc() and Realloc() are non-static but Free() is static. + + So if an allocator need to support Free(), it needs to put its pointer in + the header of memory block. + +\code +concept Allocator { + static const bool kNeedFree; //!< Whether this allocator needs to call Free(). + + // Allocate a memory block. + // \param size of the memory block in bytes. + // \returns pointer to the memory block. + void* Malloc(size_t size); + + // Resize a memory block. + // \param originalPtr The pointer to current memory block. Null pointer is permitted. + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) + // \param newSize the new size in bytes. + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); + + // Free a memory block. + // \param pointer to the memory block. Null pointer is permitted. + static void Free(void *ptr); +}; +\endcode +*/ + +/////////////////////////////////////////////////////////////////////////////// +// CrtAllocator + +//! C-runtime library allocator. +/*! This class is just wrapper for standard C library memory routines. + \implements Allocator +*/ +class CrtAllocator { +public: + static const bool kNeedFree = true; + void* Malloc(size_t size) { return malloc(size); } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { return realloc(originalPtr, newSize); } + static void Free(void *ptr) { free(ptr); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// MemoryPoolAllocator + +//! Default memory allocator used by the parser and DOM. +/*! This allocator allocate memory blocks from pre-allocated memory chunks. + + It does not free memory blocks. And Realloc() only allocate new memory. + + The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. + + User may also supply a buffer as the first chunk. + + If the user-buffer is full then additional chunks are allocated by BaseAllocator. + + The user-buffer is not deallocated by this allocator. + + \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. + \implements Allocator +*/ +template +class MemoryPoolAllocator { +public: + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) + + //! Constructor with chunkSize. + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + if (!baseAllocator_) + ownBaseAllocator_ = baseAllocator_ = new BaseAllocator(); + AddChunk(chunk_capacity_); + } + + //! Constructor with user-supplied buffer. + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. + + The user buffer will not be deallocated when this allocator is destructed. + + \param buffer User supplied buffer. + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(char *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + RAPIDJSON_ASSERT(buffer != 0); + RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); + chunkHead_ = (ChunkHeader*)buffer; + chunkHead_->capacity = size - sizeof(ChunkHeader); + chunkHead_->size = 0; + chunkHead_->next = 0; + } + + //! Destructor. + /*! This deallocates all memory chunks, excluding the user-supplied buffer. + */ + ~MemoryPoolAllocator() { + Clear(); + delete ownBaseAllocator_; + } + + //! Deallocates all memory chunks, excluding the user-supplied buffer. + void Clear() { + while(chunkHead_ != 0 && chunkHead_ != (ChunkHeader *)userBuffer_) { + ChunkHeader* next = chunkHead_->next; + baseAllocator_->Free(chunkHead_); + chunkHead_ = next; + } + } + + //! Computes the total capacity of allocated memory chunks. + /*! \return total capacity in bytes. + */ + size_t Capacity() { + size_t capacity = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + capacity += c->capacity; + return capacity; + } + + //! Computes the memory blocks allocated. + /*! \return total used bytes. + */ + size_t Size() { + size_t size = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + size += c->size; + return size; + } + + //! Allocates a memory block. (concept Allocator) + void* Malloc(size_t size) { + if (chunkHead_->size + size > chunkHead_->capacity) + AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); + + char *buffer = (char *)(chunkHead_ + 1) + chunkHead_->size; + chunkHead_->size += size; + return buffer; + } + + //! Resizes a memory block (concept Allocator) + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + if (originalPtr == 0) + return Malloc(newSize); + + // Do not shrink if new size is smaller than original + if (originalSize >= newSize) + return originalPtr; + + // Simply expand it if it is the last allocation and there is sufficient space + if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) { + size_t increment = newSize - originalSize; + if (chunkHead_->size + increment <= chunkHead_->capacity) { + chunkHead_->size += increment; + return originalPtr; + } + } + + // Realloc process: allocate and copy memory, do not free original buffer. + void* newBuffer = Malloc(newSize); + RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. + return memcpy(newBuffer, originalPtr, originalSize); + } + + //! Frees a memory block (concept Allocator) + static void Free(void *ptr) {} // Do nothing + +private: + //! Creates a new chunk. + /*! \param capacity Capacity of the chunk in bytes. + */ + void AddChunk(size_t capacity) { + ChunkHeader* chunk = (ChunkHeader*)baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity); + chunk->capacity = capacity; + chunk->size = 0; + chunk->next = chunkHead_; + chunkHead_ = chunk; + } + + static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. + + //! Chunk header for perpending to each chunk. + /*! Chunks are stored as a singly linked list. + */ + struct ChunkHeader { + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). + size_t size; //!< Current size of allocated memory in bytes. + ChunkHeader *next; //!< Next chunk in the linked list. + }; + + ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. + char *userBuffer_; //!< User supplied buffer. + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. + BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. +}; + +/////////////////////////////////////////////////////////////////////////////// +// Encoding + +/*! \class rapidjson::Encoding + \brief Concept for encoding of Unicode characters. + +\code +concept Encoding { + typename Ch; //! Type of character. + + //! \brief Encode a Unicode codepoint to a buffer. + //! \param buffer pointer to destination buffer to store the result. It should have sufficient size of encoding one character. + //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. + //! \returns the pointer to the next character after the encoded data. + static Ch* Encode(Ch *buffer, unsigned codepoint); +}; +\endcode +*/ + +/////////////////////////////////////////////////////////////////////////////// +// UTF8 + +//! UTF-8 encoding. +/*! http://en.wikipedia.org/wiki/UTF-8 + \tparam CharType Type for storing 8-bit UTF-8 data. Default is char. + \implements Encoding +*/ +template +struct UTF8 { + typedef CharType Ch; + + static Ch* Encode(Ch *buffer, unsigned codepoint) { + if (codepoint <= 0x7F) + *buffer++ = codepoint & 0xFF; + else if (codepoint <= 0x7FF) { + *buffer++ = 0xC0 | ((codepoint >> 6) & 0xFF); + *buffer++ = 0x80 | ((codepoint & 0x3F)); + } + else if (codepoint <= 0xFFFF) { + *buffer++ = 0xE0 | ((codepoint >> 12) & 0xFF); + *buffer++ = 0x80 | ((codepoint >> 6) & 0x3F); + *buffer++ = 0x80 | (codepoint & 0x3F); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + *buffer++ = 0xF0 | ((codepoint >> 18) & 0xFF); + *buffer++ = 0x80 | ((codepoint >> 12) & 0x3F); + *buffer++ = 0x80 | ((codepoint >> 6) & 0x3F); + *buffer++ = 0x80 | (codepoint & 0x3F); + } + return buffer; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF16 + +//! UTF-16 encoding. +/*! http://en.wikipedia.org/wiki/UTF-16 + \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. + \implements Encoding +*/ +template +struct UTF16 { + typedef CharType Ch; + + static Ch* Encode(Ch* buffer, unsigned codepoint) { + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + *buffer++ = codepoint; + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + *buffer++ = (v >> 10) + 0xD800; + *buffer++ = (v & 0x3FF) + 0xDC00; + } + return buffer; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF32 + +//! UTF-32 encoding. +/*! http://en.wikipedia.org/wiki/UTF-32 + \tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. + \implements Encoding +*/ +template +struct UTF32 { + typedef CharType Ch; + + static Ch *Encode(Ch* buffer, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + *buffer++ = codepoint; + return buffer; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// Stream + +/*! \class rapidjson::Stream + \brief Concept for reading and writing characters. + + For read-only stream, no need to implement PutBegin(), Put() and PutEnd(). + + For write-only stream, only need to implement Put(). + +\code +concept Stream { + typename Ch; //!< Character type of the stream. + + //! Read the current character from stream without moving the read cursor. + Ch Peek() const; + + //! Read the current character from stream and moving the read cursor to next character. + Ch Take(); + + //! Get the current read cursor. + //! \return Number of characters read from start. + size_t Tell(); + + //! Begin writing operation at the current read pointer. + //! \return The begin writer pointer. + Ch* PutBegin(); + + //! Write a character. + void Put(Ch c); + + //! End the writing operation. + //! \param begin The begin write pointer returned by PutBegin(). + //! \return Number of characters written. + size_t PutEnd(Ch* begin); +} +\endcode +*/ + +//! Put N copies of a character to a stream. +template +inline void PutN(Stream& stream, Ch c, size_t n) { + for (size_t i = 0; i < n; i++) + stream.Put(c); +} + +/////////////////////////////////////////////////////////////////////////////// +// StringStream + +//! Read-only string stream. +/*! \implements Stream +*/ +template +struct GenericStringStream { + typedef typename Encoding::Ch Ch; + + GenericStringStream(const Ch *src) : src_(src), head_(src) {} + + Ch Peek() const { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() const { return src_ - head_; } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch c) { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch* begin) { RAPIDJSON_ASSERT(false); return 0; } + + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. +}; + +typedef GenericStringStream > StringStream; + +/////////////////////////////////////////////////////////////////////////////// +// InsituStringStream + +//! A read-write string stream. +/*! This string stream is particularly designed for in-situ parsing. + \implements Stream +*/ +template +struct GenericInsituStringStream { + typedef typename Encoding::Ch Ch; + + GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} + + // Read + Ch Peek() { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() { return src_ - head_; } + + // Write + Ch* PutBegin() { return dst_ = src_; } + void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } + size_t PutEnd(Ch* begin) { return dst_ - begin; } + + Ch* src_; + Ch* dst_; + Ch* head_; +}; + +typedef GenericInsituStringStream > InsituStringStream; + +/////////////////////////////////////////////////////////////////////////////// +// Type + +//! Type of JSON value +enum Type { + kNullType = 0, //!< null + kFalseType = 1, //!< false + kTrueType = 2, //!< true + kObjectType = 3, //!< object + kArrayType = 4, //!< array + kStringType = 5, //!< string + kNumberType = 6, //!< number +}; + +} // namespace rapidjson + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/cpp-netlib/libs/network/example/twitter/rapidjson/reader.h b/cpp-netlib/libs/network/example/twitter/rapidjson/reader.h new file mode 100644 index 00000000..a0164978 --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/rapidjson/reader.h @@ -0,0 +1,664 @@ +#ifndef RAPIDJSON_READER_H_ +#define RAPIDJSON_READER_H_ + +// Copyright (c) 2011 Milo Yip (miloyip@gmail.com) +// Version 0.1 + +#include "rapidjson.h" +#include "internal/pow10.h" +#include "internal/stack.h" +#include + +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#endif + +#ifndef RAPIDJSON_PARSE_ERROR +#define RAPIDJSON_PARSE_ERROR(msg, offset) do { parseError_ = msg; errorOffset_ = offset; longjmp(jmpbuf_, 1); } while(false) +#endif + +namespace rapidjson { + +/////////////////////////////////////////////////////////////////////////////// +// ParseFlag + +//! Combination of parseFlags +enum ParseFlag { + kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer. + kParseInsituFlag = 1 //!< In-situ(destructive) parsing. +}; + +/////////////////////////////////////////////////////////////////////////////// +// Handler + +/*! \class rapidjson::Handler + \brief Concept for receiving events from GenericReader upon parsing. +\code +concept Handler { + typename Ch; + + void Null(); + void Bool(bool b); + void Int(int i); + void Uint(unsigned i); + void Int64(int64_t i); + void Uint64(uint64_t i); + void Double(double d); + void String(const Ch* str, SizeType length, bool copy); + void StartObject(); + void EndObject(SizeType memberCount); + void StartArray(); + void EndArray(SizeType elementCount); +}; +\endcode +*/ +/////////////////////////////////////////////////////////////////////////////// +// BaseReaderHandler + +//! Default implementation of Handler. +/*! This can be used as base class of any reader handler. + \implements Handler +*/ +template > +struct BaseReaderHandler { + typedef typename Encoding::Ch Ch; + + void Default() {} + void Null() { Default(); } + void Bool(bool b) { Default(); } + void Int(int i) { Default(); } + void Uint(unsigned i) { Default(); } + void Int64(int64_t i) { Default(); } + void Uint64(uint64_t i) { Default(); } + void Double(double d) { Default(); } + void String(const Ch* str, SizeType length, bool copy) { Default(); } + void StartObject() { Default(); } + void EndObject(SizeType memberCount) { Default(); } + void StartArray() { Default(); } + void EndArray(SizeType elementCount) { Default(); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// SkipWhitespace + +//! Skip the JSON white spaces in a stream. +/*! \param stream A input stream for skipping white spaces. + \note This function has SSE2/SSE4.2 specialization. +*/ +template +void SkipWhitespace(Stream& stream) { + Stream s = stream; // Use a local copy for optimization + while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') + s.Take(); + stream = s; +} + +#ifdef RAPIDJSON_SSE42 +//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + static const char whitespace[16] = " \n\r\t"; + __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]); + + for (;;) { + __m128i s = _mm_loadu_si128((const __m128i *)p); + unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); + if (r == 0) // all 16 characters are whitespace + p += 16; + else { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + if (_BitScanForward(&offset, r)) + return p + offset; +#else + if (r != 0) + return p + __builtin_ffs(r) - 1; +#endif + } + } +} + +#elif defined(RAPIDJSON_SSE2) + +//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + static const char whitespaces[4][17] = { + " ", + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", + "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; + + __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); + __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); + __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); + __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); + + for (;;) { + __m128i s = _mm_loadu_si128((const __m128i *)p); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = ~_mm_movemask_epi8(x); + if (r == 0) // all 16 characters are whitespace + p += 16; + else { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + if (_BitScanForward(&offset, r)) + return p + offset; +#else + if (r != 0) + return p + __builtin_ffs(r) - 1; +#endif + } + } +} + +#endif // RAPIDJSON_SSE2 + +#ifdef RAPIDJSON_SIMD +//! Template function specialization for InsituStringStream +template<> inline void SkipWhitespace(InsituStringStream& stream) { + stream.src_ = const_cast(SkipWhitespace_SIMD(stream.src_)); +} + +//! Template function specialization for StringStream +template<> inline void SkipWhitespace(StringStream& stream) { + stream.src_ = SkipWhitespace_SIMD(stream.src_); +} +#endif // RAPIDJSON_SIMD + +/////////////////////////////////////////////////////////////////////////////// +// GenericReader + +//! SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator. +/*! GenericReader parses JSON text from a stream, and send events synchronously to an + object implementing Handler concept. + + It needs to allocate a stack for storing a single decoded string during + non-destructive parsing. + + For in-situ parsing, the decoded string is directly written to the source + text string, no temporary buffer is required. + + A GenericReader object can be reused for parsing multiple JSON text. + + \tparam Encoding Encoding of both the stream and the parse output. + \tparam Allocator Allocator type for stack. +*/ +template > +class GenericReader { +public: + typedef typename Encoding::Ch Ch; + + //! Constructor. + /*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) + \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) + */ + GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {} + + //! Parse JSON text. + /*! \tparam parseFlags Combination of ParseFlag. + \tparam Stream Type of input stream. + \tparam Handler Type of handler which must implement Handler concept. + \param stream Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + bool Parse(Stream& stream, Handler& handler) { + parseError_ = 0; + errorOffset_ = 0; + + if (setjmp(jmpbuf_)) { + stack_.Clear(); + return false; + } + + SkipWhitespace(stream); + + if (stream.Peek() == '\0') + RAPIDJSON_PARSE_ERROR("Text only contains white space(s)", stream.Tell()); + else { + switch (stream.Peek()) { + case '{': ParseObject(stream, handler); break; + case '[': ParseArray(stream, handler); break; + default: RAPIDJSON_PARSE_ERROR("Expect either an object or array at root", stream.Tell()); return false; + } + SkipWhitespace(stream); + + if (stream.Peek() != '\0') + RAPIDJSON_PARSE_ERROR("Nothing should follow the root object or array.", stream.Tell()); + } + + return true; + } + + bool HasParseError() const { return parseError_ != 0; } + const char* GetParseError() const { return parseError_; } + size_t GetErrorOffset() const { return errorOffset_; } + +private: + // Parse object: { string : value, ... } + template + void ParseObject(Stream& stream, Handler& handler) { + RAPIDJSON_ASSERT(stream.Peek() == '{'); + stream.Take(); // Skip '{' + handler.StartObject(); + SkipWhitespace(stream); + + if (stream.Peek() == '}') { + stream.Take(); + handler.EndObject(0); // empty object + return; + } + + for (SizeType memberCount = 0;;) { + if (stream.Peek() != '"') { + RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", stream.Tell()); + break; + } + + ParseString(stream, handler); + SkipWhitespace(stream); + + if (stream.Take() != ':') { + RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", stream.Tell()); + break; + } + SkipWhitespace(stream); + + ParseValue(stream, handler); + SkipWhitespace(stream); + + ++memberCount; + + switch(stream.Take()) { + case ',': SkipWhitespace(stream); break; + case '}': handler.EndObject(memberCount); return; + default: RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", stream.Tell()); + } + } + } + + // Parse array: [ value, ... ] + template + void ParseArray(Stream& stream, Handler& handler) { + RAPIDJSON_ASSERT(stream.Peek() == '['); + stream.Take(); // Skip '[' + handler.StartArray(); + SkipWhitespace(stream); + + if (stream.Peek() == ']') { + stream.Take(); + handler.EndArray(0); // empty array + return; + } + + for (SizeType elementCount = 0;;) { + ParseValue(stream, handler); + ++elementCount; + SkipWhitespace(stream); + + switch (stream.Take()) { + case ',': SkipWhitespace(stream); break; + case ']': handler.EndArray(elementCount); return; + default: RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", stream.Tell()); + } + } + } + + template + void ParseNull(Stream& stream, Handler& handler) { + RAPIDJSON_ASSERT(stream.Peek() == 'n'); + stream.Take(); + + if (stream.Take() == 'u' && stream.Take() == 'l' && stream.Take() == 'l') + handler.Null(); + else + RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1); + } + + template + void ParseTrue(Stream& stream, Handler& handler) { + RAPIDJSON_ASSERT(stream.Peek() == 't'); + stream.Take(); + + if (stream.Take() == 'r' && stream.Take() == 'u' && stream.Take() == 'e') + handler.Bool(true); + else + RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell()); + } + + template + void ParseFalse(Stream& stream, Handler& handler) { + RAPIDJSON_ASSERT(stream.Peek() == 'f'); + stream.Take(); + + if (stream.Take() == 'a' && stream.Take() == 'l' && stream.Take() == 's' && stream.Take() == 'e') + handler.Bool(false); + else + RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1); + } + + // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). + template + unsigned ParseHex4(Stream& stream) { + Stream s = stream; // Use a local copy for optimization + unsigned codepoint = 0; + for (int i = 0; i < 4; i++) { + Ch c = s.Take(); + codepoint <<= 4; + codepoint += c; + if (c >= '0' && c <= '9') + codepoint -= '0'; + else if (c >= 'A' && c <= 'F') + codepoint -= 'A' - 10; + else if (c >= 'a' && c <= 'f') + codepoint -= 'a' - 10; + else { + RAPIDJSON_PARSE_ERROR("Incorrect hex digit after \\u escape", s.Tell() - 1); + return 0; + } + } + stream = s; // Restore stream + return codepoint; + } + + // Parse string, handling the prefix and suffix double quotes and escaping. + template + void ParseString(Stream& stream, Handler& handler) { +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + static const Ch escape[256] = { + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, + 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, + 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 + }; +#undef Z16 + + Stream s = stream; // Use a local copy for optimization + RAPIDJSON_ASSERT(s.Peek() == '\"'); + s.Take(); // Skip '\"' + Ch *head; + SizeType len; + if (parseFlags & kParseInsituFlag) + head = s.PutBegin(); + else + len = 0; + +#define RAPIDJSON_PUT(x) \ + do { \ + if (parseFlags & kParseInsituFlag) \ + s.Put(x); \ + else { \ + *stack_.template Push() = x; \ + ++len; \ + } \ + } while(false) + + for (;;) { + Ch c = s.Take(); + if (c == '\\') { // Escape + Ch e = s.Take(); + if ((sizeof(Ch) == 1 || e < 256) && escape[(unsigned char)e]) + RAPIDJSON_PUT(escape[(unsigned char)e]); + else if (e == 'u') { // Unicode + unsigned codepoint = ParseHex4(s); + if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair + if (s.Take() != '\\' || s.Take() != 'u') { + RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", s.Tell() - 2); + return; + } + unsigned codepoint2 = ParseHex4(s); + if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) { + RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", s.Tell() - 2); + return; + } + codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } + + Ch buffer[4]; + SizeType count = SizeType(Encoding::Encode(buffer, codepoint) - &buffer[0]); + + if (parseFlags & kParseInsituFlag) + for (SizeType i = 0; i < count; i++) + s.Put(buffer[i]); + else { + memcpy(stack_.template Push(count), buffer, count * sizeof(Ch)); + len += count; + } + } + else { + RAPIDJSON_PARSE_ERROR("Unknown escape character", stream.Tell() - 1); + return; + } + } + else if (c == '"') { // Closing double quote + if (parseFlags & kParseInsituFlag) { + size_t length = s.PutEnd(head); + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + RAPIDJSON_PUT('\0'); // null-terminate the string + handler.String(head, SizeType(length), false); + } + else { + RAPIDJSON_PUT('\0'); + handler.String(stack_.template Pop(len), len - 1, true); + } + stream = s; // restore stream + return; + } + else if (c == '\0') { + RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", stream.Tell() - 1); + return; + } + else if ((unsigned)c < 0x20) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", stream.Tell() - 1); + return; + } + else + RAPIDJSON_PUT(c); // Normal character, just copy + } +#undef RAPIDJSON_PUT + } + + template + void ParseNumber(Stream& stream, Handler& handler) { + Stream s = stream; // Local copy for optimization + // Parse minus + bool minus = false; + if (s.Peek() == '-') { + minus = true; + s.Take(); + } + + // Parse int: zero / ( digit1-9 *DIGIT ) + unsigned i; + bool try64bit = false; + if (s.Peek() == '0') { + i = 0; + s.Take(); + } + else if (s.Peek() >= '1' && s.Peek() <= '9') { + i = s.Take() - '0'; + + if (minus) + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i >= 214748364) { // 2^31 = 2147483648 + if (i != 214748364 || s.Peek() > '8') { + try64bit = true; + break; + } + } + i = i * 10 + (s.Take() - '0'); + } + else + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i >= 429496729) { // 2^32 - 1 = 4294967295 + if (i != 429496729 || s.Peek() > '5') { + try64bit = true; + break; + } + } + i = i * 10 + (s.Take() - '0'); + } + } + else { + RAPIDJSON_PARSE_ERROR("Expect a value here.", stream.Tell()); + return; + } + + // Parse 64bit int + uint64_t i64; + bool useDouble = false; + if (try64bit) { + i64 = i; + if (minus) + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i64 >= 922337203685477580uLL) // 2^63 = 9223372036854775808 + if (i64 != 922337203685477580uLL || s.Peek() > '8') { + useDouble = true; + break; + } + i64 = i64 * 10 + (s.Take() - '0'); + } + else + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i64 >= 1844674407370955161uLL) // 2^64 - 1 = 18446744073709551615 + if (i64 != 1844674407370955161uLL || s.Peek() > '5') { + useDouble = true; + break; + } + i64 = i64 * 10 + (s.Take() - '0'); + } + } + + // Force double for big integer + double d; + if (useDouble) { + d = (double)i64; + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (d >= 1E307) { + RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell()); + return; + } + d = d * 10 + (s.Take() - '0'); + } + } + + // Parse frac = decimal-point 1*DIGIT + int expFrac = 0; + if (s.Peek() == '.') { + if (!useDouble) { + d = try64bit ? (double)i64 : (double)i; + useDouble = true; + } + s.Take(); + + if (s.Peek() >= '0' && s.Peek() <= '9') { + d = d * 10 + (s.Take() - '0'); + --expFrac; + } + else { + RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", stream.Tell()); + return; + } + + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (expFrac > -16) { + d = d * 10 + (s.Peek() - '0'); + --expFrac; + } + s.Take(); + } + } + + // Parse exp = e [ minus / plus ] 1*DIGIT + int exp = 0; + if (s.Peek() == 'e' || s.Peek() == 'E') { + if (!useDouble) { + d = try64bit ? (double)i64 : (double)i; + useDouble = true; + } + s.Take(); + + bool expMinus = false; + if (s.Peek() == '+') + s.Take(); + else if (s.Peek() == '-') { + s.Take(); + expMinus = true; + } + + if (s.Peek() >= '0' && s.Peek() <= '9') { + exp = s.Take() - '0'; + while (s.Peek() >= '0' && s.Peek() <= '9') { + exp = exp * 10 + (s.Take() - '0'); + if (exp > 308) { + RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell()); + return; + } + } + } + else { + RAPIDJSON_PARSE_ERROR("At least one digit in exponent", s.Tell()); + return; + } + + if (expMinus) + exp = -exp; + } + + // Finish parsing, call event according to the type of number. + if (useDouble) { + d *= internal::Pow10(exp + expFrac); + handler.Double(minus ? -d : d); + } + else { + if (try64bit) { + if (minus) + handler.Int64(-(int64_t)i64); + else + handler.Uint64(i64); + } + else { + if (minus) + handler.Int(-(int)i); + else + handler.Uint(i); + } + } + + stream = s; // restore stream + } + + // Parse any JSON value + template + void ParseValue(Stream& stream, Handler& handler) { + switch (stream.Peek()) { + case 'n': ParseNull (stream, handler); break; + case 't': ParseTrue (stream, handler); break; + case 'f': ParseFalse (stream, handler); break; + case '"': ParseString(stream, handler); break; + case '{': ParseObject(stream, handler); break; + case '[': ParseArray (stream, handler); break; + default : ParseNumber(stream, handler); + } + } + + static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. + internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. + jmp_buf jmpbuf_; //!< setjmp buffer for fast exit from nested parsing function calls. + const char* parseError_; + size_t errorOffset_; +}; // class GenericReader + +//! Reader with UTF8 encoding and default allocator. +typedef GenericReader > Reader; + +} // namespace rapidjson + +#endif // RAPIDJSON_READER_H_ diff --git a/cpp-netlib/libs/network/example/twitter/rapidjson/stringbuffer.h b/cpp-netlib/libs/network/example/twitter/rapidjson/stringbuffer.h new file mode 100644 index 00000000..d69e3d1c --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/rapidjson/stringbuffer.h @@ -0,0 +1,49 @@ +#ifndef RAPIDJSON_STRINGBUFFER_H_ +#define RAPIDJSON_STRINGBUFFER_H_ + +#include "rapidjson.h" +#include "internal/stack.h" + +namespace rapidjson { + +//! Represents an in-memory output stream. +/*! + \tparam Encoding Encoding of the stream. + \tparam Allocator type for allocating memory buffer. + \implements Stream +*/ +template +struct GenericStringBuffer { + typedef typename Encoding::Ch Ch; + + GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + + void Put(Ch c) { *stack_.template Push() = c; } + + void Clear() { stack_.Clear(); } + + const char* GetString() const { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.template Pop(1); + + return stack_.template Bottom(); + } + + size_t Size() const { return stack_.Size(); } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; +}; + +typedef GenericStringBuffer > StringBuffer; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { + memset(stream.stack_.Push(n), c, n * sizeof(c)); +} + +} // namespace rapidjson + +#endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/cpp-netlib/libs/network/example/twitter/rapidjson/writer.h b/cpp-netlib/libs/network/example/twitter/rapidjson/writer.h new file mode 100644 index 00000000..1d028cc6 --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/rapidjson/writer.h @@ -0,0 +1,224 @@ +#ifndef RAPIDJSON_WRITER_H_ +#define RAPIDJSON_WRITER_H_ + +#include "rapidjson.h" +#include "internal/stack.h" +#include "internal/strfunc.h" +#include // snprintf() or _sprintf_s() +#include // placement new + +namespace rapidjson { + +//! JSON writer +/*! Writer implements the concept Handler. + It generates JSON text by events to an output stream. + + User may programmatically calls the functions of a writer to generate JSON text. + + On the other side, a writer can also be passed to objects that generates events, + + for example Reader::Parse() and Document::Accept(). + + \tparam Stream Type of ouptut stream. + \tparam Encoding Encoding of both source strings and output. + \implements Handler +*/ +template, typename Allocator = MemoryPoolAllocator<> > +class Writer { +public: + typedef typename Encoding::Ch Ch; + + Writer(Stream& stream, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : + stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level)) {} + + //@name Implementation of Handler + //@{ + Writer& Null() { Prefix(kNullType); WriteNull(); return *this; } + Writer& Bool(bool b) { Prefix(b ? kTrueType : kFalseType); WriteBool(b); return *this; } + Writer& Int(int i) { Prefix(kNumberType); WriteInt(i); return *this; } + Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u); return *this; } + Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64); return *this; } + Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; } + Writer& Double(double d) { Prefix(kNumberType); WriteDouble(d); return *this; } + + Writer& String(const Ch* str, SizeType length, bool copy = false) { + Prefix(kStringType); + WriteString(str, length); + return *this; + } + + Writer& StartObject() { + Prefix(kObjectType); + new (level_stack_.template Push()) Level(false); + WriteStartObject(); + return *this; + } + + Writer& EndObject(SizeType memberCount = 0) { + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + WriteEndObject(); + return *this; + } + + Writer& StartArray() { + Prefix(kArrayType); + new (level_stack_.template Push()) Level(true); + WriteStartArray(); + return *this; + } + + Writer& EndArray(SizeType elementCount = 0) { + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + WriteEndArray(); + return *this; + } + //@} + + //! Simpler but slower overload. + Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); } + +protected: + //! Information for each nested level + struct Level { + Level(bool inArray) : inArray(inArray), valueCount(0) {} + bool inArray; //!< true if in array, otherwise in object + size_t valueCount; //!< number of values in this level + }; + + static const size_t kDefaultLevelDepth = 32; + + void WriteNull() { + stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l'); + } + + void WriteBool(bool b) { + if (b) { + stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e'); + } + else { + stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e'); + } + } + + void WriteInt(int i) { + if (i < 0) { + stream_.Put('-'); + i = -i; + } + WriteUint((unsigned)i); + } + + void WriteUint(unsigned u) { + char buffer[10]; + char *p = buffer; + do { + *p++ = (u % 10) + '0'; + u /= 10; + } while (u > 0); + + do { + --p; + stream_.Put(*p); + } while (p != buffer); + } + + void WriteInt64(int64_t i64) { + if (i64 < 0) { + stream_.Put('-'); + i64 = -i64; + } + WriteUint64((uint64_t)i64); + } + + void WriteUint64(uint64_t u64) { + char buffer[20]; + char *p = buffer; + do { + *p++ = char(u64 % 10) + '0'; + u64 /= 10; + } while (u64 > 0); + + do { + --p; + stream_.Put(*p); + } while (p != buffer); + } + + //! \todo Optimization with custom double-to-string converter. + void WriteDouble(double d) { + char buffer[100]; +#if _MSC_VER + int ret = sprintf_s(buffer, sizeof(buffer), "%g", d); +#else + int ret = snprintf(buffer, sizeof(buffer), "%g", d); +#endif + RAPIDJSON_ASSERT(ret >= 1); + for (int i = 0; i < ret; i++) + stream_.Put(buffer[i]); + } + + void WriteString(const Ch* str, SizeType length) { + static const char hexDigits[] = "0123456789ABCDEF"; + static const char escape[256] = { +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 + 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 + Z16, Z16, // 30~4F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF +#undef Z16 + }; + + stream_.Put('\"'); + for (const Ch* p = str; p != str + length; ++p) { + if ((sizeof(Ch) == 1 || *p < 256) && escape[(unsigned char)*p]) { + stream_.Put('\\'); + stream_.Put(escape[(unsigned char)*p]); + if (escape[(unsigned char)*p] == 'u') { + stream_.Put('0'); + stream_.Put('0'); + stream_.Put(hexDigits[(*p) >> 4]); + stream_.Put(hexDigits[(*p) & 0xF]); + } + } + else + stream_.Put(*p); + } + stream_.Put('\"'); + } + + void WriteStartObject() { stream_.Put('{'); } + void WriteEndObject() { stream_.Put('}'); } + void WriteStartArray() { stream_.Put('['); } + void WriteEndArray() { stream_.Put(']'); } + + void Prefix(Type type) { + if (level_stack_.GetSize() != 0) { // this value is not at root + Level* level = level_stack_.template Top(); + if (level->valueCount > 0) { + if (level->inArray) + stream_.Put(','); // add comma if it is not the first element in array + else // in object + stream_.Put((level->valueCount % 2 == 0) ? ',' : ':'); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else + RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); + } + + Stream& stream_; + internal::Stack level_stack_; +}; + +} // namespace rapidjson + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/cpp-netlib/libs/network/example/twitter/search.cpp b/cpp-netlib/libs/network/example/twitter/search.cpp new file mode 100644 index 00000000..c9f8f138 --- /dev/null +++ b/cpp-netlib/libs/network/example/twitter/search.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Glyn Matthews 2011, 2012. +// 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 +#include "rapidjson/rapidjson.h" +#include "rapidjson/document.h" +#include + +// This example uses the Twitter Search API. +// +// https://dev.twitter.com/docs/using-search + +int main(int argc, char *argv[]) { + using namespace boost::network; + using namespace rapidjson; + + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + try { + http::client client; + + uri::uri base_uri("http://search.twitter.com/search.json"); + + std::cout << "Searching Twitter for query: " << argv[1] << std::endl; + uri::uri search; + search << base_uri << uri::query("q", uri::encoded(argv[1])); + http::client::request request(search); + http::client::response response = client.get(request); + + Document d; + if (!d.Parse<0>(response.body().c_str()).HasParseError()) { + const Value &results = d["results"]; + for (SizeType i = 0; i < results.Size(); ++i) { + const Value &user = results[i]["from_user_name"]; + const Value &text = results[i]["text"]; + std::cout << "From: " << user.GetString() << std::endl << " " + << text.GetString() << std::endl << std::endl; + } + } + } + catch (std::exception &e) { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/cpp-netlib/libs/network/example/uri_builder.cpp b/cpp-netlib/libs/network/example/uri_builder.cpp new file mode 100644 index 00000000..03e4b073 --- /dev/null +++ b/cpp-netlib/libs/network/example/uri_builder.cpp @@ -0,0 +1,20 @@ +// Copyright (c) Glyn Matthews 2011. +// 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 +#include +#include + +using namespace boost::network; + +int main(int argc, char *argv[]) { + + uri::uri url; + url << uri::scheme("http") << uri::host("www.github.com") + << uri::path("/cpp-netlib"); + std::cout << url << std::endl; + + return 0; +} diff --git a/cpp-netlib/libs/network/experiment/CMakeLists.txt b/cpp-netlib/libs/network/experiment/CMakeLists.txt new file mode 100644 index 00000000..7fdd3b87 --- /dev/null +++ b/cpp-netlib/libs/network/experiment/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright 2013 Google, Inc. +# Copyright 2010 Dean Michael Berris +# 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) + +# Commenting this out until it's ready for prime-time later on. +# include_directories(${CPP-NETLIB_SOURCE_DIR}) +# set(CMAKE_BUILD_TYPE Release) +# if (Boost_FOUND) +# add_executable(cpp-netlib-utils_base64_experiment utils_base64_experiment.cpp) +# target_link_libraries(cpp-netlib-utils_base64_experiment ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +# if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") +# target_link_libraries(cpp-netlib-utils_base64_experiment rt) +# endif() +# set_target_properties(cpp-netlib-utils_base64_experiment +# PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/tests) +# endif() diff --git a/cpp-netlib/libs/network/experiment/utils/base64-standalone.hpp b/cpp-netlib/libs/network/experiment/utils/base64-standalone.hpp new file mode 100644 index 00000000..6e3430af --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils/base64-standalone.hpp @@ -0,0 +1,423 @@ +#ifndef BOOST_NETWORK_UTILS_BASE64_STANDALONE_HPP +#define BOOST_NETWORK_UTILS_BASE64_STANDALONE_HPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace utils { + +// Implements a BASE64 converter working on an iterator range from the +// scratch. If the input sequence does not end at the three-byte +// boundary, +// the last encoded value part is remembered in an encoding state to be +// able +// to continue with the next chunk; the BASE64 encoding processes the +// input +// by byte-triplets. +// +// Summarized interface: +// +// struct state { +// bool empty () const; +// void clear(); +// } +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output, State & rest) +// OutputIterator encode_rest(OutputIterator output, State & rest) +// OutputIterator encode(InputRange const & input, OutputIterator output, +// State & rest) +// OutputIterator encode(char const * value, OutputIterator output, +// state & rest) +// std::basic_string encode(InputRange const & value, State & rest) +// std::basic_string encode(char const * value, state & rest) +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output) +// OutputIterator encode(InputRange const & input, OutputIterator output) +// OutputIterator encode(char const * value, OutputIterator output) +// std::basic_string encode(InputRange const & value) +// std::basic_string encode(char const * value) { + +namespace base64_standalone { + +namespace detail { + +// Picks a character from the output alphabet for another 6-bit value +// from the input sequence to encode. +template +char encode_value(Value value) { + static char const* encoding = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + "+/"; + return encoding[static_cast(value)]; +} + +} // namespace detail + +// Stores the state after processing the last chunk by the encoder. If +// the +// chunk byte-length is not divisible by three, the last (incomplete) +// value +// quantum canot be encoded right away; it has to wait for the next +// chunk +// of octets which will be processed joined (as if the trailing rest +// from +// the previous one was at its beinning). +template +struct state { + state() : triplet_index(0), last_encoded_value(0) {} + + state(state const& source) + : triplet_index(source.triplet_index), + last_encoded_value(source.last_encoded_value) {} + + bool empty() const { return triplet_index == 0; } + + void clear() { + // indicate that no rest has been left in the last encoded value + // and no padding is needed for the encoded output + triplet_index = 0; + // the last encoded value, which may have been left from the last + // encoding step, must be zeroed too; it is important before the + // next encoding begins, because it works as a cyclic buffer and + // must start empty - with zero + last_encoded_value = 0; + } + + unsigned short padding_length() const { + // the fewer octets from the triplet processed, the more characters + // needed as padding padding - that is why the complement here + return triplet_index ? 3 - triplet_index : 0; + } + + protected: + // number of the octet in the incomplete quantum, which has been + // processed the last time; 0 means that the previous quantum was + // complete 3 octets, 1 that just one octet was avalable and 2 that + // two octets were available + unsigned char triplet_index; + // the value made of the previously shifted and or-ed octets which + // was not completely split to 6-bit codes, because the last quantum + // did not stop on the boundary of three octets + Value last_encoded_value; + + // encoding of an input chunk needs to read and update the state + template + friend OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output, State& rest); + + // finishing the encoding needs to read and clear the state + template + friend OutputIterator encode_rest(OutputIterator output, State& rest); +}; + +// Encodes an input sequence to BASE64 writing it to the output iterator +// and stopping if the last input tree-octet quantum was not complete, +// in +// which case it stores the state for the later continuation, when +// another +// input chunk is ready for the encoding. The encoding must be finished +// by calling the encode_rest after processing the last chunk. +// +// std::vector buffer = ...; +// std::basic_string result; +// std::back_insert_iterator > appender(result); +// base64::state rest; +// base64::encode(buffer.begin(), buffer.end(), appender, rest); +// ... +// base64::encode_rest(appender, rest); +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output, State& rest) { + typedef typename iterator_value::type value_type; + // continue with the rest of the last chunk - 2 or 4 bits which + // are already shifted to the left and need to be or-ed with the + // continuing data up to the target 6 bits + value_type encoded_value = rest.last_encoded_value; + // if the previous chunk stopped at encoding the first (1) or the + // second + // (2) octet of the three-byte quantum, jump to the right place, + // otherwise start the loop with an empty encoded value buffer + switch (rest.triplet_index) { + // this loop processes the input sequence of bit-octets by bits, + // shifting the current_value (used as a cyclic buffer) left and + // or-ing next bits there, while pulling the bit-sextets from the + // high word of the current_value + for (value_type current_value;;) { + case 0: + // if the input sequence is empty or reached its end at the + // 3-byte boundary, finish with an empty encoding state + if (begin == end) { + rest.triplet_index = 0; + // the last encoded value is not interesting - it would not + // be used, because processing of the next chunk will start + // at the 3-byte boundary + rest.last_encoded_value = 0; + return output; + } + // read the first octet from the current triplet + current_value = *begin++; + // use just the upper 6 bits to encode it to the target alphabet + encoded_value = (current_value & 0xfc) >> 2; + *output++ = detail::encode_value(encoded_value); + // shift the remaining two bits up to make place for the upoming + // part of the next octet + encoded_value = (current_value & 0x03) << 4; + case 1: + // if the input sequence reached its end after the first octet + // from the quantum triplet, store the encoding state and finish + if (begin == end) { + rest.triplet_index = 1; + rest.last_encoded_value = encoded_value; + return output; + } + // read the second first octet from the current triplet + current_value = *begin++; + // combine the upper four bits (as the lower part) with the + // previous two bits to encode it to the target alphabet + encoded_value |= (current_value & 0xf0) >> 4; + *output++ = detail::encode_value(encoded_value); + // shift the remaining four bits up to make place for the + // upoming + // part of the next octet + encoded_value = (current_value & 0x0f) << 2; + case 2: + // if the input sequence reached its end after the second octet + // from the quantum triplet, store the encoding state and finish + if (begin == end) { + rest.triplet_index = 2; + rest.last_encoded_value = encoded_value; + return output; + } + // read the third octet from the current triplet + current_value = *begin++; + // combine the upper two bits (as the lower part) with the + // previous four bits to encode it to the target alphabet + encoded_value |= (current_value & 0xc0) >> 6; + *output++ = detail::encode_value(encoded_value); + // encode the remaining 6 bits to the target alphabet + encoded_value = current_value & 0x3f; + *output++ = detail::encode_value(encoded_value); + } + } + return output; +} + +// Finishes encoding of the previously processed chunks. If their total +// byte-length was divisible by three, nothing is needed, if not, the +// last +// quantum will be encoded as if padded with zeroes, which will be +// indicated +// by appending '=' characters to the output. This method must be +// always +// used at the end of encoding, if the previous chunks were encoded by +// the +// method overload accepting the encoding state. +// +// std::vector buffer = ...; +// std::basic_string result; +// std::back_insert_iterator > appender(result); +// base64::state rest; +// base64::encode(buffer.begin(), buffer.end(), appender, rest); +// ... +// base64::encode_rest(appender, rest); +template +OutputIterator encode_rest(OutputIterator output, State& rest) { + if (!rest.empty()) { + // process the last part of the trailing octet (either 4 or 2 bits) + // as if the input was padded with zeros - without or-ing the next + // input value to it; it has been already shifted to the left + *output++ = detail::encode_value(rest.last_encoded_value); + // at least one padding '=' will be always needed - at least two + // bits are missing in the finally encoded 6-bit value + *output++ = '='; + // if the last octet was the first in the triplet (the index was + // 1), four bits are missing in the finally encoded 6-bit value; + // another '=' character is needed for the another two bits + if (rest.triplet_index < 2) *output++ = '='; + // clear the state all the time to make sure that another call to + // the encode_rest would not cause damage; the last encoded value, + // which may have been left there, must be zeroed too; it is + // important before the next encoding begins, because it works as + // a cyclic buffer and must start empty - with zero + rest.clear(); + } + return output; +} + +// Encodes a part of an input sequence specified by the pair of begin +// and +// end iterators.to BASE64 writing it to the output iterator. If its +// total +// byte-length was not divisible by three, the output will be padded by +// the +// '=' characters. If you encode an input consisting of mutiple chunks, +// use the method overload maintaining the encoding state. +// +// std::vector buffer = ...; +// std::basic_string result; +// base64::encode(buffer.begin(), buffer.end(), +// std::back_inserter(result)); +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output) { + state::type> rest; + output = encode(begin, end, output, rest); + return encode_rest(output, rest); +} + +// Encodes an entire input sequence to BASE64, which either supports +// begin() +// and end() methods returning boundaries of the sequence or the +// boundaries +// can be computed by the Boost::Range, writing it to the output +// iterator +// and stopping if the last input tree-octet quantum was not complete, +// in +// which case it stores the state for the later continuation, when +// another +// input chunk is ready for the encoding. The encoding must be finished +// by calling the encode_rest after processing the last chunk. +// +// Warning: Buffers identified by C-pointers are processed including +// their +// termination character, if they have any. This is unexpected at least +// for the storing literals, which have a specialization here to avoid +// it. +// +// std::vector buffer = ...; +// std::basic_string result; +// std::back_insert_iterator > appender(result); +// base64::state rest; +// base64::encode(buffer, appender, rest); +// ... +// base64::encode_rest(appender, rest); +template +OutputIterator encode(InputRange const& input, OutputIterator output, + State& rest) { + return encode(boost::begin(input), boost::end(input), output, rest); +} + +// Encodes an entire string literal to BASE64, writing it to the output +// iterator and stopping if the last input tree-octet quantum was not +// complete, in which case it stores the state for the later +// continuation, +// when another input chunk is ready for the encoding. The encoding +// must +// be finished by calling the encode_rest after processing the last +// chunk. +// +// The string literal is encoded without processing its terminating zero +// character, which is the usual expectation. +// +// std::basic_string result; +// std::back_insert_iterator > appender(result); +// base64::state rest; +// base64::encode("ab", appender, rest); +// ... +// base64::encode_rest(appender, rest); +template +OutputIterator encode(char const* value, OutputIterator output, + state& rest) { + return encode(value, value + strlen(value), output, rest); +} + +// Encodes an entire input sequence to BASE64 writing it to the output +// iterator, which either supports begin() and end() methods returning +// boundaries of the sequence or the boundaries can be computed by the +// Boost::Range. If its total byte-length was not divisible by three, +// the output will be padded by the '=' characters. If you encode an +// input consisting of mutiple chunks, use the method overload +// maintaining +// the encoding state. +// +// Warning: Buffers identified by C-pointers are processed including +// their +// termination character, if they have any. This is unexpected at least +// for the storing literals, which have a specialization here to avoid +// it. +// +// std::vector buffer = ...; +// std::basic_string result; +// base64::encode(buffer, std::back_inserter(result)); +template +OutputIterator encode(InputRange const& value, OutputIterator output) { + return encode(boost::begin(value), boost::end(value), output); +} + +// Encodes an entire string literal to BASE64 writing it to the output +// iterator. If its total length (without the trailing zero) was not +// divisible by three, the output will be padded by the '=' characters. +// If you encode an input consisting of mutiple chunks, use the method +// overload maintaining the encoding state. +// +// The string literal is encoded without processing its terminating zero +// character, which is the usual expectation. +// +// std::basic_string result; +// base64::encode("ab", std::back_inserter(result)); +template +OutputIterator encode(char const* value, OutputIterator output) { + return encode(value, value + strlen(value), output); +} + +// Encodes an entire input sequence to BASE64 returning the result as +// string, which either supports begin() and end() methods returning +// boundaries of the sequence or the boundaries can be computed by the +// Boost::Range. If its total byte-length was not divisible by three, +// the output will be padded by the '=' characters. If you encode an +// input consisting of mutiple chunks, use other method maintaining +// the encoding state writing to an output iterator. +// +// Warning: Buffers identified by C-pointers are processed including +// their +// termination character, if they have any. This is unexpected at least +// for the storing literals, which have a specialization here to avoid +// it. +// +// std::vector buffer = ...; +// std::basic_string result = base64::encode(buffer); +template +std::basic_string encode(InputRange const& value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +// Encodes an entire string literal to BASE64 returning the result as +// string. If its total byte-length was not divisible by three, the +// output will be padded by the '=' characters. If you encode an +// input consisting of mutiple chunks, use other method maintaining +// the encoding state writing to an output iterator. +// +// The string literal is encoded without processing its terminating zero +// character, which is the usual expectation. +// +// std::basic_string result = base64::encode("ab"); +template +std::basic_string encode(char const* value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +// the function overloads for string literals encode the input without +// the terminating zero, which is usually expected, because the trailing +// zero byte is not considered a part of the string value; the overloads +// foran input range would wrap the string literal by Boost.Range and +// encodethe full memory occupated by the string literal - including the +// unwanted last zero byte + +} // namespace base64_standalone + +} // namespace utils +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_UTILS_BASE64_STANDALONE_HPP diff --git a/cpp-netlib/libs/network/experiment/utils/base64-stateful_buffer.hpp b/cpp-netlib/libs/network/experiment/utils/base64-stateful_buffer.hpp new file mode 100644 index 00000000..794149e6 --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils/base64-stateful_buffer.hpp @@ -0,0 +1,215 @@ +#ifndef BOOST_NETWORK_UTILS_BASE64_STATEFUL_BUFFER_HPP +#define BOOST_NETWORK_UTILS_BASE64_STATEFUL_BUFFER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace utils { + +// Uses base64_from_binary and transform_width to implement a BASE64 +// converter working on an iterator range. Because the transform_width +// encodes immediately every input byte, while the BASE64 encoding +// processes +// the input by byte-triplets, if the input sequence does not end at the +// three-byte boundary, the rest is remembered in an encoding state to +// be able to continue with the next chunk. It uses an internal buffer +// of 4095 input octets to be able to read the input by octet-triplets. +// +// Summarized interface: +// +// struct state { +// bool empty () const; +// void clear(); +// } +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output, State & rest) +// OutputIterator encode_rest(OutputIterator output, State & rest) +// OutputIterator encode(InputRange const & input, OutputIterator output, +// State & rest) +// OutputIterator encode(char const * value, OutputIterator output, +// state & rest) +// std::basic_string encode(InputRange const & value, State & rest) +// std::basic_string encode(char const * value, state & rest) +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output) +// OutputIterator encode(InputRange const & input, OutputIterator output) +// OutputIterator encode(char const * value, OutputIterator output) +// std::basic_string encode(InputRange const & value) +// std::basic_string encode(char const * value) { + +namespace base64_stateful_buffer { + +// force using the ostream_iterator from boost::archive to write wide +// characters reliably, althoth wchar_t may not be a native character +// type +using namespace boost::archive::iterators; + +template +struct state { + state() : size(0) {} + + state(state const& source) : data(source.data), size(source.size) {} + + bool empty() const { return size == 0; } + + void clear() { size = 0; } + + private: + typedef boost::array data_type; + typedef typename data_type::const_iterator const_iterator_type; + + template + void fill(InputIterator begin, InputIterator end) { + // make sure that there is always zero padding for the incomplete + // triplet; the encode will read three bytes from the vector + data.fill(0); + size = std::copy(begin, end, data.begin()) - data.begin(); + } + + template + OutputIterator write(OutputIterator output) { + return std::copy(data.begin(), data.begin() + size, output); + } + + const_iterator_type begin() const { return data.begin(); } + + const_iterator_type end() const { return data.begin() + size; } + + data_type data; + std::size_t size; + + template + friend OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output, State& rest); + template + friend OutputIterator encode_rest(OutputIterator output, State& rest); +}; + +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output, State& rest) { + typedef typename iterator_value::type value_type; + // declare the buffer type for 1365 octet triplets; make sure that the + // number is divisible by three if you change it (!) + const std::size_t BufferSize = 4095; + BOOST_STATIC_ASSERT(BufferSize / 3 * 3 == BufferSize); + typedef boost::array buffer_type; + // declare the encoding iterator type + typedef base64_from_binary > base64_text; + if (begin != end) { + // declare the buffer, a variable to remmeber its size and the size + // which can be encoded (the nearest lower size divisible by three) + buffer_type buffer; + std::size_t buffer_size = 0, encode_size = 0; + // if the previous state contained an incomplete octet triplet, put + // it to the start of the buffer to get it prepended to the input + if (!rest.empty()) { + buffer_size = rest.size; + rest.write(buffer.begin()); + rest.clear(); + } + // iterate over the entire input + while (begin != end) { + // fill the buffer with the input as much as possible + while (begin != end && buffer_size < buffer.size()) + buffer[buffer_size++] = *begin++; + // if the buffer could not be filled completely, compute + // the size which can be encoded immediately. + encode_size = buffer_size / 3 * 3; + if (encode_size > 0) { + // encode the buffer part of the size divisible by three + base64_text base64_begin(buffer.begin()), + base64_end(buffer.begin() + encode_size); + output = std::copy(base64_begin, base64_end, output); + // zero the buffer size to prepare for the next iteration + buffer_size = 0; + } + } + // if the complete buffer could not be encoded, store the last + // incomplete octet triplet to the transiting state + if (buffer_size > encode_size) + rest.fill(buffer.begin() + encode_size, buffer.begin() + buffer_size); + } + return output; +} + +template +OutputIterator encode_rest(OutputIterator output, State& rest) { + typedef typename State::const_iterator_type iterator_type; + // declare the encoding iterator type + typedef base64_from_binary > base64_text; + if (!rest.empty()) { + // encode the incomplete octet triplet using zeros as padding + // (an artificial input continuation) + base64_text base64_begin(rest.begin()), base64_end(rest.end()); + output = std::copy(base64_begin, base64_end, output); + // at least one padding '=' will be always needed - at least two + // bits are missing in the finally encoded 6-bit value + if (rest.size > 0) { + *output++ = '='; + // if the last octet was the first in the triplet (the index was, + // four bits are missing in the finally encoded 6-bit value; + // another '=' character is needed for the another two bits + if (rest.size == 1) *output++ = '='; + } + rest.clear(); + } + return output; +} + +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output) { + state::type> rest; + output = encode(begin, end, output, rest); + return encode_rest(output, rest); +} + +template +OutputIterator encode(InputRange const& value, OutputIterator output) { + return encode(boost::begin(value), boost::end(value), output); +} + +template +OutputIterator encode(char const* value, OutputIterator output) { + return encode(value, value + strlen(value), output); +} + +template +std::basic_string encode(InputRange const& value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +template +std::basic_string encode(char const* value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +// the function overloads for string literals encode the input without +// the terminating zero, which is usually expected, because the trailing +// zero byte is not considered a part of the string value; the overloads +// foran input range would wrap the string literal by Boost.Range and +// encodethe full memory occupated by the string literal - including the +// unwanted last zero byte + +} // namespace base64_stateful_buffer + +} // namespace utils +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_UTILS_BASE64_STATEFUL_BUFFER_HPP diff --git a/cpp-netlib/libs/network/experiment/utils/base64-stateful_iterator.hpp b/cpp-netlib/libs/network/experiment/utils/base64-stateful_iterator.hpp new file mode 100644 index 00000000..1c69e4ca --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils/base64-stateful_iterator.hpp @@ -0,0 +1,167 @@ +#ifndef BOOST_NETWORK_UTILS_BASE64_STATEFUL_ITERATOR_HPP +#define BOOST_NETWORK_UTILS_BASE64_STATEFUL_ITERATOR_HPP + +#include +#include "iterators/stateful_transform_width.hpp" +#include "iterators/iterator_with_state.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace utils { + +// Uses base64_from_binary and stateful_transform_width to implement a +// BASE64 +// converter working on an iterator range. Based on transform_width, the +// stateful_transform_width relies on the end iterator and the encoding +// state +// stored in the transformed iterator; usually by using the iterator +// adaptor +// - iterator_with_state. Storing the encoding state in the transformed +// iterator practically means adapting every such iterator, but the +// iterators +// which wrap the stateful_transform_width, like the base64_from_binary, +// do +// not need to be re-declared with an extra constructor to pass the end +// iterator and the encoding state to an extended transform_width. +// +// Summarized interface: +// +// struct state { +// bool empty () const; +// void clear(); +// unsigned short padding_length() const; +// } +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output, State & rest) +// OutputIterator encode_rest(OutputIterator output, State & rest) +// OutputIterator encode(InputRange const & input, OutputIterator output, +// State & rest) +// OutputIterator encode(char const * value, OutputIterator output, +// state & rest) +// std::basic_string encode(InputRange const & value, State & rest) +// std::basic_string encode(char const * value, state & rest) +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output) +// OutputIterator encode(InputRange const & input, OutputIterator output) +// OutputIterator encode(char const * value, OutputIterator output) +// std::basic_string encode(InputRange const & value) +// std::basic_string encode(char const * value) { + +namespace base64_stateful_iterator { + +// force using the ostream_iterator from boost::archive to write wide +// characters reliably, althoth wchar_t may not be a native character +// type +using namespace boost::archive::iterators; +using namespace boost::network::utils::iterators; + +template +struct state : public state_for_transform_width { + typedef state this_t; + typedef state_for_transform_width super_t; + + state() {} + state(this_t const& source) : super_t(source) {} + + unsigned short padding_length() const { + // the BASE64 encoding unit consists of 6 bits; if the 8-bit + // input cannot be completely divided to 6-bit chunks, 2 or + // 4 bits can remain, which the bit_count returns as displacement + // of the 8-bit value (right shift length) - 6 or 4 + unsigned short bits = super_t::bit_count(); + return bits > 0 ? 6 / bits : 0; + } +}; + +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output, State& rest) { + typedef boost::iterator_with_state stateful_input; + // declare the encoding iterator type + typedef base64_from_binary > + base64_input; + // declare the stateful transforming itarators + stateful_input stateful_begin(begin, end, rest), stateful_end(end); + // declare the iterator to transform the encoded 6-bit units to the + // BASE64 alphabet + base64_input base64_begin(stateful_begin), base64_end(stateful_end); + return std::copy(base64_begin, base64_end, output); +} + +template +OutputIterator encode_rest(OutputIterator output, State& rest) { + unsigned short padding_length = rest.padding_length(); + if (padding_length > 0) { + typedef typename State::value_type value_type; + // declare the input padding type and the adapted iterator including + // the encoding state for it - see below + typedef boost::array pillow_input; + typedef boost::iterator_with_state stateful_input; + // declare the encoding iterator type + typedef base64_from_binary > + base64_input; + // although containing encoding state to continue with the next + // chunk, the stateful_transform_width still reads from the input + // iterator and needs the complete quantum for the encoding; the + // zero padding will make for an artifitial input ending here + pillow_input pillow = {{0, 0}}; + stateful_input stateful_begin(pillow.begin(), pillow.end(), rest); + base64_input base64_begin(stateful_begin); + *output++ = *base64_begin; + if (padding_length > 0) { + *output++ = '='; + if (padding_length > 1) *output++ = '='; + } + } + return output; +} + +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output) { + state::type> rest; + output = encode(begin, end, output, rest); + return encode_rest(output, rest); +} + +template +OutputIterator encode(InputRange const& input, OutputIterator output) { + return encode(boost::begin(input), boost::end(input), output); +} + +template +OutputIterator encode(char const* value, OutputIterator output) { + return encode(value, value + strlen(value), output); +} + +template +std::basic_string encode(InputRange const& value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +template +std::basic_string encode(char const* value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +} // namespace base64_stateful_iterator + +} // namespace utils +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_UTILS_BASE64_STATEFUL_ITERATOR_HPP diff --git a/cpp-netlib/libs/network/experiment/utils/base64-stateful_transform.hpp b/cpp-netlib/libs/network/experiment/utils/base64-stateful_transform.hpp new file mode 100644 index 00000000..3b7002f1 --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils/base64-stateful_transform.hpp @@ -0,0 +1,169 @@ +#ifndef BOOST_NETWORK_UTILS_BASE64_STATEFUL_TRANSFORM_HPP +#define BOOST_NETWORK_UTILS_BASE64_STATEFUL_TRANSFORM_HPP + +#include "iterators/stateful_base64_from_binary.hpp" +#include "iterators/transform_width_with_state.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace utils { + +// Uses stateful_base64_from_binary and transform_width_with_state to +// implement a BASE64 converter working on an iterator range. Based on +// transform_width, the transform_width_with_state stores the end iterator +// and the encoding state to be able to process the encoding input by +// chunks. The stateful_base64_from_binary just passes through the +// constructor parameters, which the transform_width_with_state needs. +// Storing the encoding state in the transforming iterator makes any +// input iterator transformable without adapting, but the iterators which +// wrap it, like the base64_from_binary, needs to be re-declared with +// the extra constructor. +// +// Summarized interface: +// +// struct state { +// bool empty () const; +// void clear(); +// unsigned short padding_length() const; +// } +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output, State & rest) +// OutputIterator encode_rest(OutputIterator output, State & rest) +// OutputIterator encode(InputRange const & input, OutputIterator output, +// State & rest) +// OutputIterator encode(char const * value, OutputIterator output, +// state & rest) +// std::basic_string encode(InputRange const & value, State & rest) +// std::basic_string encode(char const * value, state & rest) +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output) +// OutputIterator encode(InputRange const & input, OutputIterator output) +// OutputIterator encode(char const * value, OutputIterator output) +// std::basic_string encode(InputRange const & value) +// std::basic_string encode(char const * value) { + +namespace base64_stateful_transform { + +// force using the ostream_iterator from boost::archive to write wide +// characters reliably, althoth wchar_t may not be a native character +// type +using namespace boost::archive::iterators; +using namespace boost::network::utils::iterators; + +template +struct state : public transform_width_state { + typedef transform_width_state super_t; + + state() {} + state(state const& source) : super_t(source) {} + + unsigned short padding_length() const { + // the BASE64 encoding unit consists of 6 bits; if the 8-bit + // input cannot be completely divided to 6-bit chunks, 2 or + // 4 bits can remain, which the bit_count returns as displacement + // of the 8-bit value (right shift length) - 6 or 4 + unsigned short bits = super_t::bit_count(); + return bits > 0 ? 6 / bits : 0; + } +}; + +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output, State& rest) { + // declare the transforming iterator type + typedef transform_width_with_state stateful_input; + // declare the encoding iterator type + typedef stateful_base64_from_binary base64_input; + base64_input base64_begin(begin, end, rest), base64_end(end); + return std::copy(base64_begin, base64_end, output); +} + +template +OutputIterator encode_rest(OutputIterator output, State& rest) { + unsigned short padding_length = rest.padding_length(); + if (padding_length > 0) { + typedef typename State::value_type value_type; + // declare the input padding type and the adapted iterator including + // the encoding state for it - see below + typedef boost::array pillow_input; + // declare the transforming iterator type + typedef transform_width_with_state stateful_input; + // declare the encoding iterator type + typedef stateful_base64_from_binary base64_input; + // although containing encoding state to continue with the next + // chunk, the stateful_transform_width still reads from the input + // iterator and needs the complete quantum for the encoding; the + // zero padding will make for an artifitial input ending here + pillow_input pillow = {{0, 0}}; + base64_input base64_begin(pillow.begin(), pillow.end(), rest), + base64_end(pillow.end()); + *output++ = *base64_begin; + if (padding_length > 0) { + *output++ = '='; + if (padding_length > 1) *output++ = '='; + } + } + return output; +} + +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output) { + state::type> rest; + output = encode(begin, end, output, rest); + return encode_rest(output, rest); +} + +template +OutputIterator encode(InputRange const& input, OutputIterator output, + State& rest) { + return encode(boost::begin(input), boost::end(input), output, rest); +} + +template +OutputIterator encode(char const* value, OutputIterator output, + state& rest) { + return encode(value, value + strlen(value), output, rest); +} + +template +OutputIterator encode(InputRange const& input, OutputIterator output) { + return encode(boost::begin(input), boost::end(input), output); +} + +template +OutputIterator encode(char const* value, OutputIterator output) { + return encode(value, value + strlen(value), output); +} + +template +std::basic_string encode(InputRange const& value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +template +std::basic_string encode(char const* value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +} // namespace base64_stateful_transform + +} // namespace utils +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_UTILS_BASE64_STATEFUL_TRANSFORM_HPP diff --git a/cpp-netlib/libs/network/experiment/utils/base64-stateless.hpp b/cpp-netlib/libs/network/experiment/utils/base64-stateless.hpp new file mode 100644 index 00000000..79b04604 --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils/base64-stateless.hpp @@ -0,0 +1,97 @@ +#ifndef BOOST_NETWORK_UTILS_BASE64_STATELESS_HPP +#define BOOST_NETWORK_UTILS_BASE64_STATELESS_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace network { +namespace utils { + +// Uses base64_from_binary and transform_width to implement a BASE64 +// converter working on an iterator range. While it is a nice example +// of code reuse, the input sequence must either end at the three-byte +// boundary or be padded with a zero, otherwise the transforming +// iterator tries to read behind the end iterator. +// +// Summarized interface: +// +// OutputIterator encode(InputIterator begin, InputIterator end, +// OutputIterator output) +// OutputIterator encode(InputRange const & input, OutputIterator output) +// OutputIterator encode(char const * value, OutputIterator output) +// std::basic_string encode(InputRange const & value) +// std::basic_string encode(char const * value) + +namespace base64_stateless { + +// force using the ostream_iterator from boost::archive to write wide +// characters reliably, although wchar_t may not be a native character +// type +using namespace boost::archive::iterators; + +template +OutputIterator encode(InputIterator begin, InputIterator end, + OutputIterator output) { + // declare the encoding iterator type + typedef base64_from_binary > base64_text; + base64_text base64_begin(begin), base64_end(end); + // iterate through the input by the encoding iterator one encoded + // unit at a time to learn how many units were encoded without + // requiring neither the input iterators nor the output ones to be + // random access iterators (supporting subtraction end - begin) + std::size_t encoded_count = 0; + while (base64_begin != base64_end) { + *output++ = *base64_begin++; + ++encoded_count; + } + // the encoding iterator advanced so many times as is the encoded + // output + // size, but the padding is determined by the number of bytes in the + // last + // (incomplete) input byte-triplet; first compute the input length and + // then how many trailing bytes followed the last complete quantum + std::size_t incomplete_length = encoded_count * 6 / 8 % 3; + if (incomplete_length > 0) { + *output++ = '='; + if (incomplete_length < 2) *output++ = '='; + } + return output; +} + +template +OutputIterator encode(InputRange const& input, OutputIterator output) { + return encode(boost::begin(input), boost::end(input), output); +} + +template +OutputIterator encode(char const* value, OutputIterator output) { + return encode(value, value + strlen(value), output); +} + +template +std::basic_string encode(InputRange const& value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +template +std::basic_string encode(char const* value) { + std::basic_string result; + encode(value, std::back_inserter(result)); + return result; +} + +} // namespace base64_stateless + +} // namespace utils +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_UTILS_BASE64_STATELESS_HPP diff --git a/cpp-netlib/libs/network/experiment/utils/iterators/iterator_with_state.hpp b/cpp-netlib/libs/network/experiment/utils/iterators/iterator_with_state.hpp new file mode 100644 index 00000000..09827ba6 --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils/iterators/iterator_with_state.hpp @@ -0,0 +1,77 @@ +#ifndef BOOST_ITERATOR_WITH_STATE_HPP +#define BOOST_ITERATOR_WITH_STATE_HPP + +#include +#include +#include +#include +#include + +// The class iterator_with_state adds storing the end iterator and the +// transforming state to an existing iterator, so that it can be used as +// a base in the transform_width_with_state. + +namespace boost { +template +class iterator_with_state; + +namespace detail { +template +struct iterator_with_state_base { + typedef iterator_adaptor< + iterator_with_state, Iterator, use_default, + typename mpl::if_< + is_convertible::type, + random_access_traversal_tag>, + bidirectional_traversal_tag, use_default>::type> type; +}; +} + +template +class iterator_with_state + : public detail::iterator_with_state_base::type { + typedef typename detail::iterator_with_state_base::type + super_t; + + friend class iterator_core_access; + + public: + iterator_with_state() {} + + typedef State state_type; + + iterator_with_state(Iterator x, Iterator end_, State& state_) + : super_t(x), m_end(end_), m_state(&state_) {} + + iterator_with_state(Iterator x) : super_t(x) {} + + template + iterator_with_state( + iterator_with_state const& t, + typename enable_if_convertible::type* = 0) + : super_t(t.base()), m_end(t.end()), m_state(&t.state()) {} + + Iterator const& end() const { return m_end; } + + State const& state() const { return *m_state; } + + State& state() { return *m_state; } + + private: + void increment() { ++this->base_reference(); } + + void decrement() { --(this->base_reference()); } + + Iterator m_end; + State* m_state; +}; + +template +iterator_with_state make_iterator_with_state( + Iterator x, Iterator end = Iterator(), State state = State()) { + return iterator_with_state(x, end, state); +} + +} // namespace boost + +#endif // BOOST_ITERATOR_WITH_STATE_HPP diff --git a/cpp-netlib/libs/network/experiment/utils/iterators/stateful_base64_from_binary.hpp b/cpp-netlib/libs/network/experiment/utils/iterators/stateful_base64_from_binary.hpp new file mode 100644 index 00000000..c4d5a614 --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils/iterators/stateful_base64_from_binary.hpp @@ -0,0 +1,67 @@ +#ifndef BOOST_NETWORK_UTILS_ITERATORS_STATEFUL_BASE64_FROM_BINARY_HPP +#define BOOST_NETWORK_UTILS_ITERATORS_STATEFUL_BASE64_FROM_BINARY_HPP + +#include +#include +#include +#include +#include + +// The class stateful_base64_from_binary works like base64_from_binary from +// boost/archive/iterators, only expecting an iterator base which supports +// transformng state and needs the end iterator and the state passed to the +// constructor. The transform_width_with_state, for example. + +namespace boost { +namespace network { +namespace utils { +namespace iterators { + +namespace detail { + +template +struct from_6_bit { + typedef CharType result_type; + CharType operator()(CharType t) const { + const char* lookup_table = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "+/"; + BOOST_ASSERT(t < 64); + return lookup_table[static_cast(t)]; + } +}; + +} // namespace detail + +template ::type> +class stateful_base64_from_binary + : public transform_iterator, Base> { + friend class boost::iterator_core_access; + typedef transform_iterator, Base> + super_t; + + public: + template + stateful_base64_from_binary(BOOST_PFTO_WRAPPER(T) start, + BOOST_PFTO_WRAPPER(T) end, State& state) + : super_t( + Base(BOOST_MAKE_PFTO_WRAPPER(static_cast(start)), end, state), + detail::from_6_bit()) {} + template + stateful_base64_from_binary(BOOST_PFTO_WRAPPER(T) start) + : super_t(Base(BOOST_MAKE_PFTO_WRAPPER(static_cast(start))), + detail::from_6_bit()) {} + // intel 7.1 doesn't like default copy constructor + stateful_base64_from_binary(const stateful_base64_from_binary& rhs) + : super_t(Base(rhs.base_reference()), detail::from_6_bit()) {} +}; + +} // namespace iterators +} // namespace utils +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_UTILS_ITERATORS_STATEFUL_BASE64_FROM_BINARY_HPP diff --git a/cpp-netlib/libs/network/experiment/utils/iterators/stateful_transform_width.hpp b/cpp-netlib/libs/network/experiment/utils/iterators/stateful_transform_width.hpp new file mode 100644 index 00000000..68233a8c --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils/iterators/stateful_transform_width.hpp @@ -0,0 +1,206 @@ +#ifndef BOOST_NETWORK_UTILS_ITERATORS_STATEFUL_TRANSFORM_WIDTH_HPP +#define BOOST_NETWORK_UTILS_ITERATORS_STATEFUL_TRANSFORM_WIDTH_HPP + +#include +#include +#include +#include + +// The class stateful_transform_width works like transform_width from +// boost/archive/iterators if the collection of input values can be converted +// to the output without padding the input with zeros. (The total input bit +// count is divisible by the bit size of an output value.) It it cannot, the +// partially encoded last value, which would have to be padded with zero, +// is stored to the state_for_transform_width, which can be used later to +// continue the encoding when another chunk of input values is available. +// The end iterator is needed to detect the end transformation. +// +// The encoding state and the end iterator are owned by the input iterator +// which has to provide access to them. The iterator adaptor +// iterator_with_state is supposed to be used to add this functionality to +// existing iterators. + +namespace boost { +namespace network { +namespace utils { +namespace iterators { + +template +class state_for_transform_width { + public: + typedef Value value_type; + + state_for_transform_width() : m_displacement(0) {} + + state_for_transform_width(state_for_transform_width const &source) + : m_displacement(source.m_displacement), m_buffer(source.m_buffer) {} + + bool empty() const { return bit_count() == 0; } + + void clear() { m_displacement = 0; } + + protected: + unsigned short bit_count() const { + return m_displacement > 0 ? BitsIn - m_displacement : 0; + } + + private: + unsigned short m_displacement; + value_type m_buffer; + + template + friend class stateful_transform_width; +}; + +template < + class Base, int BitsOut, int BitsIn, + class Char = typename boost::iterator_value::type // output character + > +class stateful_transform_width + : public boost::iterator_adaptor< + stateful_transform_width, Base, Char, + single_pass_traversal_tag, Char> { + friend class boost::iterator_core_access; + typedef typename boost::iterator_adaptor< + stateful_transform_width, Base, Char, + single_pass_traversal_tag, Char> super_t; + + typedef stateful_transform_width this_t; + typedef typename iterator_value::type base_value_type; + + Char fill(); + + Char dereference_impl() { + if (!m_full) { + m_current_value = fill(); + m_full = true; + } + return m_current_value; + } + + Char dereference() const { + return const_cast(this)->dereference_impl(); + } + + bool equal(const this_t &rhs) const { + return this->base_reference() == rhs.base_reference(); + } + + void increment() { + m_displacement += BitsOut; + + while (m_displacement >= BitsIn) { + m_displacement -= BitsIn; + if (0 == m_displacement) m_bufferfull = false; + if (!m_bufferfull) ++this->base_reference(); + } + + // detect if the number of bits in the m_buffer is not enough + // to encode a full 6-bit unit - read the next byte from the input + if (m_displacement >= 0 && BitsIn - m_displacement < BitsOut) { + // the following condition is compilable only with this variable + typename this_t::base_type const &end_ = this->base_reference().end(); + if (this->base_reference() != end_) { + // read the next byte from the input or make it zero to + // provide padding to encode th elast byte + m_next_buffer = + ++this->base_reference() != end_ ? *this->base_reference() : 0; + m_nextfull = true; + } + // store the encoding state if we encountered the last byte + if (this->base_reference() == end_) { + typename Base::state_type &state = this->base_reference().state(); + state.m_displacement = m_displacement; + state.m_buffer = m_buffer; + } + } + + m_full = false; + } + + // the most recent encoded character + Char m_current_value; + // number of bits left in current input character buffer + unsigned int m_displacement; + // value to be just encoded and a next value to be encoded + base_value_type m_buffer, m_next_buffer; + // flag to current output character is ready - just used to save time + bool m_full; + // flag to indicate that m_buffer and/or m_nextbuffer have data + bool m_bufferfull, m_nextfull; + + public: + template + stateful_transform_width(BOOST_PFTO_WRAPPER(T) start) + : super_t(Base(BOOST_MAKE_PFTO_WRAPPER(static_cast(start)))), + m_displacement(0), + m_full(false), + m_bufferfull(false), + m_nextfull(false) {} + + stateful_transform_width(const stateful_transform_width &rhs) + : super_t(rhs.base_reference()), + m_current_value(rhs.m_current_value), + m_displacement(rhs.m_displacement), + m_buffer(rhs.m_buffer), + m_next_buffer(rhs.m_next_buffer), + m_full(rhs.m_full), + m_bufferfull(rhs.m_bufferfull), + m_nextfull(rhs.m_nextfull) {} +}; + +template +Char stateful_transform_width::fill() { + typename Base::state_type &state = this->base_reference().state(); + if (!state.empty()) { + // initialize the m_buffer from the state and put the current input + // byte to the m_next_buffer to make it follow right after + m_displacement = state.m_displacement; + m_buffer = state.m_buffer; + m_bufferfull = true; + m_next_buffer = *this->base_reference(); + m_nextfull = true; + state.clear(); + } + Char retval = 0; + unsigned int missing_bits = BitsOut; + for (;;) { + unsigned int bcount; + if (!m_bufferfull) { + // fill the current m_buffer firstly from m_next_buffer if + // available then read the input sequence + if (m_nextfull) { + m_buffer = m_next_buffer; + m_nextfull = false; + } else { + m_buffer = *this->base_reference(); + } + m_bufferfull = true; + bcount = BitsIn; + } else + bcount = BitsIn - m_displacement; + unsigned int i = (std::min)(bcount, missing_bits); + // shift interesting bits to least significant position + unsigned int j = m_buffer >> (bcount - i); + // strip off uninteresting bits + // (note presumption of two's complement arithmetic) + j &= ~(-(1 << i)); + // append then interesting bits to the output value + retval <<= i; + retval |= j; + missing_bits -= i; + if (0 == missing_bits) break; + // if we used a byte from the input sequence and not from the + // prepared m_next_buffer, advance the input sequence iterator + if (!m_nextfull) ++this->base_reference(); + m_bufferfull = false; + } + return retval; +} + +} // namespace iterators +} // namespace utils +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_UTILS_ITERATORS_STATEFUL_TRANSFORM_WIDTH_HPP diff --git a/cpp-netlib/libs/network/experiment/utils/iterators/transform_width_with_state.hpp b/cpp-netlib/libs/network/experiment/utils/iterators/transform_width_with_state.hpp new file mode 100644 index 00000000..f380a7f4 --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils/iterators/transform_width_with_state.hpp @@ -0,0 +1,230 @@ +#ifndef BOOST_NETWORK_UTILS_ITERATORS_TRANSFORM_WIDTH_WITH_STATE_HPP +#define BOOST_NETWORK_UTILS_ITERATORS_TRANSFORM_WIDTH_WITH_STATE_HPP + +#include +#include +#include +#include + +// The class transform_width_with_state works like transform_width from +// boost/archive/iterators if the collection of input values can be converted +// to the output without padding the input with zeros. (The total input bit +// count is divisible by the bit size of an output value.) It it cannot, the +// partially encoded last value, which would have to be padded with zero, +// is stored to the transform_width_state, which can be used later to +// continue the encoding when another chunk of input values is available. +// The end iterator is needed to detect the end transformation. +// +// The encoding state and the end iterator are owned by the transforming +// iterator and they have to be passed to its constructor. Iterator adaptors +// need to propagate the state and the end iterator to the transforming +// iterator's constructor, which is inconvenient. + +namespace boost { +namespace network { +namespace utils { +namespace iterators { + +template +class transform_width_state { + public: + typedef Value value_type; + + transform_width_state() : m_displacement(0) {} + + transform_width_state(transform_width_state const &source) + : m_displacement(source.m_displacement), m_buffer(source.m_buffer) {} + + bool empty() const { return bit_count() == 0; } + + void clear() { m_displacement = 0; } + + protected: + unsigned short bit_count() const { + return m_displacement > 0 ? BitsIn - m_displacement : 0; + } + + private: + unsigned short m_displacement; + value_type m_buffer; + + template + friend class transform_width_with_state; +}; + +template ::type, // output character + class State = transform_width_state< + typename iterator_value::type, BitsOut, BitsIn> > +class transform_width_with_state + : public boost::iterator_adaptor< + transform_width_with_state, Base, Char, + single_pass_traversal_tag, Char> { + friend class boost::iterator_core_access; + typedef typename boost::iterator_adaptor< + transform_width_with_state, Base, Char, + single_pass_traversal_tag, Char> super_t; + + typedef transform_width_with_state this_t; + typedef typename iterator_value::type base_value_type; + + Char fill(); + + Char dereference_impl() { + if (!m_full) { + m_current_value = fill(); + m_full = true; + } + return m_current_value; + } + + Char dereference() const { + return const_cast(this)->dereference_impl(); + } + + bool equal(const this_t &rhs) const { + return this->base_reference() == rhs.base_reference(); + } + + void increment() { + m_displacement += BitsOut; + + while (m_displacement >= BitsIn) { + m_displacement -= BitsIn; + if (0 == m_displacement) m_bufferfull = false; + if (!m_bufferfull) ++this->base_reference(); + } + + // detect if the number of bits in the m_buffer is not enough + // to encode a full 6-bit unit - read the next byte from the input + if (m_displacement >= 0 && BitsIn - m_displacement < BitsOut) { + // the following condition is compilable only with this variable + typename this_t::base_type const &end_ = this->end(); + if (this->base_reference() != end_) { + // read the next byte from the input or make it zero to + // provide padding to encode th elast byte + m_next_buffer = + ++this->base_reference() != end_ ? *this->base_reference() : 0; + m_nextfull = true; + } + // store the encoding state if we encountered the last byte + if (this->base_reference() == end_) { + State &state = this->state(); + state.m_displacement = m_displacement; + state.m_buffer = m_buffer; + } + } + + m_full = false; + } + + Base const &end() const { return m_end; } + + State const &state() const { return *m_state; } + + State &state() { return *m_state; } + + // iterator end for the iterator start sent to the constructor + Base m_end; + // encoding state to use and update + State *m_state; + // the most recent encoded character + Char m_current_value; + // number of bits left in current input character buffer + unsigned int m_displacement; + // value to be just encoded and a next value to be encoded + base_value_type m_buffer, m_next_buffer; + // flag to current output character is ready - just used to save time + bool m_full; + // flag to indicate that m_buffer and/or m_nextbuffer have data + bool m_bufferfull, m_nextfull; + + public: + template + transform_width_with_state(BOOST_PFTO_WRAPPER(T) start, + BOOST_PFTO_WRAPPER(T) end, State &state) + : super_t(Base(BOOST_MAKE_PFTO_WRAPPER(static_cast(start)))), + m_end(end), + m_state(&state), + m_displacement(0), + m_full(false), + m_bufferfull(false), + m_nextfull(false) {} + + template + transform_width_with_state(BOOST_PFTO_WRAPPER(T) start) + : super_t(Base(BOOST_MAKE_PFTO_WRAPPER(static_cast(start)))), + m_displacement(0), + m_full(false), + m_bufferfull(false), + m_nextfull(false) {} + + transform_width_with_state(const transform_width_with_state &rhs) + : super_t(rhs.base_reference()), + m_end(rhs.m_end), + m_state(rhs.m_state), + m_current_value(rhs.m_current_value), + m_displacement(rhs.m_displacement), + m_buffer(rhs.m_buffer), + m_next_buffer(rhs.m_next_buffer), + m_full(rhs.m_full), + m_bufferfull(rhs.m_bufferfull), + m_nextfull(rhs.m_nextfull) {} +}; + +template +Char transform_width_with_state::fill() { + State &state = this->state(); + if (!state.empty()) { + // initialize the m_buffer from the state and put the current input + // byte to the m_next_buffer to make it follow right after + m_displacement = state.m_displacement; + m_buffer = state.m_buffer; + m_bufferfull = true; + m_next_buffer = *this->base_reference(); + m_nextfull = true; + state.clear(); + } + Char retval = 0; + unsigned int missing_bits = BitsOut; + for (;;) { + unsigned int bcount; + if (!m_bufferfull) { + // fill the current m_buffer firstly from m_next_buffer if + // available then read the input sequence + if (m_nextfull) { + m_buffer = m_next_buffer; + m_nextfull = false; + } else { + m_buffer = *this->base_reference(); + } + m_bufferfull = true; + bcount = BitsIn; + } else + bcount = BitsIn - m_displacement; + unsigned int i = (std::min)(bcount, missing_bits); + // shift interesting bits to least significant position + unsigned int j = m_buffer >> (bcount - i); + // strip off uninteresting bits + // (note presumption of two's complement arithmetic) + j &= ~(-(1 << i)); + // append then interesting bits to the output value + retval <<= i; + retval |= j; + missing_bits -= i; + if (0 == missing_bits) break; + // if we used a byte from the input sequence and not from the + // prepared m_next_buffer, advance the input sequence iterator + if (!m_nextfull) ++this->base_reference(); + m_bufferfull = false; + } + return retval; +} + +} // namespace iterators +} // namespace utils +} // namespace network +} // namespace boost + +#endif // BOOST_NETWORK_UTILS_ITERATORS_TRANSFORM_WIDTH_WITH_STATE_HPP diff --git a/cpp-netlib/libs/network/experiment/utils_base64_experiment.cpp b/cpp-netlib/libs/network/experiment/utils_base64_experiment.cpp new file mode 100644 index 00000000..38ebf7fc --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils_base64_experiment.cpp @@ -0,0 +1,120 @@ +#include +#include +#include +#include "utils/base64-standalone.hpp" +// Since we're having issues with libc++ on OS X we're excluding this in the +// meantime if we're using libc++ +#ifndef _LIBCPP_VERSION +#include "utils/base64-stateless.hpp" +#include "utils/base64-stateful_buffer.hpp" +#endif +#include "utils/base64-stateful_iterator.hpp" +#include "utils/base64-stateful_transform.hpp" +#include +#include +#include +#include +#include +#include + +// the main entry point does nothing; the tests are run by constructors +// of testing classes, which are executed by global variables +int main(int argc, char const* argv[]) { return 0; } + +using namespace boost::network::utils; + +// macros to build names of test classes ans gobal runner variables +#define stringify_internal(x) #x +#define stringify(x) stringify_internal(x) +#define concatenate_internal(x, y) x##y +#define concatenate(x, y) concatenate_internal(x, y) + +#ifdef NDEBUG +// testing block sizes (im MB) which let the tests run approximately +// 5s on my machine in the optimized mode +#define single_block_size 160 +#define multiple_block_size 320 +#define multiple_block_count 1280 +#else +// testing block sizes (im MB) which let the tests run approximately +// 5s on my machine in the not optimized mode +#define single_block_size 16 +#define multiple_block_size 64 +#define multiple_block_count 256 +#endif + +// the class name of a test suite; base64 has to be defined as a namespace +// name with an alternative implementation of the base64 encoding interface +#define test_name concatenate(base64, _test) + +// the code which actually performs the encoding; base64 has to be defined +// as a namespace name - see above +#define encode_single_block std::string result = base64::encode(buffer) +#define encode_multiple_blocks \ + std::string result; \ + std::back_insert_iterator result_encoder(result); \ + base64::state rest; \ + for (unsigned block_index = 0; block_index < buffers.size(); \ + ++block_index) { \ + std::vector const& buffer = buffers[block_index]; \ + base64::encode(buffer.begin(), buffer.end(), result_encoder, rest); \ + } \ + base64::encode_rest(result_encoder, rest) + +// testing the code from experimental/base64-stateless.hpp +// NOTE(dberris): Only do this if we're NOT using libc++. +#ifndef _LIBCPP_VERSION +#define base64 base64_stateless +#include "utils_base64_experiment.ipp" +#undef base64 + +// enable the second test case, which encodes the input buffer chunk by chunk +// and remembers the encoding state to be able to continue +#define base64_with_state + +// testing the code from experimental/base64-stateful_buffer.hpp +#define base64 base64_stateful_buffer +#include "utils_base64_experiment.ipp" +#undef base64 +#endif // _LIBCPP_VERSION + +// testing the code from experimental/base64-stateful_transform.hpp +#define base64 base64_stateful_transform +#include "utils_base64_experiment.ipp" +#undef base64 + +// testing the code from experimental/base64-stateful_iterator.hpp +#define base64 base64_stateful_iterator +#include "utils_base64_experiment.ipp" +#undef base64 + +// testing the code from experimental/base64-standalone.hpp, +// which has become the code in boost/network/utils/base64/encode.hpp +#define base64 base64_standalone +#include "utils_base64_experiment.ipp" +#undef base64 + +// redefine the testing code to use the iostream implementation from +// boost/network/utils/base64/encode-io.hpp which depends on the +// interface from boost/network/utils/base64/encode.hpp +#undef test_name +#undef encode_single_block +#undef encode_multiple_blocks +#define test_name concatenate(concatenate(base64, _standalone_io), _test) +#define encode_single_block \ + std::stringstream result; \ + result << base64::io::encode(buffer) << base64::io::encode_rest +#define encode_multiple_blocks \ + std::stringstream result; \ + for (unsigned block_index = 0; block_index < buffers.size(); \ + ++block_index) { \ + std::vector const& buffer = buffers[block_index]; \ + result << base64::io::encode(buffer.begin(), buffer.end()); \ + } \ + result << base64::io::encode_rest + +// testing the iostream implementation with the code from +// boost/network/utils/base64/encode.hpp +#define base64 base64 +#include "utils_base64_experiment.ipp" +#undef base64 diff --git a/cpp-netlib/libs/network/experiment/utils_base64_experiment.ipp b/cpp-netlib/libs/network/experiment/utils_base64_experiment.ipp new file mode 100644 index 00000000..0e8d54aa --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils_base64_experiment.ipp @@ -0,0 +1,48 @@ +class test_name { + void test_single_block(); + void test_multiple_blocks(); + + public: + test_name() { + std::cout << "Executing " stringify(test_name) ":" << std::endl; + test_single_block(); + test_multiple_blocks(); + } +}; + +test_name concatenate(run_, test_name); + +void test_name::test_single_block() { + std::cout << " Encoding " << single_block_size << " MB buffer took "; + // Fill a single vector with random bytes. + std::vector buffer(single_block_size * 1024 * 1024); + for (std::vector::iterator current = buffer.begin(); + current != buffer.end(); ++current) + *current = static_cast(rand() % 255); + // Encode the single vector to a single BASE64 string. + clock_t start = clock(); + encode_single_block; + clock_t end = clock(); + std::cout << (double)(end - start) / CLOCKS_PER_SEC << "s." << std::endl; +} + +void test_name::test_multiple_blocks() { +#ifdef base64_with_state + std::cout << " Encoding " << multiple_block_count << " x " + << multiple_block_size << " KB buffers took "; + // Fill multiple vectors with random bytes. + std::vector > buffers(multiple_block_count); + for (unsigned block_index = 0; block_index < buffers.size(); ++block_index) { + std::vector& buffer = buffers[block_index]; + buffer.resize(multiple_block_size * 1024); + for (std::vector::iterator current = buffer.begin(); + current != buffer.end(); ++current) + *current = static_cast(rand() % 255); + } + // Encode the multiple vectors to a single BASE64 string. + clock_t start = clock(); + encode_multiple_blocks; + clock_t end = clock(); + std::cout << (double)(end - start) / CLOCKS_PER_SEC << "s." << std::endl; +#endif +} diff --git a/cpp-netlib/libs/network/experiment/utils_base64_experiment.txt b/cpp-netlib/libs/network/experiment/utils_base64_experiment.txt new file mode 100644 index 00000000..94674424 --- /dev/null +++ b/cpp-netlib/libs/network/experiment/utils_base64_experiment.txt @@ -0,0 +1,55 @@ +Benchmark results from GCC 4.6.4 without any optimization (no switches): + + Executing base64_stateless_test: + Encoding 16 MB buffer took 4.81s. + Executing base64_stateful_buffer_test: + Encoding 16 MB buffer took 4.93s. + Encoding 256 x 64 KB buffers took 4.92s. + Executing base64_stateful_transform_test: + Encoding 16 MB buffer took 5.32s. + Encoding 256 x 64 KB buffers took 5.25s. + Executing base64_stateful_iterator_test: + Encoding 16 MB buffer took 7.03s. + Encoding 256 x 64 KB buffers took 7.02s. + Executing base64_standalone_test: + Encoding 16 MB buffer took 0.93s. + Encoding 256 x 64 KB buffers took 1.01s. + Executing base64_standalone_io_test: + Encoding 16 MB buffer took 2.31s. + Encoding 256 x 64 KB buffers took 2.32s. + +Benchmark results from GCC 4.6.4 with the -O3 optimization; the processed +data were 10 times bigger than for the test run without any optimization: + + Executing base64_stateless_test: + Encoding 160 MB buffer took 3.42s. + Executing base64_stateful_buffer_test: + Encoding 160 MB buffer took 3.69s. + Encoding 1280 x 320 KB buffers took 9.43s. + Executing base64_stateful_transform_test: + Encoding 160 MB buffer took 4.71s. + Encoding 1280 x 320 KB buffers took 12.27s. + Executing base64_stateful_iterator_test: + Encoding 160 MB buffer took 4.65s. + Encoding 1280 x 320 KB buffers took 11.92s. + Executing base64_standalone_test: + Encoding 160 MB buffer took 1.46s. + Encoding 1280 x 320 KB buffers took 4.09s. + Executing base64_standalone_io_test: + Encoding 160 MB buffer took 3.93s. + Encoding 1280 x 320 KB buffers took 10.18s. + +Testing the base64_stateless was done for the sake of completeness just to +test the pure boost implementation only; state is needed for chunked encoding. + +The three different base64_stateful_xxx implementations are comparable; +the base64_stateful_iterator may have spent more time in copy constructors, +because the state is owned lower - by the transformed iterator adaptor. +The iostream interface brings noticeable overhead, especially if the +encoding state (stored in the internal extensible array of the output stream) +is used extensively. + +The boost transforming iterators are not enough to implement BASE64 encoding +of a chunked input. Taking the additional code into consideration, the amount +of code for the non-boost base64_standalone implementation is not so different +and offers better performance. diff --git a/cpp-netlib/libs/network/src/CMakeLists.txt b/cpp-netlib/libs/network/src/CMakeLists.txt new file mode 100644 index 00000000..3f22165d --- /dev/null +++ b/cpp-netlib/libs/network/src/CMakeLists.txt @@ -0,0 +1,54 @@ +# Copyright (c) Glyn Matthews 2011. +# Copyright 2011 Dean Michael Berris (dberris@google.com) +# Copyright 2011 Google, Inc. +# 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_directories(${CPP-NETLIB_SOURCE_DIR}) + +file(GLOB_RECURSE CPP-NETLIB_HEADERS + "${CPP-NETLIB_SOURCE_DIR}/boost/" "*.hpp") + +set(CPP-NETLIB_URI_SRCS uri/uri.cpp uri/schemes.cpp) +add_library(cppnetlib-uri ${CPP-NETLIB_URI_SRCS}) +set_target_properties(cppnetlib-uri + PROPERTIES VERSION ${CPPNETLIB_VERSION_STRING} + SOVERSION ${CPPNETLIB_VERSION_MAJOR} + PUBLIC_HEADER "${CPP-NETLIB_HEADERS}") +install(TARGETS cppnetlib-uri + EXPORT cppnetlibTargets + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) + +set(CPP-NETLIB_HTTP_SERVER_SRCS server_request_parsers_impl.cpp) +add_library(cppnetlib-server-parsers ${CPP-NETLIB_HTTP_SERVER_SRCS}) +set_target_properties(cppnetlib-server-parsers + PROPERTIES VERSION ${CPPNETLIB_VERSION_STRING} + SOVERSION ${CPPNETLIB_VERSION_MAJOR} + PUBLIC_HEADER "${CPP-NETLIB_HEADERS}") +install(TARGETS cppnetlib-server-parsers + EXPORT cppnetlibTargets + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) + +set(CPP-NETLIB_HTTP_CLIENT_SRCS client.cpp) +add_library(cppnetlib-client-connections ${CPP-NETLIB_HTTP_CLIENT_SRCS}) +set_target_properties(cppnetlib-client-connections + PROPERTIES VERSION ${CPPNETLIB_VERSION_STRING} + SOVERSION ${CPPNETLIB_VERSION_MAJOR} + PUBLIC_HEADER "${CPP-NETLIB_HEADERS}") +if (OPENSSL_FOUND) + target_link_libraries(cppnetlib-client-connections ${OPENSSL_LIBRARIES}) +endif () +if (Boost_FOUND) + target_link_libraries(cppnetlib-client-connections ${Boost_LIBRARIES}) +endif () +install(TARGETS cppnetlib-client-connections + EXPORT cppnetlibTargets + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}) diff --git a/cpp-netlib/libs/network/src/client.cpp b/cpp-netlib/libs/network/src/client.cpp new file mode 100644 index 00000000..3ce8c1f1 --- /dev/null +++ b/cpp-netlib/libs/network/src/client.cpp @@ -0,0 +1,17 @@ + +// Copyright 2011 Dean Michael Berris (dberris@google.com). +// Copyright 2011 Google, Inc. +// 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) + +#ifdef BOOST_NETWORK_NO_LIB +#warn Building the library even with BOOST_NETWORK_NO_LIB defined. +#undef BOOST_NETWORK_NO_LIB +#endif + +#include + +#ifdef BOOST_NETWORK_ENABLE_HTTPS +#include +#endif diff --git a/cpp-netlib/libs/network/src/server_request_parsers_impl.cpp b/cpp-netlib/libs/network/src/server_request_parsers_impl.cpp new file mode 100644 index 00000000..1b3d4246 --- /dev/null +++ b/cpp-netlib/libs/network/src/server_request_parsers_impl.cpp @@ -0,0 +1,10 @@ +// Copyright 2010 Dean Michael Berris. +// 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) + +#ifdef BOOST_NETWORK_NO_LIB +#undef BOOST_NETWORK_NO_LIB +#endif + +#include diff --git a/cpp-netlib/libs/network/src/uri/schemes.cpp b/cpp-netlib/libs/network/src/uri/schemes.cpp new file mode 100644 index 00000000..86f89c0a --- /dev/null +++ b/cpp-netlib/libs/network/src/uri/schemes.cpp @@ -0,0 +1,60 @@ +// Copyright 2012 Glyn Matthews. +// 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 +#include + +namespace boost { +namespace network { +namespace uri { +namespace { +static boost::unordered_set hierarchical_schemes_; +static boost::unordered_set opaque_schemes_; + +bool register_hierarchical_schemes() { + hierarchical_schemes_.insert("http"); + hierarchical_schemes_.insert("https"); + hierarchical_schemes_.insert("shttp"); + hierarchical_schemes_.insert("ftp"); + hierarchical_schemes_.insert("file"); + hierarchical_schemes_.insert("dns"); + hierarchical_schemes_.insert("nfs"); + hierarchical_schemes_.insert("imap"); + hierarchical_schemes_.insert("nntp"); + hierarchical_schemes_.insert("pop"); + hierarchical_schemes_.insert("rsync"); + hierarchical_schemes_.insert("snmp"); + hierarchical_schemes_.insert("telnet"); + hierarchical_schemes_.insert("svn"); + hierarchical_schemes_.insert("svn+ssh"); + hierarchical_schemes_.insert("git"); + hierarchical_schemes_.insert("git+ssh"); + return true; +} + +bool register_opaque_schemes() { + opaque_schemes_.insert("mailto"); + opaque_schemes_.insert("news"); + opaque_schemes_.insert("im"); + opaque_schemes_.insert("sip"); + opaque_schemes_.insert("sms"); + opaque_schemes_.insert("xmpp"); + return true; +} + +static bool hierarchical = register_hierarchical_schemes(); +static bool opaque = register_opaque_schemes(); +} // namespace + +bool hierarchical_schemes::exists(const std::string &scheme) { + return hierarchical_schemes_.end() != hierarchical_schemes_.find(scheme); +} + +bool opaque_schemes::exists(const std::string &scheme) { + return opaque_schemes_.end() != opaque_schemes_.find(scheme); +} +} // namespace uri +} // namespace network +} // namespace boost diff --git a/cpp-netlib/libs/network/src/uri/uri.cpp b/cpp-netlib/libs/network/src/uri/uri.cpp new file mode 100644 index 00000000..b7fc1f8a --- /dev/null +++ b/cpp-netlib/libs/network/src/uri/uri.cpp @@ -0,0 +1,6 @@ +// Copyright 2012 Glyn Matthews. +// 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 diff --git a/cpp-netlib/libs/network/test/CMakeLists.txt b/cpp-netlib/libs/network/test/CMakeLists.txt new file mode 100644 index 00000000..7d1e5386 --- /dev/null +++ b/cpp-netlib/libs/network/test/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (c) Dean Michael Berris 2010. +# 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_directories(${CPP-NETLIB_SOURCE_DIR}) + +add_subdirectory(uri) +add_subdirectory(http) + +if (Boost_FOUND) + set( + TESTS + message_test + message_transform_test + utils_thread_pool + # utils_base64_test -- turn on when ready. + ) + foreach (test ${TESTS}) + if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU) + set_source_files_properties(${test}.cpp + PROPERTIES COMPILE_FLAGS "-Wall") + endif() + add_executable(cpp-netlib-${test} ${test}.cpp) + add_dependencies(cpp-netlib-${test} cppnetlib-uri) + target_link_libraries(cpp-netlib-${test} ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} cppnetlib-uri) + if (OPENSSL_FOUND) + target_link_libraries(cpp-netlib-${test} ${OPENSSL_LIBRARIES}) + endif() + if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU AND ${CMAKE_SYSTEM_NAME} MATCHES "Windows") + target_link_libraries(cpp-netlib-${test} ws2_32 wsock32) + endif() + if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_link_libraries(cpp-netlib-${test} rt) + endif() + set_target_properties(cpp-netlib-${test} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/tests) + add_test(cpp-netlib-${test} + ${CPP-NETLIB_BINARY_DIR}/tests/cpp-netlib-${test}) + endforeach (test) + + # Also copy the server directory to the root of the build directory. + file(COPY server DESTINATION ${CPP-NETLIB_BINARY_DIR}/libs/network/test/) + +endif() + diff --git a/cpp-netlib/libs/network/test/client_server_include_failure.cpp b/cpp-netlib/libs/network/test/client_server_include_failure.cpp new file mode 100644 index 00000000..4a15dff8 --- /dev/null +++ b/cpp-netlib/libs/network/test/client_server_include_failure.cpp @@ -0,0 +1,22 @@ +// Copyright (c) Glyn Matthews 2010. +// 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) + +#define BOOST_TEST_MODULE Client and server includes +#include + +// +// The problem here is a bizarre compilation failure in including +// these two files, and instantiating a client. It's described at +// http://github.com/cpp-netlib/cpp-netlib/issues#issue/13 +// +#include +#include + +BOOST_AUTO_TEST_CASE(test1) { + typedef boost::network::http::basic_client< + boost::network::http::tags::http_keepalive_8bit_udp_resolve, 1, 1> + http_client; + http_client client; +} diff --git a/cpp-netlib/libs/network/test/http/CMakeLists.txt b/cpp-netlib/libs/network/test/http/CMakeLists.txt new file mode 100644 index 00000000..019fe012 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/CMakeLists.txt @@ -0,0 +1,93 @@ + +# Copyright 2010 Dean Michael Berris. +# 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_directories(${CPP-NETLIB_SOURCE_DIR}) + +if (OPENSSL_FOUND) + include_directories( ${OPENSSL_INCLUDE_DIR} ) + add_definitions(-DBOOST_NETWORK_ENABLE_HTTPS) +endif() + +if (Boost_FOUND) + set ( TESTS + response_incremental_parser_test + request_incremental_parser_test + request_linearize_test + ) + foreach ( test ${TESTS} ) + add_executable(cpp-netlib-http-${test} ${test}.cpp) + add_dependencies(cpp-netlib-http-${test} + cppnetlib-uri) + target_link_libraries(cpp-netlib-http-${test} + ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-uri) + if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU AND ${CMAKE_SYSTEM_NAME} MATCHES "Windows") + target_link_libraries(cpp-netlib-http-${test} ws2_32) + endif() + if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_link_libraries(cpp-netlib-http-${test} rt) + endif() + set_target_properties(cpp-netlib-http-${test} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/tests) + add_test(cpp-netlib-http-${test} + ${CPP-NETLIB_BINARY_DIR}/tests/cpp-netlib-http-${test}) + endforeach (test) + set ( TESTS + client_constructor_test + client_get_test + client_get_different_port_test + client_get_timeout_test + client_get_streaming_test + ) + foreach ( test ${TESTS} ) + add_executable(cpp-netlib-http-${test} ${test}.cpp) + add_dependencies(cpp-netlib-http-${test} + cppnetlib-uri + cppnetlib-client-connections) + target_link_libraries(cpp-netlib-http-${test} + ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + cppnetlib-uri + cppnetlib-client-connections) + if (OPENSSL_FOUND) + target_link_libraries(cpp-netlib-http-${test} ${OPENSSL_LIBRARIES}) + endif() + if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU AND ${CMAKE_SYSTEM_NAME} MATCHES "Windows") + target_link_libraries(cpp-netlib-http-${test} ws2_32) + endif() + if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_link_libraries(cpp-netlib-http-${test} rt) + endif() + set_target_properties(cpp-netlib-http-${test} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/tests) + add_test(cpp-netlib-http-${test} + ${CPP-NETLIB_BINARY_DIR}/tests/cpp-netlib-http-${test}) + endforeach (test) + + set ( SERVER_API_TESTS + server_constructor_test + server_async_run_stop_concurrency + server_header_parser_test + ) + foreach ( test ${SERVER_API_TESTS} ) + add_executable(cpp-netlib-http-${test} ${test}.cpp) + add_dependencies(cpp-netlib-http-${test} cppnetlib-server-parsers) + target_link_libraries(cpp-netlib-http-${test} ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} cppnetlib-server-parsers) + if (OPENSSL_FOUND) + target_link_libraries(cpp-netlib-http-${test} ${OPENSSL_LIBRARIES}) + endif() + if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU AND ${CMAKE_SYSTEM_NAME} MATCHES "Windows") + target_link_libraries(cpp-netlib-http-${test} ws2_32 wsock32) + endif() + if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_link_libraries(cpp-netlib-http-${test} rt) + endif() + set_target_properties(cpp-netlib-http-${test} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/tests) + add_test(cpp-netlib-http-${test} + ${CPP-NETLIB_BINARY_DIR}/tests/cpp-netlib-http-${test}) + endforeach (test) + +endif() diff --git a/cpp-netlib/libs/network/test/http/client_constructor_test.cpp b/cpp-netlib/libs/network/test/http/client_constructor_test.cpp new file mode 100644 index 00000000..f5a6dad1 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/client_constructor_test.cpp @@ -0,0 +1,34 @@ + +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP 1.0 Client Constructor Test +#include +#include +#include "client_types.hpp" + +namespace http = boost::network::http; + +BOOST_AUTO_TEST_CASE_TEMPLATE(http_client_constructor_test, client, + client_types) { + typename client::options options; + client instance; + client instance2( + options.io_service(boost::make_shared())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(http_cient_constructor_params_test, client, + client_types) { + typename client::options options; + client instance(options.follow_redirects(true).cache_resolved(true)); + client instance2( + options.openssl_certificate("foo").openssl_verify_path("bar")); + client instance3( + options.openssl_certificate_file("foo").openssl_private_key_file("bar")); + client instance4( + options.follow_redirects(true) + .io_service(boost::make_shared()) + .cache_resolved(true)); +} diff --git a/cpp-netlib/libs/network/test/http/client_get_different_port_test.cpp b/cpp-netlib/libs/network/test/http/client_get_different_port_test.cpp new file mode 100644 index 00000000..3279f22c --- /dev/null +++ b/cpp-netlib/libs/network/test/http/client_get_different_port_test.cpp @@ -0,0 +1,24 @@ + +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP Client Get Different Port Test +#include +#include +#include "client_types.hpp" + +namespace net = boost::network; +namespace http = boost::network::http; + +BOOST_AUTO_TEST_CASE_TEMPLATE(http_get_test_different_port, client, + client_types) { + typename client::request request("http://www.boost.org:80/"); + client client_; + typename client::response response_ = client_.get(request); + typename net::headers_range::type range = + headers(response_)["Content-Type"]; + BOOST_CHECK(boost::begin(range) != boost::end(range)); + BOOST_CHECK(body(response_).size() != 0); +} diff --git a/cpp-netlib/libs/network/test/http/client_get_streaming_test.cpp b/cpp-netlib/libs/network/test/http/client_get_streaming_test.cpp new file mode 100644 index 00000000..4925814a --- /dev/null +++ b/cpp-netlib/libs/network/test/http/client_get_streaming_test.cpp @@ -0,0 +1,46 @@ +// Copyright 2011 Dean Michael Berris <mikhailberis@gmail.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) + +#define BOOST_TEST_MODULE HTTP 1.1 Get Streaming Test +#include +#include +#include +#include "client_types.hpp" + +namespace net = boost::network; +namespace http = boost::network::http; + +struct body_handler { + + explicit body_handler(std::string& body) : body(body) {} + + BOOST_NETWORK_HTTP_BODY_CALLBACK(operator(), range, error) { + body.append(boost::begin(range), boost::end(range)); + } + + std::string& body; +}; + +BOOST_AUTO_TEST_CASE_TEMPLATE(http_client_get_streaming_test, client, + async_only_client_types) { + typename client::request request("http://www.boost.org"); + typename client::response response; + typename client::string_type body_string; + typename client::string_type dummy_body; + body_handler handler_instance(body_string); + { + client client_; + BOOST_CHECK_NO_THROW(response = client_.get(request, handler_instance)); + typename net::headers_range::type range = + headers(response)["Content-Type"]; + BOOST_CHECK(!boost::empty(range)); + BOOST_CHECK_EQUAL(body(response).size(), 0u); + BOOST_CHECK_EQUAL(response.version().substr(0, 7), std::string("HTTP/1.")); + BOOST_CHECK_EQUAL(response.status(), 200u); + BOOST_CHECK_EQUAL(response.status_message(), std::string("OK")); + dummy_body = body(response); + } + BOOST_CHECK(dummy_body == typename client::string_type()); +} diff --git a/cpp-netlib/libs/network/test/http/client_get_test.cpp b/cpp-netlib/libs/network/test/http/client_get_test.cpp new file mode 100644 index 00000000..3cc59636 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/client_get_test.cpp @@ -0,0 +1,53 @@ +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP 1.0 Get Test +#include +#include +#include "client_types.hpp" + +namespace net = boost::network; +namespace http = boost::network::http; + +BOOST_AUTO_TEST_CASE_TEMPLATE(http_client_get_test, client, client_types) { + typename client::request request("http://www.boost.org"); + client client_; + typename client::response response; + BOOST_REQUIRE_NO_THROW(response = client_.get(request)); + typename net::headers_range::type range = + headers(response)["Content-Type"]; + BOOST_CHECK(!boost::empty(range)); + BOOST_REQUIRE_NO_THROW(BOOST_CHECK(body(response).size() != 0)); + BOOST_CHECK_EQUAL(response.version().substr(0, 7), std::string("HTTP/1.")); + BOOST_CHECK_EQUAL(response.status(), 200u); + BOOST_CHECK_EQUAL(response.status_message(), std::string("OK")); +} + +#ifdef BOOST_NETWORK_ENABLE_HTTPS + +BOOST_AUTO_TEST_CASE_TEMPLATE(https_client_get_test, client, client_types) { + typename client::request request("https://www.google.com/"); + client client_; + typename client::response response_ = client_.get(request); + typename net::headers_range::type range = + headers(response_)["Content-Type"]; + BOOST_CHECK(boost::begin(range) != boost::end(range)); + BOOST_CHECK(body(response_).size() != 0); +} + +#endif + +BOOST_AUTO_TEST_CASE_TEMPLATE(http_temp_client_get_test, client, client_types) { + typename client::request request("http://www.google.co.kr"); + typename client::response response; + BOOST_REQUIRE_NO_THROW(response = client().get(request)); + typename net::headers_range::type range = + headers(response)["Content-Type"]; + BOOST_CHECK(!boost::empty(range)); + BOOST_REQUIRE_NO_THROW(BOOST_CHECK(body(response).size() != 0)); + BOOST_CHECK_EQUAL(response.version().substr(0, 7), std::string("HTTP/1.")); + BOOST_CHECK_EQUAL(response.status(), 200u); + BOOST_CHECK_EQUAL(response.status_message(), std::string("OK")); +} diff --git a/cpp-netlib/libs/network/test/http/client_get_timeout_test.cpp b/cpp-netlib/libs/network/test/http/client_get_timeout_test.cpp new file mode 100644 index 00000000..4fc4d97c --- /dev/null +++ b/cpp-netlib/libs/network/test/http/client_get_timeout_test.cpp @@ -0,0 +1,67 @@ + +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP Client Get Timeout Test +#include +#include +#include +#include "client_types.hpp" +#include "http_test_server.hpp" + +struct localhost_server_fixture { + localhost_server_fixture() { + if (!server.start()) { + std::cout << "Failed to start HTTP server for test!" << std::endl; + std::abort(); + } + } + + ~localhost_server_fixture() { + if (!server.stop()) { + std::cout << "Failed to stop HTTP server for test!" << std::endl; + std::abort(); + } + } + + http_test_server server; +}; + +BOOST_GLOBAL_FIXTURE(localhost_server_fixture); + +BOOST_AUTO_TEST_CASE_TEMPLATE(http_get_test_timeout_1_0, client, client_types) { + typename client::request request("http://localhost:12121/"); + typename client::response response_; + client client_; + boost::uint16_t port_ = port(request); + typename client::response::string_type temp; + BOOST_CHECK_EQUAL(12121, port_); + BOOST_CHECK_THROW(response_ = client_.get(request); temp = body(response_); + , std::exception); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(http_get_test_timeout_with_options, client, client_types) { + typename client::request request("http://localhost:8000/cgi-bin/sleep.py?3"); + typename client::response response; + typename client::options options; + client client_(options.timeout(1)); + typename client::response::string_type temp; + BOOST_CHECK_THROW(response = client_.get(request); temp = body(response); + , std::exception); +} + +#ifdef BOOST_NETWORK_ENABLE_HTTPS + +BOOST_AUTO_TEST_CASE_TEMPLATE(https_get_test_timeout_with_options, client, client_types) { + typename client::request request("https://localhost:8000/cgi-bin/sleep.py?3"); + typename client::response response; + typename client::options options; + client client_(options.timeout(1)); + typename client::response::string_type temp; + BOOST_CHECK_THROW(response = client_.get(request); temp = body(response); + , std::exception); +} + +#endif diff --git a/cpp-netlib/libs/network/test/http/client_include_inlined.cpp b/cpp-netlib/libs/network/test/http/client_include_inlined.cpp new file mode 100644 index 00000000..68c92915 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/client_include_inlined.cpp @@ -0,0 +1,22 @@ +// Copyright 2011 Dean Michael Berris <mikhailberis@gmail.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) + +#define BOOST_NETWORK_NO_LIB +#include + +int main(int argc, char* argv[]) { + using namespace boost; + using namespace boost::network; + http::client c; + http::client::request req("http://www.boost.org/"); + try { + http::client::response res = c.get(req); + } + catch (...) { + // ignore the error, we just want to make sure + // the interface works inlined. + } + return 0; +} diff --git a/cpp-netlib/libs/network/test/http/client_localhost_normal_test.cpp b/cpp-netlib/libs/network/test/http/client_localhost_normal_test.cpp new file mode 100644 index 00000000..29202158 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/client_localhost_normal_test.cpp @@ -0,0 +1,366 @@ +// +// Copyright Divye Kapoor 2008. +// 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) +// +// Changes by Kim Grasman 2008 +// Changes by Dean Michael Berris 2008, 2010 + +#define BOOST_TEST_MODULE http 1.0 localhost tests + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "http_test_server.hpp" + +using std::cout; +using std::endl; + +namespace { +const std::string base_url = "http://localhost:8000"; +const std::string cgi_url = base_url + "/cgi-bin/requestinfo.py"; + +struct running_server_fixture { + // NOTE: Can't use BOOST_REQUIRE_MESSAGE here, as Boost.Test data structures + // are not fully set up when the global fixture runs. + running_server_fixture() { + if (!server.start()) + cout << "Failed to start HTTP server for test!" << endl; + } + + ~running_server_fixture() { + if (!server.stop()) cout << "Failed to stop HTTP server for test!" << endl; + } + + http_test_server server; +}; + +std::size_t readfile(std::ifstream& file, std::vector& buffer) { + using std::ios; + + std::istreambuf_iterator src(file); + std::istreambuf_iterator eof; + std::copy(src, eof, std::back_inserter(buffer)); + + return buffer.size(); +} + +std::map parse_headers(std::string const& body) { + std::map headers; + + std::istringstream stream(body); + while (stream.good()) { + std::string line; + std::getline(stream, line); + if (!stream.eof()) { + std::size_t colon = line.find(':'); + if (colon != std::string::npos) { + std::string header = line.substr(0, colon); + std::string value = line.substr(colon + 2); + headers[header] = value; + } + } + } + + return headers; +} + +std::string get_content_length(std::string const& content) { + return boost::lexical_cast(content.length()); +} +} + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +// Uncomment the below if you're running Python pre-2.6. There was a bug +// in the Python HTTP server for earlier versions that causes this test +// case to fail. +// BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(text_query_preserves_crlf, 2); +#endif + +BOOST_GLOBAL_FIXTURE(running_server_fixture); + +BOOST_AUTO_TEST_CASE(body_test) { + // Tests presence of body in http responses + using namespace boost::network; + http::client::request request_(base_url); + http::client client_; + http::client::response response_; + BOOST_REQUIRE_NO_THROW(response_ = client_.get(request_)); + BOOST_CHECK(body(response_).size() != 0); +} + +BOOST_AUTO_TEST_CASE(text_content_type_test) { + // Tests correct parsing of the content-type header sent by the server + using namespace boost::network; + http::client::request request_(base_url); + http::client client_; + http::client::response response_; + BOOST_REQUIRE_NO_THROW(response_ = client_.get(request_)); + BOOST_REQUIRE(headers(response_).count("Content-type") != 0); + headers_range::type range = + headers(response_)["Content-type"]; + BOOST_CHECK(boost::begin(range)->first == "Content-type"); + BOOST_CHECK(boost::begin(range)->second == "text/html"); +} + +BOOST_AUTO_TEST_CASE(binary_content_type_test) { + // Tests correct parsing of content-type for binary files such as .zip files + using namespace boost::network; + http::client::request request_(base_url + "/boost.jpg"); + http::client client_; + http::client::response response_; + BOOST_REQUIRE_NO_THROW(response_ = client_.get(request_)); + BOOST_REQUIRE(headers(response_).count("Content-type") != 0); + headers_range::type range = + headers(response_)["Content-type"]; + BOOST_CHECK(boost::begin(range)->first == "Content-type"); + BOOST_CHECK(boost::begin(range)->second == "image/jpeg"); +} + +BOOST_AUTO_TEST_CASE(content_length_header_test) { + // Uses the test.xml file to ensure that the file was received at the correct + // length for a text encoding + using namespace boost::network; + http::client::request request_(base_url + "/test.xml"); + http::client client_; + http::client::response response_; + BOOST_REQUIRE_NO_THROW(response_ = client_.get(request_)); + BOOST_REQUIRE(headers(response_).count("Content-Length") != 0); + headers_range::type range = + headers(response_)["Content-Length"]; + BOOST_CHECK_EQUAL(boost::begin(range)->first, "Content-Length"); + BOOST_CHECK_EQUAL(boost::begin(range)->second, "113"); + BOOST_CHECK(body(response_).size() != 0); +} + +BOOST_AUTO_TEST_CASE(text_query_preserves_crlf) { + // Tests proper transfer of a text file + using namespace boost::network; + http::client::request request_(base_url + "/test.xml"); + http::client client_; + http::client::response response_; + BOOST_REQUIRE_NO_THROW(response_ = client_.get(request_)); + + http::client::response::string_type body_ = body(response_); + BOOST_CHECK(body(response_).size() != 0); + + using std::ios; + + std::ifstream file("libs/network/test/server/test.xml", + ios::in | ios::binary); + if (!file) { + file.clear(); + file.open("server/test.xml", ios::in | ios::binary); + } + + BOOST_REQUIRE_MESSAGE(file, "Could not open local test.xml"); + + std::vector memblock; + std::size_t size = readfile(file, memblock); + + BOOST_CHECK(size != 0); + BOOST_CHECK_EQUAL(body_.size(), size); + + if (body(response_).size() == size) { + std::pair::iterator, std::string::const_iterator> + diff_pos = + std::mismatch(memblock.begin(), memblock.end(), body_.begin()); + BOOST_CHECK_EQUAL( + boost::numeric_cast(diff_pos.first - memblock.begin()), + size); + } +} + +BOOST_AUTO_TEST_CASE(binary_file_query) { + // Tests proper transfer of a binary image + using namespace boost::network; + http::client::request request_(base_url + "/boost.jpg"); + http::client client_; + http::client::response response_; + BOOST_REQUIRE_NO_THROW(response_ = client_.get(request_)); + + http::client::response::string_type body_ = body(response_); + BOOST_CHECK(body_.size() != 0); + + using std::ios; + + std::ifstream file("libs/network/test/server/boost.jpg", + ios::in | ios::binary); + if (!file) { + file.clear(); + file.open("server/boost.jpg", ios::in | ios::binary); + } + + BOOST_REQUIRE_MESSAGE(file, "Could not open boost.jpg locally"); + + std::vector memblock; + std::size_t size = readfile(file, memblock); + + BOOST_CHECK(size != 0); + BOOST_CHECK_EQUAL(body_.size(), size); + + std::pair::iterator, std::string::const_iterator> diff_pos = + std::mismatch(memblock.begin(), memblock.end(), body_.begin()); + BOOST_CHECK_EQUAL( + boost::numeric_cast(diff_pos.first - memblock.begin()), + size); +} + +BOOST_AUTO_TEST_CASE(cgi_query) { + // Get a dynamic request with no Content-Length header + // Ensure that we have a body + using namespace boost::network; + + http::client::request req(cgi_url + "?query=1"); + http::client c; + http::client::response r; + BOOST_REQUIRE_NO_THROW(r = c.get(req)); + BOOST_CHECK(body(r).size() != 0); + BOOST_CHECK(boost::empty(headers(r)["Content-Length"])); +} + +BOOST_AUTO_TEST_CASE(cgi_multi_line_headers) { + using namespace boost::network; + + http::client::request req(base_url + "/cgi-bin/multiline-header.py?query=1"); + http::client c; + http::client::response r; + BOOST_REQUIRE_NO_THROW(r = c.get(req)); + BOOST_CHECK(body(r).size() != 0); + BOOST_CHECK(boost::empty(headers(r)["Content-Type"])); + headers_range::type range = + headers(r)["X-CppNetlib-Test"]; + BOOST_REQUIRE(boost::begin(range) != boost::end(range)); + BOOST_REQUIRE(distance(range) == 2); + BOOST_CHECK_EQUAL(boost::begin(range)->second, + std::string("multi-line-header")); + BOOST_CHECK_EQUAL((++boost::begin(range))->second, + std::string("that-should-concatenate")); +} + +BOOST_AUTO_TEST_CASE(file_not_found) { + // Request for a non existing file. + // Ensure that we have a body even in the presence of an error response + using namespace boost::network; + + http::client::request req(base_url + "/file_not_found"); + http::client c; + http::client::response r = c.get(req); + + BOOST_CHECK(body(r).size() != 0); +} + +BOOST_AUTO_TEST_CASE(head_test) { + using namespace boost::network; + http::client::request request_(base_url + "/test.xml"); + http::client client_; + http::client::response response_; + BOOST_REQUIRE_NO_THROW(response_ = client_.head(request_)); + BOOST_REQUIRE(headers(response_).count("Content-Length") != 0); + headers_range::type range = + headers(response_)["Content-Length"]; + BOOST_CHECK_EQUAL(boost::begin(range)->first, "Content-Length"); + BOOST_CHECK_EQUAL(boost::begin(range)->second, "113"); + BOOST_CHECK(body(response_).size() == 0); +} + +BOOST_AUTO_TEST_CASE(post_with_explicit_headers) { + // This test checks that the headers echoed through echo_headers.py + // are in fact the same as what are sent through the POST request + using namespace boost::network; + + const std::string postdata = "empty"; + const std::string content_length = get_content_length(postdata); + const std::string content_type = "application/x-www-form-urlencoded"; + + http::client::request req(base_url + "/cgi-bin/echo_headers.py"); + req << header("Content-Length", content_length); + req << header("Content-Type", content_type); + req << body(postdata); + + http::client c; + http::client::response r; + BOOST_REQUIRE_NO_THROW(r = c.post(req)); + + std::map headers = parse_headers(body(r)); + BOOST_CHECK_EQUAL(headers["content-length"], content_length); + BOOST_CHECK_EQUAL(headers["content-type"], content_type); +} + +BOOST_AUTO_TEST_CASE(post_with_implicit_headers) { + // This test checks that post(request, body) derives Content-Length + // and Content-Type + using namespace boost::network; + + const std::string postdata = "empty"; + + http::client::request req(base_url + "/cgi-bin/echo_headers.py"); + + http::client c; + http::client::response r; + BOOST_REQUIRE_NO_THROW(r = c.post(req, postdata)); + + std::map headers = parse_headers(body(r)); + BOOST_CHECK_EQUAL(headers["content-length"], get_content_length(postdata)); + BOOST_CHECK_EQUAL(headers["content-type"], "x-application/octet-stream"); +} + +BOOST_AUTO_TEST_CASE(post_with_explicit_content_type) { + // This test checks that post(request, content_type, body) derives + // Content-Length, + // and keeps Content-Type + using namespace boost::network; + + const std::string postdata = "empty"; + const std::string content_type = "application/x-my-content-type"; + + http::client::request req(base_url + "/cgi-bin/echo_headers.py"); + + http::client c; + http::client::response r; + BOOST_REQUIRE_NO_THROW(r = c.post(req, content_type, postdata)); + + std::map headers = parse_headers(body(r)); + BOOST_CHECK_EQUAL(headers["content-length"], get_content_length(postdata)); + BOOST_CHECK_EQUAL(headers["content-type"], content_type); +} + +BOOST_AUTO_TEST_CASE(post_body_default_content_type) { + // This test checks that post(request, body) gets the post data + // through to the server + using namespace boost::network; + + const std::string postdata = "firstname=bill&lastname=badger"; + + http::client::request req(base_url + "/cgi-bin/echo_body.py"); + + http::client c; + http::client::response r; + BOOST_REQUIRE_NO_THROW(r = c.post(req, postdata)); + http::client::response::string_type body_ = body(r); + BOOST_CHECK_EQUAL(postdata, body_); +} + +BOOST_AUTO_TEST_CASE(post_with_custom_headers) { + // This test checks that custom headers pass through to the server + // when posting + using namespace boost::network; + + http::client::request req(base_url + "/cgi-bin/echo_headers.py"); + req << header("X-Cpp-Netlib", "rocks!"); + + http::client c; + http::client::response r; + BOOST_REQUIRE_NO_THROW(r = c.post(req, std::string())); + + std::map headers = parse_headers(body(r)); + BOOST_CHECK_EQUAL(headers["x-cpp-netlib"], "rocks!"); +} diff --git a/cpp-netlib/libs/network/test/http/client_localhost_ssl_test.cpp b/cpp-netlib/libs/network/test/http/client_localhost_ssl_test.cpp new file mode 100644 index 00000000..a28e5645 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/client_localhost_ssl_test.cpp @@ -0,0 +1,341 @@ +// +// Copyright Divye Kapoor 2008. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Changes by Kim Grasman 2008 +// Changes by Dean Michael Berris 2008, 2009 + +#define BOOST_TEST_MODULE https 1.0 localhost tests + +#include +#include +#include +#include +#include +#include +#include +#include + +#define HTTPS_SERVER_TEST +#include "http_test_server.hpp" + +using std::cout; +using std::endl; + +namespace { +const std::string base_url = "https://localhost:8443"; +const std::string cgi_url = base_url + "/cgi-bin/requestinfo.py"; + +struct running_server_fixture { + // NOTE: Can't use BOOST_REQUIRE_MESSAGE here, as Boost.Test data structures + // are not fully set up when the global fixture runs. + running_server_fixture() { + if (!server.start()) + cout << "Failed to start HTTP server for test!" << endl; + } + + ~running_server_fixture() { + if (!server.stop()) cout << "Failed to stop HTTP server for test!" << endl; + } + + http_test_server server; +}; + +std::size_t readfile(std::ifstream& file, std::vector& buffer) { + using std::ios; + + std::istreambuf_iterator src(file); + std::istreambuf_iterator eof; + std::copy(src, eof, std::back_inserter(buffer)); + + return buffer.size(); +} +} + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +// Uncomment the below if you're running Python pre-2.6. There was a bug +// in the Python HTTP server for earlier versions that causes this test +// case to fail. +// BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(text_query_preserves_crlf, 2); +#endif + +BOOST_GLOBAL_FIXTURE(running_server_fixture); + +BOOST_AUTO_TEST_CASE(body_test) { + // Tests presence of body in http responses + using namespace boost::network; + http::client::request request_(base_url); + http::client client_; + http::client::response response_ = client_.get(request_); + BOOST_CHECK(body(response_).size() != 0); +} + +BOOST_AUTO_TEST_CASE(text_content_type_test) { + // Tests correct parsing of the content-type header sent by the server + using namespace boost::network; + http::client::request request_(base_url); + http::client client_; + http::client::response response_ = client_.get(request_); + BOOST_REQUIRE(headers(response_).count("Content-type") != 0); + headers_range::type range = + headers(response_)["Content-type"]; + BOOST_CHECK(boost::begin(range)->first == "Content-type"); + BOOST_CHECK(boost::begin(range)->second == "text/html"); +} + +BOOST_AUTO_TEST_CASE(binary_content_type_test) { + // Tests correct parsing of content-type for binary files such as .zip files + using namespace boost::network; + http::client::request request_(base_url + "/boost.jpg"); + http::client client_; + http::client::response response_ = client_.get(request_); + BOOST_REQUIRE(headers(response_).count("Content-type") != 0); + headers_range::type range = + headers(response_)["Content-type"]; + BOOST_CHECK(boost::begin(range)->first == "Content-type"); + BOOST_CHECK(boost::begin(range)->second == "image/jpeg"); +} + +BOOST_AUTO_TEST_CASE(content_length_header_test) { + // Uses the test.xml file to ensure that the file was received at the correct + // length for a text encoding + using namespace boost::network; + http::client::request request_(base_url + "/test.xml"); + http::client client_; + http::client::response response_ = client_.get(request_); + BOOST_REQUIRE(headers(response_).count("Content-Length") != 0); + headers_range::type range = + headers(response_)["Content-Length"]; + BOOST_CHECK_EQUAL(boost::begin(range)->first, "Content-Length"); + BOOST_CHECK_EQUAL(boost::begin(range)->second, "113"); + BOOST_CHECK(body(response_).size() != 0); +} + +BOOST_AUTO_TEST_CASE(text_query_preserves_crlf) { + // Tests proper transfer of a text file + using namespace boost::network; + http::client::request request_(base_url + "/test.xml"); + http::client client_; + http::client::response response_ = client_.get(request_); + + http::client::response::string_type body_ = body(response_); + BOOST_CHECK(body_.size() != 0); + + using std::ios; + + std::ifstream file("libs/network/test/server/test.xml", + ios::in | ios::binary); + if (!file) { + file.clear(); + file.open("server/test.xml", ios::in | ios::binary); + } + + BOOST_REQUIRE_MESSAGE(file, "Could not open local test.xml"); + + std::vector memblock; + std::size_t size = readfile(file, memblock); + + BOOST_CHECK(size != 0); + BOOST_CHECK_EQUAL(body(response_).size(), size); + + if (body(response_).size() == size) { + std::pair::iterator, std::string::const_iterator> + diff_pos = + std::mismatch(memblock.begin(), memblock.end(), body_.begin()); + BOOST_CHECK_EQUAL( + boost::numeric_cast(diff_pos.first - memblock.begin()), + size); + } +} + +BOOST_AUTO_TEST_CASE(binary_file_query) { + // Tests proper transfer of a binary image + using namespace boost::network; + http::client::request request_(base_url + "/boost.jpg"); + http::client client_; + http::client::response response_; + BOOST_CHECK_NO_THROW(response_ = client_.get(request_)); + + http::client::response::string_type body_ = body(response_); + BOOST_CHECK(body_.size() != 0); + + using std::ios; + + std::ifstream file("libs/network/test/server/boost.jpg", + ios::in | ios::binary); + if (!file) { + file.clear(); + file.open("server/boost.jpg", ios::in | ios::binary); + } + + BOOST_REQUIRE_MESSAGE(file, "Could not open boost.jpg locally"); + + std::vector memblock; + std::size_t size = readfile(file, memblock); + + BOOST_CHECK(size != 0); + BOOST_CHECK_EQUAL(body(response_).size(), size); + + std::pair::iterator, std::string::const_iterator> diff_pos = + std::mismatch(memblock.begin(), memblock.end(), body_.begin()); + BOOST_CHECK_EQUAL( + boost::numeric_cast(diff_pos.first - memblock.begin()), + size); +} + +// BOOST_AUTO_TEST_CASE(cgi_query) { +// // Get a dynamic request with no Content-Length header +// // Ensure that we have a body +// using namespace boost::network; +// +// http::client::request req(cgi_url + "?query=1"); +// http::client c; +// http::client::response r; +// BOOST_REQUIRE_NO_THROW(r = c.get(req)); +// BOOST_CHECK(body(r).size() != 0); +// BOOST_CHECK(headers(r)["Content-Type"].begin() != +// headers(r)["Content-Type"].end()); +//} +// +// BOOST_AUTO_TEST_CASE(cgi_multi_line_headers) { +// using namespace boost::network; +// +// http::client::request req(base_url + +// "/cgi-bin/multiline-header.py?query=1"); +// http::client c; +// http::client::response r; +// BOOST_REQUIRE_NO_THROW(r = c.get(req)); +// BOOST_CHECK(body(r).size() != 0); +// BOOST_CHECK(headers(r)["Content-Type"].begin() != +// headers(r)["Content-Type"].end()); +// headers_range::type +// range=headers(r)["X-CppNetlib-Test"]; +// BOOST_REQUIRE(boost::begin(range) != boost::end(range)); +// BOOST_REQUIRE(distance(range) == 2); +// BOOST_CHECK_EQUAL(boost::begin(range)->second, +// std::string("multi-line-header")); +// BOOST_CHECK_EQUAL((++boost::begin(range))->second, +// std::string("that-should-concatenate")); +//} + +BOOST_AUTO_TEST_CASE(file_not_found) { + // Request for a non existing file. + // Ensure that we have a body even in the presence of an error response + using namespace boost::network; + + http::client::request req(base_url + "/file_not_found"); + http::client c; + http::client::response r = c.get(req); + + BOOST_CHECK(body(r).size() != 0); +} + +BOOST_AUTO_TEST_CASE(head_test) { + using namespace boost::network; + http::client::request request_(base_url + "/test.xml"); + http::client client_; + http::client::response response_ = client_.head(request_); + BOOST_REQUIRE(headers(response_).count("Content-Length") != 0); + headers_range::type range = + headers(response_)["Content-Length"]; + BOOST_CHECK_EQUAL(boost::begin(range)->first, "Content-Length"); + BOOST_CHECK_EQUAL(boost::begin(range)->second, "113"); + BOOST_CHECK(body(response_).size() == 0); +} + +// BOOST_AUTO_TEST_CASE(post_with_explicit_headers) { +// // This test checks that the headers echoed through echo_headers.py +// // are in fact the same as what are sent through the POST request +// using namespace boost::network; +// +// const std::string postdata = "empty"; +// const std::string content_length = get_content_length(postdata); +// const std::string content_type = "application/x-www-form-urlencoded"; +// +// http::client::request req(base_url + "/cgi-bin/echo_headers.py"); +// req << header("Content-Length", content_length); +// req << header("Content-Type", content_type); +// req << body(postdata); +// +// http::client c; +// http::client::response r; +// BOOST_REQUIRE_NO_THROW(r = c.post(req)); +// +// std::map headers = parse_headers(body(r)); +// BOOST_CHECK_EQUAL(headers["content-length"], content_length); +// BOOST_CHECK_EQUAL(headers["content-type"], content_type); +//} +// +// BOOST_AUTO_TEST_CASE(post_with_implicit_headers) { +// // This test checks that post(request, body) derives Content-Length +// // and Content-Type +// using namespace boost::network; +// +// const std::string postdata = "empty"; +// +// http::client::request req(base_url + "/cgi-bin/echo_headers.py"); +// +// http::client c; +// http::client::response r; +// BOOST_REQUIRE_NO_THROW(r = c.post(req, postdata)); +// +// std::map headers = parse_headers(body(r)); +// BOOST_CHECK_EQUAL(headers["content-length"], +// get_content_length(postdata)); +// BOOST_CHECK_EQUAL(headers["content-type"], "x-application/octet-stream"); +//} +// +// BOOST_AUTO_TEST_CASE(post_with_explicit_content_type) { +// // This test checks that post(request, content_type, body) derives +// Content-Length, +// // and keeps Content-Type +// using namespace boost::network; +// +// const std::string postdata = "empty"; +// const std::string content_type = "application/x-my-content-type"; +// +// http::client::request req(base_url + "/cgi-bin/echo_headers.py"); +// +// http::client c; +// http::client::response r; +// BOOST_REQUIRE_NO_THROW(r = c.post(req, content_type, postdata)); +// +// std::map headers = parse_headers(body(r)); +// BOOST_CHECK_EQUAL(headers["content-length"], +// get_content_length(postdata)); +// BOOST_CHECK_EQUAL(headers["content-type"], content_type); +//} +// +// BOOST_AUTO_TEST_CASE(post_body_default_content_type) { +// // This test checks that post(request, body) gets the post data +// // through to the server +// using namespace boost::network; +// +// const std::string postdata = "firstname=bill&lastname=badger"; +// +// http::client::request req(base_url + "/cgi-bin/echo_body.py"); +// +// http::client c; +// http::client::response r; +// BOOST_REQUIRE_NO_THROW(r = c.post(req, postdata)); +// +// BOOST_CHECK_EQUAL(postdata, body(r)); +//} +// +// BOOST_AUTO_TEST_CASE(post_with_custom_headers) { +// // This test checks that custom headers pass through to the server +// // when posting +// using namespace boost::network; +// +// http::client::request req(base_url + "/cgi-bin/echo_headers.py"); +// req << header("X-Cpp-Netlib", "rocks!"); +// +// http::client c; +// http::client::response r; +// BOOST_REQUIRE_NO_THROW(r = c.post(req, std::string())); +// +// std::map headers = parse_headers(body(r)); +// BOOST_CHECK_EQUAL(headers["x-cpp-netlib"], "rocks!"); +//} diff --git a/cpp-netlib/libs/network/test/http/client_types.hpp b/cpp-netlib/libs/network/test/http/client_types.hpp new file mode 100644 index 00000000..3b547427 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/client_types.hpp @@ -0,0 +1,41 @@ +#ifndef CLIENT_TYPES_ROOWQCLE +#define CLIENT_TYPES_ROOWQCLE + +// Copyright 2010 Dean Michael Berris. +// 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 "tag_types.hpp" +#include +#include +#include +#include +#include +#include + +namespace mpl = boost::mpl; + +template +struct client_adapter { + template + struct apply { + typedef boost::network::http::basic_client type; + }; +}; + +typedef mpl::transform >::type client_1_0; + +typedef mpl::transform >::type client_1_1; + +typedef mpl::joint_view::type client_types; + +typedef mpl::joint_view< + mpl::transform >::type, + client_adapter<1, 0> >::type, + mpl::transform >::type, + client_adapter<1, 1> >::type>::type async_only_client_types; + +#endif /* CLIENT_TYPES_ROOWQCLE */ diff --git a/cpp-netlib/libs/network/test/http/http_test_server.hpp b/cpp-netlib/libs/network/test/http/http_test_server.hpp new file mode 100644 index 00000000..1438165a --- /dev/null +++ b/cpp-netlib/libs/network/test/http/http_test_server.hpp @@ -0,0 +1,158 @@ +// +// Copyright Kim Grasman 2008. +// 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) +// +// Changes by Allister Levi Sanchez 2008 +// Changes by Dean Michael Berris 2010 +#ifndef __NETWORK_TEST_HTTP_TEST_SERVER_HPP__ +#define __NETWORK_TEST_HTTP_TEST_SERVER_HPP__ + +#define BOOST_FILESYSTEM_VERSION 3 +#include + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(MIN) +#include + +// ShellExecuteEx +#include +#pragma comment(lib, "shell32") +#else +#include // fork, execlp etc. +#include +#include // for waitpid +#include // for chmod +#include // for kill +#endif + +struct http_test_server { + bool start() { + using namespace boost::filesystem; + + path script_path = get_server_path(current_path()); + if (script_path.empty()) return false; + + path cgibin_path = script_path.parent_path() / "cgi-bin"; + if (!set_cgibin_permissions(cgibin_path)) return false; + + server_child = launch_python_script(script_path); + if (server_child == 0) return false; + + return true; + } + + bool stop() { + kill_script(server_child); + return true; + } + + private: +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + typedef HANDLE script_handle_t; +#else + typedef pid_t script_handle_t; +#endif + + boost::filesystem::path get_server_path( + const boost::filesystem::path& base_path) { + using namespace boost::filesystem; + + const path script_name = +#if defined(HTTPS_SERVER_TEST) + "https_test_server.py" +#else + "http_test_server.py" +#endif + ; + + // if executed from $CPP_NETLIB_HOME + path server_path = base_path / "libs/network/test/server" / script_name; + if (exists(server_path)) + return server_path; + + // if executed from $CPP_NETLIB_HOME/libs/network/test + server_path = base_path / "server" / script_name; + if (exists(server_path)) + return server_path; + + // if executed from $CPP_NETLIB_HOME/libs/network/test/* + server_path = base_path / "../server" / script_name; + if (exists(server_path)) + return server_path; + + return path(); + } + + script_handle_t launch_python_script( + const boost::filesystem::path& python_script_path) { + using namespace boost::filesystem; + + path::string_type script_name = python_script_path.filename().native(); + path::string_type script_dir = python_script_path.parent_path().native(); + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + SHELLEXECUTEINFOA sei = {0}; + sei.cbSize = sizeof(sei); + sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; + sei.lpVerb = "open"; + sei.lpFile = "python.exe"; + sei.lpParameters = reinterpret_cast(script_name.c_str()); + sei.lpDirectory = reinterpret_cast(script_dir.c_str()); + sei.nShow = SW_SHOWNOACTIVATE; + + if (!ShellExecuteExA(&sei)) return 0; + + return sei.hProcess; +#else + // Try general Unix code + pid_t child_process = fork(); + if (child_process < 0) return false; + + if (child_process == 0) { + // child process + + // cd into script dir and launch python script + current_path(script_dir); + + if (execlp("python", "python", script_name.c_str(), (char*)NULL) == -1) + return 0; + } else { + // parent + sleep(1); + } + + return child_process; +#endif + } + + void kill_script(script_handle_t h) { +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + TerminateProcess(h, 0U); + CloseHandle(h); +#else + kill(h, SIGTERM); +#endif + } + + bool set_cgibin_permissions(const boost::filesystem::path& cgibin_path) { + using namespace boost::filesystem; + +#if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) + // set the CGI script execute permission + for (directory_iterator i(cgibin_path); i != directory_iterator(); ++i) { + if (is_regular_file(i->status())) { + path::string_type file_path = i->path().string(); + if (chmod(file_path.c_str(), S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH | + S_IRUSR | S_IRGRP | S_IROTH) != 0) + return false; + } + } +#endif + return true; + } + + script_handle_t server_child; +}; + +#endif // __NETWORK_TEST_HTTP_TEST_SERVER_HPP__ diff --git a/cpp-netlib/libs/network/test/http/message_async_ready_test.cpp b/cpp-netlib/libs/network/test/http/message_async_ready_test.cpp new file mode 100644 index 00000000..0ffda0ab --- /dev/null +++ b/cpp-netlib/libs/network/test/http/message_async_ready_test.cpp @@ -0,0 +1,18 @@ + +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP Async Response Test +#include +#include + +namespace http = boost::network::http; + +BOOST_AUTO_TEST_CASE(unready_state_response) { + typedef http::basic_response + response; + response r; + BOOST_CHECK(!ready(r)); +} diff --git a/cpp-netlib/libs/network/test/http/message_test.cpp b/cpp-netlib/libs/network/test/http/message_test.cpp new file mode 100644 index 00000000..a3f58592 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/message_test.cpp @@ -0,0 +1,167 @@ + +// Copyright 2010 (c) Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP message test +#include +#include +#include +#include +#include +#include + +using namespace boost::network; + +typedef boost::mpl::list tag_types; + +struct fixtures {}; + +BOOST_FIXTURE_TEST_SUITE(http_message_test_suite, fixtures) + +BOOST_AUTO_TEST_CASE_TEMPLATE(request_constructor_test, T, tag_types) { + http::basic_request request("http://boost.org"); + typedef typename http::basic_request::string_type string_type; + string_type host = http::host(request); + boost::uint16_t port = http::port(request); + string_type path = http::path(request); + string_type query = http::query(request); + string_type anchor = http::anchor(request); + string_type protocol = http::protocol(request); + BOOST_CHECK_EQUAL(host, "boost.org"); + BOOST_CHECK_EQUAL(port, 80u); + BOOST_CHECK_EQUAL(path, "/"); + BOOST_CHECK_EQUAL(query, ""); + BOOST_CHECK_EQUAL(anchor, ""); + BOOST_CHECK_EQUAL(protocol, "http"); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(request_copy_constructor_test, T, tag_types) { + http::basic_request request("http://boost.org/handler.php"); + request << header("Content-Type", "text/plain") << body("Hello, World!"); + http::basic_request copy(request); + typedef typename http::basic_request::string_type string_type; + string_type orig_host = http::host(request), copy_host = http::host(copy); + boost::uint16_t orig_port = http::port(request), copy_port = http::port(copy); + string_type orig_path = http::path(request), copy_path = http::path(copy); + string_type orig_body = body(request), copy_body = body(copy); + BOOST_CHECK_EQUAL(orig_host, copy_host); + BOOST_CHECK_EQUAL(orig_port, copy_port); + BOOST_CHECK_EQUAL(orig_path, copy_path); + BOOST_CHECK_EQUAL(orig_body, copy_body); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(request_assignment_test, T, tag_types) { + http::basic_request request("http://boost.org/handler.php"); + request << header("Content-Type", "text/plain") << body("Hello, World!"); + http::basic_request copy; + copy = request; + typedef typename http::basic_request::string_type string_type; + string_type orig_host = http::host(request), copy_host = http::host(copy); + boost::uint16_t orig_port = http::port(request), copy_port = http::port(copy); + string_type orig_path = http::path(request), copy_path = http::path(copy); + string_type orig_body = body(request), copy_body = body(copy); + BOOST_CHECK_EQUAL(orig_host, copy_host); + BOOST_CHECK_EQUAL(orig_port, copy_port); + BOOST_CHECK_EQUAL(orig_path, copy_path); + BOOST_CHECK_EQUAL(orig_body, copy_body); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(request_swap_test, T, tag_types) { + boost::network::http::basic_request request("http://boost.org/"); + boost::network::http::basic_request other; + swap(other, request); // ADL + typedef typename http::basic_request::string_type string_type; + string_type orig_host = http::host(request), orig_path = http::path(request), + copy_host = http::host(other), copy_path = http::path(other); + boost::uint16_t orig_port = http::port(request), + copy_port = http::port(request); + BOOST_CHECK_EQUAL(orig_host, ""); + BOOST_CHECK_EQUAL(orig_port, 80u); + BOOST_CHECK_EQUAL(orig_path, "/"); + BOOST_CHECK_EQUAL(copy_host, "boost.org"); + BOOST_CHECK_EQUAL(copy_port, 80u); + BOOST_CHECK_EQUAL(copy_path, "/"); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(request_uri_directive_test, T, tag_types) { + http::basic_request request; + request << http::uri("http://boost.org/"); + typename http::basic_request::string_type uri_ = http::uri(request); + BOOST_CHECK_EQUAL(uri_, "http://boost.org/"); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(response_constructor_test, T, tag_types) { + http::basic_response response; + typename http::basic_response::string_type body_ = body(response); + BOOST_CHECK_EQUAL(body_, std::string()); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(response_copy_construct_test, T, tag_types) { + using namespace http; + http::basic_response response; + response << http::version("HTTP/1.1") << http::status(200u) + << body("The quick brown fox jumps over the lazy dog") + << http::status_message("OK"); + http::basic_response copy(response); + + typename http::basic_response::string_type version_orig = + version(response), + version_copy = version(copy); + BOOST_CHECK_EQUAL(version_orig, version_copy); + boost::uint16_t status_orig = status(response), status_copy = status(copy); + BOOST_CHECK_EQUAL(status_orig, status_copy); + typename http::basic_response::string_type status_message_orig = + status_message(response), + status_message_copy = + status_message(copy), + body_orig = body(response), + body_copy = body(copy); + BOOST_CHECK_EQUAL(status_message_orig, status_message_copy); + BOOST_CHECK_EQUAL(body_orig, body_copy); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(response_assignment_construct_test, T, + tag_types) { + http::basic_response response; + response << http::version("HTTP/1.1") << http::status(200) + << http::status_message("OK") + << body("The quick brown fox jumps over the lazy dog"); + http::basic_response copy; + copy = response; + typedef typename http::basic_response::string_type string_type; + string_type version_orig = version(response), version_copy = version(copy); + BOOST_CHECK_EQUAL(version_orig, version_copy); + boost::uint16_t status_orig = status(response), status_copy = status(copy); + BOOST_CHECK_EQUAL(status_orig, status_copy); + string_type status_message_orig = status_message(response), + status_message_copy = status_message(copy); + BOOST_CHECK_EQUAL(status_message_orig, status_message_copy); + string_type body_orig = body(response), body_copy = body(copy); + BOOST_CHECK_EQUAL(body_orig, body_copy); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(response_swap_test, T, tag_types) { + using namespace boost::network::http; + http::basic_response response; + response << version("HTTP/1.1") << status(200) << status_message("OK") + << body("RESPONSE"); + boost::network::http::basic_response swapped; + BOOST_REQUIRE_NO_THROW(swap(response, swapped)); + BOOST_CHECK_EQUAL(response.version(), std::string()); + BOOST_CHECK_EQUAL(response.status(), 0u); + BOOST_CHECK_EQUAL(response.status_message(), std::string()); + typename http::basic_response::string_type orig_body = body(response), + swapped_body = body(swapped); + BOOST_CHECK_EQUAL(orig_body, std::string()); + BOOST_CHECK_EQUAL(swapped.version(), std::string("HTTP/1.1")); + BOOST_CHECK_EQUAL(swapped.status(), 200u); + BOOST_CHECK_EQUAL(swapped.status_message(), std::string("OK")); + BOOST_CHECK_EQUAL(swapped_body, std::string("RESPONSE")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/cpp-netlib/libs/network/test/http/request_incremental_parser_test.cpp b/cpp-netlib/libs/network/test/http/request_incremental_parser_test.cpp new file mode 100644 index 00000000..37c860c0 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/request_incremental_parser_test.cpp @@ -0,0 +1,141 @@ +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP Incremental Request Parser Test +#include +#include +#include +#include +#include +#include +#include +#include + +/** Synopsis + * + * Test for the HTTP Request Incremental Parser + * -------------------------------------------- + * + * In this test we fully intend to specify how an incremental HTTP request + * parser should be used. This follows the HTTP Response Incremental Parser + * example, and models the Incremental Parser Concept. + * + */ + +namespace tags = boost::network::tags; +namespace logic = boost::logic; +namespace fusion = boost::fusion; +using namespace boost::network::http; + +BOOST_AUTO_TEST_CASE(incremental_parser_constructor) { + request_parser p; // default constructible +} + +BOOST_AUTO_TEST_CASE(incremental_parser_parse_http_method) { + request_parser p; + logic::tribool parsed_ok = false; + typedef request_parser request_parser_type; + typedef boost::iterator_range range_type; + range_type result_range; + + std::string valid_http_method = "GET "; + fusion::tie(parsed_ok, result_range) = + p.parse_until(request_parser_type::method_done, valid_http_method); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(!boost::empty(result_range)); + std::string parsed(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " [state:" << p.state() << "] " + << std::endl; + + std::string invalid_http_method = "get "; + p.reset(); + fusion::tie(parsed_ok, result_range) = + p.parse_until(request_parser_type::method_done, invalid_http_method); + BOOST_CHECK_EQUAL(parsed_ok, false); + parsed.assign(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " [state:" << p.state() << "] " + << std::endl; +} + +BOOST_AUTO_TEST_CASE(incremental_parser_parse_http_uri) { + request_parser p; + logic::tribool parsed_ok = false; + typedef request_parser request_parser_type; + typedef boost::iterator_range range_type; + range_type result_range; + + std::string valid_http_request = "GET / HTTP/1.1\r\n"; + fusion::tie(parsed_ok, result_range) = + p.parse_until(request_parser_type::uri_done, valid_http_request); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(!boost::empty(result_range)); + std::string parsed(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " [state:" << p.state() << "] " + << std::endl; + + std::string invalid_http_request = "GET /\t HTTP/1.1\r\n"; + p.reset(); + fusion::tie(parsed_ok, result_range) = + p.parse_until(request_parser_type::uri_done, invalid_http_request); + BOOST_CHECK_EQUAL(parsed_ok, false); + parsed.assign(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " [state:" << p.state() << "] " + << std::endl; +} + +BOOST_AUTO_TEST_CASE(incremental_parser_parse_http_version) { + request_parser p; + logic::tribool parsed_ok = false; + typedef request_parser request_parser_type; + typedef boost::iterator_range range_type; + range_type result_range; + + std::string valid_http_request = "GET / HTTP/1.1\r\n"; + fusion::tie(parsed_ok, result_range) = + p.parse_until(request_parser_type::version_done, valid_http_request); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(!boost::empty(result_range)); + std::string parsed(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " [state:" << p.state() << "] " + << std::endl; + + std::string invalid_http_request = "GET / HTTP 1.1\r\n"; + p.reset(); + fusion::tie(parsed_ok, result_range) = + p.parse_until(request_parser_type::version_done, invalid_http_request); + BOOST_CHECK_EQUAL(parsed_ok, false); + parsed.assign(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " [state:" << p.state() << "] " + << std::endl; +} + +BOOST_AUTO_TEST_CASE(incremental_parser_parse_http_headers) { + request_parser p; + logic::tribool parsed_ok = false; + typedef request_parser request_parser_type; + typedef boost::iterator_range range_type; + range_type result_range; + + std::string valid_http_request = + "GET / HTTP/1.1\r\nHost: cpp-netlib.org\r\n\r\n"; + fusion::tie(parsed_ok, result_range) = + p.parse_until(request_parser_type::headers_done, valid_http_request); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(!boost::empty(result_range)); + std::string parsed(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " [state:" << p.state() << "] " + << std::endl; + + valid_http_request = + "GET / HTTP/1.1\r\nHost: cpp-netlib.org\r\nConnection: close\r\n\r\n"; + p.reset(); + fusion::tie(parsed_ok, result_range) = + p.parse_until(request_parser_type::headers_done, valid_http_request); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(!boost::empty(result_range)); + parsed.assign(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " [state:" << p.state() << "] " + << std::endl; +} diff --git a/cpp-netlib/libs/network/test/http/request_linearize_test.cpp b/cpp-netlib/libs/network/test/http/request_linearize_test.cpp new file mode 100644 index 00000000..204fbff1 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/request_linearize_test.cpp @@ -0,0 +1,70 @@ + +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP Request Linearize Test +#include +#include +#include +#include +#include +#include + +namespace http = boost::network::http; +namespace tags = boost::network::http::tags; +namespace mpl = boost::mpl; +namespace net = boost::network; + +typedef mpl::list tag_types; + +BOOST_AUTO_TEST_CASE_TEMPLATE(linearize_request, T, tag_types) { + http::basic_request request("http://www.boost.org"); + static char http_1_0_output[] = + "GET / HTTP/1.0\r\n" + "Host: www.boost.org\r\n" + "Accept: */*\r\n" + "Connection: Close\r\n" + "\r\n"; + static char http_1_1_output[] = + "GET / HTTP/1.1\r\n" + "Host: www.boost.org\r\n" + "Accept: */*\r\n" + "Accept-Encoding: identity;q=1.0, *;q=0\r\n" + "Connection: Close\r\n" + "\r\n"; + typename http::basic_request::string_type output_1_0; + linearize(request, "GET", 1, 0, std::back_inserter(output_1_0)); + BOOST_CHECK_EQUAL(output_1_0, http_1_0_output); + typename http::basic_request::string_type output_1_1; + linearize(request, "GET", 1, 1, std::back_inserter(output_1_1)); + BOOST_CHECK_EQUAL(output_1_1, http_1_1_output); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(linearize_request_override_headers, T, + tag_types) { + http::basic_request request("http://www.boost.org"); + // We can override the defaulted headers and test that here. + request << net::header("Accept", ""); + static char http_1_0_no_accept_output[] = + "GET / HTTP/1.0\r\n" + "Host: www.boost.org\r\n" + "Connection: Close\r\n" + "\r\n"; + static char http_1_1_no_accept_output[] = + "GET / HTTP/1.1\r\n" + "Host: www.boost.org\r\n" + "Accept-Encoding: identity;q=1.0, *;q=0\r\n" + "Connection: Close\r\n" + "\r\n"; + typename http::basic_request::string_type output_1_0; + linearize(request, "GET", 1, 0, std::back_inserter(output_1_0)); + BOOST_CHECK_EQUAL(output_1_0, http_1_0_no_accept_output); + typename http::basic_request::string_type output_1_1; + linearize(request, "GET", 1, 1, std::back_inserter(output_1_1)); + BOOST_CHECK_EQUAL(output_1_1, http_1_1_no_accept_output); +} diff --git a/cpp-netlib/libs/network/test/http/response_incremental_parser_test.cpp b/cpp-netlib/libs/network/test/http/response_incremental_parser_test.cpp new file mode 100644 index 00000000..a749cf36 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/response_incremental_parser_test.cpp @@ -0,0 +1,361 @@ + +// Copyright Dean Michael Berris 2010. +// 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) + +#define BOOST_TEST_MODULE HTTP Incremental Parser Test +#include +#include +#include +#include +#include +#include +#include + +/** Synopsis + * + * Test for HTTP Response Incremental Parser + * ----------------------------------------- + * + * In this test we fully intend to specify how an incremental + * HTTP Response parser should be used. This defines the bare + * minimum implementation for an Incremental Parser concept, + * and shall follow an interface that puts a premium on simplicity. + * + * The motivation for coming up with a re-startable stateful + * incremental parser comes from the requirement in the asynchronous + * HTTP client implementation that allows for parsing an HTTP + * response as the data comes in. By being able to process some + * parts of the message ahead of others, we are allowed to set + * the promise values bound to futures that the users of the client + * would be waiting on. + * + * The basic interface that we're looking for is a means of providing: + * - a range of input + * - a means of resetting the parser's state + * - a means of initializing the parser to a given state + * - a parse_until function that takes a state as parameter and + * a range from which the parser will operate on, returns + * a tuple of a boost::logic::tribool and a resulting range + * + * One of the possible implementations can use the Boost.MSM library + * to create the state machine. The test however does not specify what + * implementation should be used, but rather that the interface and the + * semantics are according to expectations. + * + * Date: September 9, 2010 + * Author: Dean Michael Berris + */ + +namespace tags = boost::network::tags; +namespace logic = boost::logic; +namespace fusion = boost::fusion; +using namespace boost::network::http; + +struct crlf { + static const std::string literal; +}; +const std::string crlf::literal = "\r\n"; +struct lf { + static const std::string literal; +}; +const std::string lf::literal = "\n"; +typedef boost::mpl::vector eol_types; + +BOOST_AUTO_TEST_CASE(incremental_parser_constructor) { + response_parser p; // default constructible +} + +/** In this test we want to be able to parse incrementally a + * range passed in as input, and specify to the parser that + * it should stop when we reach a certain state. In this case + * we want it to parse until it either finds the HTTP version + * or there is an error encountered. + */ +BOOST_AUTO_TEST_CASE(incremental_parser_parse_http_version) { + response_parser p; // default constructible + logic::tribool parsed_ok = false; + typedef response_parser response_parser_type; + typedef boost::iterator_range range_type; + range_type result_range; + + std::string valid_http_version = "HTTP/1.0 "; + fusion::tie(parsed_ok, result_range) = p.parse_until( + response_parser_type::http_version_done, valid_http_version); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(!boost::empty(result_range)); + std::string parsed(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; + p.reset(); + valid_http_version = "HTTP/1.1 "; + fusion::tie(parsed_ok, result_range) = p.parse_until( + response_parser_type::http_version_done, valid_http_version); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(!boost::empty(result_range)); + parsed.assign(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; + + p.reset(); + std::string invalid_http_version = "HTTP 1.0"; + parsed_ok = logic::indeterminate; + fusion::tie(parsed_ok, result_range) = p.parse_until( + response_parser_type::http_version_done, invalid_http_version); + BOOST_CHECK_EQUAL(parsed_ok, false); + parsed.assign(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; + + p.reset(); + valid_http_version = "HTTP/0.9 "; + parsed_ok = logic::indeterminate; + fusion::tie(parsed_ok, result_range) = p.parse_until( + response_parser_type::http_version_done, valid_http_version); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed.assign(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; +} + +/** In this test we then want to check that we can parse a status + * string right after the version string. We should expect that + * the parser doesn't do any conversions from string to integer + * and outsource that part to the user of the parser. + */ +BOOST_AUTO_TEST_CASE_TEMPLATE(incremental_parser_parse_status, eol, eol_types) { + typedef response_parser response_parser_type; + typedef boost::iterator_range range_type; + // We want to create a parser that has been initialized to a specific + // state. In this case we assume that the parser has already parsed + // the version part of the HTTP Response. + response_parser_type p(response_parser_type::http_version_done); + + std::string valid_status = "200 "; + logic::tribool parsed_ok; + range_type result_range; + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_status_done, valid_status); + BOOST_CHECK_EQUAL(parsed_ok, true); + std::string parsed = + std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; + + p.reset(response_parser_type::http_version_done); + std::string invalid_status = "200x "; + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_status_done, invalid_status); + BOOST_CHECK_EQUAL(parsed_ok, false); + parsed = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; + + valid_status = "200" + eol::literal; + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_status_done, valid_status); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; +} + +/** In this test then we get the rest of the first line of the HTTP + * Response, and treat it as the status message. + */ +BOOST_AUTO_TEST_CASE_TEMPLATE(incremental_parser_parse_status_message, eol, + eol_types) { + typedef response_parser response_parser_type; + typedef boost::iterator_range range_type; + response_parser_type p(response_parser_type::http_status_done); + + std::string valid_status_message = "OK" + eol::literal + "Server: Foo"; + logic::tribool parsed_ok; + range_type result_range; + fusion::tie(parsed_ok, result_range) = p.parse_until( + response_parser_type::http_status_message_done, valid_status_message); + BOOST_CHECK_EQUAL(parsed_ok, true); + std::string parsed = + std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; + + p.reset(response_parser_type::http_status_done); + valid_status_message = "OK" + eol::literal; + fusion::tie(parsed_ok, result_range) = p.parse_until( + response_parser_type::http_status_message_done, valid_status_message); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; + + p.reset(response_parser_type::http_status_done); + valid_status_message = "Internal Server Error" + eol::literal; + fusion::tie(parsed_ok, result_range) = p.parse_until( + response_parser_type::http_status_message_done, valid_status_message); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; + + p.reset(response_parser_type::http_status_done); + valid_status_message = eol::literal; + fusion::tie(parsed_ok, result_range) = p.parse_until( + response_parser_type::http_status_message_done, valid_status_message); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; + + p.reset(response_parser_type::http_status_done); + valid_status_message = "한글메시지" + eol::literal; + fusion::tie(parsed_ok, result_range) = p.parse_until( + response_parser_type::http_status_message_done, valid_status_message); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl; +} + +/** This test specifices how one-line-per-header parsing happens incrementally. + */ +BOOST_AUTO_TEST_CASE_TEMPLATE(incremental_parser_parse_header_lines, eol, + eol_types) { + typedef response_parser response_parser_type; + typedef boost::iterator_range range_type; + response_parser_type p(response_parser_type::http_status_message_done); + + std::string valid_headers = "Server: Foo" + eol::literal + + "Content-Type: application/json" + eol::literal + + eol::literal; + logic::tribool parsed_ok; + range_type result_range; + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + std::string parsed1 = + std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed1 << " state=" << p.state() << std::endl; + p.reset(response_parser_type::http_status_message_done); + std::string::const_iterator end = valid_headers.end(); + valid_headers.assign(boost::end(result_range), end); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + std::string parsed2 = + std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed2 << " state=" << p.state() << std::endl; + valid_headers.assign(boost::end(result_range), end); + p.reset(response_parser_type::http_status_message_done); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_headers_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(parsed1 != parsed2); + + p.reset(response_parser_type::http_status_message_done); + valid_headers = " Server: Foo" + eol::literal + + " Content-Type: application/json" + eol::literal + + eol::literal; + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed1 = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed1 << " state=" << p.state() << std::endl; + p.reset(response_parser_type::http_status_message_done); + end = valid_headers.end(); + valid_headers.assign(boost::end(result_range), end); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed2 = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed2 << " state=" << p.state() << std::endl; + valid_headers.assign(boost::end(result_range), end); + p.reset(response_parser_type::http_status_message_done); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_headers_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(parsed1 != parsed2); + + p.reset(response_parser_type::http_status_message_done); + valid_headers = "_Server: Foo" + eol::literal + + "_Content-Type: application/json" + eol::literal + + eol::literal; + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed1 = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed1 << " state=" << p.state() << std::endl; + p.reset(response_parser_type::http_status_message_done); + end = valid_headers.end(); + valid_headers.assign(boost::end(result_range), end); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed2 = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed2 << " state=" << p.state() << std::endl; + valid_headers.assign(boost::end(result_range), end); + p.reset(response_parser_type::http_status_message_done); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_headers_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(parsed1 != parsed2); + + p.reset(response_parser_type::http_status_message_done); + valid_headers = "Server: " + eol::literal + "Content-Type: application/json" + + eol::literal + eol::literal; + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed1 = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed1 << " state=" << p.state() << std::endl; + p.reset(response_parser_type::http_status_message_done); + end = valid_headers.end(); + valid_headers.assign(boost::end(result_range), end); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed2 = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed2 << " state=" << p.state() << std::endl; + valid_headers.assign(boost::end(result_range), end); + p.reset(response_parser_type::http_status_message_done); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_headers_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(parsed1 != parsed2); + + p.reset(response_parser_type::http_status_message_done); + valid_headers = "Server: 서버" + eol::literal + + "Content-Type: application/json" + eol::literal + + eol::literal; + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed1 = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed1 << " state=" << p.state() << std::endl; + p.reset(response_parser_type::http_status_message_done); + end = valid_headers.end(); + valid_headers.assign(boost::end(result_range), end); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed2 = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed2 << " state=" << p.state() << std::endl; + valid_headers.assign(boost::end(result_range), end); + p.reset(response_parser_type::http_status_message_done); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_headers_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(parsed1 != parsed2); + + p.reset(response_parser_type::http_status_message_done); + valid_headers = "Content-Type: text/html;" + eol::literal + "charset=utf-8" + + eol::literal + eol::literal; + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed1 = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed1 << " state=" << p.state() << std::endl; + p.reset(response_parser_type::http_status_message_done); + end = valid_headers.end(); + valid_headers.assign(boost::end(result_range), end); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_header_line_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + parsed2 = std::string(boost::begin(result_range), boost::end(result_range)); + std::cout << "PARSED: " << parsed2 << " state=" << p.state() << std::endl; + valid_headers.assign(boost::end(result_range), end); + p.reset(response_parser_type::http_status_message_done); + fusion::tie(parsed_ok, result_range) = + p.parse_until(response_parser_type::http_headers_done, valid_headers); + BOOST_CHECK_EQUAL(parsed_ok, true); + BOOST_CHECK(parsed1 != parsed2); +} diff --git a/cpp-netlib/libs/network/test/http/server_async.cpp b/cpp-netlib/libs/network/test/http/server_async.cpp new file mode 100644 index 00000000..e117085f --- /dev/null +++ b/cpp-netlib/libs/network/test/http/server_async.cpp @@ -0,0 +1,52 @@ + +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP Asynchronous Server Tests + +#include +#include +#include +#include + +namespace net = boost::network; +namespace http = boost::network::http; +namespace utils = boost::network::utils; + +struct async_hello_world; +typedef http::async_server server; + +struct async_hello_world { + + struct is_content_length { + template + bool operator()(Header const& header) { + return boost::iequals(name(header), "content-length"); + } + }; + + void operator()(server::request const& request, + server::connection_ptr connection) { + static server::response_header headers[] = {{"Connection", "close"}, + {"Content-Type", "text/plain"}, + {"Server", "cpp-netlib/0.9"}, + {"Content-Length", "13"}}; + static std::string hello_world("Hello, World!"); + connection->set_status(server::connection::ok); + connection->set_headers(boost::make_iterator_range(headers, headers + 4)); + connection->write(hello_world); + } +}; + +int main(int argc, char* argv[]) { + utils::thread_pool thread_pool(2); + async_hello_world handler; + std::string port = "8000"; + if (argc > 1) port = argv[1]; + server instance("localhost", port, handler, thread_pool, + http::_reuse_address = true); + instance.run(); + return 0; +} diff --git a/cpp-netlib/libs/network/test/http/server_async_less_copy.cpp b/cpp-netlib/libs/network/test/http/server_async_less_copy.cpp new file mode 100644 index 00000000..b4220b1c --- /dev/null +++ b/cpp-netlib/libs/network/test/http/server_async_less_copy.cpp @@ -0,0 +1,61 @@ + +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP Asynchronous Server Tests + +#include + +#include +#include +#include +#include +#include + +namespace net = boost::network; +namespace http = boost::network::http; +namespace utils = boost::network::utils; + +struct async_hello_world; +typedef http::async_server server; + +struct async_hello_world { + + struct is_content_length { + template + bool operator()(Header const& header) { + return boost::iequals(name(header), "content-length"); + } + }; + + void operator()(server::request const& request, + server::connection_ptr connection) { + static server::response_header headers[] = {{"Connection", "close"}, + {"Content-Type", "text/plain"}, + {"Server", "cpp-netlib/0.9"}, + {"Content-Length", "13"}}; + static char const* hello_world = "Hello, World!"; + connection->set_status(server::connection::ok); + connection->set_headers(boost::make_iterator_range(headers, headers + 4)); + std::vector iovec; + iovec.push_back(boost::asio::const_buffer(hello_world, 13)); + connection->write(iovec, boost::bind(&async_hello_world::error, this, _1)); + } + + void error(boost::system::error_code const& ec) { + // do nothing here. + } +}; + +int main(int argc, char* argv[]) { + utils::thread_pool thread_pool(2); + async_hello_world handler; + std::string port = "8000"; + if (argc > 1) port = argv[1]; + server instance("127.0.0.1", port, handler, thread_pool, + http::_reuse_address = true); + instance.run(); + return 0; +} diff --git a/cpp-netlib/libs/network/test/http/server_async_run_stop_concurrency.cpp b/cpp-netlib/libs/network/test/http/server_async_run_stop_concurrency.cpp new file mode 100644 index 00000000..f3a69e8a --- /dev/null +++ b/cpp-netlib/libs/network/test/http/server_async_run_stop_concurrency.cpp @@ -0,0 +1,154 @@ +#define BOOST_TEST_MODULE HTTP Asynchronous Server Tests +#ifdef BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#endif /* BOOST_TEST_DYN_LINK */ + +#include +#include +#include + +namespace http = boost::network::http; +namespace util = boost::network::utils; + +struct dummy_async_handler; +typedef http::async_server async_server; + +struct dummy_async_handler { + void operator()(async_server::request const& req, + async_server::connection_ptr conn) { + // Really, this is just for testing purposes + } +}; + +// In this batch of tests we ensure that calling run and stop on an +// async_server, in any sequence, is thread safe. + +int main(int argc, char* argv[]) { + dummy_async_handler async_handler; + +#define ASYNC_SERVER_TEST_CONFIG \ + options.address("127.0.0.1").port("8007").reuse_address(true) + +#define ASYNC_SERVER_SLEEP_TIME boost::posix_time::milliseconds(100) + + // stop from main thread + { + BOOST_NETWORK_MESSAGE("TEST: stop without running"); + async_server::options options(async_handler); + async_server server_instance(ASYNC_SERVER_TEST_CONFIG); + server_instance.stop(); + } + + // run-stop from main thread + { + BOOST_NETWORK_MESSAGE("TEST: stop from main thread"); + async_server::options options(async_handler); + async_server server_instance(ASYNC_SERVER_TEST_CONFIG); + + boost::thread running_thread( + boost::bind(&async_server::run, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + server_instance.stop(); + running_thread.join(); + } + + // run-stop from another thread + { + BOOST_NETWORK_MESSAGE("TEST: stop from another thread"); + async_server::options options(async_handler); + async_server server_instance(ASYNC_SERVER_TEST_CONFIG); + + boost::thread running_thread( + boost::bind(&async_server::run, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + boost::thread stopping_thread( + boost::bind(&async_server::stop, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + stopping_thread.join(); + running_thread.join(); + } + + // run-stop-run-stop from another thread + { + BOOST_NETWORK_MESSAGE("TEST: run-stop-run-stop from another thread"); + async_server::options options(async_handler); + async_server server_instance(ASYNC_SERVER_TEST_CONFIG); + + boost::thread running_thread( + boost::bind(&async_server::run, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + boost::thread stopping_thread( + boost::bind(&async_server::stop, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + boost::thread second_running_thread( + boost::bind(&async_server::run, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + boost::thread second_stopping_thread( + boost::bind(&async_server::stop, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + stopping_thread.join(); + running_thread.join(); + second_stopping_thread.join(); + second_running_thread.join(); + } + + // run-run-stop from another thread + { + BOOST_NETWORK_MESSAGE("TEST: run-run-stop from another thread"); + async_server::options options(async_handler); + async_server server_instance(ASYNC_SERVER_TEST_CONFIG); + + boost::thread running_thread( + boost::bind(&async_server::run, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + boost::thread second_running_thread( + boost::bind(&async_server::run, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + boost::thread stopping_thread( + boost::bind(&async_server::stop, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + stopping_thread.join(); + running_thread.join(); + second_running_thread.join(); + } + + // run-stop-stop from another thread + { + BOOST_NETWORK_MESSAGE("TEST: run-stop-stop from another thread"); + async_server::options options(async_handler); + async_server server_instance(ASYNC_SERVER_TEST_CONFIG); + + boost::thread running_thread( + boost::bind(&async_server::run, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + boost::thread stopping_thread( + boost::bind(&async_server::stop, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + boost::thread second_stopping_thread( + boost::bind(&async_server::stop, &server_instance)); + boost::this_thread::sleep(ASYNC_SERVER_SLEEP_TIME); + + stopping_thread.join(); + second_stopping_thread.join(); + running_thread.join(); + } + +#undef ASYNC_SERVER_TEST_CONFIG + + return 0; +} +#ifdef BOOST_TEST_DYN_LINK +#undef BOOST_TEST_NO_MAIN +#endif /* BOOST_TEST_DYN_LINK */ diff --git a/cpp-netlib/libs/network/test/http/server_constructor_test.cpp b/cpp-netlib/libs/network/test/http/server_constructor_test.cpp new file mode 100644 index 00000000..dc8349b4 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/server_constructor_test.cpp @@ -0,0 +1,83 @@ + +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP Server Construtor Tests + +#include +#include + +namespace http = boost::network::http; +namespace util = boost::network::utils; + +struct dummy_sync_handler; +struct dummy_async_handler; +typedef http::server sync_server; +typedef http::async_server async_server; + +struct dummy_sync_handler { + void operator()(sync_server::request const &req, sync_server::response &res) { + // Really, this is just for testing purposes + } + + void log(char const *) {} +}; + +struct dummy_async_handler { + void operator()(async_server::request const &req, + async_server::connection_ptr conn) { + // Really, this is just for testing purposes + } +}; + +BOOST_AUTO_TEST_CASE(minimal_constructor) { + dummy_sync_handler sync_handler; + dummy_async_handler async_handler; + sync_server::options sync_options(sync_handler); + async_server::options async_options(async_handler); + BOOST_CHECK_NO_THROW( + sync_server sync_instance(sync_options.address("127.0.0.1").port("80"))); + BOOST_CHECK_NO_THROW(async_server async_instance( + async_options.address("127.0.0.1").port("80"))); +} + +BOOST_AUTO_TEST_CASE(with_io_service_parameter) { + dummy_sync_handler sync_handler; + dummy_async_handler async_handler; + boost::shared_ptr thread_pool; + boost::shared_ptr io_service; + sync_server::options sync_options(sync_handler); + async_server::options async_options(async_handler); + + BOOST_CHECK_NO_THROW( + sync_server sync_instance(sync_options.address("127.0.0.1") + .port("80") + .io_service(io_service) + .thread_pool(thread_pool))); + BOOST_CHECK_NO_THROW( + async_server async_instance(async_options.address("127.0.0.1") + .port("80") + .io_service(io_service) + .thread_pool(thread_pool))); +} + +BOOST_AUTO_TEST_CASE(throws_on_failure) { + dummy_sync_handler sync_handler; + dummy_async_handler async_handler; + boost::shared_ptr thread_pool; + boost::shared_ptr io_service; + sync_server::options sync_options(sync_handler); + async_server::options async_options(async_handler); + sync_server sync_instance(sync_options.address("127.0.0.1") + .port("80") + .io_service(io_service) + .thread_pool(thread_pool)); + async_server async_instance(async_options.address("127.0.0.1") + .port("80") + .io_service(io_service) + .thread_pool(thread_pool)); + BOOST_CHECK_THROW(sync_instance.run(), std::runtime_error); + BOOST_CHECK_THROW(async_instance.run(), std::runtime_error); +} diff --git a/cpp-netlib/libs/network/test/http/server_header_parser_test.cpp b/cpp-netlib/libs/network/test/http/server_header_parser_test.cpp new file mode 100644 index 00000000..7bfefbf2 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/server_header_parser_test.cpp @@ -0,0 +1,55 @@ +// Copyright 2013 Rudolfs Bundulis +// 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) + +#define BOOST_TEST_MODULE HTTP Server Header Parser Test +#include +#include +#include +#define BOOST_LOCALE_NO_LIB +#include +#include +#include + +/** Synopsis +* +* Test for Utf8 support in the asynchronous connection header parser +* -------------------------------------------- +* +* This test checks for Utf8 support in the header parser +* for asynchronous connection +* +*/ + +namespace tags = boost::network::tags; +namespace logic = boost::logic; +namespace fusion = boost::fusion; +using namespace boost::network::http; + +BOOST_AUTO_TEST_CASE(async_connection_parse_headers) { + std::wstring utf16_test_name = L"R\u016bdolfs"; + request_header_narrow utf8_header = { + "X-Utf8-Test-Header", + boost::locale::conv::utf_to_utf(utf16_test_name)}; + std::string valid_http_request; + valid_http_request.append(utf8_header.name) + .append(": ") + .append(utf8_header.value) + .append("\r\n\r\n"); + std::vector headers; + parse_headers(valid_http_request, headers); + std::vector::iterator header_iterator = + headers.begin(); + for (; header_iterator != headers.end(); ++header_iterator) { + if (header_iterator->name == utf8_header.name && + header_iterator->value == utf8_header.value) + break; + } + std::wstring utf16_test_name_from_header = + boost::locale::conv::utf_to_utf(header_iterator->value); + BOOST_CHECK(header_iterator != headers.end()); + BOOST_CHECK(utf16_test_name_from_header == utf16_test_name); + std::cout << "utf8 header parsed, name: " << header_iterator->name + << ", value: " << header_iterator->value; +} diff --git a/cpp-netlib/libs/network/test/http/server_hello_world.cpp b/cpp-netlib/libs/network/test/http/server_hello_world.cpp new file mode 100644 index 00000000..7f9ce869 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/server_hello_world.cpp @@ -0,0 +1,51 @@ +// Copyright 2009 (c) Tarro, Inc. +// Copyright 2009-2010 (c) Dean Michael Berris +// 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 +#include +#include +#include +#include +#include +#include + +namespace http = boost::network::http; +using boost::assign::list_of; +using boost::lexical_cast; +using std::string; +using std::cerr; +using std::endl; + +struct hello_world; +typedef http::server server; + +struct hello_world { + + void operator()(server::request const& request, server::response& response) { + static server::response::header_type header = {"Connection", "close"}; + response = + server::response::stock_reply(server::response::ok, "Hello, World!"); + response.headers.push_back(header); + assert(response.status == server::response::ok); + assert(response.headers.size() == 3); + assert(response.content == "Hello, World!"); + } + + void log(string const& data) { + cerr << data << endl; + abort(); + } +}; + +int main(int argc, char* argv[]) { + hello_world handler; + std::string port = "8000"; + if (argc > 1) port = argv[1]; + server server_("127.0.0.1", port, handler, http::_reuse_address = true); + server_.run(); + return EXIT_SUCCESS; +} diff --git a/cpp-netlib/libs/network/test/http/server_include_inlined.cpp b/cpp-netlib/libs/network/test/http/server_include_inlined.cpp new file mode 100644 index 00000000..b4d1b20c --- /dev/null +++ b/cpp-netlib/libs/network/test/http/server_include_inlined.cpp @@ -0,0 +1,60 @@ +// Copyright 2009 (c) Tarro, Inc. +// Copyright 2009-2010 (c) Dean Michael Berris +// 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 +#include +#define BOOST_NETWORK_NO_LIB +#include +#include +#include +#include +#include +#include + +namespace http = boost::network::http; +using boost::assign::list_of; +using boost::lexical_cast; +using std::string; +using std::cerr; +using std::endl; + +struct hello_world; +typedef http::server server; + +struct hello_world { + + void operator()(server::request const& request, server::response& response) { + static server::response::header_type header = {"Connection", "close"}; + response = + server::response::stock_reply(server::response::ok, "Hello, World!"); + response.headers.push_back(header); + assert(response.status == server::response::ok); + assert(response.headers.size() == 3); + assert(response.content == "Hello, World!"); + } + + void log(string const& data) { + cerr << data << endl; + abort(); + } +}; + +int main(int argc, char* argv[]) { + hello_world handler; + std::string port = "8000"; + if (argc > 1) port = argv[1]; + server server_("127.0.0.1", port, handler, http::_reuse_address = true); + boost::thread runner(boost::bind(&server::run, &server_)); + try { + server_.stop(); + runner.join(); + } + catch (...) { + /* ignore all errors */ + } + return EXIT_SUCCESS; +} diff --git a/cpp-netlib/libs/network/test/http/tag_types.hpp b/cpp-netlib/libs/network/test/http/tag_types.hpp new file mode 100644 index 00000000..1d8df092 --- /dev/null +++ b/cpp-netlib/libs/network/test/http/tag_types.hpp @@ -0,0 +1,21 @@ +#ifndef TAG_TYPES_4NNM8B5T +#define TAG_TYPES_4NNM8B5T + +// Copyright 2010 Dean Michael Berris. +// 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 +#include + +namespace http = boost::network::http; + +typedef boost::mpl::vector tag_types; + +#endif /* TAG_TYPES_4NNM8B5T */ diff --git a/cpp-netlib/libs/network/test/http_server_async_less_copy.cpp b/cpp-netlib/libs/network/test/http_server_async_less_copy.cpp new file mode 100644 index 00000000..91cc4ee4 --- /dev/null +++ b/cpp-netlib/libs/network/test/http_server_async_less_copy.cpp @@ -0,0 +1,74 @@ + +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE HTTP Asynchronous Server Tests + +#include + +#include +#include +#include +#include + +namespace net = boost::network; +namespace http = boost::network::http; +namespace utils = boost::network::utils; + +struct async_hello_world; +typedef http::async_server server; + +struct async_hello_world { + + struct is_content_length { + template + bool operator()(Header const& header) { + return boost::iequals(header.name, "content-length"); + } + }; + + void operator()(server::request const& request, + server::connection_ptr connection) { + static server::response_header headers[] = { + {"Connection", "close"}, {"Content-Type", "text/plain"}, + {"Server", "cpp-netlib/0.9-devel"}}; + if (request.method == "HEAD") { + connection->set_status(server::connection::ok); + connection->set_headers(boost::make_iterator_range(headers, headers + 3)); + } else { + if (request.method == "PUT" || request.method == "POST") { + static std::string bad_request("Bad Request."); + server::request::headers_container_type::iterator found = + boost::find_if(request.headers, is_content_length()); + if (found == request.headers.end()) { + connection->set_status(server::connection::bad_request); + connection->set_headers( + boost::make_iterator_range(headers, headers + 3)); + connection->write(bad_request); + return; + } + } + static char const* hello_world = "Hello, World!"; + connection->set_status(server::connection::ok); + connection->set_headers(boost::make_iterator_range(headers, headers + 3)); + std::vector iovec; + iovec.push_back(boost::asio::const_buffer(hello_world, 13)); + connection->write(iovec, + boost::bind(&async_hello_world::error, this, _1)); + } + } + + void error(boost::system::error_code const& ec) { + // do nothing here. + } +}; + +int main(int argc, char* argv[]) { + utils::thread_pool thread_pool(2); + async_hello_world handler; + server instance("127.0.0.1", "8000", handler, thread_pool); + instance.run(); + return 0; +} diff --git a/cpp-netlib/libs/network/test/httplib_acceptance.py b/cpp-netlib/libs/network/test/httplib_acceptance.py new file mode 100644 index 00000000..935b9860 --- /dev/null +++ b/cpp-netlib/libs/network/test/httplib_acceptance.py @@ -0,0 +1,81 @@ +# Copyright (c) 2010. +# 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) + +#!/bin/env python + +from sys import argv +from time import sleep +import httplib2 as httplib +from subprocess import Popen,PIPE + +if len(argv) < 4: + print('I need the executable to run, the port to run it on, and the final touched file indicator.') + exit(1) + +print('Running {0} on port {1}...'.format(argv[1], argv[2])) + +pipe = None +try: + pipe = Popen(args=[argv[1], argv[2]], executable=argv[1], stdin=PIPE, stdout=PIPE, close_fds=True) + print('Done with spawning {0}.'.format(argv[1])) + print('Sleeping to give the server a chance to run...') + sleep(1) +except: + print('I cannot spawn \'{0}\' properly.'.format(argv[1])) + exit(1) + +status = 0 +client = httplib.Http(timeout=5) +expected = b'Hello, World!' + +def test(url, method, expected, headers={}, body=''): + global status + try: + print('Request: {method} {url} body=\'{body}\''.format(method=method, url=url, body=body)), + resp, content = client.request(url, method, headers=headers, body=body) + if content != expected: + print('ERROR: \'{0}\' != \'{1}\'; sizes: {2} != {3}'.format(content, expected, len(content), len(expected))) + status = 1 + else: + print('... passed.') + except Exception as e: + print('Caught Exception: {0}'.format(e)) + status = 1 + +def test_status(url, method, expected, headers={}, body=''): + global status + try: + print('Request: {method} {url} body=\'{body}\''.format(method=method, url=url, body=body)), + resp, content = client.request('http://localhost:8000/', 'PUT', body='') + if resp['status'] != expected: + print('ERROR: response status (got {0}) != expecting {1}'.format(resp['status'], expected)) + status = 1 + else: + print('... passed.') + except Exception as e: + print('Caught Exception: {0}'.format(e)) + status = 1 + +url = 'http://127.0.0.1:{0}/'.format(argv[2]) +test(url, 'GET', expected) +test(url, 'DELETE', expected) +# Good request case, there's a content-length header for POST +test(url, 'POST', expected, {'Content-Length': '0'}) +# Good request case, there's a content-length header for PUT +test(url, 'PUT', expected, {'Content-Length': '0'}) +# Bad request case, no content-length for POST +test_status(url, 'POST', '400') +# Bad request case, no content-length for PUT +test_status(url, 'PUT', '400') + +if status != 0: + print('Failures encountered.') + pipe.terminate() + exit(status) + +open(argv[len(argv) - 1], 'w').close() +print('All tests pass.') +pipe.terminate() + diff --git a/cpp-netlib/libs/network/test/message_test.cpp b/cpp-netlib/libs/network/test/message_test.cpp new file mode 100644 index 00000000..d3142968 --- /dev/null +++ b/cpp-netlib/libs/network/test/message_test.cpp @@ -0,0 +1,177 @@ + +// Copyright Dean Michael Berris 2007. +// 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) + +#define BOOST_TEST_MODULE message test +#include +#include +#include +#include +#include + +using namespace boost::network; + +typedef boost::mpl::list tag_types; + +struct string_header_name { + static std::string string; +}; + +std::string string_header_name::string = "Header"; + +struct wstring_header_name { + static std::wstring string; +}; + +std::wstring wstring_header_name::string = L"Header"; + +struct string_header_value { + static std::string string; +}; + +std::string string_header_value::string = "Value"; + +struct wstring_header_value { + static std::wstring string; +}; + +std::wstring wstring_header_value::string = L"Value"; + +template +struct header_name : string_header_name {}; + +template <> +struct header_name : wstring_header_name {}; + +template +struct header_value : string_header_value {}; + +template <> +struct header_value : wstring_header_value {}; + +struct string_body_data { + static std::string string; +}; + +std::string string_body_data::string = + "The quick brown fox jumps over the lazy dog."; + +struct wstring_body_data { + static std::wstring string; +}; + +std::wstring wstring_body_data::string = + L"The quick brown fox jumps over the lazy dog."; + +template +struct body_data : string_body_data {}; + +template <> +struct body_data : wstring_body_data {}; + +struct string_source_data { + static std::string string; +}; + +std::string string_source_data::string = "Source"; + +struct wstring_source_data { + static std::wstring string; +}; + +std::wstring wstring_source_data::string = L"Source"; + +template +struct source_data : string_source_data {}; + +template <> +struct source_data : wstring_body_data {}; + +struct string_destination_data { + static std::string string; +}; + +std::string string_destination_data::string = "Destination"; + +struct wstring_destination_data { + static std::wstring string; +}; + +std::wstring wstring_destination_data::string = L"Destination"; + +template +struct destination_data : string_destination_data {}; + +template <> +struct destination_data : wstring_destination_data {}; + +/** + * Defines a set of template functions that can be used to test + * generic code. + */ + +BOOST_AUTO_TEST_CASE_TEMPLATE(copy_constructor_test, T, tag_types) { + basic_message instance; + instance << header(header_name::string, header_value::string); + basic_message copy(instance); + BOOST_CHECK_EQUAL(headers(copy).count(header_name::string), + static_cast(1)); + typename headers_range >::type range = + headers(copy)[header_name::string]; + BOOST_CHECK(boost::begin(range) != boost::end(range)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(swap_test, T, tag_types) { + basic_message instance; + instance << header(header_name::string, header_value::string); + basic_message other; + swap(instance, other); + BOOST_CHECK_EQUAL(headers(instance).count(header_name::string), + static_cast(0)); + BOOST_CHECK_EQUAL(headers(other).count(header_name::string), + static_cast(1)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(headers_directive_test, T, tag_types) { + basic_message instance; + instance << header(header_name::string, header_value::string); + BOOST_CHECK_EQUAL(headers(instance).count(header_name::string), + static_cast(1)); + typename headers_range >::type range = + headers(instance)[header_name::string]; + BOOST_CHECK(boost::begin(range) != boost::end(range)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(body_directive_test, T, tag_types) { + basic_message instance; + instance << ::boost::network::body(body_data::string); + typename string::type body_string = body(instance); + BOOST_CHECK(body_string == body_data::string); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(source_directive_test, T, tag_types) { + basic_message instance; + instance << ::boost::network::source(source_data::string); + typename string::type source_string = source(instance); + BOOST_CHECK(source_string == source_data::string); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(destination_directive_test, T, tag_types) { + basic_message instance; + instance << destination(destination_data::string); + BOOST_CHECK(destination(instance) == destination_data::string); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(remove_header_directive_test, T, tag_types) { + basic_message instance; + instance << header(header_name::string, header_value::string) + << remove_header(header_name::string); + typename headers_range >::type range = headers(instance); + BOOST_CHECK(boost::begin(range) == boost::end(range)); +} diff --git a/cpp-netlib/libs/network/test/message_transform_test.cpp b/cpp-netlib/libs/network/test/message_transform_test.cpp new file mode 100644 index 00000000..bab8c4ed --- /dev/null +++ b/cpp-netlib/libs/network/test/message_transform_test.cpp @@ -0,0 +1,39 @@ + +// Copyright Dean Michael Berris 2007. +// 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) + +#define BOOST_TEST_MODULE message test +#include +#include +#include +#include + +BOOST_AUTO_TEST_CASE(message_transform_toupper) { + using namespace boost::network; + + message msg; + msg << source("me"); + BOOST_CHECK_EQUAL(source(msg), "me"); + msg << transform(to_upper_, source_); + BOOST_CHECK_EQUAL(source(msg), "ME"); + msg << destination("you"); + BOOST_CHECK_EQUAL(destination(msg), "you"); + msg << transform(to_upper_, destination_); + BOOST_CHECK_EQUAL(destination(msg), "YOU"); +} + +BOOST_AUTO_TEST_CASE(message_transform_tolower) { + using namespace boost::network; + + message msg; + msg << source("ME"); + BOOST_CHECK_EQUAL(source(msg), "ME"); + msg << transform(to_lower_, source_); + BOOST_CHECK_EQUAL(source(msg), "me"); + msg << destination("YOU"); + BOOST_CHECK_EQUAL(destination(msg), "YOU"); + msg << transform(to_lower_, destination_); + BOOST_CHECK_EQUAL(destination(msg), "you"); +} diff --git a/cpp-netlib/libs/network/test/server/boost.jpg b/cpp-netlib/libs/network/test/server/boost.jpg new file mode 100644 index 00000000..3857e53d Binary files /dev/null and b/cpp-netlib/libs/network/test/server/boost.jpg differ diff --git a/cpp-netlib/libs/network/test/server/certificate.pem b/cpp-netlib/libs/network/test/server/certificate.pem new file mode 100644 index 00000000..7e1b6cff --- /dev/null +++ b/cpp-netlib/libs/network/test/server/certificate.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICAzCCAWwCCQDVrANJOmGIcjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMCAXDTA5MTIxNzIzMTcwN1oYDzE5MTcwMzExMTAyMDM1WjBFMQsw +CQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJu +ZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCw +c3j9E+LMKqw2PBf/a5zLIAfNxDadFW2OB3S85kXgr72x/00oi5JiPOeA7LGrmhuJ ++nDXiO+AWL1O6fOzOkyTd0Nh1hCHJzjrJEfIt3iqdQGHiocVupWN5iCQRzCrErbP +vtvvs/r7mMheb9W3q9lntKPwiZ7mmr/daYdAbVuQpQIDAQABMA0GCSqGSIb3DQEB +BQUAA4GBAHz1OhxKYSc5kYmgkMYYwtmHFWWTL2jy6xk4+yv5sGAmze4dvtQqCNiA +TaljCHWdAkHaXXBzbZ7+e3qem2M1Y31HqO0ZiQezpJ1TFLPc5/0uNX8JIPovb+s7 +c/wevNe16tw4dhM0DQ2V3FH8AwiQANUtZ8yFk91RH4rTaQBQDYOE +-----END CERTIFICATE----- diff --git a/cpp-netlib/libs/network/test/server/cgi-bin/cgisupport.py b/cpp-netlib/libs/network/test/server/cgi-bin/cgisupport.py new file mode 100755 index 00000000..45d80177 --- /dev/null +++ b/cpp-netlib/libs/network/test/server/cgi-bin/cgisupport.py @@ -0,0 +1,42 @@ +#!/usr/bin/python +# +# Copyright Kim Grasman 2008. +# 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) +# + +class http_headers: + def __init__(self, header_str): + self.parse(header_str) + + def raw_headers(self): + return self.raw + + def iteritems(self): + return self.headers.iteritems() + + def value(self, name): + return self.headers[name] + + def parse(self, header_str): + self.raw = header_str + self.headers = self.__parse_headers(header_str) + + def __parse_headers(self, str): + dict = {} + + # I'm sure there are better ways to do this in Python, + # but I don't know my way around so well + lines = str.split('\n') + for line in lines: + header = line.split(': ') + if len(header) > 0: + name = header[0] + if len(header) > 1: + value = ': '.join(header[1:]) # re-join the rest of the items as value + + if len(name) > 0: + dict[name] = value + + return dict diff --git a/cpp-netlib/libs/network/test/server/cgi-bin/echo_body.py b/cpp-netlib/libs/network/test/server/cgi-bin/echo_body.py new file mode 100755 index 00000000..51d62aff --- /dev/null +++ b/cpp-netlib/libs/network/test/server/cgi-bin/echo_body.py @@ -0,0 +1,20 @@ +#!/usr/bin/python +# +# Copyright Divye Kapoor 2008. +# 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) +# +# This program sets up a CGI application on localhost +# It can be accessed by http://localhost:8000/cgi-bin/echo_form.py +# It returns the query parameters passed to the CGI Script as plain text. +# +import cgitb; cgitb.enable() # for debugging only +import cgi +import os, sys + +sys.stdout.write( "Content-type: text/plain; charset=us-ascii\r\n\r\n" ) +sys.stdout.write( "\r\n" ) + +# POST data/form data is available in the .value property +sys.stdout.write( cgi.FieldStorage().value ) diff --git a/cpp-netlib/libs/network/test/server/cgi-bin/echo_headers.py b/cpp-netlib/libs/network/test/server/cgi-bin/echo_headers.py new file mode 100755 index 00000000..8546e01e --- /dev/null +++ b/cpp-netlib/libs/network/test/server/cgi-bin/echo_headers.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +# +# Copyright Kim Grasman 2008. +# 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) +# +# This program sets up a CGI application on localhost +# It can be accessed by http://localhost:8000/cgi-bin/echo_headers.py +# +import cgi +import os, sys +import cgisupport + +sys.stdout.write( "Content-type: text/plain; charset=us-ascii\r\n\r\n" ) +sys.stdout.write( "\r\n" ) + +hdrs = cgisupport.http_headers(os.environ.get('HTTP_ALL_HEADERS')) + +for h,v in hdrs.iteritems(): + print h + ": " + v diff --git a/cpp-netlib/libs/network/test/server/cgi-bin/multiline-header.py b/cpp-netlib/libs/network/test/server/cgi-bin/multiline-header.py new file mode 100755 index 00000000..ce66a288 --- /dev/null +++ b/cpp-netlib/libs/network/test/server/cgi-bin/multiline-header.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +# +# Copyright Divye Kapoor 2008. +# 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) +# +# This program sets up a CGI application on localhost +# It can be accessed by http://localhost:8000/cgi-bin/requestinfo.py +# It returns the query parameters passed to the CGI Script as plain text. +# +import cgitb; cgitb.enable() # for debugging only +import cgi +import os, sys + +print "X-CppNetlib-Test: multi-line-header\r\n" +print " that-should-concatenate\r\n" +print "Content-type: text/plain; charset=us-ascii\r\n\r\n" +print "\r\n" + +form = cgi.FieldStorage() +qstring = "" +qstring_dict = {} + +if os.environ.has_key("QUERY_STRING"): + qstring = os.environ["QUERY_STRING"] + try: + qstring_dict = cgi.parse_qs(qstring,1,1) # parse_qs(query_string,keep_blanks,strict_parsing) + except ValueError: + print "Error parsing query string." + +print "Query string:", qstring + +print "GET parameters:", +for i in qstring_dict.keys(): + print i,"-",qstring_dict[i],";", +print + +# Remove GET params and print only the POST ones +print "POST parameters:", +for i in form.keys(): + if i not in qstring_dict.keys(): + print i,"-",form.getfirst(i, ""),";", +print diff --git a/cpp-netlib/libs/network/test/server/cgi-bin/requestinfo.py b/cpp-netlib/libs/network/test/server/cgi-bin/requestinfo.py new file mode 100755 index 00000000..332c3663 --- /dev/null +++ b/cpp-netlib/libs/network/test/server/cgi-bin/requestinfo.py @@ -0,0 +1,56 @@ +#!/usr/bin/python +# +# Copyright Divye Kapoor 2008. +# 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) +# +# This program sets up a CGI application on localhost +# It can be accessed by http://localhost:8000/cgi-bin/requestinfo.py +# It returns the query parameters passed to the CGI Script as plain text. +# +import cgitb; cgitb.enable() # for debugging only +import cgi +import os, sys + +sys.stdout.write( "HTTP/1.0 200 Requestinfo.py Output follows\r\n" ) +sys.stdout.write( "Content-type: text/plain; charset=us-ascii\r\n\r\n" ) +sys.stdout.write( "\r\n" ) + +form = cgi.FieldStorage() +qstring = "" +qstring_dict = {} + +print "Headers: ",form.headers + +if os.environ.has_key("QUERY_STRING"): + qstring = os.environ["QUERY_STRING"] + try: + qstring_dict = cgi.parse_qs(qstring,1,1) # parse_qs(query_string,keep_blanks,strict_parsing) + except ValueError: + print "Error parsing query string." + + +print "Query string:", qstring + +print "GET parameters:", +for i in qstring_dict.keys(): + print i,"-",qstring_dict[i],";", +print + +# Remove GET params and print only the POST ones +print "POST parameters:", +try: + for i in form.keys(): + if i not in qstring_dict.keys(): + print i,"-",form.getfirst(i, ""),";", + print +except TypeError: # In case of empty POST bodies. + pass + +print 'HTTP HEADERS-------------------' +print 'Content-Type:', os.environ.get('CONTENT_TYPE') +print 'Content-Length:', os.environ.get('CONTENT_LENGTH') +for k in os.environ.keys(): + if k.startswith('HTTP_'): + print k, ':', os.environ[k] diff --git a/cpp-netlib/libs/network/test/server/cgi-bin/sleep.py b/cpp-netlib/libs/network/test/server/cgi-bin/sleep.py new file mode 100755 index 00000000..046fa5da --- /dev/null +++ b/cpp-netlib/libs/network/test/server/cgi-bin/sleep.py @@ -0,0 +1,8 @@ +#!/usr/bin/python +import os, sys, time + +if os.environ.has_key("QUERY_STRING") and os.environ["QUERY_STRING"].isdigit(): + time.sleep(int(os.environ["QUERY_STRING"])) + +sys.stdout.write( "HTTP/1.0 200\r\n" ) +sys.stdout.write( "\r\n" ) diff --git a/cpp-netlib/libs/network/test/server/cgi_server.py b/cpp-netlib/libs/network/test/server/cgi_server.py new file mode 100644 index 00000000..53ef7065 --- /dev/null +++ b/cpp-netlib/libs/network/test/server/cgi_server.py @@ -0,0 +1,34 @@ +#!/usr/bin/python +# +# Copyright Divye Kapoor 2008. +# 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) +# +# This program sets up a CGI HTTP Server at port 8000 on localhost +# It will be used to test the http::client interface of the library + +import CGIHTTPServer +import BaseHTTPServer +import threading + +from threading import Thread, Event + +stop_serving = Event() +server_thread = None + +def run(server_class=BaseHTTPServer.HTTPServer, handler_class=CGIHTTPServer.CGIHTTPRequestHandler): + server_address = ('',8000) + httpd = server_class(server_address, handler_class) + while not stop_serving.isSet(): + httpd.handle_request() + + +def start_server(): + server_thread = Thread(None, run, "HTTP Server",(), None, None) + server_thread.start() + server_thread.join() + + +if __name__ == '__main__': + start_server() diff --git a/cpp-netlib/libs/network/test/server/http_test_server.py b/cpp-netlib/libs/network/test/server/http_test_server.py new file mode 100644 index 00000000..ba96c4fe --- /dev/null +++ b/cpp-netlib/libs/network/test/server/http_test_server.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# +# Copyright Allister Levi Sanchez 2008. +# 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) +# +# This program sets up a CGI HTTP Server at port 8000 on localhost +# It will be used to test the http::client interface of the library + +import BaseHTTPServer +import CGIHTTPServer +import os + +class HttpTestHandler(CGIHTTPServer.CGIHTTPRequestHandler): + + def run_cgi(self): + """Version of run_cgi that provides more HTTP headers.""" + headers_str = '' + for a in self.headers.items(): + headers_str += "%s: %s\n" % a + + os.environ['HTTP_ALL_HEADERS'] = headers_str + + # run the rest of run_cgi + CGIHTTPServer.CGIHTTPRequestHandler.run_cgi(self) + +def run_server(server_class=BaseHTTPServer.HTTPServer, handler_class=HttpTestHandler): + server_address = ('',8000) + httpd = server_class(server_address, handler_class) + httpd.serve_forever() + +if __name__ == '__main__': + run_server() diff --git a/cpp-netlib/libs/network/test/server/https_test_server.py b/cpp-netlib/libs/network/test/server/https_test_server.py new file mode 100644 index 00000000..23cd3a00 --- /dev/null +++ b/cpp-netlib/libs/network/test/server/https_test_server.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# Copyright 2009 Jeroen Habraken +# Copyright 2009 Dean Michael Berris +# 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 socket + +from BaseHTTPServer import HTTPServer +from SimpleHTTPServer import SimpleHTTPRequestHandler +from CGIHTTPServer import CGIHTTPRequestHandler + +from OpenSSL import SSL + +import os + +class SecureHTTPServer(HTTPServer): + def __init__(self, server_address, HandlerClass): + HTTPServer.__init__(self, server_address, HandlerClass) + + ctx = SSL.Context(SSL.SSLv23_METHOD) + ctx.use_privatekey_file ("key.pem") + ctx.use_certificate_file("certificate.pem") + self.socket = SSL.Connection(ctx, socket.socket(self.address_family, + self.socket_type)) + self.server_bind() + self.server_activate() + +class SecureHTTPRequestHandler(CGIHTTPRequestHandler): + def setup(self): + self.connection = self.request + self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) + self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) + + def run_cgi(self): + """Version of run_cgi that provides more HTTP headers.""" + headers_str = '' + for a in self.headers.items(): + headers_str += "%s: %s\n" % a + + os.environ['HTTP_ALL_HEADERS'] = headers_str + + # run the rest of run_cgi + CGIHTTPRequestHandler.run_cgi(self) + +if __name__ == '__main__': + SecureHTTPServer(('127.0.0.1', 8443), SecureHTTPRequestHandler).serve_forever() + diff --git a/cpp-netlib/libs/network/test/server/key.pem b/cpp-netlib/libs/network/test/server/key.pem new file mode 100644 index 00000000..773af771 --- /dev/null +++ b/cpp-netlib/libs/network/test/server/key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCwc3j9E+LMKqw2PBf/a5zLIAfNxDadFW2OB3S85kXgr72x/00o +i5JiPOeA7LGrmhuJ+nDXiO+AWL1O6fOzOkyTd0Nh1hCHJzjrJEfIt3iqdQGHiocV +upWN5iCQRzCrErbPvtvvs/r7mMheb9W3q9lntKPwiZ7mmr/daYdAbVuQpQIDAQAB +AoGBAIJ7MXn8TZdq6uRENf7ERjMTIZIwya4JnXUM4G+b3QqVCrLottcHtxz8Krl0 +zsG1+S1kTDOmaG1BseP8LyFXOC4Ni8H6vjnFG/vTzuArPhtoB9B5wXDnPfPQH22a +10XH3aGbOoyP9sg0HF0ZJsnou3QgQfg49whWa8gl8SUSckI1AkEA4NFwJ7GpVmIA +ZuVzguKEKNNxC9PNUDeGUCyjH5fejolL2wIQQ4rKpml05TbUuugQByxBi+Gbd51j +hGeFOncVywJBAMjsrWoOyGpDJIe2H0Aklecp9awn2H59GFNBmDvUO6LAAkr5Dkky +64QGLCZLAdswH9QaMuBvzKSZkzGcfDKwpU8CQBxTJt9Jaf1hMY3FQO1vnpkKMsb7 +s3V02W5GgXLcjoTE1ZLNSsFHvkqDJOAwLVMzI7nToJqAHTdP1Bb9d/KqyEsCQA0x +/fGJJwBTiIKhI0xDGtUjnE7CDyW/cWmGVUkYlxIJKh1iXd3QykbRYPTi2Cxc7Lox +PkYfEYF91Hzdmgp6L2ECQFcCg0qKfvy1YeTChrDFMBrZx4yoqYGBnqEqxshksAJg +o1r5HVSlO71aVgeAs/5DD4IIb2OyiJE/dv6t0L8TQeQ= +-----END RSA PRIVATE KEY----- diff --git a/cpp-netlib/libs/network/test/server/test.xml b/cpp-netlib/libs/network/test/server/test.xml new file mode 100644 index 00000000..54decb47 --- /dev/null +++ b/cpp-netlib/libs/network/test/server/test.xml @@ -0,0 +1,4 @@ + + Hi! This is node 1 + Node 2 here. + diff --git a/cpp-netlib/libs/network/test/uri/CMakeLists.txt b/cpp-netlib/libs/network/test/uri/CMakeLists.txt new file mode 100644 index 00000000..d4b9334b --- /dev/null +++ b/cpp-netlib/libs/network/test/uri/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) Dean Michael Berris 2010. +# 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_directories(${CPP-NETLIB_SOURCE_DIR}) + +if (Boost_FOUND) + set( + TESTS + uri_test + uri_builder_test + uri_builder_stream_test + uri_encoding_test + relative_uri_test + ) + foreach (test ${TESTS}) + if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU) + set_source_files_properties(${test}.cpp + PROPERTIES COMPILE_FLAGS "-Wall") + endif() + add_executable(cpp-netlib-${test} ${test}.cpp) + add_dependencies(cpp-netlib-${test} cppnetlib-uri) + target_link_libraries(cpp-netlib-${test} + ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} cppnetlib-uri) + if (OPENSSL_FOUND) + target_link_libraries(cpp-netlib-${test} ${OPENSSL_LIBRARIES}) + endif() + if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU AND ${CMAKE_SYSTEM_NAME} MATCHES "Windows") + target_link_libraries(cpp-netlib-${test} ws2_32) + endif() + set_target_properties(cpp-netlib-${test} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/tests) + add_test(cpp-netlib-${test} + ${CPP-NETLIB_BINARY_DIR}/tests/cpp-netlib-${test}) + endforeach (test) + +endif() diff --git a/cpp-netlib/libs/network/test/uri/relative_uri_test.cpp b/cpp-netlib/libs/network/test/uri/relative_uri_test.cpp new file mode 100644 index 00000000..b95b4ef5 --- /dev/null +++ b/cpp-netlib/libs/network/test/uri/relative_uri_test.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Glyn Matthews 2012. +// 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) + +#define BOOST_TEST_MODULE Relative URL Test +#include +#include +#include +#include + +using namespace boost::network; + +BOOST_AUTO_TEST_CASE(relative_uri_test) { + // don't yet support relative URIs + uri::uri instance("example.com"); + BOOST_REQUIRE(!uri::valid(instance)); +} diff --git a/cpp-netlib/libs/network/test/uri/uri_builder_stream_test.cpp b/cpp-netlib/libs/network/test/uri/uri_builder_stream_test.cpp new file mode 100644 index 00000000..6b2a920d --- /dev/null +++ b/cpp-netlib/libs/network/test/uri/uri_builder_stream_test.cpp @@ -0,0 +1,121 @@ +// Copyright (c) Glyn Matthews 2011. +// 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) + +#define BOOST_TEST_MODULE URI builder stream test +#include +#include +#include +#include +#include + +using namespace boost::network; + +BOOST_AUTO_TEST_CASE(builder_test) { + uri::uri instance; + instance << uri::scheme("http") << uri::host("www.example.com") + << uri::path("/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/", instance.string()); +} + +BOOST_AUTO_TEST_CASE(full_uri_builder_test) { + uri::uri instance; + instance << uri::scheme("http") << uri::user_info("user:password") + << uri::host("www.example.com") << uri::port("80") + << uri::path("/path") << uri::query("query") + << uri::fragment("fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL( + "http://user:password@www.example.com:80/path?query#fragment", + instance.string()); +} + +BOOST_AUTO_TEST_CASE(port_test) { + uri::uri instance; + instance << uri::scheme("http") << uri::host("www.example.com") + << uri::port(8000) << uri::path("/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com:8000/", instance.string()); +} + +BOOST_AUTO_TEST_CASE(encoded_path_test) { + uri::uri instance; + instance << uri::scheme("http") << uri::host("www.example.com") + << uri::port(8000) + << uri::encoded_path("/Path With (Some) Encoded Characters!"); + ; + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL( + "http://www.example.com:8000/" + "Path%20With%20%28Some%29%20Encoded%20Characters%21", + instance.string()); +} + +BOOST_AUTO_TEST_CASE(query_test) { + uri::uri instance; + instance << uri::scheme("http") << uri::host("www.example.com") + << uri::path("/") << uri::query("key", "value"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/?key=value", instance.string()); +} + +BOOST_AUTO_TEST_CASE(query_2_test) { + uri::uri instance; + instance << uri::scheme("http") << uri::host("www.example.com") + << uri::path("/") << uri::query("key1", "value1") + << uri::query("key2", "value2"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/?key1=value1&key2=value2", + instance.string()); +} + +BOOST_AUTO_TEST_CASE(fragment_test) { + uri::uri instance; + instance << uri::scheme("http") << uri::host("www.example.com") + << uri::path("/") << uri::fragment("fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/#fragment", instance.string()); +} + +BOOST_AUTO_TEST_CASE(from_base_test) { + uri::uri base_uri("http://www.example.com"); + uri::uri instance; + instance << base_uri << uri::path("/") << uri::fragment("fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/#fragment", instance.string()); +} + +BOOST_AUTO_TEST_CASE(scheme_http_test) { + uri::uri instance; + instance << uri::schemes::http << uri::host("www.example.com") + << uri::path("/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/", instance.string()); +} + +BOOST_AUTO_TEST_CASE(scheme_https_test) { + uri::uri instance; + instance << uri::schemes::https << uri::host("www.example.com") + << uri::path("/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("https://www.example.com/", instance.string()); +} + +BOOST_AUTO_TEST_CASE(encoded_null_char_test) { + // there is a potential bug in the way we process ranges if the + // strings are null terminated. + uri::uri instance; + instance << uri::scheme("http") << uri::host("www.example.com") + << uri::encoded_path("/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/", instance.string()); +} + +BOOST_AUTO_TEST_CASE(mailto_builder_test) { + uri::uri instance; + instance << uri::scheme("mailto") << uri::path("cpp-netlib@example.com"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("mailto:cpp-netlib@example.com", instance.string()); +} diff --git a/cpp-netlib/libs/network/test/uri/uri_builder_test.cpp b/cpp-netlib/libs/network/test/uri/uri_builder_test.cpp new file mode 100644 index 00000000..dd1840f3 --- /dev/null +++ b/cpp-netlib/libs/network/test/uri/uri_builder_test.cpp @@ -0,0 +1,134 @@ +// Copyright (c) Glyn Matthews 2012. +// 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) + +#define BOOST_TEST_MODULE URI builder test +#include +#include +#include +#include + +using namespace boost::network; + +BOOST_AUTO_TEST_CASE(builder_test) { + uri::uri instance; + uri::builder builder(instance); + builder.scheme("http").host("www.example.com").path("/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/", instance.string()); +} + +BOOST_AUTO_TEST_CASE(full_uri_builder_test) { + uri::uri instance; + uri::builder builder(instance); + builder.scheme("http") + .user_info("user:password") + .host("www.example.com") + .port("80") + .path("/path") + .query("query") + .fragment("fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL( + "http://user:password@www.example.com:80/path?query#fragment", + instance.string()); +} + +BOOST_AUTO_TEST_CASE(port_test) { + uri::uri instance; + uri::builder(instance).scheme("http").host("www.example.com").port(8000).path( + "/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com:8000/", instance.string()); +} + +BOOST_AUTO_TEST_CASE(encoded_path_test) { + uri::uri instance; + uri::builder builder(instance); + builder.scheme("http").host("www.example.com").port(8000).encoded_path( + "/Path With (Some) Encoded Characters!"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL( + "http://www.example.com:8000/" + "Path%20With%20%28Some%29%20Encoded%20Characters%21", + instance.string()); +} + +BOOST_AUTO_TEST_CASE(query_test) { + uri::uri instance; + uri::builder builder(instance); + builder.scheme("http").host("www.example.com").path("/").query("key", + "value"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/?key=value", instance.string()); +} + +BOOST_AUTO_TEST_CASE(query_2_test) { + uri::uri instance; + uri::builder builder(instance); + builder.scheme("http") + .host("www.example.com") + .path("/") + .query("key1", "value1") + .query("key2", "value2"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/?key1=value1&key2=value2", + instance.string()); +} + +BOOST_AUTO_TEST_CASE(fragment_test) { + uri::uri instance; + uri::builder builder(instance); + builder.scheme("http").host("www.example.com").path("/").fragment("fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/#fragment", instance.string()); +} + +BOOST_AUTO_TEST_CASE(from_base_test) { + uri::uri instance("http://www.example.com"); + uri::builder builder(instance); + builder.path("/").fragment("fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/#fragment", instance.string()); +} + +BOOST_AUTO_TEST_CASE(encoded_null_char_test) { + // there is a potential bug in the way we process ranges if the + // strings are null terminated. + uri::uri instance; + uri::builder builder(instance); + builder.scheme("http").host("www.example.com").encoded_path("/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://www.example.com/", instance.string()); +} + +BOOST_AUTO_TEST_CASE(mailto_builder_test) { + uri::uri instance; + uri::builder builder(instance); + builder.scheme("mailto").path("cpp-netlib@example.com"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("mailto:cpp-netlib@example.com", instance.string()); +} + +BOOST_AUTO_TEST_CASE(ipv4_address) { + using namespace boost::asio::ip; + uri::uri instance; + uri::builder builder(instance); + builder.scheme("http").host(address_v4::loopback()).path("/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL("http://127.0.0.1/", instance.string()); +} + +// BOOST_AUTO_TEST_CASE(ipv6_address) { +// using namespace boost::asio::ip; +// uri::uri instance; +// uri::builder builder(instance); +// builder +// .scheme("http") +// .host(address_v6::loopback()) +// .path("/") +// ; +// BOOST_REQUIRE(uri::valid(instance)); +// BOOST_CHECK_EQUAL("http://[::1]/", instance.string()); +//} diff --git a/cpp-netlib/libs/network/test/uri/uri_encoding_test.cpp b/cpp-netlib/libs/network/test/uri/uri_encoding_test.cpp new file mode 100644 index 00000000..aaff45db --- /dev/null +++ b/cpp-netlib/libs/network/test/uri/uri_encoding_test.cpp @@ -0,0 +1,49 @@ +// Copyright (c) Glyn Matthews 2011. +// 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) + +#define BOOST_TEST_MODULE URL encoding test +#include +#include +#include +#include +#include + +using namespace boost::network; + +BOOST_AUTO_TEST_CASE(encoding_test) { + const std::string unencoded(" !\"#$%&\'()*"); + const std::string encoded("%20%21%22%23%24%25%26%27%28%29%2A"); + + std::string instance; + uri::encode(unencoded, std::back_inserter(instance)); + BOOST_CHECK_EQUAL(instance, encoded); +} + +BOOST_AUTO_TEST_CASE(decoding_test) { + const std::string unencoded(" !\"#$%&\'()*"); + const std::string encoded("%20%21%22%23%24%25%26%27%28%29%2A"); + + std::string instance; + uri::decode(encoded, std::back_inserter(instance)); + BOOST_CHECK_EQUAL(instance, unencoded); +} + +BOOST_AUTO_TEST_CASE(encoding_multibyte_test) { + const std::string unencoded("한글 테스트"); + const std::string encoded("%ED%95%9C%EA%B8%80%20%ED%85%8C%EC%8A%A4%ED%8A%B8"); + + std::string instance; + uri::encode(unencoded, std::back_inserter(instance)); + BOOST_CHECK_EQUAL(instance, encoded); +} + +BOOST_AUTO_TEST_CASE(decoding_multibyte_test) { + const std::string unencoded("한글 테스트"); + const std::string encoded("%ED%95%9C%EA%B8%80%20%ED%85%8C%EC%8A%A4%ED%8A%B8"); + + std::string instance; + uri::decode(encoded, std::back_inserter(instance)); + BOOST_CHECK_EQUAL(instance, unencoded); +} diff --git a/cpp-netlib/libs/network/test/uri/uri_test.cpp b/cpp-netlib/libs/network/test/uri/uri_test.cpp new file mode 100644 index 00000000..c6a15076 --- /dev/null +++ b/cpp-netlib/libs/network/test/uri/uri_test.cpp @@ -0,0 +1,581 @@ +// Copyright 2009, 2010, 2011 Dean Michael Berris, Jeroen Habraken, Glyn +// Matthews. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt of copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE URL Test +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::network; + +BOOST_AUTO_TEST_CASE(basic_uri_scheme_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "http"); +} + +BOOST_AUTO_TEST_CASE(basic_uri_user_info_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::user_info(instance), ""); +} + +BOOST_AUTO_TEST_CASE(basic_uri_host_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::host(instance), "www.example.com"); +} + +BOOST_AUTO_TEST_CASE(basic_uri_port_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::port(instance), ""); +} + +BOOST_AUTO_TEST_CASE(basic_uri_path_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::path(instance), "/"); +} + +BOOST_AUTO_TEST_CASE(basic_uri_query_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::query(instance), ""); +} + +BOOST_AUTO_TEST_CASE(basic_uri_fragment_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::fragment(instance), ""); +} + +BOOST_AUTO_TEST_CASE(basic_uri_value_semantics_test) { + uri::uri original; + uri::uri assigned; + assigned = original; + BOOST_CHECK(original == assigned); + assigned = "http://www.example.com/"; + BOOST_CHECK(original != assigned); + uri::uri copy(assigned); + BOOST_CHECK(copy == assigned); +} + +BOOST_AUTO_TEST_CASE(basic_uri_range_scheme_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(instance.scheme_range()); + BOOST_CHECK(instance.begin() == boost::begin(instance.scheme_range())); + BOOST_CHECK(boost::equal(instance.scheme_range(), boost::as_literal("http"))); +} + +BOOST_AUTO_TEST_CASE(basic_uri_range_user_info_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(!instance.user_info_range()); + BOOST_CHECK(boost::begin(instance.host_range()) == + boost::begin(instance.user_info_range())); + BOOST_CHECK(boost::begin(instance.host_range()) == + boost::end(instance.user_info_range())); +} + +BOOST_AUTO_TEST_CASE(basic_uri_range_host_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(instance.host_range()); + BOOST_CHECK(boost::equal(instance.host_range(), + boost::as_literal("www.example.com"))); +} + +BOOST_AUTO_TEST_CASE(basic_uri_range_port_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(!instance.port_range()); + BOOST_CHECK(boost::end(instance.host_range()) == + boost::begin(instance.port_range())); + BOOST_CHECK(boost::end(instance.host_range()) == + boost::end(instance.port_range())); +} + +BOOST_AUTO_TEST_CASE(basic_uri_range_path_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(instance.path_range()); + BOOST_CHECK(boost::equal(instance.path_range(), boost::as_literal("/"))); + BOOST_CHECK(instance.end() == boost::end(instance.path_range())); +} + +BOOST_AUTO_TEST_CASE(basic_uri_range_query_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(!instance.query_range()); + BOOST_CHECK(instance.end() == boost::begin(instance.query_range())); + BOOST_CHECK(instance.end() == boost::end(instance.query_range())); +} + +BOOST_AUTO_TEST_CASE(basic_uri_range_fragment_test) { + uri::uri instance("http://www.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(!instance.fragment_range()); + BOOST_CHECK(instance.end() == boost::begin(instance.fragment_range())); + BOOST_CHECK(instance.end() == boost::end(instance.fragment_range())); +} + +BOOST_AUTO_TEST_CASE(full_uri_scheme_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "http"); +} + +BOOST_AUTO_TEST_CASE(full_uri_user_info_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::user_info(instance), "user:password"); +} + +BOOST_AUTO_TEST_CASE(full_uri_host_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::host(instance), "www.example.com"); +} + +BOOST_AUTO_TEST_CASE(full_uri_port_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::port(instance), "80"); + BOOST_CHECK(uri::port_us(instance)); + BOOST_CHECK_EQUAL(uri::port_us(instance).get(), 80); +} + +BOOST_AUTO_TEST_CASE(full_uri_path_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::path(instance), "/path"); +} + +BOOST_AUTO_TEST_CASE(full_uri_query_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::query(instance), "query"); +} + +BOOST_AUTO_TEST_CASE(full_uri_fragment_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::fragment(instance), "fragment"); +} + +BOOST_AUTO_TEST_CASE(full_uri_range_scheme_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(instance.scheme_range()); + BOOST_CHECK(instance.begin() == boost::begin(instance.scheme_range())); + BOOST_CHECK(boost::equal(instance.scheme_range(), boost::as_literal("http"))); +} + +BOOST_AUTO_TEST_CASE(full_uri_range_user_info_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(instance.user_info_range()); + BOOST_CHECK(boost::equal(instance.user_info_range(), + boost::as_literal("user:password"))); +} + +BOOST_AUTO_TEST_CASE(full_uri_range_host_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(instance.host_range()); + BOOST_CHECK(boost::equal(instance.host_range(), + boost::as_literal("www.example.com"))); +} + +BOOST_AUTO_TEST_CASE(full_uri_range_port_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(instance.port_range()); + BOOST_CHECK(boost::equal(instance.port_range(), boost::as_literal("80"))); +} + +BOOST_AUTO_TEST_CASE(full_uri_range_path_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(instance.path_range()); + BOOST_CHECK(boost::equal(instance.path_range(), boost::as_literal("/path"))); +} + +BOOST_AUTO_TEST_CASE(full_uri_range_query_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(instance.query_range()); + BOOST_CHECK(boost::equal(instance.query_range(), boost::as_literal("query"))); +} + +BOOST_AUTO_TEST_CASE(full_uri_range_fragment_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(instance.fragment_range()); + BOOST_CHECK( + boost::equal(instance.fragment_range(), boost::as_literal("fragment"))); + BOOST_CHECK(instance.end() == boost::end(instance.fragment_range())); +} + +BOOST_AUTO_TEST_CASE(mailto_test) { + uri::uri instance("mailto:john.doe@example.com"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "mailto"); + BOOST_CHECK_EQUAL(uri::path(instance), "john.doe@example.com"); +} + +BOOST_AUTO_TEST_CASE(file_test) { + uri::uri instance("file:///bin/bash"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "file"); + BOOST_CHECK_EQUAL(uri::path(instance), "/bin/bash"); +} + +BOOST_AUTO_TEST_CASE(xmpp_test) { + uri::uri instance( + "xmpp:example-node@example.com?message;subject=Hello%20World"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "xmpp"); + BOOST_CHECK_EQUAL(uri::path(instance), "example-node@example.com"); + BOOST_CHECK_EQUAL(uri::query(instance), "message;subject=Hello%20World"); +} + +BOOST_AUTO_TEST_CASE(ipv4_address_test) { + uri::uri instance("http://129.79.245.252/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "http"); + BOOST_CHECK_EQUAL(uri::host(instance), "129.79.245.252"); + BOOST_CHECK_EQUAL(uri::path(instance), "/"); +} + +BOOST_AUTO_TEST_CASE(ipv4_loopback_test) { + uri::uri instance("http://127.0.0.1/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "http"); + BOOST_CHECK_EQUAL(uri::host(instance), "127.0.0.1"); + BOOST_CHECK_EQUAL(uri::path(instance), "/"); +} + +BOOST_AUTO_TEST_CASE(ipv6_address_test_1) { + uri::uri instance("http://[1080:0:0:0:8:800:200C:417A]/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "http"); + BOOST_CHECK_EQUAL(uri::host(instance), "[1080:0:0:0:8:800:200C:417A]"); + BOOST_CHECK_EQUAL(uri::path(instance), "/"); +} + +BOOST_AUTO_TEST_CASE(ipv6_address_test_2) { + uri::uri instance("http://[2001:db8:85a3:8d3:1319:8a2e:370:7348]/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "http"); + BOOST_CHECK_EQUAL(uri::host(instance), + "[2001:db8:85a3:8d3:1319:8a2e:370:7348]"); + BOOST_CHECK_EQUAL(uri::path(instance), "/"); +} + +// BOOST_AUTO_TEST_CASE(ipv6_loopback_test) { +// uri::uri instance("http://[::1]/"); +// BOOST_REQUIRE(uri::valid(instance)); +// BOOST_CHECK_EQUAL(uri::scheme(instance), "http"); +// BOOST_CHECK_EQUAL(uri::host(instance), "[::1]"); +// BOOST_CHECK_EQUAL(uri::path(instance), "/"); +//} + +BOOST_AUTO_TEST_CASE(ftp_test) { + uri::uri instance("ftp://john.doe@ftp.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "ftp"); + BOOST_CHECK_EQUAL(uri::user_info(instance), "john.doe"); + BOOST_CHECK_EQUAL(uri::host(instance), "ftp.example.com"); + BOOST_CHECK_EQUAL(uri::path(instance), "/"); +} + +BOOST_AUTO_TEST_CASE(news_test) { + uri::uri instance("news:comp.infosystems.www.servers.unix"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "news"); + BOOST_CHECK_EQUAL(uri::path(instance), "comp.infosystems.www.servers.unix"); +} + +BOOST_AUTO_TEST_CASE(tel_test) { + uri::uri instance("tel:+1-816-555-1212"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "tel"); + BOOST_CHECK_EQUAL(uri::path(instance), "+1-816-555-1212"); +} + +BOOST_AUTO_TEST_CASE(encoded_uri_test) { + uri::uri instance( + "http://www.example.com/" + "Path%20With%20%28Some%29%20Encoded%20Characters%21"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::scheme(instance), "http"); + BOOST_CHECK_EQUAL(uri::host(instance), "www.example.com"); + BOOST_CHECK_EQUAL(uri::path(instance), + "/Path%20With%20%28Some%29%20Encoded%20Characters%21"); + BOOST_CHECK_EQUAL(uri::decoded_path(instance), + "/Path With (Some) Encoded Characters!"); +} + +BOOST_AUTO_TEST_CASE(copy_constructor_test) { + uri::uri instance("http://www.example.com/"); + uri::uri copy = instance; + BOOST_CHECK_EQUAL(instance, copy); +} + +BOOST_AUTO_TEST_CASE(assignment_test) { + uri::uri instance("http://www.example.com/"); + uri::uri copy; + copy = instance; + BOOST_CHECK_EQUAL(instance, copy); +} + +BOOST_AUTO_TEST_CASE(swap_test) { + uri::uri instance("http://www.example.com/"); + uri::uri copy("http://www.example.org/"); + uri::swap(instance, copy); + BOOST_CHECK_EQUAL(instance.string(), "http://www.example.org/"); + BOOST_CHECK_EQUAL(copy.string(), "http://www.example.com/"); +} + +BOOST_AUTO_TEST_CASE(equality_test) { + uri::uri uri_1("http://www.example.com/"); + uri::uri uri_2("http://www.example.com/"); + BOOST_CHECK(uri_1 == uri_2); +} + +BOOST_AUTO_TEST_CASE(equality_test_1) { + uri::uri uri_1("http://www.example.com/"); + std::string uri_2("http://www.example.com/"); + BOOST_CHECK(uri_1 == uri_2); +} + +BOOST_AUTO_TEST_CASE(equality_test_2) { + std::string uri_1("http://www.example.com/"); + uri::uri uri_2("http://www.example.com/"); + BOOST_CHECK(uri_1 == uri_2); +} + +BOOST_AUTO_TEST_CASE(equality_test_3) { + uri::uri uri_1("http://www.example.com/"); + std::string uri_2("http://www.example.com/"); + BOOST_CHECK(uri_1 == uri_2.c_str()); +} + +BOOST_AUTO_TEST_CASE(equality_test_4) { + std::string uri_1("http://www.example.com/"); + uri::uri uri_2("http://www.example.com/"); + BOOST_CHECK(uri_1.c_str() == uri_2); +} + +BOOST_AUTO_TEST_CASE(inequality_test) { + uri::uri uri_1("http://www.example.com/"); + uri::uri uri_2("http://www.example.com/"); + BOOST_CHECK(!(uri_1 != uri_2)); +} + +BOOST_AUTO_TEST_CASE(less_than_test) { + // uri_1 is lexicographically less than uri_2 + uri::uri uri_1("http://www.example.com/"); + uri::uri uri_2("http://www.example.org/"); + BOOST_CHECK(uri_1 < uri_2); +} + +BOOST_AUTO_TEST_CASE(username_test) { + uri::uri instance("ftp://john.doe@ftp.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::username(instance), "john.doe"); +} + +BOOST_AUTO_TEST_CASE(pasword_test) { + uri::uri instance("ftp://john.doe:password@ftp.example.com/"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::password(instance), "password"); +} + +BOOST_AUTO_TEST_CASE(hierarchical_part_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::hierarchical_part(instance), + "user:password@www.example.com:80/path"); +} + +BOOST_AUTO_TEST_CASE(partial_hierarchical_part_test) { + uri::uri instance("http://www.example.com?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::hierarchical_part(instance), "www.example.com"); +} + +BOOST_AUTO_TEST_CASE(authority_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::authority(instance), + "user:password@www.example.com:80"); +} + +BOOST_AUTO_TEST_CASE(partial_authority_test) { + uri::uri instance("http://www.example.com/path?query#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK_EQUAL(uri::authority(instance), "www.example.com"); +} + +BOOST_AUTO_TEST_CASE(http_query_map_test) { + uri::uri instance( + "http://user:password@www.example.com:80/path?query=something#fragment"); + BOOST_REQUIRE(uri::valid(instance)); + + std::map queries; + uri::query_map(instance, queries); + BOOST_REQUIRE_EQUAL(queries.size(), std::size_t(1)); + BOOST_CHECK_EQUAL(queries.begin()->first, "query"); + BOOST_CHECK_EQUAL(queries.begin()->second, "something"); +} + +BOOST_AUTO_TEST_CASE(xmpp_query_map_test) { + uri::uri instance( + "xmpp:example-node@example.com?message;subject=Hello%20World"); + BOOST_REQUIRE(uri::valid(instance)); + + std::map queries; + uri::query_map(instance, queries); + BOOST_REQUIRE_EQUAL(queries.size(), std::size_t(2)); + BOOST_CHECK_EQUAL(queries.begin()->first, "message"); + BOOST_CHECK_EQUAL(queries.begin()->second, ""); + BOOST_CHECK_EQUAL((++queries.begin())->first, "subject"); + BOOST_CHECK_EQUAL((++queries.begin())->second, "Hello%20World"); +} + +BOOST_AUTO_TEST_CASE(range_test) { + const std::string url("http://www.example.com/"); + uri::uri instance(url); + BOOST_REQUIRE(uri::valid(instance)); + BOOST_CHECK(boost::equal(instance, url)); +} + +BOOST_AUTO_TEST_CASE(issue_67_test) { + // https://github.com/cpp-netlib/cpp-netlib/issues/67 + const std::string site_name("http://www.google.com"); + uri::uri bar0; + uri::uri bar1 = site_name; + bar0 = site_name; + BOOST_CHECK(uri::is_valid(bar0)); + BOOST_CHECK(uri::is_valid(bar1)); +} + +BOOST_AUTO_TEST_CASE(from_parts_1) { + BOOST_CHECK_EQUAL(uri::uri("http://www.example.com/path?query#fragment"), + uri::from_parts(uri::uri("http://www.example.com"), "/path", + "query", "fragment")); +} + +BOOST_AUTO_TEST_CASE(from_parts_2) { + BOOST_CHECK_EQUAL( + uri::uri("http://www.example.com/path?query#fragment"), + uri::from_parts("http://www.example.com", "/path", "query", "fragment")); +} + +BOOST_AUTO_TEST_CASE(from_parts_3) { + BOOST_CHECK_EQUAL( + uri::uri("http://www.example.com/path?query"), + uri::from_parts("http://www.example.com", "/path", "query")); +} + +BOOST_AUTO_TEST_CASE(from_parts_4) { + BOOST_CHECK_EQUAL(uri::uri("http://www.example.com/path"), + uri::from_parts("http://www.example.com", "/path")); +} + +BOOST_AUTO_TEST_CASE(from_file) { + boost::filesystem::path path("/a/path/to/a/file.txt"); + BOOST_CHECK_EQUAL(uri::uri("file:///a/path/to/a/file.txt"), + uri::from_file(path)); +} + +BOOST_AUTO_TEST_CASE(issue_104_test) { + // https://github.com/cpp-netlib/cpp-netlib/issues/104 + boost::scoped_ptr instance(new uri::uri("http://www.example.com/")); + uri::uri copy = *instance; + instance.reset(); + BOOST_CHECK_EQUAL(uri::scheme(copy), "http"); +} + +BOOST_AUTO_TEST_CASE(uri_set_test) { + std::set uri_set; + uri_set.insert(uri::uri("http://www.example.com/")); + BOOST_REQUIRE(!uri_set.empty()); + BOOST_CHECK_EQUAL((*uri_set.begin()), uri::uri("http://www.example.com/")); +} + +BOOST_AUTO_TEST_CASE(uri_unordered_set_test) { + boost::unordered_set uri_set; + uri_set.insert(uri::uri("http://www.example.com/")); + BOOST_REQUIRE(!uri_set.empty()); + BOOST_CHECK_EQUAL((*uri_set.begin()), uri::uri("http://www.example.com/")); +} + +BOOST_AUTO_TEST_CASE(issue_161_test) { + uri::uri instance( + "http://www.example.com/" + "path?param1=-¶m2=some+plus+encoded+text¶m3=~"); + BOOST_REQUIRE(uri::valid(instance)); + + std::map queries; + uri::query_map(instance, queries); + BOOST_REQUIRE_EQUAL(queries.size(), std::size_t(3)); + BOOST_CHECK_EQUAL(queries["param1"], "-"); + BOOST_CHECK_EQUAL(queries["param2"], "some+plus+encoded+text"); + BOOST_CHECK_EQUAL(queries["param3"], "~"); + BOOST_CHECK_EQUAL(uri::decoded(queries["param2"]), "some plus encoded text"); +} + +BOOST_AUTO_TEST_CASE(issue_364_test) { + uri::uri instance; + uri::schemes::http(instance) << uri::host("my.awesome.server.com"); + BOOST_CHECK_EQUAL("my.awesome.server.com", uri::authority(instance)); +} + +BOOST_AUTO_TEST_CASE(issue_447_test) { + uri::uri instance("http://[www.foo.com/"); + BOOST_REQUIRE(!uri::valid(instance)); +} + +BOOST_AUTO_TEST_CASE(issue_499_test) { + uri::uri instance( + "http://www.example.com/path?param1¶m2=¶m3=value"); + BOOST_REQUIRE(uri::valid(instance)); + + std::map queries; + uri::query_map(instance, queries); + BOOST_REQUIRE_EQUAL(queries.size(), std::size_t(3)); + BOOST_CHECK_EQUAL(queries["param1"], ""); + BOOST_CHECK_EQUAL(queries["param2"], ""); + BOOST_CHECK_EQUAL(queries["param3"], "value"); +} diff --git a/cpp-netlib/libs/network/test/utils_base64_test.cpp b/cpp-netlib/libs/network/test/utils_base64_test.cpp new file mode 100644 index 00000000..a61f78c0 --- /dev/null +++ b/cpp-netlib/libs/network/test/utils_base64_test.cpp @@ -0,0 +1,203 @@ +#define BOOST_TEST_MODULE BASE64 Test +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::network::utils; + +// proves that all public functions are compilable; the result check +// is very minimum here, so that the test doesn't look so stupid ;-) +BOOST_AUTO_TEST_CASE(interface_test) { + std::string result; + base64::state state; + + // check string literal + BOOST_CHECK_EQUAL(base64::encode("abc"), "YWJj"); + + base64::encode("abc", std::back_inserter(result)); + BOOST_CHECK_EQUAL(result, "YWJj"); + + result.clear(); + base64::encode("abc", std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "YWJj"); + + // check std::string + std::string input("abc"); + + BOOST_CHECK_EQUAL(base64::encode(input), "YWJj"); + + result.clear(); + base64::encode(input, std::back_inserter(result)); + BOOST_CHECK_EQUAL(result, "YWJj"); + + result.clear(); + base64::encode(input.begin(), input.end(), std::back_inserter(result)); + BOOST_CHECK_EQUAL(result, "YWJj"); + + result.clear(); + base64::encode(input, std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "YWJj"); + + result.clear(); + base64::encode(input.begin(), input.end(), std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "YWJj"); + + // check array of chars + char char_array[] = {'a', 'b', 'c', 0}; + + BOOST_CHECK_EQUAL(base64::encode(char_array), "YWJj"); + + // check boost::array of chars + boost::array char_boost_array = {{'a', 'b', 'c'}}; + + BOOST_CHECK_EQUAL(base64::encode(char_boost_array), "YWJj"); + + // check std::vector of chars + std::vector char_vector(char_array, char_array + 3); + + BOOST_CHECK_EQUAL(base64::encode(char_vector), "YWJj"); + + // check array of ints + int int_array[] = {'a', 'b', 'c'}; + + BOOST_CHECK_EQUAL(base64::encode(int_array), "YWJj"); + + // check boost::array of ints + boost::array int_boost_array = {{'a', 'b', 'c'}}; + + BOOST_CHECK_EQUAL(base64::encode(int_boost_array), "YWJj"); + + // check std::vector of ints + std::vector int_vector(int_array, int_array + 3); + + BOOST_CHECK_EQUAL(base64::encode(int_vector), "YWJj"); + + // check that base64::encode_rest is compilable and callable + result.clear(); + base64::encode_rest(std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, ""); + + // check that the iostream interface is compilable and callable + std::ostringstream output; + output << base64::io::encode("abc") + << base64::io::encode(input.begin(), input.end()) + << base64::io::encode(int_array) << base64::io::encode(int_boost_array) + << base64::io::encode(char_array) + << base64::io::encode(char_boost_array) + << base64::io::encode(char_vector) << base64::io::encode_rest; + BOOST_CHECK_EQUAL(output.str(), "YWJjYWJjYWJjYWJjYWJjYWJjYWJj"); +} + +// checks that functions encoding a single chunk append the correct padding +// if the input byte count is not divisible by 3 +BOOST_AUTO_TEST_CASE(padding_test) { + BOOST_CHECK_EQUAL(base64::encode(""), ""); + BOOST_CHECK_EQUAL(base64::encode("a"), "YQ=="); + BOOST_CHECK_EQUAL(base64::encode("aa"), "YWE="); + BOOST_CHECK_EQUAL(base64::encode("aaa"), "YWFh"); +} + +// check that functions using encoding state interrupt and resume encoding +// correcly if the byte count of the partial input is not divisible by 3 +BOOST_AUTO_TEST_CASE(state_test) { + base64::state state; + std::string result; + + // check encoding empty input; including the state value + base64::encode("", std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, ""); + BOOST_CHECK(state.empty()); + result.clear(); + state.clear(); + + // check one third of quantum which needs two character padding; + // including how the state develops when encoded by single character + base64::encode("a", std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "Y"); + BOOST_CHECK(!state.empty()); + base64::encode_rest(std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "YQ=="); + BOOST_CHECK(state.empty()); + result.clear(); + state.clear(); + + // check two thirds of quantum which needs one character padding; + // including how the state develops when encoded by single character + base64::encode("a", std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "Y"); + BOOST_CHECK(!state.empty()); + base64::encode("a", std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "YW"); + BOOST_CHECK(!state.empty()); + base64::encode_rest(std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "YWE="); + BOOST_CHECK(state.empty()); + result.clear(); + state.clear(); + + // check a complete quantum which needs no padding; including + // how the state develops when encoded by single character + base64::encode("a", std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "Y"); + BOOST_CHECK(!state.empty()); + base64::encode("a", std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "YW"); + BOOST_CHECK(!state.empty()); + base64::encode("a", std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "YWFh"); + BOOST_CHECK(state.empty()); + base64::encode_rest(std::back_inserter(result), state); + BOOST_CHECK_EQUAL(result, "YWFh"); + BOOST_CHECK(state.empty()); +} + +// checks that the base64 output can be returned as wchar_t too +BOOST_AUTO_TEST_CASE(wide_character_test) { + BOOST_CHECK(base64::encode("abc") == L"YWJj"); + BOOST_CHECK(base64::encode(std::string("abc")) == L"YWJj"); + + std::wostringstream output; + output << base64::io::encode("abc") << base64::io::encode_rest; + BOOST_CHECK(output.str() == L"YWJj"); +} + +// checks that the base64-io manipulators are compilable and work +BOOST_AUTO_TEST_CASE(io_test) { + // check complete quantum where no state has to be remembered + std::ostringstream output; + output << base64::io::encode("abc") << base64::io::encode_rest; + BOOST_CHECK_EQUAL(output.str(), "YWJj"); + + // check that encode_rest clears the state + output.str(""); + output << base64::io::encode("a"); + BOOST_CHECK(!base64::io::empty_state(output)); + output << base64::io::encode_rest; + BOOST_CHECK(base64::io::empty_state(output)); + + // check that forced clearing the state works + output.str(""); + output << base64::io::encode("a"); + BOOST_CHECK(!base64::io::empty_state(output)); + output << base64::io::clear_state; + BOOST_CHECK(base64::io::empty_state(output)); + + // check one third of quantum which has to be remembered in state + output.str(""); + output << base64::io::encode("a") << base64::io::encode("bc") + << base64::io::encode_rest; + BOOST_CHECK_EQUAL(output.str(), "YWJj"); + + // check two thirds of quantum which have to be remembered in state. + output.str(""); + output << base64::io::encode("ab") << base64::io::encode("c") + << base64::io::encode_rest; + BOOST_CHECK_EQUAL(output.str(), "YWJj"); +} diff --git a/cpp-netlib/libs/network/test/utils_thread_pool.cpp b/cpp-netlib/libs/network/test/utils_thread_pool.cpp new file mode 100644 index 00000000..f2e42499 --- /dev/null +++ b/cpp-netlib/libs/network/test/utils_thread_pool.cpp @@ -0,0 +1,46 @@ + +// Copyright 2010 Dean Michael Berris. +// 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) + +#define BOOST_TEST_MODULE utils thread pool test +#include +#include +#include +#include + +using namespace boost::network; + +// This test specifies the requirements for a thread pool interface. At the +// very least any thread pool implementation should be able to pass the simple +// tests that this unit test requires of thread pools. Ultimately the +// requirements will show up in the Concept documentation, but this test is the +// canonical definition of what a thread pool should look like at least +// syntactically. +// + +BOOST_AUTO_TEST_CASE(default_constructor) { + utils::thread_pool pool; + BOOST_CHECK_EQUAL(pool.thread_count(), std::size_t(1)); +} + +struct foo { + foo() : val_(0) {} + void bar(int val) { val_ += val; } + int const val() const { return val_; } + + protected: + int val_; +}; + +BOOST_AUTO_TEST_CASE(post_work) { + foo instance; + { + utils::thread_pool pool; + BOOST_CHECK_NO_THROW(pool.post(boost::bind(&foo::bar, &instance, 1))); + BOOST_CHECK_NO_THROW(pool.post(boost::bind(&foo::bar, &instance, 2))); + // require that pool is destroyed here, RAII baby + } + BOOST_CHECK_EQUAL(instance.val(), 3); +} diff --git a/cpp-netlib/package.sh b/cpp-netlib/package.sh new file mode 100755 index 00000000..8338a276 --- /dev/null +++ b/cpp-netlib/package.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# +# Copyright 2012 Dean Michael Berris +# Copyright 2012 Google, Inc. +# 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) +# + +VERSION="$1" +if [ "$VERSION" = "" ]; then + VERSION="`git log --format=oneline | awk '{print $1}' | head -1`" +fi + +# Break down the version in form "M.m.p" into individual variables. +BOOST_NETLIB_VERSION_MAJOR=`echo $VERSION | sed 's/[\._\-]/ /g' | awk '{print $1}'` +BOOST_NETLIB_VERSION_MINOR=`echo $VERSION | sed 's/[\._\-]/ /g' | awk '{print $2}'` +BOOST_NETLIB_VERSION_INCREMENT=`echo $VERSION | sed 's/[\._\-]/ /g' | awk '{print $3}'` + +echo $BOOST_NETLIB_VERSION_MAJOR +echo $BOOST_NETLIB_VERSION_MINOR +echo $BOOST_NETLIB_VERSION_INCREMENT + +# Then update the version. +sed -i '' 's/BOOST_NETLIB_VERSION_MAJOR [0-9]*/BOOST_NETLIB_VERSION_MAJOR '$BOOST_NETLIB_VERSION_MAJOR'/g' boost/network/version.hpp +sed -i '' 's/BOOST_NETLIB_VERSION_MINOR [0-9]*/BOOST_NETLIB_VERSION_MINOR '$BOOST_NETLIB_VERSION_MINOR'/g' boost/network/version.hpp +sed -i '' 's/BOOST_NETLIB_VERSION_INCREMENT [0-9]*/BOOST_NETLIB_VERSION_INCREMENT '$BOOST_NETLIB_VERSION_INCREMENT'/g' boost/network/version.hpp + +# Show the diff +git diff boost/network/version.hpp + +# Commit the change +git add boost/network/version.hpp +git commit -m"Bumping release number to $VERSION" + +TAG="cpp-netlib-$VERSION" +git tag $TAG +echo "Tagged $TAG." + +git archive --prefix=cpp-netlib-$VERSION/ --format=zip $TAG >cpp-netlib-$VERSION.zip +git archive --prefix=cpp-netlib-$VERSION/ --format=tar $TAG | gzip >cpp-netlib-$VERSION.tar.gz +git archive --prefix=cpp-netlib-$VERSION/ --format=tar $TAG | bzip2 >cpp-netlib-$VERSION.tar.bz2 +echo "Packaged $TAG."