Inboarding cpp-netlib

This commit is contained in:
clemahieu 2016-04-16 10:54:17 -05:00
commit f4ec16c2c5
529 changed files with 57236 additions and 10 deletions

View file

@ -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)

38
cpp-netlib/.clang-format Normal file
View file

@ -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

11
cpp-netlib/.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
*.cmake
*.swp
*.pyc
CMakeCache.txt
CMakeFiles
Makefile
Testing
*.gch
libs/mime/test/mime-roundtrip
*.a
_build

55
cpp-netlib/.travis.yml Normal file
View file

@ -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

View file

@ -0,0 +1,72 @@
# Copyright 2013 Google, Inc.
# Copyright 2013 Dean Michael Berris <dberris@google.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)
#
# 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 }

150
cpp-netlib/CMakeLists.txt Normal file
View file

@ -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)

View file

@ -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.

64
cpp-netlib/RATIONALE.txt Normal file
View file

@ -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.

160
cpp-netlib/README.rst Normal file
View file

@ -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)

832
cpp-netlib/boost/mime.hpp Normal file
View file

@ -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 <list>
#include <string>
#include <vector>
#include <iosfwd>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/include/phoenix.hpp> // pulls in all of Phoenix
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/format.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>
// #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 traits>
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<char> body_type;
};
template <typename string_type>
struct find_mime_header {
find_mime_header(const char *str) : searchFor(str) {}
bool operator()(const std::pair<std::string, string_type> &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<std::string, std::string> phrase_t;
typedef std::vector<phrase_t> 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 <typename Iterator, typename Container>
struct mime_header_parser : qi::grammar<Iterator, Container()> {
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<qi::fail> ( mime_headerList,
std::cout
<< phoenix::val("Error! Expecting ")
<< qi::labels::_4
<< phoenix::val(" here: \"")
<< phoenix::construct<std::string>(qi::labels::_3,
qi::labels::_2)
<< phoenix::val("\"")
<< std::endl
);
*/
}
qi::rule<Iterator, Container()> mime_headerList;
qi::rule<Iterator, typename Container::value_type()> mime_header;
qi::rule<Iterator, std::string()> token, value, valueCont, valuePart, contWS;
qi::rule<Iterator> crlf;
};
template <typename Container, typename Iterator>
static Container read_headers(Iterator &begin, Iterator end) {
tracer t(__func__);
Container retVal;
mime_header_parser<Iterator, Container> 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 <typename Iterator>
struct mime_content_type_parser : qi::grammar<Iterator, mime_content_type()> {
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<Iterator, mime_content_type()> content_type_header;
qi::rule<Iterator, phrase_t()> phrase;
qi::rule<Iterator, std::string()> part, sub_part, token, attribute, value,
quoted_string, extension_token;
qi::rule<Iterator> ws, line_sep, comment;
};
template <typename string_type>
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<typename string_type::const_iterator> 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 <typename string_type>
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="<somevalue>".*'
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<char> sub_part_t;
typedef std::vector<sub_part_t> sub_parts_t;
template <typename bodyContainer>
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 <some sequence of chars> "CRLF--boundaryCRLF" -- in which
// case we return the sequence
//
// I am deliberately not checking for a termination separator here
template <typename Iterator, typename Container>
struct multipart_body_parser : qi::grammar<Iterator, Container()> {
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<Iterator, Container()> mimeBody;
qi::rule<Iterator> bareSep, sep, crlf;
};
// Break up a multi-part into its' constituent sub parts.
template <typename Iterator, typename Container>
struct multipart_part_parser : qi::grammar<Iterator, Container()> {
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<Iterator, Container()> mimeParts;
qi::rule<Iterator> sep, terminator, crlf;
};
template <typename Iterator, typename bodyContainer>
static void read_multipart_body(Iterator &begin, Iterator end,
multipart_body_type<bodyContainer> &mp_body,
const std::string &separator) {
tracer t(__func__);
typedef bodyContainer innerC;
innerC mpBody;
multipart_body_parser<Iterator, innerC> 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<Iterator, sub_parts_t> 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<char>(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<char>(std::cout));
std::cout << std::endl << "<<****Multipart Body*******" << std::endl;
#endif
}
template <typename Container, typename Iterator>
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<char>(std::cout));
std::cout << std::endl << "<<****SinglePart Body*******" << std::endl;
#endif
return retVal;
}
// FIXME: Need to break the headers at 80 chars...
template <typename headerList>
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 <typename bodyContainer>
void write_body(std::ostream &out, const bodyContainer &body) {
std::copy(body.begin(), body.end(), std::ostream_iterator<char>(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 <typename Iterator, typename traits>
static boost::shared_ptr<basic_mime<traits> > parse_mime(
Iterator &begin, Iterator end,
const char *default_content_type = "text/plain");
}
template <class traits = detail::default_types>
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<std::string, string_type> headerEntry;
typedef std::list<headerEntry> headerList;
typedef typename headerList::iterator headerIter;
typedef typename headerList::const_iterator constHeaderIter;
// Types for the parts
typedef boost::shared_ptr<basic_mime> mimePtr;
typedef std::vector<mimePtr> 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<bodyContainer> 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<string_type>(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<basic_mime> operator[](std::size_t idx) const {
check_subpart_index(idx);
return m_subparts[idx];
}
void append_part(boost::shared_ptr<basic_mime> 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<std::string>(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 <typename Iterator>
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<char>(in), std::istream_iterator<char>());
}
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 <typename Iterator>
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 <typename Iterator>
static boost::shared_ptr<basic_mime<traits> > parse_mime(Iterator &begin,
Iterator end) {
return detail::parse_mime<Iterator, traits>(begin, end);
}
// Build a mime part from a stream
static boost::shared_ptr<basic_mime> 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<string_type>(key));
}
constHeaderIter find_header(const char *key) const {
return std::find_if(header_begin(), header_end(),
detail::find_mime_header<string_type>(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
//<http://www.faqs.org/rfcs/rfc3464.html>
// 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 <typename Iterator, typename traits>
static boost::shared_ptr<basic_mime<traits> > parse_mime(
Iterator &begin, Iterator end, const char *default_content_type) {
tracer t(__func__);
typedef typename boost::mime::basic_mime<traits> mime_part;
shared_ptr<mime_part> retVal(new mime_part(
detail::read_headers<typename mime_part::headerList>(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<Iterator, traits>(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<typename traits::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<iter_type, traits>(b, e, cont_type));
}
retVal->set_body_epilog(body_and_subParts.body_epilog);
}
return retVal;
}
}
// -----------------------------------------------------------
//
// Streaming
//
// -----------------------------------------------------------
template <typename traits>
inline std::ostream &operator<<(std::ostream &stream,
basic_mime<traits> &part) {
part.stream_out(stream);
return stream;
}
template <typename traits>
inline std::ostream &operator<<(std::ostream &stream,
boost::shared_ptr<basic_mime<traits> > 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

View file

@ -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 <boost/network/message.hpp> // message type implementation
#include <boost/network/protocol.hpp> // protocols implementation
#endif // __NETWORK_HPP__

View file

@ -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 <boost/network/support/is_default_string.hpp>
#include <boost/network/support/is_default_wstring.hpp>
#include <boost/mpl/if.hpp>
namespace boost {
namespace network {
namespace impl {
template <class Tag>
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 <class Tag>
struct constants_wide {
static wchar_t const* https() {
static wchar_t https_[] = L"https";
return https_;
}
};
}
template <class Tag>
struct constants
: mpl::if_<
is_default_string<Tag>, impl::constants_narrow<Tag>,
typename mpl::if_<is_default_wstring<Tag>, impl::constants_wide<Tag>,
unsupported_tag<Tag> >::type>::type {};
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_CONSTANTS_HPP_20100808

View file

@ -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 <iostream>
#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 */

View file

@ -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 <class Tag>
struct directive_base {
typedef Tag tag;
// explicit directive_base(basic_message<tag> & message_)
// : _message(message_)
protected:
~directive_base() {}; // can only be extended
// mutable basic_message<tag> & _message;
};
} // namespace detail
} // namespace network
} // namespace boost
#endif // __NETWORK_DETAIL_DIRECTIVE_BASE_HPP__

View file

@ -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 <class Tag, class Message>
struct wrapper_base {
explicit wrapper_base(Message& message_) : _message(message_) {};
protected:
~wrapper_base() {}; // for extending only
Message& _message;
};
template <class Tag, class Message>
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__

View file

@ -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 <boost/network/protocol/http/client.hpp>
#endif // BOOST_NETWORK_INCLUDE_HTTP_CLIENT_HPP_

View file

@ -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 <boost/network/protocol/http/server.hpp>
#endif

View file

@ -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 <boost/network/tags.hpp>
#include <boost/network/message.hpp>
#endif // BOOST_NETWORK_INCLUDE_MESSAGE_HPP_

View file

@ -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 <boost/network/message_fwd.hpp>
#include <boost/network/traits/string.hpp>
#include <boost/network/traits/ostringstream.hpp>
#include <boost/network/traits/headers_container.hpp>
#include <boost/network/detail/directive_base.hpp>
#include <boost/network/detail/wrapper_base.hpp>
#include <boost/network/message/directives.hpp>
#include <boost/network/message/wrappers.hpp>
#include <boost/network/message/transformers.hpp>
#include <boost/network/message/modifiers/add_header.hpp>
#include <boost/network/message/modifiers/remove_header.hpp>
#include <boost/network/message/modifiers/clear_headers.hpp>
#include <boost/network/message/modifiers/source.hpp>
#include <boost/network/message/modifiers/destination.hpp>
#include <boost/network/message/modifiers/body.hpp>
#include <boost/network/message/message_concept.hpp>
/** 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 <class Tag>
struct basic_message {
public:
typedef Tag tag;
typedef typename headers_container<Tag>::type headers_container_type;
typedef typename headers_container_type::value_type header_type;
typedef typename string<Tag>::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<Tag> rhs) {
rhs.swap(*this);
return *this;
}
void swap(basic_message<Tag>& 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<Tag>;
friend struct detail::wrapper_base<Tag, basic_message<Tag> >;
mutable headers_container_type _headers;
mutable string_type _body;
mutable string_type _source;
mutable string_type _destination;
};
template <class Tag>
inline void swap(basic_message<Tag>& left, basic_message<Tag>& right) {
// swap for ADL
left.swap(right);
}
// Commenting this out as we don't need to do this anymore.
// BOOST_CONCEPT_ASSERT((Message<basic_message<boost::network::tags::default_string>
// >));
// BOOST_CONCEPT_ASSERT((Message<basic_message<boost::network::tags::default_wstring>
// >));
typedef basic_message<tags::default_string> message;
typedef basic_message<tags::default_wstring> wmessage;
} // namespace network
} // namespace boost
#endif // __NETWORK_MESSAGE_HPP__

View file

@ -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 <boost/network/message/directives/detail/string_directive.hpp>
#include <boost/network/message/directives/header.hpp>
#include <boost/network/message/directives/remove_header.hpp>
namespace boost {
namespace network {
template <class Tag, class Directive>
inline basic_message<Tag>& operator<<(basic_message<Tag>& 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__

View file

@ -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 <boost/network/traits/string.hpp>
#include <boost/variant/variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/network/support/is_pod.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/or.hpp>
/**
*
* 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 <class ValueType> \
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 Tag, template <class> class Message> \
typename enable_if<is_pod<Tag>, void>::type operator()( \
Message<Tag>& message) const { \
pod_body; \
} \
template <class Tag, template <class> class Message> \
typename enable_if<mpl::not_<is_pod<Tag> >, void>::type operator()( \
Message<Tag>& message) const { \
body; \
} \
}; \
\
template <class T> \
inline name##_directive<T> name(T const& input) { \
return name##_directive<T>(input); \
}
#endif /* BOOST_NETWORK_STRING_DIRECTIVE */
#endif /* BOOST_NETWORK_MESSAGE_DIRECTIVES_DETAIL_STRING_DIRECTIVE_HPP_20100915 \
*/

View file

@ -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 <boost/network/traits/string.hpp>
#include <boost/network/support/is_async.hpp>
#include <boost/network/support/is_sync.hpp>
#include <boost/thread/future.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/or.hpp>
namespace boost {
namespace network {
namespace detail {
template <class Tag>
struct string_value
: mpl::if_<is_async<Tag>, boost::shared_future<typename string<Tag>::type>,
typename mpl::if_<
mpl::or_<is_sync<Tag>, is_same<Tag, tags::default_string>,
is_same<Tag, tags::default_wstring> >,
typename string<Tag>::type, unsupported_tag<Tag> >::type> {};
} /* detail */
} /* network */
} /* boost */
#endif /* BOOST_NETWORK_MESSAGE_DIRECTIVES_DETAIL_STRING_VALUE_HPP_20100915 */

View file

@ -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 <boost/network/traits/string.hpp>
#include <boost/network/support/is_async.hpp>
#include <boost/network/support/is_sync.hpp>
#include <boost/thread/future.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/or.hpp>
#include <boost/variant/variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
namespace boost {
namespace network {
namespace impl {
template <class KeyType, class ValueType>
struct header_directive {
explicit header_directive(KeyType const& header_name,
ValueType const& header_value)
: _header_name(header_name), _header_value(header_value) {};
template <class Message>
struct pod_directive {
template <class T1, class T2>
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 <class Message>
struct normal_directive {
template <class T1, class T2>
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 <class Message>
struct directive_impl
: mpl::if_<is_base_of<tags::pod, typename Message::tag>,
pod_directive<Message>, normal_directive<Message> >::type {};
template <class Message>
void operator()(Message const& msg) const {
directive_impl<Message>::eval(msg, _header_name, _header_value);
}
private:
KeyType const& _header_name;
ValueType const& _header_value;
};
} // namespace impl
template <class T1, class T2>
inline impl::header_directive<T1, T2> header(T1 const& header_name,
T2 const& header_value) {
return impl::header_directive<T1, T2>(header_name, header_value);
}
} // namespace network
} // namespace boost
#endif // __NETWORK_MESSAGE_DIRECTIVES_HEADER_HPP__

View file

@ -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 <boost/network/traits/string.hpp>
namespace boost {
namespace network {
template <class Tag>
struct basic_message;
namespace impl {
template <class T>
struct remove_header_directive {
explicit remove_header_directive(T header_name)
: header_name_(header_name) {};
template <class MessageTag>
void operator()(basic_message<MessageTag>& msg) const {
msg.headers().erase(header_name_);
}
private:
mutable T header_name_;
};
} // namespace impl
inline impl::remove_header_directive<std::string> remove_header(
std::string header_name) {
return impl::remove_header_directive<std::string>(header_name);
}
inline impl::remove_header_directive<std::wstring> remove_header(
std::wstring header_name) {
return impl::remove_header_directive<std::wstring>(header_name);
}
} // namespace network
} // namespace boost
#endif // NETWORK_MESSAGE_DIRECTIVES_REMOVE_HEADER_HPP

View file

@ -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 <boost/concept_check.hpp>
#include <boost/network/message/traits/body.hpp>
#include <boost/network/message/traits/source.hpp>
#include <boost/network/message/traits/destination.hpp>
#include <boost/network/message/traits/headers.hpp>
#include <boost/network/message/wrappers.hpp>
#include <boost/network/message/transformers.hpp>
#include <boost/network/message/directives.hpp>
namespace boost {
namespace network {
template <class M>
struct Message : DefaultConstructible<M>, CopyConstructible<M>, Assignable<M> {
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<M>::type body_type;
typedef typename traits::source<M>::type source_type;
typedef typename traits::destination<M>::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

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/network/support/is_pod.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/not.hpp>
namespace boost {
namespace network {
namespace impl {
template <class Message, class KeyType, class ValueType, class Tag>
inline typename enable_if<
mpl::and_<mpl::not_<is_pod<Tag> >, mpl::not_<is_async<Tag> > >, void>::type
add_header(Message& message, KeyType const& key, ValueType const& value, Tag) {
message.headers().insert(std::make_pair(key, value));
}
template <class Message, class KeyType, class ValueType, class Tag>
inline typename enable_if<mpl::and_<mpl::not_<is_pod<Tag> >, is_async<Tag> >,
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 <class Message, class KeyType, class ValueType, class Tag>
inline typename enable_if<is_pod<Tag>, 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 Tag, template <class> class Message, class KeyType,
class ValueType>
inline void add_header(Message<Tag>& 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

View file

@ -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 <boost/network/support/pod_or_normal.hpp>
#include <boost/thread/future.hpp>
namespace boost {
namespace network {
template <class Tag, template <class> class Message, class ValueType>
inline void body_impl(Message<Tag>& message, ValueType const& body, tags::pod) {
message.body = body;
}
template <class Tag, template <class> class Message, class ValueType>
inline void body_impl(Message<Tag>& message, ValueType const& body,
tags::normal) {
message.body(body);
}
template <class Tag, template <class> class Message, class ValueType>
inline void body(Message<Tag>& message, ValueType const& body_) {
body_impl(message, body_, typename pod_or_normal<Tag>::type());
}
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_MODIFIERS_BODY_HPP_20100824

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/network/support/is_pod.hpp>
#include <boost/thread/future.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/and.hpp>
namespace boost {
namespace network {
namespace impl {
template <class Message, class Tag>
inline typename enable_if<
mpl::and_<mpl::not_<is_pod<Tag> >, mpl::not_<is_async<Tag> > >, void>::type
clear_headers(Message const &message, Tag const &) {
(typename Message::headers_container_type()).swap(message.headers());
}
template <class Message, class Tag>
inline typename enable_if<is_pod<Tag>, void>::type clear_headers(
Message const &message, Tag const &) {
(typename Message::headers_container_type()).swap(message.headers);
}
template <class Message, class Tag>
inline typename enable_if<mpl::and_<mpl::not_<is_pod<Tag> >, is_async<Tag> >,
void>::type
clear_headers(Message const &message, Tag const &) {
boost::promise<typename Message::headers_container_type> header_promise;
boost::shared_future<typename Message::headers_container_type> headers_future(
header_promise.get_future());
message.headers(headers_future);
header_promise.set_value(typename Message::headers_container_type());
}
} // namespace impl
template <class Tag, template <class> class Message>
inline void clear_headers(Message<Tag> const &message) {
impl::clear_headers(message, Tag());
}
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_MESSAGE_MODIFIER_CLEAR_HEADERS_HPP_20100824

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/thread/future.hpp>
namespace boost {
namespace network {
namespace impl {
template <class Message, class ValueType, class Tag>
inline void destination(Message const &message, ValueType const &destination_,
Tag const &, mpl::false_ const &) {
message.destination(destination_);
}
template <class Message, class ValueType, class Tag>
inline void destination(Message const &message, ValueType const &destination_,
Tag const &, mpl::true_ const &) {
message.destination(destination_);
}
}
template <class Tag, template <class> class Message, class ValueType>
inline void destination(Message<Tag> const &message,
ValueType const &destination_) {
impl::destination(message, destination_, Tag(), is_async<Tag>());
}
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_MESSAGE_MODIFIER_DESTINATION_HPP_20100824

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/network/support/is_pod.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/range/algorithm/remove_if.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/mpl/not.hpp>
namespace boost {
namespace network {
namespace impl {
template <class Message, class KeyType, class Tag>
inline typename enable_if<
mpl::and_<mpl::not_<is_pod<Tag> >, mpl::not_<is_async<Tag> > >, void>::type
remove_header(Message& message, KeyType const& key, Tag) {
message.headers().erase(key);
}
template <class Message, class KeyType, class Tag>
inline typename enable_if<mpl::and_<mpl::not_<is_pod<Tag> >, is_async<Tag> >,
void>::type
remove_header(Message& message, KeyType const& key, Tag) {
message.remove_header(key);
}
template <class KeyType>
struct iequals_pred {
KeyType const& key;
iequals_pred(KeyType const& key) : key(key) {}
template <class Header>
bool operator()(Header& other) const {
return boost::iequals(key, name(other));
}
};
template <class Message, class KeyType, class Tag>
inline typename enable_if<is_pod<Tag>, void>::type remove_header(
Message& message, KeyType const& key, Tag) {
message.headers.erase(
boost::remove_if(message.headers, iequals_pred<KeyType>(key)),
message.headers.end());
}
} // namespace impl
template <class Tag, template <class> class Message, class KeyType>
inline void remove_header(Message<Tag>& message, KeyType const& key) {
impl::remove_header(message, key, Tag());
}
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_MESSAGE_MODIFIER_REMOVE_HEADER_HPP_20100824

View file

@ -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 <boost/network/support/is_async.hpp>
namespace boost {
namespace network {
namespace impl {
template <class Message, class ValueType, class Tag>
inline void source(Message const &message, ValueType const &source_,
Tag const &, mpl::false_ const &) {
message.source(source_);
}
template <class Message, class ValueType, class Tag>
inline void source(Message const &message, ValueType const &source_,
Tag const &, mpl::true_ const &) {
message.source(source_);
}
} // namespace impl
template <class Tag, template <class> class Message, class ValueType>
inline void source(Message<Tag> const &message, ValueType const &source_) {
impl::source(message, source_, Tag(), is_async<Tag>());
}
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_MESSAGE_MODIFIER_SOURCE_HPP_20100824

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/network/support/is_sync.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/thread/future.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/if.hpp>
namespace boost {
namespace network {
namespace traits {
template <class Tag>
struct unsupported_tag;
template <class Message>
struct body
: mpl::if_<
is_async<typename Message::tag>,
boost::shared_future<typename string<typename Message::tag>::type>,
typename mpl::if_<
mpl::or_<is_sync<typename Message::tag>,
is_same<typename Message::tag, tags::default_string>,
is_same<typename Message::tag, tags::default_wstring> >,
typename string<typename Message::tag>::type,
unsupported_tag<typename Message::tag> >::type> {};
} // namespace traits
} /* network */
} /* boost */
#endif // BOOST_NETWORK_MESSAGE_TRAITS_BODY_HPP_20100903

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/network/support/is_sync.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/thread/future.hpp>
#include <boost/mpl/if.hpp>
namespace boost {
namespace network {
namespace traits {
template <class Tag>
struct unsupported_tag;
template <class Message>
struct destination
: mpl::if_<
is_async<typename Message::tag>,
boost::shared_future<typename string<typename Message::tag>::type>,
typename mpl::if_<
mpl::or_<is_sync<typename Message::tag>,
is_same<typename Message::tag, tags::default_string>,
is_same<typename Message::tag, tags::default_wstring> >,
typename string<typename Message::tag>::type,
unsupported_tag<typename Message::tag> >::type> {};
} // namespace traits
} /* network */
} /* boost */
#endif // BOOST_NETWORK_MESSAGE_TRAITS_DESTINATION_HPP_20100903

View file

@ -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 <boost/network/tags.hpp>
#include <boost/network/traits/string.hpp>
#include <boost/network/support/is_async.hpp>
#include <boost/network/support/is_sync.hpp>
#include <boost/thread/future.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/or.hpp>
namespace boost {
namespace network {
namespace traits {
template <class Tag>
struct unsupported_tag;
template <class Message>
struct header_key
: mpl::if_<
is_async<typename Message::tag>,
boost::shared_future<typename string<typename Message::tag>::type>,
typename mpl::if_<
mpl::or_<is_sync<typename Message::tag>,
is_same<typename Message::tag, tags::default_string>,
is_same<typename Message::tag, tags::default_wstring> >,
typename string<typename Message::tag>::type,
unsupported_tag<typename Message::tag> >::type> {};
template <class Message>
struct header_value
: mpl::if_<
is_async<typename Message::tag>,
boost::shared_future<typename string<typename Message::tag>::type>,
typename mpl::if_<
mpl::or_<is_sync<typename Message::tag>,
is_same<typename Message::tag, tags::default_string>,
is_same<typename Message::tag, tags::default_wstring> >,
typename string<typename Message::tag>::type,
unsupported_tag<typename Message::tag> >::type> {};
} // namespace traits
} /* network */
} /* boost */
#endif // BOOST_NETWORK_MESSAGE_TRAITS_HEADERS_HPP_20100903

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/network/support/is_sync.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/thread/future.hpp>
#include <boost/mpl/if.hpp>
namespace boost {
namespace network {
namespace traits {
template <class Tag>
struct unsupported_tag;
template <class Message>
struct source
: mpl::if_<
is_async<typename Message::tag>,
boost::shared_future<typename string<typename Message::tag>::type>,
typename mpl::if_<
mpl::or_<is_sync<typename Message::tag>,
is_same<typename Message::tag, tags::default_string>,
is_same<typename Message::tag, tags::default_wstring> >,
typename string<typename Message::tag>::type,
unsupported_tag<typename Message::tag> >::type> {};
} // namespace traits
} /* network */
} /* boost */
#endif // BOOST_NETWORK_MESSAGE_TRAITS_SOURCE_HPP_20100903

View file

@ -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 <boost/network/message/transformers/selectors.hpp>
#include <boost/network/message/transformers/to_upper.hpp>
#include <boost/network/message/transformers/to_lower.hpp>
#include <boost/type_traits.hpp>
namespace boost {
namespace network {
namespace impl {
template <class Algorithm, class Selector>
struct get_real_algorithm {
typedef typename boost::function_traits<
typename boost::remove_pointer<Algorithm>::type>::result_type::
template type<typename boost::function_traits<
typename boost::remove_pointer<Selector>::type>::result_type> type;
};
template <class Algorithm, class Selector>
struct transform_impl : public get_real_algorithm<Algorithm, Selector>::type {};
} // namspace impl
template <class Algorithm, class Selector>
inline impl::transform_impl<Algorithm, Selector> transform(Algorithm,
Selector) {
return impl::transform_impl<Algorithm, Selector>();
}
template <class Tag, class Algorithm, class Selector>
inline basic_message<Tag>& operator<<(
basic_message<Tag>& msg_,
impl::transform_impl<Algorithm, Selector> const& transformer) {
transformer(msg_);
return msg_;
}
} // namespace network
} // namespace boost
#endif // __NETWORK_MESSAGE_TRANSFORMERS_HPP__

View file

@ -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__

View file

@ -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 <boost/algorithm/string.hpp>
/** 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 <class Selector>
struct to_lower_transformer {};
template <>
struct to_lower_transformer<selectors::source_selector> {
template <class Tag>
void operator()(basic_message<Tag> &message_) const {
boost::to_lower(message_.source());
}
protected:
~to_lower_transformer() {}
};
template <>
struct to_lower_transformer<selectors::destination_selector> {
template <class Tag>
void operator()(basic_message<Tag> &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 <class Selector>
struct type : public impl::to_lower_transformer<Selector> {};
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__

View file

@ -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 <boost/algorithm/string.hpp>
/** 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 <class Selector>
struct to_upper_transformer {};
template <>
struct to_upper_transformer<selectors::source_selector> {
template <class Tag>
void operator()(basic_message<Tag> &message_) const {
boost::to_upper(message_.source());
}
protected:
~to_upper_transformer() {};
};
template <>
struct to_upper_transformer<selectors::destination_selector> {
template <class Tag>
void operator()(basic_message<Tag> &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 <class Selector>
struct type : public impl::to_upper_transformer<Selector> {};
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__

View file

@ -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 <boost/network/message/wrappers/headers.hpp>
#include <boost/network/message/wrappers/body.hpp>
#include <boost/network/message/wrappers/source.hpp>
#include <boost/network/message/wrappers/destination.hpp>
#endif // __NETWORK_MESSAGE_WRAPPERS_HPP__

View file

@ -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 <boost/network/traits/string.hpp>
#include <boost/network/detail/wrapper_base.hpp>
#include <boost/range/iterator.hpp>
namespace boost {
namespace network {
template <class Message>
struct body_range {
typedef typename boost::iterator_range<
typename Message::string_type::const_iterator> type;
};
namespace impl {
template <class Tag>
struct body_wrapper : public detail::wrapper_base<Tag, basic_message<Tag> > {
typedef basic_message<Tag> message_type;
typedef typename string<Tag>::type string_type;
typedef detail::wrapper_base<Tag, basic_message<Tag> > wrapper_base;
explicit body_wrapper(basic_message<Tag>& 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<string_type>::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 <class Tag>
struct body_wrapper_const
: public detail::wrapper_base_const<Tag, basic_message<Tag> > {
typedef basic_message<Tag> message_type;
typedef typename string<Tag>::type string_type;
typedef detail::wrapper_base_const<Tag, basic_message<Tag> > wrapper_base;
explicit body_wrapper_const(basic_message<Tag> 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<string_type>() const {
return boost::make_iterator_range(wrapper_base::_message.body());
}
};
template <class Tag>
inline std::ostream& operator<<(std::ostream& os,
body_wrapper<Tag> const& body) {
os << static_cast<typename body_wrapper<Tag>::string_type>(body);
return os;
}
template <class Tag>
inline std::ostream& operator<<(std::ostream& os,
body_wrapper_const<Tag> const& body) {
os << static_cast<typename body_wrapper_const<Tag>::string_type>(body);
return os;
}
} // namespace impl
template <class Tag>
inline impl::body_wrapper<Tag> const body(basic_message<Tag>& message_) {
return impl::body_wrapper<Tag>(message_);
}
template <class Tag>
inline impl::body_wrapper_const<Tag> const body(
basic_message<Tag> const& message_) {
return impl::body_wrapper_const<Tag>(message_);
}
} // namespace network
} // namespace boost
#endif // __NETWORK_MESSAGE_WRAPPERS_BODY_HPP__

View file

@ -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 <boost/network/traits/string.hpp>
namespace boost {
namespace network {
namespace impl {
template <class Tag>
struct destination_wrapper
: public detail::wrapper_base<Tag, basic_message<Tag> > {
typedef Tag tag;
typedef basic_message<tag> message_type;
typedef typename string<Tag>::type string_type;
typedef detail::wrapper_base<Tag, basic_message<Tag> > 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 <class Tag>
inline typename string<Tag>::type destination(basic_message<Tag>& message_) {
return impl::destination_wrapper<Tag>(message_);
}
} // namespace network
} // namespace boost
#endif // __NETWORK_MESSAGE_WRAPPERS_DESTINATION_HPP__

View file

@ -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 <boost/network/traits/string.hpp>
#include <boost/network/traits/headers_container.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/functions.hpp>
#include <boost/network/detail/wrapper_base.hpp>
namespace boost {
namespace network {
/// Template metaprogram to get the range type for a message
template <class Message>
struct headers_range {
typedef typename headers_container<typename Message::tag>::type
headers_container_type;
typedef typename boost::iterator_range<
typename headers_container_type::const_iterator> type;
};
template <class Tag>
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<iterator, iterator>)
* whose keys are all equal to the index string.
*
* This type is also convertible to a
* headers_range<basic_message<tag> >::type
* Which allows for full range support.
*
* The type is also convertible to a
* headers_container<Tag>::type
* Which copies the headers from the wrapped message.
*
*/
namespace impl {
template <class Tag>
struct headers_wrapper
: public detail::wrapper_base_const<Tag, basic_message<Tag> > {
typedef Tag tag;
typedef basic_message<Tag> message_type;
typedef typename string<Tag>::type string_type;
typedef typename headers_range<message_type>::type range_type;
typedef typename headers_container<Tag>::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<Tag, basic_message<Tag> > wrapper_base;
explicit headers_wrapper(basic_message<Tag> const& message_)
: wrapper_base(message_) {};
range_type operator[](string_type const& key) const {
return headers_wrapper<Tag>::_message.headers().equal_range(key);
};
typename message_type::headers_container_type::size_type count(
string_type const& key) const {
return headers_wrapper<Tag>::_message.headers().count(key);
};
const_iterator begin() const {
return headers_wrapper<Tag>::_message.headers().begin();
};
const_iterator end() const {
return headers_wrapper<Tag>::_message.headers().end();
};
operator range_type() {
return make_iterator_range(headers_wrapper<Tag>::_message.headers().begin(),
headers_wrapper<Tag>::_message.headers().end());
};
operator headers_container_type() {
return headers_wrapper<Tag>::_message.headers();
}
};
} // namespace impl
/// Factory method to create the right wrapper object
template <class Tag>
inline impl::headers_wrapper<Tag> headers(basic_message<Tag> const& message_) {
return impl::headers_wrapper<Tag>(message_);
}
} // namespace network
} // namespace boost
#endif // __NETWORK_MESSAGE_WRAPPERS_HEADERS_HPP__

View file

@ -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 <boost/network/traits/string.hpp>
namespace boost {
namespace network {
namespace impl {
template <class Tag>
struct source_wrapper : public detail::wrapper_base<Tag, basic_message<Tag> > {
typedef Tag tag;
typedef basic_message<tag> message_type;
typedef typename string<tag>::type string_type;
typedef detail::wrapper_base<Tag, basic_message<Tag> > wrapper_base;
explicit source_wrapper(basic_message<tag>& message_)
: wrapper_base(message_) {};
operator string_type() const {
return string_type(wrapper_base::_message.source());
};
};
} // namespace impl
template <class Tag>
inline typename string<Tag>::type source(basic_message<Tag>& message_) {
return impl::source_wrapper<Tag>(message_);
}
} // namespace network
} // namespace boost
#endif // __NETWORK_MESSAGE_WRAPPERS_SOURCE_HPP__

View file

@ -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 <class Tag>
struct basic_message;
} // namespace boost
} // namespace network
#endif // __2008817MESSAGE_FWD_INC__

View file

@ -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 <boost/network/protocol/http.hpp> // include HTTP implementation
#endif // __NETWORK_PROTOCOLS_20070908-1_HPP__

View file

@ -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 <boost/network/protocol/http/response.hpp>
#include <boost/network/protocol/http/request.hpp>
#include <boost/network/protocol/http/client.hpp>
#include <boost/network/protocol/http/errors.hpp>
#endif // __NETWORK_PROTOCOL_HTTP_20070908-1_HPP__

View file

@ -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 <algorithm>
#include <bitset>
#include <boost/network/traits/string.hpp>
#include <boost/network/protocol/http/message/header/name.hpp>
#include <boost/network/protocol/http/message/header/value.hpp>
#include <boost/network/protocol/http/message/header_concept.hpp>
#include <boost/network/protocol/http/request_concept.hpp>
#include <boost/network/constants.hpp>
#include <boost/concept/requires.hpp>
#include <boost/optional.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/algorithm/string/compare.hpp>
#include <boost/version.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct linearize_header {
typedef typename string<Tag>::type string_type;
template <class Arguments>
struct result;
template <class This, class Arg>
struct result<This(Arg)> {
typedef string_type type;
};
template <class ValueType>
BOOST_CONCEPT_REQUIRES(((Header<typename boost::remove_cv<ValueType>::type>)),
(string_type))
operator()(ValueType& header) {
typedef typename ostringstream<Tag>::type output_stream;
typedef constants<Tag> consts;
output_stream header_line;
header_line << name(header) << consts::colon() << consts::space()
<< value(header) << consts::crlf();
return header_line.str();
}
};
template <class Request, class OutputIterator>
BOOST_CONCEPT_REQUIRES(((ClientRequest<Request>)), (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<Tag> consts;
typedef typename string<Tag>::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<string_type>(version_major),
version_minor_str =
boost::lexical_cast<string_type>(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<MAX> 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<Request>::type headers_range;
typedef typename range_value<headers_range>::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<boost::uint16_t> 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<string_type>(*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<Tag>::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<Request>::type body_data = body(request).range();
return boost::copy(body_data, oi);
}
} /* http */
} /* net */
} /* boost */
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_ALGORITHMS_LINEARIZE_HPP_20101028 */

View file

@ -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 <boost/network/version.hpp>
#include <boost/network/traits/ostringstream.hpp>
#include <boost/network/protocol/http/message.hpp>
#include <boost/network/protocol/http/response.hpp>
#include <boost/network/protocol/http/request.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/foreach.hpp>
#include <ostream>
#include <istream>
#include <string>
#include <stdexcept>
#include <map>
#include <boost/network/protocol/http/client/facade.hpp>
#include <boost/network/protocol/http/client/macros.hpp>
#include <boost/network/protocol/http/client/options.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag, unsigned version_major, unsigned version_minor>
struct basic_client : basic_client_facade<Tag, version_major, version_minor> {
private:
typedef basic_client_facade<Tag, version_major, version_minor>
base_facade_type;
public:
typedef basic_request<Tag> request;
typedef basic_response<Tag> response;
typedef typename string<Tag>::type string_type;
typedef Tag tag_type;
typedef client_options<Tag> 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<BOOST_NETWORK_HTTP_CLIENT_DEFAULT_TAG, 1, 1> client;
} // namespace http
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_20091215

View file

@ -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 <boost/asio/io_service.hpp>
#include <boost/asio/strand.hpp>
#include <boost/thread/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/bind.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag, unsigned version_major, unsigned version_minor>
struct basic_client_impl;
namespace impl {
template <class Tag, unsigned version_major, unsigned version_minor>
struct async_client
: connection_policy<Tag, version_major, version_minor>::type {
typedef typename connection_policy<Tag, version_major, version_minor>::type
connection_base;
typedef typename resolver<Tag>::type resolver_type;
typedef typename string<Tag>::type string_type;
typedef function<void(boost::iterator_range<char const*> const&,
system::error_code const&)> body_callback_function_type;
typedef function<bool(string_type&)> body_generator_function_type;
async_client(bool cache_resolved, bool follow_redirect,
bool always_verify_peer, int timeout,
boost::shared_ptr<boost::asio::io_service> service,
optional<string_type> const& certificate_filename,
optional<string_type> const& verify_path,
optional<string_type> const& certificate_file,
optional<string_type> const& private_key_file,
optional<string_type> const& ciphers, long ssl_options)
: connection_base(cache_resolved, follow_redirect, timeout),
service_ptr(service.get()
? service
: boost::make_shared<boost::asio::io_service>()),
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<Tag> const request_skeleton(
basic_request<Tag> 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<boost::asio::io_service> service_ptr;
boost::asio::io_service& service_;
resolver_type resolver_;
boost::shared_ptr<boost::asio::io_service::work> sentinel_;
boost::shared_ptr<boost::thread> lifetime_thread_;
optional<string_type> certificate_filename_;
optional<string_type> verify_path_;
optional<string_type> certificate_file_;
optional<string_type> private_key_file_;
optional<string_type> 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

View file

@ -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 <dberris@google.com>
// 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 <boost/network/protocol/http/response.hpp>
#include <boost/network/protocol/http/client/connection/connection_delegate_factory.hpp>
#include <boost/network/protocol/http/traits/delegate_factory.hpp>
#include <boost/network/protocol/http/client/connection/async_normal.hpp>
namespace boost {
namespace network {
namespace http {
namespace impl {
template <class Tag, unsigned version_major, unsigned version_minor>
struct async_connection_base {
typedef async_connection_base<Tag, version_major, version_minor> this_type;
typedef typename resolver_policy<Tag>::type resolver_base;
typedef typename resolver_base::resolver_type resolver_type;
typedef typename resolver_base::resolve_function resolve_function;
typedef typename string<Tag>::type string_type;
typedef basic_request<Tag> request;
typedef basic_response<Tag> response;
typedef iterator_range<char const *> char_const_range;
typedef function<void(char_const_range const &, system::error_code const &)>
body_callback_function_type;
typedef function<bool(string_type &)> body_generator_function_type;
typedef shared_ptr<this_type> 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<string_type> certificate_filename = optional<string_type>(),
optional<string_type> const &verify_path = optional<string_type>(),
optional<string_type> certificate_file = optional<string_type>(),
optional<string_type> private_key_file = optional<string_type>(),
optional<string_type> ciphers = optional<string_type>(),
long ssl_options = 0) {
typedef http_async_connection<Tag, version_major, version_minor>
async_connection;
typedef typename delegate_factory<Tag>::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

View file

@ -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 <boost/network/version.hpp>
#include <boost/network/detail/debug.hpp>
#include <boost/thread/future.hpp>
#include <boost/throw_exception.hpp>
#include <boost/cstdint.hpp>
#include <boost/range/algorithm/transform.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/network/constants.hpp>
#include <boost/network/traits/ostream_iterator.hpp>
#include <boost/network/traits/istream.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/network/protocol/http/parser/incremental.hpp>
#include <boost/network/protocol/http/message/wrappers/uri.hpp>
#include <boost/network/protocol/http/client/connection/async_protocol_handler.hpp>
#include <boost/network/protocol/http/algorithms/linearize.hpp>
#include <boost/array.hpp>
#include <boost/assert.hpp>
#include <boost/bind/protect.hpp>
#include <iterator>
#include <boost/network/protocol/http/traits/delegate_factory.hpp>
namespace boost {
namespace network {
namespace http {
namespace impl {
template <class Tag, unsigned version_major, unsigned version_minor>
struct async_connection_base;
namespace placeholders = boost::asio::placeholders;
template <class Tag, unsigned version_major, unsigned version_minor>
struct http_async_connection
: async_connection_base<Tag, version_major, version_minor>,
protected http_async_protocol_handler<Tag, version_major, version_minor>,
boost::enable_shared_from_this<
http_async_connection<Tag, version_major, version_minor> > {
typedef async_connection_base<Tag, version_major, version_minor> base;
typedef http_async_protocol_handler<Tag, version_major, version_minor>
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<Tag, version_major, version_minor> this_type;
typedef typename delegate_factory<Tag>::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<typename char_<Tag>::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<const char*> 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<const char*> 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<typename char_<Tag>::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

View file

@ -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 <boost/network/detail/debug.hpp>
#include <boost/network/protocol/http/algorithms/linearize.hpp>
namespace boost {
namespace network {
namespace http {
namespace impl {
template <class Tag, unsigned version_major, unsigned version_minor>
struct http_async_protocol_handler {
protected:
typedef typename string<Tag>::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<Tag>::type escaped_stream;
if (input == '\r') {
string.append("\\r");
} else if (input == '\n') {
string.append("\\n");
} else {
escaped_stream << "\\x" << static_cast<int>(input);
string.append(escaped_stream.str());
}
} else {
string.push_back(input);
}
}
};
#endif
template <class ResponseType>
void init_response(ResponseType& response_, bool get_body) {
// TODO(dberris): review parameter necessity.
(void)get_body;
boost::shared_future<string_type> source_future(
source_promise.get_future());
source(response_, source_future);
boost::shared_future<string_type> destination_future(
destination_promise.get_future());
destination(response_, destination_future);
boost::shared_future<typename headers_container<Tag>::type> headers_future(
headers_promise.get_future());
headers(response_, headers_future);
boost::shared_future<string_type> body_future(body_promise.get_future());
body(response_, body_future);
boost::shared_future<string_type> version_future(
version_promise.get_future());
version(response_, version_future);
boost::shared_future<boost::uint16_t> status_future(
status_promise.get_future());
status(response_, status_future);
boost::shared_future<string_type> status_message_future(
status_message_promise.get_future());
status_message(response_, status_message_future);
}
struct to_http_headers {
typedef typename string<Tag>::type string_type;
template <class U>
string_type const operator()(U const& pair) const {
typedef typename ostringstream<Tag>::type ostringstream_type;
typedef constants<Tag> constants;
ostringstream_type header_line;
header_line << pair.first << constants::colon() << constants::space()
<< pair.second << constants::crlf();
return header_line.str();
}
};
template <class Delegate, class Callback>
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<typename buffer_type::const_iterator>
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 <class Delegate, class Callback>
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<typename buffer_type::const_iterator>
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<boost::uint16_t>(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 <class Delegate, class Callback>
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<typename buffer_type::const_iterator>
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<typename string_type::const_iterator>
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<Tag>::type headers;
std::pair<string_type, string_type> 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<basic_response<Tag> >::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 <class Delegate, class Callback>
fusion::tuple<logic::tribool, size_t> 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<typename buffer_type::const_iterator>
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 <class Delegate, class Callback>
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<Tag> response_parser_type;
// TODO: make 1024 go away and become a configurable value.
typedef boost::array<typename char_<Tag>::type, 1024> buffer_type;
response_parser_type response_parser_;
boost::promise<string_type> version_promise;
boost::promise<boost::uint16_t> status_promise;
boost::promise<string_type> status_message_promise;
boost::promise<typename headers_container<Tag>::type> headers_promise;
boost::promise<string_type> source_promise;
boost::promise<string_type> destination_promise;
boost::promise<string_type> 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 \
*/

View file

@ -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<void(system::error_code const &)> handler) = 0;
virtual void write(
asio::streambuf &command_streambuf,
function<void(system::error_code const &, size_t)> handler) = 0;
virtual void read_some(
asio::mutable_buffers_1 const &read_buffer,
function<void(system::error_code const &, size_t)> handler) = 0;
virtual void disconnect() = 0;
virtual ~connection_delegate() {}
};
} /* impl */
} /* http */
} /* network */
} /* boost */
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_CONNECTION_DELEGATE_HPP_ \
*/

View file

@ -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 <boost/throw_exception.hpp>
#include <boost/network/protocol/http/client/connection/connection_delegate.hpp>
#include <boost/network/protocol/http/client/connection/normal_delegate.hpp>
#ifdef BOOST_NETWORK_ENABLE_HTTPS
#include <boost/network/protocol/http/client/connection/ssl_delegate.hpp>
#endif /* BOOST_NETWORK_ENABLE_HTTPS */
namespace boost {
namespace network {
namespace http {
namespace impl {
struct ssl_delegate;
struct normal_delegate;
template <class Tag>
struct connection_delegate_factory {
typedef shared_ptr<connection_delegate> connection_delegate_ptr;
typedef typename string<Tag>::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<string_type> certificate_filename,
optional<string_type> verify_path, optional<string_type> certificate_file,
optional<string_type> private_key_file, optional<string_type> 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 \
*/

View file

@ -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 <boost/network/protocol/http/client/connection/connection_delegate.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/asio/placeholders.hpp>
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<void(system::error_code const &)> handler);
virtual void write(
asio::streambuf &command_streambuf,
function<void(system::error_code const &, size_t)> handler);
virtual void read_some(
asio::mutable_buffers_1 const &read_buffer,
function<void(system::error_code const &, size_t)> handler);
virtual void disconnect();
~normal_delegate();
private:
asio::io_service &service_;
scoped_ptr<asio::ip::tcp::socket> socket_;
normal_delegate(normal_delegate const &); // = delete
normal_delegate &operator=(normal_delegate); // = delete
};
} /* impl */
} /* http */
} /* network */
} /* boost */
#ifdef BOOST_NETWORK_NO_LIB
#include <boost/network/protocol/http/client/connection/normal_delegate.ipp>
#endif /* BOOST_NETWORK_NO_LIB */
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_NORMAL_DELEGATE_20110819 \
*/

View file

@ -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 <boost/asio/ip/tcp.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/write.hpp>
#include <boost/function.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/network/protocol/http/client/connection/normal_delegate.hpp>
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<void(system::error_code const &)> 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<void(system::error_code const &, size_t)> 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<void(system::error_code const &, size_t)> 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 \
*/

View file

@ -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 <boost/asio/io_service.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/network/protocol/http/client/connection/connection_delegate.hpp>
#include <boost/optional.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/network/support/is_default_string.hpp>
#include <boost/network/support/is_default_wstring.hpp>
namespace boost {
namespace network {
namespace http {
namespace impl {
struct ssl_delegate : connection_delegate,
enable_shared_from_this<ssl_delegate> {
ssl_delegate(asio::io_service &service, bool always_verify_peer,
optional<std::string> certificate_filename,
optional<std::string> verify_path,
optional<std::string> certificate_file,
optional<std::string> private_key_file,
optional<std::string> ciphers, long ssl_options);
virtual void connect(asio::ip::tcp::endpoint &endpoint, std::string host, boost::uint16_t source_port,
function<void(system::error_code const &)> handler);
virtual void write(
asio::streambuf &command_streambuf,
function<void(system::error_code const &, size_t)> handler);
virtual void read_some(
asio::mutable_buffers_1 const &read_buffer,
function<void(system::error_code const &, size_t)> handler);
virtual void disconnect();
~ssl_delegate();
private:
asio::io_service &service_;
optional<std::string> certificate_filename_;
optional<std::string> verify_path_;
optional<std::string> certificate_file_;
optional<std::string> private_key_file_;
optional<std::string> ciphers_;
long ssl_options_;
scoped_ptr<asio::ssl::context> context_;
scoped_ptr<asio::ip::tcp::socket> tcp_socket_;
scoped_ptr<asio::ssl::stream<asio::ip::tcp::socket&> > 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<void(system::error_code const &)> handler);
};
} /* impl */
} /* http */
} /* network */
} /* boost */
#ifdef BOOST_NETWORK_NO_LIB
#include <boost/network/protocol/http/client/connection/ssl_delegate.ipp>
#endif /* BOOST_NETWORK_NO_LIB */
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_CONNECTION_SSL_DELEGATE_20110819 \
*/

View file

@ -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 <boost/network/protocol/http/client/connection/ssl_delegate.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
boost::network::http::impl::ssl_delegate::ssl_delegate(
asio::io_service &service, bool always_verify_peer,
optional<std::string> certificate_filename,
optional<std::string> verify_path,
optional<std::string> certificate_file,
optional<std::string> private_key_file,
optional<std::string> 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<void(system::error_code const &)> 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<asio::ip::tcp::socket&>(*(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<void(system::error_code const &)> 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<void(system::error_code const &, size_t)> 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<void(system::error_code const &, size_t)> 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 \
*/

View file

@ -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 <dberris@google.com>
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/network/protocol/http/traits/resolver_policy.hpp>
#include <boost/network/traits/ostringstream.hpp>
#include <boost/network/traits/istringstream.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/network/protocol/http/response.hpp>
#include <boost/network/protocol/http/client/connection/sync_normal.hpp>
#ifdef BOOST_NETWORK_ENABLE_HTTPS
#include <boost/network/protocol/http/client/connection/sync_ssl.hpp>
#endif
namespace boost {
namespace network {
namespace http {
namespace impl {
template <class Tag, unsigned version_major, unsigned version_minor>
struct sync_connection_base_impl {
protected:
typedef typename resolver_policy<Tag>::type resolver_base;
typedef typename resolver_base::resolver_type resolver_type;
typedef typename string<Tag>::type string_type;
typedef function<typename resolver_base::resolver_iterator_pair(
resolver_type&, string_type const&, string_type const&)>
resolver_function_type;
template <class Socket>
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 <class Socket>
void read_status(Socket& socket_, basic_response<Tag>& 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 <class Socket>
void read_headers(Socket& socket_, basic_response<Tag>& 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 <class Socket>
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 <class Socket>
void read_body_normal(Socket& socket_, basic_response<Tag>& response_,
boost::asio::streambuf& response_buffer,
typename ostringstream<Tag>::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 <class Socket>
void read_body_transfer_chunk_encoding(
Socket& socket_, basic_response<Tag>& response_,
boost::asio::streambuf& response_buffer,
typename ostringstream<Tag>::type& body_stream) {
boost::system::error_code error;
// look for the content-length header
typename headers_range<basic_response<Tag> >::type content_length_range =
headers(response_)["Content-Length"];
if (boost::empty(content_length_range)) {
typename headers_range<basic_response<Tag> >::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<Tag>::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<char> eos;
std::istreambuf_iterator<char> 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<size_t>(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 <class Socket>
void read_body(Socket& socket_, basic_response<Tag>& response_,
boost::asio::streambuf& response_buffer) {
typename ostringstream<Tag>::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 <class Tag, unsigned version_major, unsigned version_minor>
struct sync_connection_base {
typedef typename resolver_policy<Tag>::type resolver_base;
typedef typename resolver_base::resolver_type resolver_type;
typedef typename string<Tag>::type string_type;
typedef function<typename resolver_base::resolver_iterator_pair(
resolver_type&, string_type const&, string_type const&)>
resolver_function_type;
typedef function<bool(string_type&)> body_generator_function_type;
// FIXME make the certificate filename and verify path parameters be
// optional
// ranges
static sync_connection_base<Tag, version_major, version_minor>*
new_connection(
resolver_type& resolver, resolver_function_type resolve, bool https,
bool always_verify_peer, int timeout,
optional<string_type> const& certificate_filename =
optional<string_type>(),
optional<string_type> const& verify_path = optional<string_type>(),
optional<string_type> const& certificate_file =
optional<string_type>(),
optional<string_type> const& private_key_file =
optional<string_type>(),
optional<string_type> const& ciphers = optional<string_type>(),
long ssl_options = 0) {
if (https) {
#ifdef BOOST_NETWORK_ENABLE_HTTPS
return dynamic_cast<
sync_connection_base<Tag, version_major, version_minor>*>(
new https_sync_connection<Tag, version_major, version_minor>(
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<Tag, version_major, version_minor>*>(
new http_sync_connection<Tag, version_major, version_minor>(
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<Tag> const& request_,
body_generator_function_type generator) = 0;
virtual void read_status(basic_response<Tag>& response_,
boost::asio::streambuf& response_buffer) = 0;
virtual void read_headers(basic_response<Tag>& response_,
boost::asio::streambuf& response_buffer) = 0;
virtual void read_body(basic_response<Tag>& 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

View file

@ -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 <boost/network/protocol/http/algorithms/linearize.hpp>
#include <iterator>
#include <boost/asio/deadline_timer.hpp>
namespace boost {
namespace network {
namespace http {
namespace impl {
template <class Tag, unsigned version_major, unsigned version_minor>
struct sync_connection_base_impl;
template <class Tag, unsigned version_major, unsigned version_minor>
struct sync_connection_base;
template <class Tag, unsigned version_major, unsigned version_minor>
struct http_sync_connection
: public virtual sync_connection_base<Tag, version_major, version_minor>,
sync_connection_base_impl<Tag, version_major, version_minor>,
boost::enable_shared_from_this<
http_sync_connection<Tag, version_major, version_minor> > {
typedef typename resolver_policy<Tag>::type resolver_base;
typedef typename resolver_base::resolver_type resolver_type;
typedef typename string<Tag>::type string_type;
typedef function<typename resolver_base::resolver_iterator_pair(
resolver_type&, string_type const&, string_type const&)>
resolver_function_type;
typedef http_sync_connection<Tag, version_major, version_minor> this_type;
typedef sync_connection_base_impl<Tag, version_major, version_minor>
connection_base;
typedef function<bool(string_type&)> 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<Tag> const& request_,
body_generator_function_type generator) {
boost::asio::streambuf request_buffer;
linearize(
request_, method, version_major, version_minor,
std::ostreambuf_iterator<typename char_<Tag>::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<typename char_<Tag>::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<Tag>& response_,
boost::asio::streambuf& response_buffer) {
connection_base::read_status(socket_, response_, response_buffer);
}
void read_headers(basic_response<Tag>& response,
boost::asio::streambuf& response_buffer) {
connection_base::read_headers(socket_, response, response_buffer);
}
void read_body(basic_response<Tag>& response_,
boost::asio::streambuf& response_buffer) {
connection_base::read_body(socket_, response_, response_buffer);
typename headers_range<basic_response<Tag> >::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

View file

@ -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 <dberris@google.com>
// 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 <boost/asio/ssl.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/asio/ssl/context_base.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/function.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional/optional.hpp>
#include <boost/network/traits/string.hpp>
#include <boost/network/protocol/http/request.hpp>
#include <boost/network/protocol/http/traits/resolver_policy.hpp>
namespace boost {
namespace network {
namespace http {
namespace impl {
template <class Tag, unsigned version_major, unsigned version_minor>
struct sync_connection_base_impl;
template <class Tag, unsigned version_major, unsigned version_minor>
struct sync_connection_base;
template <class Tag, unsigned version_major, unsigned version_minor>
struct https_sync_connection
: public virtual sync_connection_base<Tag, version_major, version_minor>,
sync_connection_base_impl<Tag, version_major, version_minor>,
boost::enable_shared_from_this<
https_sync_connection<Tag, version_major, version_minor> > {
typedef typename resolver_policy<Tag>::type resolver_base;
typedef typename resolver_base::resolver_type resolver_type;
typedef typename string<Tag>::type string_type;
typedef function<typename resolver_base::resolver_iterator_pair(
resolver_type&, string_type const&, string_type const&)>
resolver_function_type;
typedef https_sync_connection<Tag, version_major, version_minor> this_type;
typedef sync_connection_base_impl<Tag, version_major, version_minor>
connection_base;
typedef function<bool(string_type&)> 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<string_type> const& certificate_filename =
optional<string_type>(),
optional<string_type> const& verify_path = optional<string_type>(),
optional<string_type> const& certificate_file = optional<string_type>(),
optional<string_type> const& private_key_file = optional<string_type>(),
optional<string_type> const& ciphers = optional<string_type>(),
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<Tag> const& request_,
body_generator_function_type generator) {
boost::asio::streambuf request_buffer;
linearize(
request_, method, version_major, version_minor,
std::ostreambuf_iterator<typename char_<Tag>::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<typename char_<Tag>::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<Tag>& response_,
boost::asio::streambuf& response_buffer) {
connection_base::read_status(socket_, response_, response_buffer);
}
void read_headers(basic_response<Tag>& response_,
boost::asio::streambuf& response_buffer) {
connection_base::read_headers(socket_, response_, response_buffer);
}
void read_body(basic_response<Tag>& response_,
boost::asio::streambuf& response_buffer) {
connection_base::read_body(socket_, response_, response_buffer);
typename headers_range<basic_response<Tag> >::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<boost::asio::ip::tcp::socket> socket_;
};
} // namespace impl
} // namespace http
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_PROTOCOL_HTTP_IMPL_HTTPS_SYNC_CONNECTION_HTTP_20100601

View file

@ -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 <dberris@google.com>
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/network/protocol/http/request.hpp>
#include <boost/network/protocol/http/response.hpp>
#include <boost/network/protocol/http/client/pimpl.hpp>
#include <boost/network/protocol/http/client/options.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_request;
template <class Tag>
struct basic_response;
template <class Tag, unsigned version_major, unsigned version_minor>
struct basic_client_facade {
typedef typename string<Tag>::type string_type;
typedef basic_request<Tag> request;
typedef basic_response<Tag> response;
typedef basic_client_impl<Tag, version_major, version_minor> pimpl_type;
typedef function<void(iterator_range<char const*> const&,
system::error_code const&)> body_callback_function_type;
typedef function<bool(string_type&)> body_generator_function_type;
explicit basic_client_facade(client_options<Tag> 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<string_type>(body.size()))
<< boost::network::body(body);
}
typename headers_range<basic_request<Tag> >::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_<Tag>::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<string_type>(body.size()))
<< boost::network::body(body);
}
typename headers_range<basic_request<Tag> >::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_<Tag>::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_type> pimpl;
void init_pimpl(client_options<Tag> 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

View file

@ -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 <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)
#include <boost/range/iterator_range.hpp>
#include <boost/system/error_code.hpp>
#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 char*> const& range_name, \
boost::system::error_code const& error_name)
#endif
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_MACROS_HPP_20110430 */

View file

@ -0,0 +1,181 @@
#ifndef BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_OPTIONS_HPP_20130128
#define BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_OPTIONS_HPP_20130128
#include <boost/network/traits/string.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/optional/optional.hpp>
#include <boost/asio/io_service.hpp>
// Copyright 2013 Google, Inc.
// Copyright 2013 Dean Michael Berris <dberris@google.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)
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct client_options {
typedef typename string<Tag>::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<boost::asio::io_service> 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<string_type> openssl_certificate() const {
return openssl_certificate_;
}
boost::optional<string_type> openssl_verify_path() const {
return openssl_verify_path_;
}
boost::optional<string_type> openssl_certificate_file() const {
return openssl_certificate_file_;
}
boost::optional<string_type> openssl_private_key_file() const {
return openssl_private_key_file_;
}
boost::optional<string_type> openssl_ciphers() const {
return openssl_ciphers_;
}
long openssl_options() const { return openssl_options_; }
boost::shared_ptr<boost::asio::io_service> 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<string_type> openssl_certificate_;
boost::optional<string_type> openssl_verify_path_;
boost::optional<string_type> openssl_certificate_file_;
boost::optional<string_type> openssl_private_key_file_;
boost::optional<string_type> openssl_ciphers_;
long openssl_options_;
boost::shared_ptr<boost::asio::io_service> io_service_;
bool always_verify_peer_;
int timeout_;
};
template <class Tag>
inline void swap(client_options<Tag>& a, client_options<Tag>& b) {
a.swap(b);
}
} /* http */
} /* network */
} /* boost */
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_CLIENT_OPTIONS_HPP_20130128 */

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/network/support/is_sync.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/if.hpp>
#include <boost/static_assert.hpp>
#include <boost/network/protocol/http/traits/connection_policy.hpp>
#include <boost/network/protocol/http/client/async_impl.hpp>
#include <boost/network/protocol/http/client/sync_impl.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag, unsigned version_major, unsigned version_minor>
struct basic_client_impl;
namespace impl {
template <class Tag, unsigned version_major, unsigned version_minor>
struct async_client;
template <class Tag, unsigned version_major, unsigned version_minor>
struct sync_client;
template <class Tag, unsigned version_major, unsigned version_minor,
class Enable = void>
struct client_base {
typedef unsupported_tag<Tag> type;
};
template <class Tag, unsigned version_major, unsigned version_minor>
struct client_base<Tag, version_major, version_minor,
typename enable_if<is_async<Tag> >::type> {
typedef async_client<Tag, version_major, version_minor> type;
};
template <class Tag, unsigned version_major, unsigned version_minor>
struct client_base<Tag, version_major, version_minor,
typename enable_if<is_sync<Tag> >::type> {
typedef sync_client<Tag, version_major, version_minor> type;
};
} // namespace impl
template <class Tag, unsigned version_major, unsigned version_minor>
struct basic_client;
template <class Tag, unsigned version_major, unsigned version_minor>
struct basic_client_impl
: impl::client_base<Tag, version_major, version_minor>::type {
BOOST_STATIC_ASSERT(
(mpl::not_<mpl::and_<is_async<Tag>, is_sync<Tag> > >::value));
typedef typename impl::client_base<Tag, version_major, version_minor>::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<string_type> const& certificate_filename,
optional<string_type> const& verify_path,
optional<string_type> const& certificate_file,
optional<string_type> const& private_key_file,
optional<string_type> const& ciphers, long ssl_options,
boost::shared_ptr<boost::asio::io_service> 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

View file

@ -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 <boost/function.hpp>
#include <boost/bind/bind.hpp>
#include <boost/optional/optional.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/network/traits/string.hpp>
#include <boost/network/protocol/http/tags.hpp>
#include <boost/network/protocol/http/traits/vector.hpp>
#include <boost/network/protocol/http/request.hpp>
#include <boost/network/protocol/http/traits/connection_policy.hpp>
// Copyright 2013 Google, Inc.
// Copyright 2010 Dean Michael Berris <dberris@google.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)
namespace boost {
namespace network {
namespace http {
template <class Tag, unsigned version_major, unsigned version_minor>
struct basic_client_impl;
namespace impl {
template <class Tag, unsigned version_major, unsigned version_minor>
struct sync_client
: connection_policy<Tag, version_major, version_minor>::type {
typedef typename string<Tag>::type string_type;
typedef typename connection_policy<Tag, version_major, version_minor>::type
connection_base;
typedef typename resolver<Tag>::type resolver_type;
typedef function<void(iterator_range<char const*> const&,
system::error_code const&)> body_callback_function_type;
typedef function<bool(string_type&)> body_generator_function_type;
friend struct basic_client_impl<Tag, version_major, version_minor>;
boost::shared_ptr<boost::asio::io_service> service_ptr;
boost::asio::io_service& service_;
resolver_type resolver_;
optional<string_type> certificate_filename_;
optional<string_type> verify_path_;
optional<string_type> certificate_file_;
optional<string_type> private_key_file_;
optional<string_type> 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<boost::asio::io_service> service,
optional<string_type> const& certificate_filename =
optional<string_type>(),
optional<string_type> const& verify_path = optional<string_type>(),
optional<string_type> const& certificate_file = optional<string_type>(),
optional<string_type> const& private_key_file = optional<string_type>(),
optional<string_type> const& ciphers = optional<string_type>(),
long ssl_options = 0)
: connection_base(cache_resolved, follow_redirect, timeout),
service_ptr(service.get() ? service
: make_shared<boost::asio::io_service>()),
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<Tag> request_skeleton(basic_request<Tag> 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

View file

@ -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 <boost/network/protocol/http/message.hpp>
#include <exception>
namespace boost {
namespace network {
namespace http {
namespace errors {
template <class Tag = tags::http_default_8bit_tcp_resolve>
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__

View file

@ -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 <boost/network/protocol/http/message.hpp>
#include <boost/lexical_cast.hpp>
#include <cstdlib>
#include <cstdio>
namespace boost {
namespace network {
namespace http {
// static member functions of boost::network::http::message
template <typename Tag>
typename message_impl<Tag>::string_type const message_impl<Tag>::url_decode(
typename message_impl<Tag>::string_type const &str) {
char decode_buf[3];
typename message_impl<Tag>::string_type result;
result.reserve(str.size());
for (typename message_impl<Tag>::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<char>(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 Tag>
typename message_impl<Tag>::string_type const message_impl<Tag>::url_encode(
typename message_impl<Tag>::string_type const &str) {
char encode_buf[4];
typename message_impl<Tag>::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<Tag>::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 Tag>
typename message_impl<Tag>::string_type const
message_impl<Tag>::make_query_string(
typename query_container<Tag>::type const &query_params) {
typename message_impl<Tag>::string_type query_string;
for (typename query_container<Tag>::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 Tag>
typename message_impl<Tag>::string_type const
message_impl<Tag>::make_set_cookie_header(
typename message_impl<Tag>::string_type const &name,
typename message_impl<Tag>::string_type const &value,
typename message_impl<Tag>::string_type const &path, bool const has_max_age,
unsigned long const max_age) {
typename message_impl<Tag>::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<message_impl<Tag>::string_type>(max_age);
set_cookie_header += '\"';
}
return set_cookie_header;
}
template <typename Tag>
bool message_impl<Tag>::base64_decode(
const typename message_impl<Tag>::string_type &input,
typename message_impl<Tag>::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<int>(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<int>(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<int>(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<int>(input_ptr[i])];
if (base64code3 == nop) // non base64 character
return false;
output += (((base64code2 << 6) & 0xc0) | base64code3);
}
}
return true;
}
template <typename Tag>
bool message_impl<Tag>::base64_encode(
typename message_impl<Tag>::string_type const &input,
typename message_impl<Tag>::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

View file

@ -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 <boost/network/protocol/http/parser.hpp>
namespace boost {
namespace network {
namespace http {
// member functions for class basic_parser<Tag,Traits>
template <typename Tag, typename ParserTraits>
boost::tribool basic_parser<Tag, Traits>::parse_http_headers(
basic_message<Tag>& 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 <typename Tag, typename ParserTraits>
boost::tribool basic_parser<Tag, Traits>::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 <typename Tag, typename ParserTraits>
std::size_t basic_parser<Tag, Traits>::consume_content(
basic_message<Tag>& 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 <typename Tag, typename ParserTraits>
std::size_t basic_parser<Tag, Traits>::consume_content_as_next_chunk(
types::chunk_cache_t& chunk_buffers) {
if (bytes_available() == 0) {
m_bytes_last_read = 0;
} else {
std::vector<char> 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 <typename Tag, typename ParserTraits>
void basic_parser<Tag, Traits>::finish(basic_request<Tag>& 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<types::headers::const_iterator, types::headers::const_iterator>
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 <typename Tag, typename ParserTraits>
void basic_parser<Tag, Traits>::finish(basic_response<Tag>& http_response) {
http_response.setIsValid(true);
http_response.setStatusCode(m_status_code);
http_response.setStatusMessage(m_status_message);
}
template <typename Tag, typename ParserTraits>
inline void basic_parser<Tag, Traits>::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 <typename Tag, typename ParserTraits>
static bool basic_parser<Tag, Traits>::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 <typename Tag, typename ParserTraits>
static bool basic_parser<Tag, Traits>::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

View file

@ -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 <boost/network/protocol/http/message.hpp>
#include <boost/network/protocol/http/message/header.hpp>
#include <boost/fusion/container/map.hpp>
#include <boost/fusion/sequence/intrinsic/at_key.hpp>
#include <boost/fusion/sequence/intrinsic/value_at_key.hpp>
#include <boost/network/uri/uri.hpp>
#include <boost/network/traits/vector.hpp>
#include <boost/network/constants.hpp>
#include <boost/network/protocol/http/message/async_message.hpp>
#include <boost/network/support/is_async.hpp>
#include <boost/network/protocol/http/support/sync_only.hpp>
#include <boost/cstdint.hpp>
namespace boost {
namespace network {
/** Specialize the traits for the http_server tag. */
template <>
struct headers_container<
http::tags::http_server> : vector<http::tags::http_server>::
apply<http::request_header<
http::tags::http_server>::type> {};
template <>
struct headers_container<
http::tags::
http_async_server> : vector<http::tags::http_async_server>::
apply<http::request_header<
http::tags::http_async_server>::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 <class Tag>
struct basic_request : public basic_message<Tag> {
mutable boost::network::uri::uri uri_;
boost::uint16_t source_port_;
typedef basic_message<Tag> base_type;
public:
typedef typename sync_only<Tag>::type tag;
typedef typename string<tag>::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<Tag>& 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_type> port = uri::port_us(uri_);
if (!port) {
typedef constants<Tag> 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 <class Tag>
struct not_quite_pod_request_base {
typedef Tag tag;
typedef typename string<Tag>::type string_type;
typedef typename request_header<Tag>::type header_type;
typedef typename vector<Tag>::template apply<header_type>::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<tags::http_async_server> : not_quite_pod_request_base<
tags::http_async_server> {};
template <>
struct basic_request<tags::http_server> : not_quite_pod_request_base<
tags::http_server> {};
template <class R>
struct ServerRequest;
BOOST_CONCEPT_ASSERT((ServerRequest<basic_request<tags::http_async_server> >));
BOOST_CONCEPT_ASSERT((ServerRequest<basic_request<tags::http_server> >));
template <class Tag>
inline void swap(basic_request<Tag>& lhs, basic_request<Tag>& rhs) {
lhs.swap(rhs);
}
} // namespace http
namespace http {
namespace impl {
template <>
struct request_headers_wrapper<tags::http_server> {
basic_request<tags::http_server> const& request_;
request_headers_wrapper(basic_request<tags::http_server> const& request_)
: request_(request_) {}
typedef headers_container<tags::http_server>::type headers_container_type;
operator headers_container_type() { return request_.headers; }
};
template <>
struct body_wrapper<basic_request<tags::http_server> > {
typedef string<tags::http_server>::type string_type;
basic_request<tags::http_server> const& request_;
body_wrapper(basic_request<tags::http_server> const& request_)
: request_(request_) {}
operator string_type() { return request_.body; }
};
template <>
struct request_headers_wrapper<tags::http_async_server> {
basic_request<tags::http_async_server> const& request_;
request_headers_wrapper(
basic_request<tags::http_async_server> const& request_)
: request_(request_) {}
typedef headers_container<tags::http_async_server>::type
headers_container_type;
operator headers_container_type() { return request_.headers; }
};
template <>
struct body_wrapper<basic_request<tags::http_async_server> > {
typedef string<tags::http_async_server>::type string_type;
basic_request<tags::http_async_server> const& request_;
body_wrapper(basic_request<tags::http_async_server> 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__

View file

@ -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 <boost/network/protocol/http/request.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
boost::tribool basic_request_parser<Tag>::consume(basic_request<Tag>& 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<Tag>::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 <class Tag>
bool basic_request_parser<Tag>::is_char(int c) {
return c >= 0 && c <= 127;
}
template <class Tag>
bool basic_request_parser<Tag>::is_ctl(int c) {
return (c >= 0 && c <= 31) || (c == 127);
}
template <class Tag>
bool basic_request_parser<Tag>::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 <class Tag>
bool basic_request_parser<Tag>::is_digit(int c) {
return c >= '0' && c <= '9';
}
} // namespace http
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_HTTP_REQUEST_PARSER_IPP

View file

@ -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 <boost/asio/buffer.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/network/protocol/http/tags.hpp>
#include <boost/network/traits/string.hpp>
#include <boost/network/protocol/http/traits/vector.hpp>
#include <boost/network/protocol/http/message/header.hpp>
namespace boost {
namespace network {
namespace http {
/// A reply to be sent to a client.
template <>
struct basic_response<tags::http_server> {
typedef tags::http_server tag;
typedef response_header<tags::http_server>::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<tags::http_server>::apply<header_type>::type headers_vector;
headers_vector headers;
/// The content to be sent in the reply.
typedef string<tags::http_server>::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<boost::asio::const_buffer> 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<const_buffer> 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<tags::http_server> stock_reply(status_type status) {
return stock_reply(status, to_string(status));
}
/// Get a stock reply with custom plain text data.
static basic_response<tags::http_server> stock_reply(status_type status,
string_type content) {
using boost::lexical_cast;
basic_response<tags::http_server> rep;
rep.status = status;
rep.content = content;
rep.headers.resize(2);
rep.headers[0].name = "Content-Length";
rep.headers[0].value = lexical_cast<string_type>(rep.content.size());
rep.headers[1].name = "Content-Type";
rep.headers[1].value = "text/html";
return rep;
}
/// Swap response objects
void swap(basic_response<tags::http_server> &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<tags::http_server>::ok:
return "";
case basic_response<tags::http_server>::created:
return
"<html>"
"<head><title>Created</title></head>"
"<body><h1>201 Created</h1></body>"
"</html>";
case basic_response<tags::http_server>::accepted:
return
"<html>"
"<head><title>Accepted</title></head>"
"<body><h1>202 Accepted</h1></body>"
"</html>";
case basic_response<tags::http_server>::non_authoritative_information:
return
"<html>"
"<head><title>Non-Authoritative Information</title></head>"
"<body><h1>203 Non-Authoritative Information</h1></body>"
"</html>";
case basic_response<tags::http_server>::no_content:
return
"<html>"
"<head><title>No Content</title></head>"
"<body><h1>204 Content</h1></body>"
"</html>";
case basic_response<tags::http_server>::reset_content:
return
"<html>"
"<head><title>Reset Content</title></head>"
"<body><h1>205 Reset Content</h1></body>"
"</html>";
case basic_response<tags::http_server>::partial_content:
return
"<html>"
"<head><title>Partial Content</title></head>"
"<body><h1>206 Partial Content</h1></body>"
"</html>";
// 3xx Redirection
case basic_response<tags::http_server>::multiple_choices:
return
"<html>"
"<head><title>Multiple Choices</title></head>"
"<body><h1>300 Multiple Choices</h1></body>"
"</html>";
case basic_response<tags::http_server>::moved_permanently:
return
"<html>"
"<head><title>Moved Permanently</title></head>"
"<body><h1>301 Moved Permanently</h1></body>"
"</html>";
case basic_response<tags::http_server>::moved_temporarily:
return
"<html>"
"<head><title>Moved Temporarily</title></head>"
"<body><h1>302 Moved Temporarily</h1></body>"
"</html>";
case basic_response<tags::http_server>::see_other:
return
"<html>"
"<head><title>See Other</title></head>"
"<body><h1>303 See Other</h1></body>"
"</html>";
case basic_response<tags::http_server>::not_modified:
return
"<html>"
"<head><title>Not Modified</title></head>"
"<body><h1>304 Not Modified</h1></body>"
"</html>";
case basic_response<tags::http_server>::use_proxy:
return
"<html>"
"<head><title>Use Proxy</title></head>"
"<body><h1>305 Use Proxy</h1></body>"
"</html>";
case basic_response<tags::http_server>::temporary_redirect:
return
"<html>"
"<head><title>Temporary Redirect</title></head>"
"<body><h1>307 Temporary Redirect</h1></body>"
"</html>";
// 4xx Client Error
case basic_response<tags::http_server>::bad_request:
return
"<html>"
"<head><title>Bad Request</title></head>"
"<body><h1>400 Bad Request</h1></body>"
"</html>";
case basic_response<tags::http_server>::unauthorized:
return
"<html>"
"<head><title>Unauthorized</title></head>"
"<body><h1>401 Unauthorized</h1></body>"
"</html>";
case basic_response<tags::http_server>::forbidden:
return
"<html>"
"<head><title>Forbidden</title></head>"
"<body><h1>403 Forbidden</h1></body>"
"</html>";
case basic_response<tags::http_server>::not_found:
return
"<html>"
"<head><title>Not Found</title></head>"
"<body><h1>404 Not Found</h1></body>"
"</html>";
case basic_response<tags::http_server>::not_supported:
return
"<html>"
"<head><title>Method Not Supported</title></head>"
"<body><h1>405 Method Not Supported</h1></body>"
"</html>";
case basic_response<tags::http_server>::not_acceptable:
return
"<html>"
"<head><title>Not Acceptable\r\n</title></head>"
"<body><h1>406 Not Acceptable</h1></body>"
"</html>";
case basic_response<tags::http_server>::proxy_authentication_required:
return
"<html>"
"<head><title>Proxy Authentication Required</title></head>"
"<body><h1>407 Proxy Authentication Required</h1></body>"
"</html>";
case basic_response<tags::http_server>::request_timeout:
return
"<html>"
"<head><title>Request Timeout</title></head>"
"<body><h1>408 Request Timeout</h1></body>"
"</html>";
case basic_response<tags::http_server>::conflict:
return
"<html>"
"<head><title>Conflict</title></head>"
"<body><h1>409 Conflict</h1></body>"
"</html>";
case basic_response<tags::http_server>::gone:
return
"<html>"
"<head><title>Gone</title></head>"
"<body><h1>410 Gone</h1></body>"
"</html>";
case basic_response<tags::http_server>::length_required:
return
"<html>"
"<head><title>Length Required</title></head>"
"<body><h1>411 Length Required</h1></body>"
"</html>";
case basic_response<tags::http_server>::precondition_failed:
return
"<html>"
"<head><title>Precondition Failed</title></head>"
"<body><h1>412 Precondition Failed</h1></body>"
"</html>";
case basic_response<tags::http_server>::request_entity_too_large:
return
"<html>"
"<head><title>Request Entity Too Large</title></head>"
"<body><h1>413 Request Entity Too Large</h1></body>"
"</html>";
case basic_response<tags::http_server>::request_uri_too_large:
return
"<html>"
"<head><title>Request-URI Too Large</title></head>"
"<body><h1>414 Request-URI Too Large</h1></body>"
"</html>";
case basic_response<tags::http_server>::unsupported_media_type:
return
"<html>"
"<head><title>Unsupported Media Type</title></head>"
"<body><h1>415 Unsupported Media Type</h1></body>"
"</html>";
case basic_response<tags::http_server>::unsatisfiable_range:
return
"<html>"
"<head><title>Unsatisfiable Range</title></head>"
"<body><h1>416 Requested Range Not "
"Satisfiable</h1></body>"
"</html>";
case basic_response<tags::http_server>::expectation_failed:
return
"<html>"
"<head><title>Expectation Failed</title></head>"
"<body><h1>417 Expectation Failed</h1></body>"
"</html>";
case basic_response<tags::http_server>::precondition_required:
return
"<html>"
"<head><title>Precondition Required</title></head>"
"<body><h1>428 Precondition Required</h1></body>"
"</html>";
case basic_response<tags::http_server>::too_many_requests:
return
"<html>"
"<head><title>Too Many Requests</title></head>"
"<body><h1>429 Too Many Requests</h1></body>"
"</html>";
case basic_response<tags::http_server>::request_header_fields_too_large:
return
"<html>"
"<head><title>Request Header Fields Too Large</title></head>"
"<body><h1>431 Request Header Fields Too Large</h1></body>"
"</html>";
// 5xx Server Error
case basic_response<tags::http_server>::internal_server_error:
return
"<html>"
"<head><title>Internal Server Error</title></head>"
"<body><h1>500 Internal Server Error</h1></body>"
"</html>";
case basic_response<tags::http_server>::not_implemented:
return
"<html>"
"<head><title>Not Implemented</title></head>"
"<body><h1>501 Not Implemented</h1></body>"
"</html>";
case basic_response<tags::http_server>::bad_gateway:
return
"<html>"
"<head><title>Bad Gateway</title></head>"
"<body><h1>502 Bad Gateway</h1></body>"
"</html>";
case basic_response<tags::http_server>::service_unavailable:
return
"<html>"
"<head><title>Service Unavailable</title></head>"
"<body><h1>503 Service Unavailable</h1></body>"
"</html>";
case basic_response<tags::http_server>::gateway_timeout:
return
"<html>"
"<head><title>Gateway Timeout</title></head>"
"<body><h1>504 Gateway Timeout</h1></body>"
"</html>";
case basic_response<tags::http_server>::http_version_not_supported:
return
"<html>"
"<head><title>HTTP Version Not Supported</title></head>"
"<body><h1>505 HTTP Version Not Supported</h1></body>"
"</html>";
case basic_response<tags::http_server>::space_unavailable:
return
"<html>"
"<head><title>Space Unavailable</title></head>"
"<body><h1>507 Insufficient Space to Store "
"Resource</h1></body>"
"</html>";
default:
return
"<html>"
"<head><title>Internal Server Error</title></head>"
"<body><h1>500 Internal Server Error</h1></body>"
"</html>";
}
}
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<tags::http_server>::ok:
return trim_null(buffer("HTTP/1.1 200 OK\r\n"));
case basic_response<tags::http_server>::created:
return trim_null(buffer("HTTP/1.1 201 Created\r\n"));
case basic_response<tags::http_server>::accepted:
return trim_null(buffer("HTTP/1.1 202 Accepted\r\n"));
case basic_response<tags::http_server>::non_authoritative_information:
return trim_null(buffer("HTTP/1.1 203 Non-Authoritative Information\r\n"));
case basic_response<tags::http_server>::no_content:
return trim_null(buffer("HTTP/1.1 204 No Content\r\n"));
case basic_response<tags::http_server>::reset_content:
return trim_null(buffer("HTTP/1.1 205 Reset Content\r\n"));
case basic_response<tags::http_server>::partial_content:
return trim_null(buffer("HTTP/1.1 206 Partial Content\r\n"));
// 3xx Redirection
case basic_response<tags::http_server>::multiple_choices:
return trim_null(buffer("HTTP/1.1 300 Multiple Choices\r\n"));
case basic_response<tags::http_server>::moved_permanently:
return trim_null(buffer("HTTP/1.1 301 Moved Permanently\r\n"));
case basic_response<tags::http_server>::moved_temporarily:
return trim_null(buffer("HTTP/1.1 302 Moved Temporarily\r\n"));
case basic_response<tags::http_server>::see_other:
return trim_null(buffer("HTTP/1.1 303 See Other\r\n"));
case basic_response<tags::http_server>::not_modified:
return trim_null(buffer("HTTP/1.1 304 Not Modified\r\n"));
case basic_response<tags::http_server>::use_proxy:
return trim_null(buffer("HTTP/1.1 305 Use Proxy\r\n"));
case basic_response<tags::http_server>::temporary_redirect:
return trim_null(buffer("HTTP/1.1 307 Temporary Redirect\r\n"));
// 4xx Client Error
case basic_response<tags::http_server>::bad_request:
return trim_null(buffer("HTTP/1.1 400 Bad Request\r\n"));
case basic_response<tags::http_server>::unauthorized:
return trim_null(buffer("HTTP/1.1 401 Unauthorized\r\n"));
case basic_response<tags::http_server>::forbidden:
return trim_null(buffer("HTTP/1.1 403 Forbidden\r\n"));
case basic_response<tags::http_server>::not_found:
return trim_null(buffer("HTTP/1.1 404 Not Found\r\n"));
case basic_response<tags::http_server>::not_supported:
return trim_null(buffer("HTTP/1.1 405 Method Not Supported\r\n"));
case basic_response<tags::http_server>::not_acceptable:
return trim_null(buffer("HTTP/1.1 406 Method Not Acceptable\r\n"));
case basic_response<tags::http_server>::proxy_authentication_required:
return trim_null(buffer("HTTP/1.1 407 Proxy Authentication Required\r\n"));
case basic_response<tags::http_server>::request_timeout:
return trim_null(buffer("HTTP/1.1 408 Request Timeout\r\n"));
case basic_response<tags::http_server>::conflict:
return trim_null(buffer("HTTP/1.1 409 Conflict\r\n"));
case basic_response<tags::http_server>::gone:
return trim_null(buffer("HTTP/1.1 410 Gone\r\n"));
case basic_response<tags::http_server>::length_required:
return trim_null(buffer("HTTP/1.1 411 Length Required\r\n"));
case basic_response<tags::http_server>::precondition_failed:
return trim_null(buffer("HTTP/1.1 412 Precondition Failed\r\n"));
case basic_response<tags::http_server>::request_entity_too_large:
return trim_null(buffer("HTTP/1.1 413 Request Entity Too Large\r\n"));
case basic_response<tags::http_server>::request_uri_too_large:
return trim_null(buffer("HTTP/1.1 414 Request-URI Too Large\r\n"));
case basic_response<tags::http_server>::unsupported_media_type:
return trim_null(buffer("HTTP/1.1 415 Unsupported Media Type\r\n"));
case basic_response<tags::http_server>::unsatisfiable_range:
return trim_null(buffer("HTTP/1.1 416 Requested Range Not Satisfiable\r\n"));
case basic_response<tags::http_server>::precondition_required:
return trim_null(buffer("HTTP/1.1 428 Precondition Required\r\n"));
case basic_response<tags::http_server>::too_many_requests:
return trim_null(buffer("HTTP/1.1 429 Too Many Requests\r\n"));
case basic_response<tags::http_server>::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<tags::http_server>::internal_server_error:
return trim_null(buffer("HTTP/1.1 500 Internal Server Error\r\n"));
case basic_response<tags::http_server>::not_implemented:
return trim_null(buffer("HTTP/1.1 501 Not Implemented\r\n"));
case basic_response<tags::http_server>::bad_gateway:
return trim_null(buffer("HTTP/1.1 502 Bad Gateway\r\n"));
case basic_response<tags::http_server>::service_unavailable:
return trim_null(buffer("HTTP/1.1 503 Service Unavailable\r\n"));
case basic_response<tags::http_server>::gateway_timeout:
return trim_null(buffer("HTTP/1.1 504 Gateway Timeout\r\n"));
case basic_response<tags::http_server>::http_version_not_supported:
return trim_null(buffer("HTTP/1.1 505 HTTP Version Not Supported\r\n"));
case basic_response<tags::http_server>::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

View file

@ -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 <boost/network/protocol/http/traits.hpp>
#include <boost/network/protocol/http/message/header/name.hpp>
#include <boost/network/protocol/http/message/header/value.hpp>
#include <boost/network/protocol/http/message/header_concept.hpp>
#include <boost/network/message.hpp>
#include <boost/network/tags.hpp>
#include <string>
namespace boost {
namespace network {
namespace http {
/// base class for HTTP messages (requests and responses)
template <typename Tag>
struct message_impl : public basic_message<Tag> {
typedef typename string<Tag>::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<Tag>::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<Tag> 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 <class Tag>
inline void swap(message_impl<Tag> &lhs, message_impl<Tag> &rhs) {
lhs.swap(rhs);
}
typedef message_impl<tags::http_default_8bit_tcp_resolve> message;
} // namespace http
} // namespace network
} // namespace boost
// import implementation file
#include <boost/network/protocol/http/impl/message.ipp>
#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HPP

View file

@ -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 <boost/thread/future.hpp>
#include <boost/cstdint.hpp>
#include <boost/optional.hpp>
// FIXME move this out to a trait
#include <set>
#include <boost/foreach.hpp>
#include <boost/network/detail/wrapper_base.hpp>
namespace boost {
namespace network {
namespace http {
namespace impl {
template <class Tag>
struct ready_wrapper;
} /* impl */
template <class Tag>
struct async_message {
typedef typename string<Tag>::type string_type;
typedef typename headers_container<Tag>::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<string_type> const& future) const {
status_message_ = future;
}
string_type const version() const { return version_.get(); }
void version(boost::shared_future<string_type> const& future) const {
version_ = future;
}
boost::uint16_t status() const { return status_.get(); }
void status(boost::shared_future<uint16_t> const& future) const {
status_ = future;
}
string_type const source() const { return source_.get(); }
void source(boost::shared_future<string_type> const& future) const {
source_ = future;
}
string_type const destination() const { return destination_.get(); }
void destination(boost::shared_future<string_type> 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<headers_container_type> 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<string_type> 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<string_type> status_message_, version_, source_,
destination_;
mutable boost::shared_future<boost::uint16_t> status_;
mutable boost::shared_future<headers_container_type> headers_;
mutable headers_container_type added_headers;
mutable std::set<string_type> removed_headers;
mutable boost::shared_future<string_type> body_;
mutable boost::optional<headers_container_type> retrieved_headers_;
friend struct boost::network::http::impl::ready_wrapper<Tag>;
};
template <class Tag>
inline void swap(async_message<Tag>& lhs, async_message<Tag>& rhs) {
lhs.swap(rhs);
}
} // namespace http
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_ASYNC_MESSAGE_HPP_20100622

View file

@ -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 <boost/network/protocol/http/support/is_server.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/cstdint.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
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 <class Tag>
void operator()(basic_request<Tag>& 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 \
*/

View file

@ -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 \
*/

View file

@ -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 <boost/network/protocol/http/support/is_server.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/cstdint.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
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 <class Tag>
void operator()(basic_request<Tag>& 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 \
*/

View file

@ -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 <boost/network/tags.hpp>
#include <boost/network/support/is_async.hpp>
#include <boost/thread/future.hpp>
#include <boost/mpl/if.hpp>
#include <boost/variant/variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/cstdint.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_response;
struct status_directive {
boost::variant<boost::uint16_t, boost::shared_future<boost::uint16_t> >
status_;
explicit status_directive(boost::uint16_t status) : status_(status) {}
explicit status_directive(boost::shared_future<boost::uint16_t> const &status)
: status_(status) {}
status_directive(status_directive const &other) : status_(other.status_) {}
template <class Tag>
struct value : mpl::if_<is_async<Tag>, boost::shared_future<boost::uint16_t>,
boost::uint16_t> {};
template <class Tag>
struct status_visitor : boost::static_visitor<> {
basic_response<Tag> const &response;
status_visitor(basic_response<Tag> const &response) : response(response) {}
void operator()(typename value<Tag>::type const &status_) const {
response.status(status_);
}
template <class T>
void operator()(T const &) const {
// FIXME fail here!
}
};
template <class Tag>
basic_response<Tag> const &operator()(basic_response<Tag> const &response)
const {
apply_visitor(status_visitor<Tag>(response), status_);
return response;
}
};
template <class T>
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

View file

@ -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 <boost/network/tags.hpp>
#include <boost/network/message/directives/detail/string_directive.hpp>
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

View file

@ -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 <boost/network/tags.hpp>
#include <boost/network/message/directives/detail/string_directive.hpp>
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

View file

@ -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 <boost/network/tags.hpp>
#include <boost/network/message/directives/detail/string_directive.hpp>
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

View file

@ -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 <boost/network/traits/string.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/network/support/is_default_wstring.hpp>
#include <boost/network/support/is_default_wstring.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
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 <class Tag>
struct request_header
: mpl::if_<is_default_string<Tag>, request_header_narrow,
typename mpl::if_<is_default_wstring<Tag>, request_header_wide,
unsupported_tag<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 <class Tag>
struct response_header
: mpl::if_<is_default_string<Tag>, response_header_narrow,
typename mpl::if_<is_default_wstring<Tag>, response_header_wide,
unsupported_tag<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

View file

@ -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 <boost/network/protocol/http/message/header.hpp>
#include <utility>
namespace boost {
namespace network {
namespace http {
template <class T1, class T2>
T1 &name(std::pair<T1, T2> 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 */

View file

@ -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 <utility>
namespace boost {
namespace network {
namespace http {
struct request_header_narrow;
struct request_header_wide;
struct response_header_narrow;
struct response_header_wide;
template <class T1, class T2>
T1& value(std::pair<T1, T2> 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 */

View file

@ -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 <boost/network/traits/string.hpp>
namespace boost {
namespace network {
namespace http {
template <class H>
struct Header : DefaultConstructible<H>, Assignable<H>, CopyConstructible<H> {
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 */

View file

@ -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 <boost/network/tags.hpp>
#include <boost/network/support/is_async.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct async_message;
template <class Tag>
struct message_impl;
template <class Tag>
struct message_base
: mpl::if_<is_async<Tag>, async_message<Tag>, message_impl<Tag> > {};
} // namespace http
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_BASE_HPP_20100603

View file

@ -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 <boost/network/protocol/http/tags.hpp>
#include <boost/network/support/is_async.hpp>
#include <boost/network/protocol/http/support/client_or_server.hpp>
#include <boost/thread/future.hpp>
#include <boost/concept/requires.hpp>
#include <boost/network/message/directives.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_response;
template <class Tag>
struct basic_request;
namespace impl {
template <class Tag, class T>
void body(basic_response<Tag> &response, T const &value, mpl::false_ const &) {
response << ::boost::network::body(value);
}
template <class Tag, class T>
void body(basic_response<Tag> &response, T const &future, mpl::true_ const &) {
response.body(future);
}
}
template <class Tag, class T>
inline void body(basic_response<Tag> &response, T const &value) {
impl::body(response, value, is_async<Tag>());
}
template <class Tag, class T>
inline void body_impl(basic_request<Tag> &request, T const &value,
tags::server) {
request.body = value;
}
template <class Tag, class T>
inline void body_impl(basic_request<Tag> &request, T const &value,
tags::client) {
request << ::boost::network::body(value);
}
template <class Tag, class T>
inline void body(basic_request<Tag> &request, T const &value) {
body_impl(request, value, typename client_or_server<Tag>::type());
}
} // namespace http
namespace impl {
template <class Message, class ValueType, class Async>
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

View file

@ -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 <boost/network/protocol/http/support/client_or_server.hpp>
#include <boost/network/support/pod_or_normal.hpp>
#include <boost/network/support/is_async.hpp>
#include <boost/thread/future.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
inline void clear_headers_impl(basic_request<Tag>& request, tags::pod) {
typedef typename basic_request<Tag>::headers_container_type headers_container;
headers_container().swap(request.headers);
}
template <class Tag>
inline void clear_headers_impl(basic_request<Tag>& request, tags::normal) {
request.headers(typename basic_request<Tag>::headers_container_type());
}
template <class Tag>
inline void clear_headers_impl(basic_request<Tag>& request, tags::client) {
clear_headers_impl(request, typename pod_or_normal<Tag>::type());
}
template <class Tag>
inline void clear_headers_impl(basic_request<Tag>& request, tags::server) {
typedef typename basic_request<Tag>::headers_container_type headers_container;
headers_container().swap(request.headers);
}
template <class Tag>
inline void clear_headers(basic_request<Tag>& request) {
clear_headers_impl(request, typename client_or_server<Tag>::type());
}
} /* http */
} /* network */
} /* boost */
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_CLEAR_HEADER_HPP_20101128 \
*/

View file

@ -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 <boost/network/protocol/http/support/client_or_server.hpp>
#include <boost/network/support/pod_or_normal.hpp>
#include <boost/network/support/is_async.hpp>
#include <boost/thread/future.hpp>
#include <boost/concept/requires.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_response;
template <class Tag>
struct basic_request;
namespace impl {
template <class Tag, class T>
void destination(basic_response<Tag> &response, T const &value,
mpl::false_ const &) {
response << ::boost::network::destination(value);
}
template <class Tag, class T>
void destination(basic_response<Tag> &response, T const &future,
mpl::true_ const &) {
response.destination(future);
}
}
template <class Tag, class T>
inline void destination(basic_response<Tag> &response, T const &value) {
impl::destination(response, value, is_async<Tag>());
}
template <class R>
struct ServerRequest;
template <class Tag, class T>
inline void destination_impl(basic_request<Tag> &request, T const &value,
tags::server) {
request.destination = value;
}
template <class Tag, class T>
inline void destination_impl(basic_request<Tag> &request, T const &value,
tags::pod) {
request.destination = value;
}
template <class Tag, class T>
inline void destination_impl(basic_request<Tag> &request, T const &value,
tags::normal) {
request.destination(value);
}
template <class Tag, class T>
inline void destination_impl(basic_request<Tag> &request, T const &value,
tags::client) {
destination_impl(request, value, typename pod_or_normal<Tag>::type());
}
template <class Tag, class T>
inline void destination(basic_request<Tag> &request, T const &value) {
destination_impl(request, value, typename client_or_server<Tag>::type());
}
} // namespace http
namespace impl {
template <class Message, class ValueType, class Async>
inline void destination(Message const &message, ValueType const &destination_,
http::tags::http_server, Async) {
message.destination = destination_;
}
} /* impl */
} // namespace network
} // namespace boost
#include <boost/network/message/modifiers/destination.hpp>
#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_DESTINATION_HPP_20100624

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/thread/future.hpp>
#include <boost/concept/requires.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_response;
template <class Tag>
struct basic_request;
namespace impl {
template <class Tag, class T>
void headers(basic_response<Tag> &response, T const &value,
mpl::false_ const &) {
response << headers(value);
}
template <class Tag, class T>
void headers(basic_response<Tag> &response, T const &future,
mpl::true_ const &) {
response.headers(future);
}
template <class Tag, class T>
void headers(basic_request<Tag> &request, T const &value,
tags::server const &) {
request.headers = value;
}
}
template <class Tag, class T>
inline void headers(basic_response<Tag> &response, T const &value) {
impl::headers(response, value, is_async<Tag>());
}
template <class Tag, class T>
inline void headers(basic_request<Tag> &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

View file

@ -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 <boost/network/protocol/http/support/is_server.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/cstdint.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_request;
template <class Tag>
inline typename enable_if<is_server<Tag>, void>::type major_version(
basic_request<Tag>& 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 \
*/

View file

@ -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 <boost/network/traits/string.hpp>
#include <boost/utility/enable_if.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_request;
template <class Tag>
inline typename enable_if<is_server<Tag>, void>::type method(
basic_request<Tag>& request, typename string<Tag>::type const& method_) {
request.method = method_;
}
} /* http */
} /* network */
} /* boost */
#endif /* BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_METHOD_HPP_20101118 */

View file

@ -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 <boost/network/protocol/http/support/is_server.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/cstdint.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_request;
template <class Tag>
inline typename enable_if<is_server<Tag>, void>::type minor_version(
basic_request<Tag>& 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 \
*/

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/network/protocol/http/support/client_or_server.hpp>
#include <boost/thread/future.hpp>
#include <boost/concept/requires.hpp>
#include <boost/network/protocol/http/tags.hpp>
#include <boost/network/message/directives.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_response;
namespace impl {
template <class Tag, class T>
void source(basic_response<Tag> &response, T const &value,
mpl::false_ const &) {
response << ::boost::network::source(value);
}
template <class Tag, class T>
void source(basic_response<Tag> &response, T const &future,
mpl::true_ const &) {
response.source(future);
}
template <class Tag, class T>
void source(basic_request<Tag> &request, T const &value, tags::server const &) {
request.source = value;
}
template <class Tag, class T>
void source(basic_request<Tag> &request, T const &value, tags::client const &) {
request << ::boost::network::source(value);
}
}
template <class Tag, class T>
inline void source(basic_response<Tag> &response, T const &value) {
impl::source(response, value, is_async<Tag>());
}
template <class Tag, class T>
inline void source_impl(basic_request<Tag> &request, T const &value,
tags::server) {
impl::source(request, value, Tag());
}
template <class Tag, class T>
inline void source_impl(basic_request<Tag> &request, T const &value,
tags::client) {
impl::source(request, value, Tag());
}
template <class Tag, class T>
inline void source(basic_request<Tag> &request, T const &value) {
source_impl(request, value, typename client_or_server<Tag>::type());
}
} // namespace http
namespace impl {
template <class Message, class ValueType, class Async>
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 <boost/network/message/modifiers/source.hpp>
#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIER_SOURCE_HPP_20100624

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/thread/future.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_response;
namespace impl {
template <class Tag, class T>
void status(basic_response<Tag> &response, T const &value,
mpl::false_ const &) {
response << boost::network::http::status(value);
}
template <class Tag, class T>
void status(basic_response<Tag> &response, T const &future,
mpl::true_ const &) {
response.status(future);
}
} // namespace impl
template <class Tag, class T>
void status(basic_response<Tag> &response, T const &value) {
impl::status(response, value, is_async<Tag>());
}
} // namespace http
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_STATUS_HPP_20100608

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/thread/future.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_response;
namespace impl {
template <class Tag, class T>
void status_message(basic_response<Tag> &response, T const &value,
mpl::false_ const &) {
response << boost::network::http::status_message(value);
}
template <class Tag, class T>
void status_message(basic_response<Tag> &response, T const &future,
mpl::true_ const &) {
response.status_message(future);
}
} // namespace impl
template <class Tag, class T>
void status_message(basic_response<Tag> &response, T const &value) {
impl::status_message(response, value, is_async<Tag>());
}
} // namespace http
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_STATUS_MESSAGE_HPP_20100608

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/thread/future.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_request;
template <class Tag, class T>
void uri(basic_request<Tag>& request, T const& value) {
request.uri(value);
}
} // namespace http
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_URI_HPP_20100621

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/network/support/is_sync.hpp>
#include <boost/thread/future.hpp>
#include <boost/mpl/if.hpp>
namespace boost {
namespace network {
namespace http {
template <class Tag>
struct basic_response;
namespace impl {
template <class Tag, class T>
void version(basic_response<Tag> &response, T const &value,
mpl::false_ const &) {
response << boost::network::http::version(value);
}
template <class Tag, class T>
void version(basic_response<Tag> &response, T const &future,
mpl::true_ const &) {
response.version(future);
}
} // namespace impl
template <class Tag, class T>
void version(basic_response<Tag> &response, T const &value) {
impl::version(response, value, is_async<Tag>());
}
} // namespace http
} // namespace network
} // namespace boost
#endif // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_MODIFIERS_VERSION_HPP_20100608

View file

@ -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 <boost/network/support/is_async.hpp>
#include <boost/cstdint.hpp>
#include <boost/network/tags.hpp>
namespace boost {
namespace network {
namespace http {
namespace traits {
template <class Tag>
struct unsupported_tag;
template <class Message>
struct status
: mpl::if_<
is_async<typename Message::tag>,
boost::shared_future<boost::uint16_t>,
typename mpl::if_<is_sync<typename Message::tag>, boost::uint16_t,
unsupported_tag<typename Message::tag> >::type> {};
} /* traits */
} /* http */
} /* network */
} /* boost */
#endif

Some files were not shown because too many files have changed in this diff Show more