[
  {
    "path": ".gitattributes",
    "content": "# Lineendings\n*.sln       eol=crlf\n*.vcproj    eol=crlf\n*.vcxproj*  eol=crlf\n\n# Whitespace rules\n# strict (no trailing, no tabs)\n*.cpp       whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol\n*.hpp       whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol\n*.c         whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol\n*.h         whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol\n\n# normal (no trailing)\n*.sql       whitespace=trailing-space,space-before-tab,cr-at-eol\n*.txt       whitespace=trailing-space,space-before-tab,cr-at-eol\n\n# special files which must ignore whitespace\n*.patch     whitespace=-trailing-space\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [zaphoyd]\n"
  },
  {
    "path": ".gitignore",
    "content": "# make .git* files visible to git\n!.gitignore\n!.gitattributes\n\n.DS_Store\n\n#vim stuff\n*~\n*.swp\n\n*.o\n*.so\n*.so.?\n*.so.?.?.?\n*.a\n*.dylib\nlib/*\n\n# CMake\n*.cmake\n*.dir\nCMakeFiles\nINSTALL.*\nZERO_CHECK.*\nCMakeCache.txt\ninstall_manifest.txt\n\n# Windows/Visual Studio\n*.vcproj*\n*.sln\n*.suo\n*.ncb\n*/Debug/*\n*/*/Debug/*\nbin/Debug\n*/Release/*\n*/*/Release/*\n*/RelWithDebInfo/*\n*/*/RelWithDebInfo/*\n\n# explicitly allow this path with /debug/ in it\n!websocketpp/transport/debug/*\n\nobjs_shared/\nobjs_static/\n\nexamples/chat_server/chat_server\nexamples/echo_server/echo_server\nexamples/chat_client/chat_client\nexamples/echo_client/echo_client\ntest/basic/tests\nlibwebsocketpp.dylib.0.1.0\n\nwebsocketpp.xcodeproj/xcuserdata/*\nwebsocketpp.xcodeproj/project.xcworkspace/xcuserdata/*\npolicy_based_notes.hpp\n\nexamples/echo_server_tls/echo_server_tls\n\nexamples/fuzzing_client/fuzzing_client\n\nexamples/stress_client/stress_client\n\nexamples/broadcast_server_tls/broadcast_server\n\ntest/basic/perf\n\nexamples/echo_server_tls/echo_server_tls\n\nexamples/concurrent_server/concurrent_server\n\nexamples/fuzzing_server_tls/fuzzing_server\n\nexamples/wsperf/wsperf\n\n.sconsign.dblite\n\nbuild/\ndoxygen/\nexamples/wsperf/wsperf_client\n\n*.out\n\n*.log\n*.opensdf\n*.sdf\n*.vcxproj\n*.vcxproj.filters\n*.user\ninstall\nMakefile\nbin\n\nTesting/Temporary/CTestCostData.txt\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: cpp\ncompiler:\n  - gcc\nbefore_install:\n #- sudo apt-get install libboost-chrono1.48-dev libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y\n - sudo add-apt-repository -y ppa:boost-latest/ppa && sudo apt-get update -q && sudo apt-get install -y libboost-chrono1.55-dev libboost-random1.55-dev libboost-regex1.55-dev libboost-system1.55-dev libboost-thread1.55-dev libboost-test1.55-dev\nenv:\n  global:\n    - BOOST_INCLUDES=/usr/include\n    - BOOST_LIBS=/usr/lib/x86_64-linux-gnu\nscript: scons -j 2 && scons test\nbranches:\n  only:\n    - master\n    - develop\nnotifications:\n  recipients:\n    - travis@zaphoyd.com\n  email:\n    on_success: change\n    on_failure: always\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "\n############ Setup project and cmake\n# Minimum cmake requirement. We should require a quite recent\n# cmake for the dependency find macros etc. to be up to date.\ncmake_minimum_required (VERSION 3.10)\n\n############ Paths\n\nset (WEBSOCKETPP_ROOT ${CMAKE_CURRENT_SOURCE_DIR})\nset (WEBSOCKETPP_INCLUDE ${WEBSOCKETPP_ROOT}/websocketpp)\nset (WEBSOCKETPP_BUILD_ROOT ${CMAKE_CURRENT_BINARY_DIR})\nset (WEBSOCKETPP_BIN ${WEBSOCKETPP_BUILD_ROOT}/bin)\nset (WEBSOCKETPP_LIB ${WEBSOCKETPP_BUILD_ROOT}/lib)\n\n# CMake install step prefix. I assume linux users want the prefix to\n# be the default /usr or /usr/local so this is only adjusted on Windows.\n# This must be set prior to any call to project or it will not be read correctly.\n# - Windows: Build the INSTALL project in your solution file.\n# - Linux/OSX: make install.\nif (WIN32)\n    set (CMAKE_INSTALL_PREFIX \"${WEBSOCKETPP_ROOT}/install\" CACHE PATH \"\")\nendif ()\n\n############ Project name and version\nset (WEBSOCKETPP_MAJOR_VERSION 0)\nset (WEBSOCKETPP_MINOR_VERSION 8)\nset (WEBSOCKETPP_PATCH_VERSION 2)\nset (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION})\n\nif(POLICY CMP0048)\n  cmake_policy(GET CMP0048 _version_policy)\nendif()\n\nif(_version_allowed STREQUAL NEW)\n  project (websocketpp VERSION ${WEBSOCKETPP_VERSION})\nelse()\n  project (websocketpp)\nendif()\n\nset_property(GLOBAL PROPERTY USE_FOLDERS ON)\n\nset(INSTALL_INCLUDE_DIR include CACHE PATH \"Installation directory for header files\")\nif (WIN32 AND NOT CYGWIN)\n  set (DEF_INSTALL_CMAKE_DIR cmake)\nelse ()\n  set (DEF_INSTALL_CMAKE_DIR lib/cmake/websocketpp)\nendif ()\nset (INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH \"Installation directory for CMake files\")\n\n# Make relative paths absolute (needed later on)\nforeach (p INCLUDE CMAKE)\n  set (var INSTALL_${p}_DIR)\n  if (NOT IS_ABSOLUTE \"${${var}}\")\n    set (${var} \"${CMAKE_INSTALL_PREFIX}/${${var}}\")\n  endif ()\nendforeach ()\n\n# Set CMake library search policy\nif (COMMAND cmake_policy)\n    cmake_policy (SET CMP0003 NEW)\n    cmake_policy (SET CMP0005 NEW)\nendif ()\n\n# Disable unnecessary build types\nset (CMAKE_CONFIGURATION_TYPES \"Release;RelWithDebInfo;Debug\" CACHE STRING \"Configurations\" FORCE)\n\n# Include our cmake macros\nset (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)\ninclude (CMakeHelpers)\n\n\n############  Build customization\n\n# Override from command line \"CMake -D<OPTION>=TRUE/FALSE/0/1/ON/OFF\"\noption (ENABLE_CPP11 \"Build websocketpp with CPP11 features enabled.\" TRUE)\noption (BUILD_EXAMPLES \"Build websocketpp examples.\" FALSE)\noption (BUILD_TESTS \"Build websocketpp tests.\" FALSE)\n\nif (BUILD_TESTS OR BUILD_EXAMPLES)\n\n    enable_testing ()\n\n    ############ Compiler specific setup\n\n    set (WEBSOCKETPP_PLATFORM_LIBS \"\")\n    set (WEBSOCKETPP_PLATFORM_TLS_LIBS \"\")\n    set (WEBSOCKETPP_BOOST_LIBS \"\")\n\n    # VC9 and C++11 reasoning\n    if (ENABLE_CPP11 AND MSVC AND MSVC90)\n        message(\"* Detected Visual Studio 9 2008, disabling C++11 support.\")\n        set (ENABLE_CPP11 FALSE)\n    endif ()\n\n    # Detect clang. Not officially reported by cmake.\n    execute_process(COMMAND \"${CMAKE_CXX_COMPILER}\" \"-v\" ERROR_VARIABLE CXX_VER_STDERR)\n    if (\"${CXX_VER_STDERR}\" MATCHES \".*clang.*\")\n        set (CMAKE_COMPILER_IS_CLANGXX 1)\n    endif ()\n\n    # C++11 defines\n    if (ENABLE_CPP11)\n        if (MSVC)\n            add_definitions (-D_WEBSOCKETPP_CPP11_FUNCTIONAL_)\n            add_definitions (-D_WEBSOCKETPP_CPP11_SYSTEM_ERROR_)\n            add_definitions (-D_WEBSOCKETPP_CPP11_RANDOM_DEVICE_)\n            add_definitions (-D_WEBSOCKETPP_CPP11_MEMORY_)\n        else()\n            add_definitions (-D_WEBSOCKETPP_CPP11_STL_)\n        endif()\n    endif ()\n\n    # Visual studio\n    if (MSVC)\n        set (WEBSOCKETPP_BOOST_LIBS system thread)\n        set (CMAKE_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE} /GL /Gy /GF /Ox /Ob2 /Ot /Oi /MP /arch:SSE2 /fp:fast\")\n        set (CMAKE_SHARED_LINKER_FLAGS_RELEASE \"${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /INCREMENTAL:NO /OPT:REF /OPT:ICF\")\n        add_definitions (/W3 /wd4996 /wd4995 /wd4355)\n        add_definitions (-DUNICODE -D_UNICODE)\n        add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)\n        add_definitions (-DNOMINMAX)\n    endif ()\n\n    # g++\n    if (CMAKE_COMPILER_IS_GNUCXX)\n        if (NOT APPLE)\n            set (WEBSOCKETPP_PLATFORM_LIBS pthread rt)\n        else()\n            set (WEBSOCKETPP_PLATFORM_LIBS pthread)\n        endif()\n        set (WEBSOCKETPP_PLATFORM_TLS_LIBS ssl crypto)\n        set (WEBSOCKETPP_BOOST_LIBS system thread)\n        set (CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++0x\")\n        if (NOT APPLE)\n            add_definitions (-DNDEBUG -Wall -Wcast-align) # todo: should we use CMAKE_C_FLAGS for these?\n        endif ()\n\n        # Try to detect version. Note: Not tested!\n        execute_process (COMMAND ${CMAKE_CXX_COMPILER} \"-dumpversion\" OUTPUT_VARIABLE GCC_VERSION)\n        if (\"${GCC_VERSION}\" STRGREATER \"4.4.0\")\n            message(\"* C++11 support partially enabled due to GCC version ${GCC_VERSION}\")\n            set (WEBSOCKETPP_BOOST_LIBS system thread)\n        endif ()\n    endif ()\n\n    # clang\n    if (CMAKE_COMPILER_IS_CLANGXX)\n        if (NOT APPLE)\n            set (WEBSOCKETPP_PLATFORM_LIBS pthread rt)\n        else()\n            set (WEBSOCKETPP_PLATFORM_LIBS pthread)\n        endif()\n        set (WEBSOCKETPP_PLATFORM_TLS_LIBS ssl crypto)\n        set (WEBSOCKETPP_BOOST_LIBS system thread)\n        set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} \"-std=c++0x -stdlib=libc++\") # todo: is libc++ really needed here?\n        if (NOT APPLE)\n            add_definitions (-DNDEBUG -Wall -Wno-padded) # todo: should we use CMAKE_C_FLAGS for these?\n        endif ()\n    endif ()\n\n    # OSX, can override above.\n    if (APPLE)\n        add_definitions (-DNDEBUG -Wall)\n    endif ()\n\n    if (BUILD_EXAMPLES)\n        list (APPEND WEBSOCKETPP_BOOST_LIBS random)\n    endif()\n\n    if (BUILD_TESTS)\n        list (APPEND WEBSOCKETPP_BOOST_LIBS unit_test_framework)\n    endif()\n\n    ############ Dependencies\n\n    # Set BOOST_ROOT env variable or pass with cmake -DBOOST_ROOT=path.\n    # BOOST_ROOT can also be defined by a previous run from cmake cache.\n    if (NOT \"$ENV{BOOST_ROOT_CPP11}\" STREQUAL \"\")\n        # Scons documentation for BOOST_ROOT_CPP11:\n        # \"look for optional second boostroot compiled with clang's libc++ STL library\n        # this prevents warnings/errors when linking code built with two different\n        # incompatible STL libraries.\"\n        file (TO_CMAKE_PATH \"$ENV{BOOST_ROOT_CPP11}\" BOOST_ROOT)\n        set (BOOST_ROOT ${BOOST_ROOT} CACHE PATH \"BOOST_ROOT dependency path\" FORCE)\n    endif ()\n    if (\"${BOOST_ROOT}\" STREQUAL \"\")\n        file (TO_CMAKE_PATH \"$ENV{BOOST_ROOT}\" BOOST_ROOT)\n        # Cache BOOST_ROOT for runs that do not define $ENV{BOOST_ROOT}.\n        set (BOOST_ROOT ${BOOST_ROOT} CACHE PATH \"BOOST_ROOT dependency path\" FORCE)\n    endif ()\n\n    message (\"* Configuring Boost\")\n    message (STATUS \"-- Using BOOST_ROOT\")\n    message (STATUS \"       \" ${BOOST_ROOT})\n\n    if (MSVC)\n        set (Boost_USE_MULTITHREADED TRUE)\n        set (Boost_USE_STATIC_LIBS TRUE)\n    else ()\n        set (Boost_USE_MULTITHREADED FALSE)\n        set (Boost_USE_STATIC_LIBS FALSE)\n    endif ()\n\n\tif (BOOST_STATIC)\n\t\tset (Boost_USE_STATIC_LIBS TRUE)\n\tendif ()\n\n    if (NOT Boost_USE_STATIC_LIBS)\n        add_definitions (-DBOOST_TEST_DYN_LINK)\n    endif ()\n\n    set (Boost_FIND_REQUIRED TRUE)\n    set (Boost_FIND_QUIETLY TRUE)\n    set (Boost_DEBUG FALSE)\n    set (Boost_USE_MULTITHREADED TRUE)\n    set (Boost_ADDITIONAL_VERSIONS \"1.39.0\" \"1.40.0\" \"1.41.0\" \"1.42.0\" \"1.43.0\" \"1.44.0\" \"1.46.1\") # todo: someone who knows better spesify these!\n\n    find_package (Boost 1.39.0 COMPONENTS \"${WEBSOCKETPP_BOOST_LIBS}\")\n\n    if (Boost_FOUND)\n        # Boost is a project wide global dependency.\n        include_directories (${Boost_INCLUDE_DIRS})\n        link_directories (${Boost_LIBRARY_DIRS})\n\n        # Pretty print status\n        message (STATUS \"-- Include Directories\")\n        foreach (include_dir ${Boost_INCLUDE_DIRS})\n            message (STATUS \"       \" ${include_dir})\n        endforeach ()\n        message (STATUS \"-- Library Directories\")\n        foreach (library_dir ${Boost_LIBRARY_DIRS})\n            message (STATUS \"       \" ${library_dir})\n        endforeach ()\n        message (STATUS \"-- Libraries\")\n        foreach (boost_lib ${Boost_LIBRARIES})\n            message (STATUS \"       \" ${boost_lib})\n        endforeach ()\n        message (\"\")\n    else ()\n        message (FATAL_ERROR \"Failed to find required dependency: boost\")\n    endif ()\n\n    find_package(OpenSSL)\n    find_package(ZLIB)\nendif()\n\n############ Add projects\n\n# Add main library\nadd_subdirectory (websocketpp)\n\n# Add examples\nif (BUILD_EXAMPLES)\n    include_subdirs (\"examples\")\nendif ()\n\n# Add tests\nif (BUILD_TESTS)\n    include_subdirs (\"test\")\nendif ()\n\nprint_used_build_config()\n\nexport (PACKAGE websocketpp)\n\ninclude(CMakePackageConfigHelpers)\nconfigure_package_config_file(websocketpp-config.cmake.in\n  \"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake\"\n  PATH_VARS INSTALL_INCLUDE_DIR\n  INSTALL_DESTINATION \"${INSTALL_CMAKE_DIR}\"\n  NO_CHECK_REQUIRED_COMPONENTS_MACRO\n)\nwrite_basic_package_version_file(\"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake\"\n  VERSION ${WEBSOCKETPP_VERSION}\n  COMPATIBILITY ExactVersion)\n\n# Install the websocketpp-config.cmake and websocketpp-configVersion.cmake\ninstall (FILES\n  \"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake\"\n  \"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake\"\n  DESTINATION \"${INSTALL_CMAKE_DIR}\" COMPONENT dev)\n\n"
  },
  {
    "path": "COPYING",
    "content": "Main Library:\n\nCopyright (c) 2014, Peter Thorson. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of the WebSocket++ Project nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nBundled Libraries:\n\n****** Base 64 Library (base64/base64.hpp) ******\nbase64.hpp is a repackaging of the base64.cpp and base64.h files into a\nsingle header suitable for use as a header only library. This conversion was\ndone by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to\nthe code are redistributed under the same license as the original, which is\nlisted below.\n\nbase64.cpp and base64.h\n\nCopyright (C) 2004-2008 René Nyffenegger\n\nThis source code is provided 'as-is', without any express or implied\nwarranty. In no event will the author be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this source code must not be misrepresented; you must not\n  claim that you wrote the original source code. If you use this source code\n  in a product, an acknowledgment in the product documentation would be\n  appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and must not be\n  misrepresented as being the original source code.\n\n3. This notice may not be removed or altered from any source distribution.\n\nRené Nyffenegger rene.nyffenegger@adp-gmbh.ch\n\n****** SHA1 Library (sha1/sha1.hpp) ******\nsha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1\nlibrary (http://code.google.com/p/smallsha1/) into a single header suitable for\nuse as a header only library. This conversion was done by Peter Thorson\n(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed\nunder the same license as the original, which is listed below.\n\n Copyright (c) 2011, Micael Hildenborg\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Micael Hildenborg nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\n EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n****** MD5 Library (common/md5.hpp) ******\nmd5.hpp is a reformulation of the md5.h and md5.c code from\nhttp://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to\nfunction as a component of a header only library. This conversion was done by\nPeter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The\nchanges are released under the same license as the original (listed below)\n\nCopyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.\n\nThis software is provided 'as-is', without any express or implied\nwarranty.  In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must not\n claim that you wrote the original software. If you use this software\n in a product, an acknowledgment in the product documentation would be\n appreciated but is not required.\n2. Altered source versions must be plainly marked as such, and must not be\n misrepresented as being the original software.\n3. This notice may not be removed or altered from any source distribution.\n\nL. Peter Deutsch\nghost@aladdin.com\n\n****** UTF8 Validation logic (utf8_validation.hpp) ******\nutf8_validation.hpp is adapted from code originally written by Bjoern Hoehrmann\n<bjoern@hoehrmann.de>. See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for\ndetails.\n\nThe original license:\n\nCopyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Doxyfile",
    "content": "# Doxyfile 1.8.8\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project.\n#\n# All text after a double hash (##) is considered a comment and is placed in\n# front of the TAG it is preceding.\n#\n# All text after a single hash (#) is considered a comment and will be ignored.\n# The format is:\n# TAG = value [value, ...]\n# For lists, items can also be appended using:\n# TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\\\" \\\").\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the config file\n# that follow. The default is UTF-8 which is also the encoding used for all text\n# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv\n# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv\n# for the list of possible encodings.\n# The default value is: UTF-8.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by\n# double-quotes, unless you are using Doxywizard) that should identify the\n# project for which the documentation is generated. This name is used in the\n# title of most generated pages and in a few other places.\n# The default value is: My Project.\n\nPROJECT_NAME           = WebSocket++\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. This\n# could be handy for archiving the generated documentation or if some version\n# control system is used.\n\nPROJECT_NUMBER         = 0.8.2\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer a\n# quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          = \"C++ websocket client/server library\"\n\n# With the PROJECT_LOGO tag one can specify an logo or icon that is included in\n# the documentation. The maximum height of the logo should not exceed 55 pixels\n# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo\n# to the output directory.\n\nPROJECT_LOGO           = \n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path\n# into which the generated documentation will be written. If a relative path is\n# entered, it will be relative to the location where doxygen was started. If\n# left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = doxygen\n\n# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-\n# directories (in 2 levels) under the output directory of each output format and\n# will distribute the generated files over these directories. Enabling this\n# option can be useful when feeding doxygen a huge amount of source files, where\n# putting all generated files in the same directory would otherwise causes\n# performance problems for the file system.\n# The default value is: NO.\n\nCREATE_SUBDIRS         = NO\n\n# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII\n# characters to appear in the names of generated files. If set to NO, non-ASCII\n# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode\n# U+3044.\n# The default value is: NO.\n\nALLOW_UNICODE_NAMES    = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,\n# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),\n# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,\n# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),\n# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,\n# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,\n# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,\n# Ukrainian and Vietnamese.\n# The default value is: English.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member\n# descriptions after the members that are listed in the file and class\n# documentation (similar to Javadoc). Set to NO to disable this.\n# The default value is: YES.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief\n# description of a member or function before the detailed description\n#\n# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n# The default value is: YES.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator that is\n# used to form the text in various listings. Each string in this list, if found\n# as the leading text of the brief description, will be stripped from the text\n# and the result, after processing the whole list, is used as the annotated\n# text. Otherwise, the brief description is used as-is. If left blank, the\n# following values are used ($name is automatically replaced with the name of\n# the entity):The $name class, The $name widget, The $name file, is, provides,\n# specifies, contains, represents, a, an and the.\n\nABBREVIATE_BRIEF       = \n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# doxygen will generate a detailed section even if there is only a brief\n# description.\n# The default value is: NO.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n# The default value is: NO.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path\n# before files name in the file list and in the header files. If set to NO the\n# shortest path that makes the file name unique will be used\n# The default value is: YES.\n\nFULL_PATH_NAMES        = YES\n\n# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.\n# Stripping is only done if one of the specified strings matches the left-hand\n# part of the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which doxygen is run is used as the path to\n# strip.\n#\n# Note that you can specify absolute paths here, but also relative paths, which\n# will be relative from the directory where doxygen is started.\n# This tag requires that the tag FULL_PATH_NAMES is set to YES.\n\nSTRIP_FROM_PATH        = \n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the\n# path mentioned in the documentation of a class, which tells the reader which\n# header file to include in order to use a class. If left blank only the name of\n# the header file containing the class definition is used. Otherwise one should\n# specify the list of include paths that are normally passed to the compiler\n# using the -I flag.\n\nSTRIP_FROM_INC_PATH    = \n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but\n# less readable) file names. This can be useful is your file systems doesn't\n# support long names like on DOS, Mac, or CD-ROM.\n# The default value is: NO.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the\n# first line (until the first dot) of a Javadoc-style comment as the brief\n# description. If set to NO, the Javadoc-style will behave just like regular Qt-\n# style comments (thus requiring an explicit @brief command for a brief\n# description.)\n# The default value is: NO.\n\nJAVADOC_AUTOBRIEF      = NO\n\n# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first\n# line (until the first dot) of a Qt-style comment as the brief description. If\n# set to NO, the Qt-style will behave just like regular Qt-style comments (thus\n# requiring an explicit \\brief command for a brief description.)\n# The default value is: NO.\n\nQT_AUTOBRIEF           = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a\n# multi-line C++ special comment block (i.e. a block of //! or /// comments) as\n# a brief description. This used to be the default behavior. The new default is\n# to treat a multi-line C++ comment block as a detailed description. Set this\n# tag to YES if you prefer the old behavior instead.\n#\n# Note that setting this tag to YES also means that rational rose comments are\n# not recognized any more.\n# The default value is: NO.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the\n# documentation from any documented member that it re-implements.\n# The default value is: YES.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a\n# new page for each member. If set to NO, the documentation of a member will be\n# part of the file/class/namespace that contains it.\n# The default value is: NO.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen\n# uses this value to replace tabs by spaces in code fragments.\n# Minimum value: 1, maximum value: 16, default value: 4.\n\nTAB_SIZE               = 4\n\n# This tag can be used to specify a number of aliases that act as commands in\n# the documentation. An alias has the form:\n# name=value\n# For example adding\n# \"sideeffect=@par Side Effects:\\n\"\n# will allow you to put the command \\sideeffect (or @sideeffect) in the\n# documentation, which will result in a user-defined paragraph with heading\n# \"Side Effects:\". You can put \\n's in the value part of an alias to insert\n# newlines.\n\nALIASES                = \n\n# This tag can be used to specify a number of word-keyword mappings (TCL only).\n# A mapping has the form \"name=value\". For example adding \"class=itcl::class\"\n# will allow you to use the command class in the itcl::class meaning.\n\nTCL_SUBST              = \n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources\n# only. Doxygen will then generate output that is more tailored for C. For\n# instance, some of the names that are used will be different. The list of all\n# members will be omitted, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_FOR_C  = NO\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or\n# Python sources only. Doxygen will then generate output that is more tailored\n# for that language. For instance, namespaces will be presented as packages,\n# qualified scopes will look different, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n# sources. Doxygen will then generate output that is tailored for Fortran.\n# The default value is: NO.\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\n# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n# sources. Doxygen will then generate output that is tailored for VHDL.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# Doxygen selects the parser to use depending on the extension of the files it\n# parses. With this tag you can assign which parser to use for a given\n# extension. Doxygen has a built-in mapping, but you can override or extend it\n# using this tag. The format is ext=language, where ext is a file extension, and\n# language is one of the parsers supported by doxygen: IDL, Java, Javascript,\n# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:\n# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:\n# Fortran. In the later case the parser tries to guess whether the code is fixed\n# or free formatted code, this is the default for Fortran type files), VHDL. For\n# instance to make doxygen treat .inc files as Fortran files (default is PHP),\n# and .f files as C (default is Fortran), use: inc=Fortran f=C.\n#\n# Note For files without extension you can use no_extension as a placeholder.\n#\n# Note that for custom extensions you also need to set FILE_PATTERNS otherwise\n# the files are not read by doxygen.\n\nEXTENSION_MAPPING      = \n\n# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments\n# according to the Markdown format, which allows for more readable\n# documentation. See http://daringfireball.net/projects/markdown/ for details.\n# The output of markdown processing is further processed by doxygen, so you can\n# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in\n# case of backward compatibilities issues.\n# The default value is: YES.\n\nMARKDOWN_SUPPORT       = YES\n\n# When enabled doxygen tries to link words that correspond to documented\n# classes, or namespaces to their corresponding documentation. Such a link can\n# be prevented in individual cases by by putting a % sign in front of the word\n# or globally by setting AUTOLINK_SUPPORT to NO.\n# The default value is: YES.\n\nAUTOLINK_SUPPORT       = YES\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should set this\n# tag to YES in order to let doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string);\n# versus func(std::string) {}). This also make the inheritance and collaboration\n# diagrams that involve STL classes more complete and accurate.\n# The default value is: NO.\n\nBUILTIN_STL_SUPPORT    = YES\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n# The default value is: NO.\n\nCPP_CLI_SUPPORT        = NO\n\n# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:\n# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen\n# will parse them like normal C++ but will assume all classes use public instead\n# of private inheritance when no explicit protection keyword is present.\n# The default value is: NO.\n\nSIP_SUPPORT            = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate\n# getter and setter methods for a property. Setting this option to YES will make\n# doxygen to replace the get and set methods by a property in the documentation.\n# This will only work if the methods are indeed getting or setting a simple\n# type. If this is not the case, or you want to show the methods anyway, you\n# should set this option to NO.\n# The default value is: YES.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES, then doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n# The default value is: NO.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# Set the SUBGROUPING tag to YES to allow class member groups of the same type\n# (for instance a group of public functions) to be put as a subgroup of that\n# type (e.g. under the Public Functions section). Set it to NO to prevent\n# subgrouping. Alternatively, this can be done per class using the\n# \\nosubgrouping command.\n# The default value is: YES.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions\n# are shown inside the group in which they are included (e.g. using \\ingroup)\n# instead of on a separate page (for HTML and Man pages) or section (for LaTeX\n# and RTF).\n#\n# Note that this feature does not work in combination with\n# SEPARATE_MEMBER_PAGES.\n# The default value is: NO.\n\nINLINE_GROUPED_CLASSES = NO\n\n# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions\n# with only public data fields or simple typedef fields will be shown inline in\n# the documentation of the scope in which they are defined (i.e. file,\n# namespace, or group documentation), provided this scope is documented. If set\n# to NO, structs, classes, and unions are shown on a separate page (for HTML and\n# Man pages) or section (for LaTeX and RTF).\n# The default value is: NO.\n\nINLINE_SIMPLE_STRUCTS  = NO\n\n# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or\n# enum is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically be\n# useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n# The default value is: NO.\n\nTYPEDEF_HIDES_STRUCT   = NO\n\n# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This\n# cache is used to resolve symbols given their name and scope. Since this can be\n# an expensive process and often the same symbol appears multiple times in the\n# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small\n# doxygen will become slower. If the cache is too large, memory is wasted. The\n# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range\n# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536\n# symbols. At the end of a run doxygen will report the cache usage and suggest\n# the optimal cache size from a speed point of view.\n# Minimum value: 0, maximum value: 9, default value: 0.\n\nLOOKUP_CACHE_SIZE      = 0\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in\n# documentation are documented, even if no documentation was available. Private\n# class members and static file members will be hidden unless the\n# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.\n# Note: This will also disable the warnings about undocumented members that are\n# normally produced when WARNINGS is set to YES.\n# The default value is: NO.\n\nEXTRACT_ALL            = NO\n\n# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will\n# be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIVATE        = NO\n\n# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal\n# scope will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PACKAGE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES all static members of a file will be\n# included in the documentation.\n# The default value is: NO.\n\nEXTRACT_STATIC         = YES\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined\n# locally in source files will be included in the documentation. If set to NO\n# only classes defined in header files are included. Does not have any effect\n# for Java sources.\n# The default value is: YES.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. When set to YES local methods,\n# which are defined in the implementation section but not in the interface are\n# included in the documentation. If set to NO only methods in the interface are\n# included.\n# The default value is: NO.\n\nEXTRACT_LOCAL_METHODS  = NO\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base name of\n# the file that contains the anonymous namespace. By default anonymous namespace\n# are hidden.\n# The default value is: NO.\n\nEXTRACT_ANON_NSPACES   = NO\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all\n# undocumented members inside documented classes or files. If set to NO these\n# members will be included in the various overviews, but no documentation\n# section is generated. This option has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy. If set\n# to NO these classes will be included in the various overviews. This option has\n# no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend\n# (class|struct|union) declarations. If set to NO these declarations will be\n# included in the documentation.\n# The default value is: NO.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any\n# documentation blocks found inside the body of a function. If set to NO these\n# blocks will be appended to the function's detailed documentation block.\n# The default value is: NO.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation that is typed after a\n# \\internal command is included. If the tag is set to NO then the documentation\n# will be excluded. Set it to YES to include the internal documentation.\n# The default value is: NO.\n\nINTERNAL_DOCS          = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file\n# names in lower-case letters. If set to YES upper-case letters are also\n# allowed. This is useful if you have classes or files whose names only differ\n# in case and if your file system supports case sensitive file names. Windows\n# and Mac users are advised to set this option to NO.\n# The default value is: system dependent.\n\nCASE_SENSE_NAMES       = NO\n\n# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with\n# their full class and namespace scopes in the documentation. If set to YES the\n# scope will be hidden.\n# The default value is: NO.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of\n# the files that are included by a file in the documentation of that file.\n# The default value is: YES.\n\nSHOW_INCLUDE_FILES     = YES\n\n# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each\n# grouped member an include statement to the documentation, telling the reader\n# which file to include in order to use the member.\n# The default value is: NO.\n\nSHOW_GROUPED_MEMB_INC  = NO\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include\n# files with double quotes in the documentation rather than with sharp brackets.\n# The default value is: NO.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the\n# documentation for inline members.\n# The default value is: YES.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the\n# (detailed) documentation of file and class members alphabetically by member\n# name. If set to NO the members will appear in declaration order.\n# The default value is: YES.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief\n# descriptions of file, namespace and class members alphabetically by member\n# name. If set to NO the members will appear in declaration order. Note that\n# this will also influence the order of the classes in the class list.\n# The default value is: NO.\n\nSORT_BRIEF_DOCS        = NO\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the\n# (brief and detailed) documentation of class members so that constructors and\n# destructors are listed first. If set to NO the constructors will appear in the\n# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.\n# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief\n# member documentation.\n# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting\n# detailed member documentation.\n# The default value is: NO.\n\nSORT_MEMBERS_CTORS_1ST = NO\n\n# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy\n# of group names into alphabetical order. If set to NO the group names will\n# appear in their defined order.\n# The default value is: NO.\n\nSORT_GROUP_NAMES       = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by\n# fully-qualified names, including namespaces. If set to NO, the class list will\n# be sorted only by class name, not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the alphabetical\n# list.\n# The default value is: NO.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper\n# type resolution of all parameters of a function it will reject a match between\n# the prototype and the implementation of a member function even if there is\n# only one candidate or it is obvious which candidate to choose by doing a\n# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still\n# accept a match between prototype and implementation in such cases.\n# The default value is: NO.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the\n# todo list. This list is created by putting \\todo commands in the\n# documentation.\n# The default value is: YES.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the\n# test list. This list is created by putting \\test commands in the\n# documentation.\n# The default value is: YES.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug\n# list. This list is created by putting \\bug commands in the documentation.\n# The default value is: YES.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)\n# the deprecated list. This list is created by putting \\deprecated commands in\n# the documentation.\n# The default value is: YES.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional documentation\n# sections, marked by \\if <section_label> ... \\endif and \\cond <section_label>\n# ... \\endcond blocks.\n\nENABLED_SECTIONS       = \n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the\n# initial value of a variable or macro / define can have for it to appear in the\n# documentation. If the initializer consists of more lines than specified here\n# it will be hidden. Use a value of 0 to hide initializers completely. The\n# appearance of the value of individual variables and macros / defines can be\n# controlled using \\showinitializer or \\hideinitializer command in the\n# documentation regardless of this setting.\n# Minimum value: 0, maximum value: 10000, default value: 30.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at\n# the bottom of the documentation of classes and structs. If set to YES the list\n# will mention the files that were used to generate the documentation.\n# The default value is: YES.\n\nSHOW_USED_FILES        = YES\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This\n# will remove the Files entry from the Quick Index and from the Folder Tree View\n# (if specified).\n# The default value is: YES.\n\nSHOW_FILES             = YES\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces\n# page. This will remove the Namespaces entry from the Quick Index and from the\n# Folder Tree View (if specified).\n# The default value is: YES.\n\nSHOW_NAMESPACES        = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command command input-file, where command is the value of the\n# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided\n# by doxygen. Whatever the program writes to standard output is used as the file\n# version. For an example see the documentation.\n\nFILE_VERSION_FILTER    = \n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. To create the layout file\n# that represents doxygen's defaults, run doxygen with the -l option. You can\n# optionally specify a file name after the option, if omitted DoxygenLayout.xml\n# will be used as the name of the layout file.\n#\n# Note that if you run doxygen from a directory containing a file called\n# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE\n# tag is left empty.\n\nLAYOUT_FILE            = \n\n# The CITE_BIB_FILES tag can be used to specify one or more bib files containing\n# the reference definitions. This must be a list of .bib files. The .bib\n# extension is automatically appended if omitted. This requires the bibtex tool\n# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.\n# For LaTeX the style of the bibliography can be controlled using\n# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the\n# search path. See also \\cite for info how to create references.\n\nCITE_BIB_FILES         = \n\n#---------------------------------------------------------------------------\n# Configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated to\n# standard output by doxygen. If QUIET is set to YES this implies that the\n# messages are off.\n# The default value is: NO.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES\n# this implies that the warnings are on.\n#\n# Tip: Turn warnings on while writing the documentation.\n# The default value is: YES.\n\nWARNINGS               = YES\n\n# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate\n# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: YES.\n\nWARN_IF_UNDOCUMENTED   = YES\n\n# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for\n# potential errors in the documentation, such as not documenting some parameters\n# in a documented function, or documenting parameters that don't exist or using\n# markup commands wrongly.\n# The default value is: YES.\n\nWARN_IF_DOC_ERROR      = YES\n\n# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that\n# are documented, but have no documentation for their parameters or return\n# value. If set to NO doxygen will only warn about wrong or incomplete parameter\n# documentation, but not about the absence of documentation.\n# The default value is: NO.\n\nWARN_NO_PARAMDOC       = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that doxygen\n# can produce. The string should contain the $file, $line, and $text tags, which\n# will be replaced by the file and line number from which the warning originated\n# and the warning text. Optionally the format may contain $version, which will\n# be replaced by the version of the file (if it could be obtained via\n# FILE_VERSION_FILTER)\n# The default value is: $file:$line: $text.\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning and error\n# messages should be written. If left blank the output is written to standard\n# error (stderr).\n\nWARN_LOGFILE           = \n\n#---------------------------------------------------------------------------\n# Configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag is used to specify the files and/or directories that contain\n# documented source files. You may enter file names like myfile.cpp or\n# directories like /usr/src/myproject. Separate the files or directories with\n# spaces.\n# Note: If this tag is empty the current directory is searched.\n\nINPUT                  = readme.md \\\n                         changelog.md \\\n                         roadmap.md \\\n                         websocketpp \\\n                         tutorials \\\n                         docs\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses\n# libiconv (or the iconv built into libc) for the transcoding. See the libiconv\n# documentation (see: http://www.gnu.org/software/libiconv) for the list of\n# possible encodings.\n# The default value is: UTF-8.\n\nINPUT_ENCODING         = UTF-8\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and\n# *.h) to filter out the source-files in the directories. If left blank the\n# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,\n# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,\n# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,\n# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,\n# *.qsf, *.as and *.js.\n\nFILE_PATTERNS          = \n\n# The RECURSIVE tag can be used to specify whether or not subdirectories should\n# be searched for input files as well.\n# The default value is: NO.\n\nRECURSIVE              = YES\n\n# The EXCLUDE tag can be used to specify files and/or directories that should be\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n#\n# Note that relative paths are relative to the directory from which doxygen is\n# run.\n\nEXCLUDE                = build\n\n# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n# The default value is: NO.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories.\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       = \n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# AClass::ANamespace, ANamespace::*Test\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories use the pattern */test/*\n\nEXCLUDE_SYMBOLS        = \n\n# The EXAMPLE_PATH tag can be used to specify one or more files or directories\n# that contain example code fragments that are included (see the \\include\n# command).\n\nEXAMPLE_PATH           = \n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and\n# *.h) to filter out the source-files in the directories. If left blank all\n# files are included.\n\nEXAMPLE_PATTERNS       = \n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude commands\n# irrespective of the value of the RECURSIVE tag.\n# The default value is: NO.\n\nEXAMPLE_RECURSIVE      = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or directories\n# that contain images that are to be included in the documentation (see the\n# \\image command).\n\nIMAGE_PATH             = \n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command:\n#\n# <filter> <input-file>\n#\n# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the\n# name of an input file. Doxygen will then use the output that the filter\n# program writes to standard output. If FILTER_PATTERNS is specified, this tag\n# will be ignored.\n#\n# Note that the filter must not add or remove lines; it is applied before the\n# code is scanned, but not when the output code is generated. If lines are added\n# or removed, the anchors will not be placed correctly.\n\nINPUT_FILTER           = \n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis. Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match. The filters are a list of the form: pattern=filter\n# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how\n# filters are used. If the FILTER_PATTERNS tag is empty or if none of the\n# patterns match the file name, INPUT_FILTER is applied.\n\nFILTER_PATTERNS        = \n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER ) will also be used to filter the input files that are used for\n# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).\n# The default value is: NO.\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and\n# it is also possible to disable source filtering for a specific pattern using\n# *.ext= (so without naming a filter).\n# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.\n\nFILTER_SOURCE_PATTERNS = \n\n# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that\n# is part of the input, its contents will be placed on the main page\n# (index.html). This can be useful if you have a project on for instance GitHub\n# and want to reuse the introduction page also for the doxygen output.\n\nUSE_MDFILE_AS_MAINPAGE = \n\n#---------------------------------------------------------------------------\n# Configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will be\n# generated. Documented entities will be cross-referenced with these sources.\n#\n# Note: To get rid of all source code in the generated output, make sure that\n# also VERBATIM_HEADERS is set to NO.\n# The default value is: NO.\n\nSOURCE_BROWSER         = YES\n\n# Setting the INLINE_SOURCES tag to YES will include the body of functions,\n# classes and enums directly into the documentation.\n# The default value is: NO.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any\n# special comment blocks from generated source code fragments. Normal C, C++ and\n# Fortran comments will always remain visible.\n# The default value is: YES.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES then for each documented\n# function all documented functions referencing it will be listed.\n# The default value is: NO.\n\nREFERENCED_BY_RELATION = NO\n\n# If the REFERENCES_RELATION tag is set to YES then for each documented function\n# all documented entities called/used by that function will be listed.\n# The default value is: NO.\n\nREFERENCES_RELATION    = NO\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set\n# to YES, then the hyperlinks from functions in REFERENCES_RELATION and\n# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will\n# link to the documentation.\n# The default value is: YES.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the\n# source code will show a tooltip with additional information such as prototype,\n# brief description and links to the definition and documentation. Since this\n# will make the HTML file larger and loading of large files a bit slower, you\n# can opt to disable this feature.\n# The default value is: YES.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nSOURCE_TOOLTIPS        = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code will\n# point to the HTML generated by the htags(1) tool instead of doxygen built-in\n# source browser. The htags tool is part of GNU's global source tagging system\n# (see http://www.gnu.org/software/global/global.html). You will need version\n# 4.8.6 or higher.\n#\n# To use it do the following:\n# - Install the latest version of global\n# - Enable SOURCE_BROWSER and USE_HTAGS in the config file\n# - Make sure the INPUT points to the root of the source tree\n# - Run doxygen as normal\n#\n# Doxygen will invoke htags (and that will in turn invoke gtags), so these\n# tools must be available from the command line (i.e. in the search path).\n#\n# The result: instead of the source browser generated by doxygen, the links to\n# source code will now point to the output of htags.\n# The default value is: NO.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a\n# verbatim copy of the header file for each class for which an include is\n# specified. Set to NO to disable this.\n# See also: Section \\class.\n# The default value is: YES.\n\nVERBATIM_HEADERS       = YES\n\n# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the\n# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the\n# cost of reduced performance. This can be particularly helpful with template\n# rich C++ code for which doxygen's built-in parser lacks the necessary type\n# information.\n# Note: The availability of this option depends on whether or not doxygen was\n# compiled with the --with-libclang option.\n# The default value is: NO.\n\nCLANG_ASSISTED_PARSING = YES\n\n# If clang assisted parsing is enabled you can provide the compiler with command\n# line options that you would normally use when invoking the compiler. Note that\n# the include paths will already be set by doxygen for the files and directories\n# specified with INPUT and INCLUDE_PATH.\n# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.\n\nCLANG_OPTIONS          = \n\n#---------------------------------------------------------------------------\n# Configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all\n# compounds will be generated. Enable this if the project contains a lot of\n# classes, structs, unions or interfaces.\n# The default value is: YES.\n\nALPHABETICAL_INDEX     = YES\n\n# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in\n# which the alphabetical index list will be split.\n# Minimum value: 1, maximum value: 20, default value: 5.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nCOLS_IN_ALPHA_INDEX    = 5\n\n# In case all classes in a project start with a common prefix, all classes will\n# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag\n# can be used to specify a prefix (or a list of prefixes) that should be ignored\n# while generating the index headers.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nIGNORE_PREFIX          = \n\n#---------------------------------------------------------------------------\n# Configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output\n# The default value is: YES.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each\n# generated HTML page (for example: .htm, .php, .asp).\n# The default value is: .html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a user-defined HTML header file for\n# each generated HTML page. If the tag is left blank doxygen will generate a\n# standard header.\n#\n# To get valid HTML the header file that includes any scripts and style sheets\n# that doxygen needs, which is dependent on the configuration options used (e.g.\n# the setting GENERATE_TREEVIEW). It is highly recommended to start with a\n# default header using\n# doxygen -w html new_header.html new_footer.html new_stylesheet.css\n# YourConfigFile\n# and then modify the file new_header.html. See also section \"Doxygen usage\"\n# for information on how to generate the default header that doxygen normally\n# uses.\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. For a description\n# of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_HEADER            = \n\n# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each\n# generated HTML page. If the tag is left blank doxygen will generate a standard\n# footer. See HTML_HEADER for more information on how to generate a default\n# footer and what special commands can be used inside the footer. See also\n# section \"Doxygen usage\" for information on how to generate the default footer\n# that doxygen normally uses.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FOOTER            = \n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style\n# sheet that is used by each HTML page. It can be used to fine-tune the look of\n# the HTML output. If left blank doxygen will generate a default style sheet.\n# See also section \"Doxygen usage\" for information on how to generate the style\n# sheet that doxygen normally uses.\n# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as\n# it is more robust and this tag (HTML_STYLESHEET) will in the future become\n# obsolete.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_STYLESHEET        = \n\n# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# cascading style sheets that are included after the standard style sheets\n# created by doxygen. Using this option one can overrule certain style aspects.\n# This is preferred over using HTML_STYLESHEET since it does not replace the\n# standard style sheet and is therefor more robust against future updates.\n# Doxygen will copy the style sheet files to the output directory.\n# Note: The order of the extra stylesheet files is of importance (e.g. the last\n# stylesheet in the list overrules the setting of the previous ones in the\n# list). For an example see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_STYLESHEET  = docs/manual.css\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that the\n# files will be copied as-is; there are no commands or markers available.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_FILES       = \n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen\n# will adjust the colors in the stylesheet and background images according to\n# this color. Hue is specified as an angle on a colorwheel, see\n# http://en.wikipedia.org/wiki/Hue for more information. For instance the value\n# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300\n# purple, and 360 is red again.\n# Minimum value: 0, maximum value: 359, default value: 220.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_HUE    = 236\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors\n# in the HTML output. For a value of 0 the output will use grayscales only. A\n# value of 255 will produce the most vivid colors.\n# Minimum value: 0, maximum value: 255, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_SAT    = 0\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the\n# luminance component of the colors in the HTML output. Values below 100\n# gradually make the output lighter, whereas values above 100 make the output\n# darker. The value divided by 100 is the actual gamma applied, so 80 represents\n# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not\n# change the gamma.\n# Minimum value: 40, maximum value: 240, default value: 80.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_GAMMA  = 148\n\n# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\n# page will contain the date and time when the page was generated. Setting this\n# to NO can help when comparing the output of multiple runs.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_TIMESTAMP         = NO\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries\n# shown in the various tree structured indices initially; the user can expand\n# and collapse entries dynamically later on. Doxygen will expand the tree to\n# such a level that at most the specified number of entries are visible (unless\n# a fully collapsed tree already exceeds this amount). So setting the number of\n# entries 1 will produce a full collapsed tree by default. 0 is a special value\n# representing an infinite number of entries and will result in a full expanded\n# tree by default.\n# Minimum value: 0, maximum value: 9999, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_INDEX_NUM_ENTRIES = 100\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files will be\n# generated that can be used as input for Apple's Xcode 3 integrated development\n# environment (see: http://developer.apple.com/tools/xcode/), introduced with\n# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a\n# Makefile in the HTML output directory. Running make will produce the docset in\n# that directory and running make install will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at\n# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html\n# for more information.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_DOCSET        = NO\n\n# This tag determines the name of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# The default value is: Doxygen generated docs.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# This tag specifies a string that should uniquely identify the documentation\n# set bundle. This should be a reverse domain-name style string, e.g.\n# com.mycompany.MyDocSet. Doxygen will append .docset to the name.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_BUNDLE_ID       = org.doxygen.Project\n\n# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n# The default value is: org.doxygen.Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_ID    = org.doxygen.Publisher\n\n# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.\n# The default value is: Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three\n# additional HTML index files: index.hhp, index.hhc, and index.hhk. The\n# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop\n# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on\n# Windows.\n#\n# The HTML Help Workshop contains a compiler that can convert all HTML output\n# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML\n# files are now used as the Windows 98 help format, and will replace the old\n# Windows help format (.hlp) on all Windows platforms in the future. Compressed\n# HTML files also contain an index, a table of contents, and you can search for\n# words in the documentation. The HTML workshop also contains a viewer for\n# compressed HTML files.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_HTMLHELP      = NO\n\n# The CHM_FILE tag can be used to specify the file name of the resulting .chm\n# file. You can add a path in front of the file if the result should not be\n# written to the html output directory.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_FILE               = \n\n# The HHC_LOCATION tag can be used to specify the location (absolute path\n# including file name) of the HTML help compiler ( hhc.exe). If non-empty\n# doxygen will try to run the HTML help compiler on the generated index.hhp.\n# The file has to be specified with full path.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nHHC_LOCATION           = \n\n# The GENERATE_CHI flag controls if a separate .chi index file is generated (\n# YES) or that it should be included in the master .chm file ( NO).\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nGENERATE_CHI           = NO\n\n# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)\n# and project file content.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_INDEX_ENCODING     = \n\n# The BINARY_TOC flag controls whether a binary table of contents is generated (\n# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it\n# enables the Previous and Next buttons.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members to\n# the table of contents of the HTML help documentation and to the tree view.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nTOC_EXPAND             = NO\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that\n# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help\n# (.qch) of the generated HTML documentation.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify\n# the file name of the resulting .qch file. The path specified is relative to\n# the HTML output folder.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQCH_FILE               = \n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help\n# Project output. For more information please see Qt Help Project / Namespace\n# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_NAMESPACE          = org.doxygen.Project\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt\n# Help Project output. For more information please see Qt Help Project / Virtual\n# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-\n# folders).\n# The default value is: doc.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom\n# filter to add. For more information please see Qt Help Project / Custom\n# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-\n# filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_NAME   = \n\n# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see Qt Help Project / Custom\n# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-\n# filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_ATTRS  = \n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's filter section matches. Qt Help Project / Filter Attributes (see:\n# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_SECT_FILTER_ATTRS  = \n\n# The QHG_LOCATION tag can be used to specify the location of Qt's\n# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the\n# generated .qhp file.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHG_LOCATION           = \n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be\n# generated, together with the HTML files, they form an Eclipse help plugin. To\n# install this plugin and make it available under the help contents menu in\n# Eclipse, the contents of the directory containing the HTML and XML files needs\n# to be copied into the plugins directory of eclipse. The name of the directory\n# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.\n# After copying Eclipse needs to be restarted before the help appears.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the Eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have this\n# name. Each documentation set should have its own identifier.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# If you want full control over the layout of the generated HTML pages it might\n# be necessary to disable the index and replace it with your own. The\n# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top\n# of each HTML page. A value of NO enables the index and the value YES disables\n# it. Since the tabs in the index contain the same information as the navigation\n# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nDISABLE_INDEX          = NO\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information. If the tag\n# value is set to YES, a side panel will be generated containing a tree-like\n# index structure (just like the one that is generated for HTML Help). For this\n# to work a browser that supports JavaScript, DHTML, CSS and frames is required\n# (i.e. any modern browser). Windows users are probably better off using the\n# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can\n# further fine-tune the look of the index. As an example, the default style\n# sheet generated by doxygen has an example that shows how to put an image at\n# the root of the tree instead of the PROJECT_NAME. Since the tree basically has\n# the same information as the tab index, you could consider setting\n# DISABLE_INDEX to YES when enabling this option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_TREEVIEW      = NO\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that\n# doxygen will group on one line in the generated HTML documentation.\n#\n# Note that a value of 0 will completely suppress the enum values from appearing\n# in the overview section.\n# Minimum value: 0, maximum value: 20, default value: 4.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nENUM_VALUES_PER_LINE   = 4\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used\n# to set the initial width (in pixels) of the frame in which the tree is shown.\n# Minimum value: 0, maximum value: 1500, default value: 250.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nTREEVIEW_WIDTH         = 250\n\n# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to\n# external symbols imported via tag files in a separate window.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# Use this tag to change the font size of LaTeX formulas included as images in\n# the HTML documentation. When you change the font size after a successful\n# doxygen run you need to manually remove any form_*.png images from the HTML\n# output directory to force them to be regenerated.\n# Minimum value: 8, maximum value: 50, default value: 10.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_FONTSIZE       = 10\n\n# Use the FORMULA_TRANPARENT tag to determine whether or not the images\n# generated for formulas are transparent PNGs. Transparent PNGs are not\n# supported properly for IE 6.0, but are supported on all modern browsers.\n#\n# Note that when changing this option you need to delete any form_*.png files in\n# the HTML output directory before the changes have effect.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_TRANSPARENT    = YES\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see\n# http://www.mathjax.org) which uses client side Javascript for the rendering\n# instead of using prerendered bitmaps. Use this if you do not have LaTeX\n# installed or if you want to formulas look prettier in the HTML output. When\n# enabled you may also need to install MathJax separately and configure the path\n# to it using the MATHJAX_RELPATH option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nUSE_MATHJAX            = NO\n\n# When MathJax is enabled you can set the default output format to be used for\n# the MathJax output. See the MathJax site (see:\n# http://docs.mathjax.org/en/latest/output.html) for more details.\n# Possible values are: HTML-CSS (which is slower, but has the best\n# compatibility), NativeMML (i.e. MathML) and SVG.\n# The default value is: HTML-CSS.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_FORMAT         = HTML-CSS\n\n# When MathJax is enabled you need to specify the location relative to the HTML\n# output directory using the MATHJAX_RELPATH option. The destination directory\n# should contain the MathJax.js script. For instance, if the mathjax directory\n# is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax\n# Content Delivery Network so you can quickly see the result without installing\n# MathJax. However, it is strongly recommended to install a local copy of\n# MathJax from http://www.mathjax.org before deployment.\n# The default value is: http://cdn.mathjax.org/mathjax/latest.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest\n\n# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax\n# extension names that should be enabled during MathJax rendering. For example\n# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_EXTENSIONS     = \n\n# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces\n# of code that will be used on startup of the MathJax code. See the MathJax site\n# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an\n# example see the documentation.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_CODEFILE       = \n\n# When the SEARCHENGINE tag is enabled doxygen will generate a search box for\n# the HTML output. The underlying search engine uses javascript and DHTML and\n# should work on any modern browser. Note that when using HTML help\n# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)\n# there is already a search function so this one should typically be disabled.\n# For large projects the javascript based search engine can be slow, then\n# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to\n# search using the keyboard; to jump to the search box use <access key> + S\n# (what the <access key> is depends on the OS and browser, but it is typically\n# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down\n# key> to jump into the search results window, the results can be navigated\n# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel\n# the search. The filter options can be selected when the cursor is inside the\n# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>\n# to select a filter and <Enter> or <escape> to activate or cancel the filter\n# option.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSEARCHENGINE           = YES\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a web server instead of a web client using Javascript. There\n# are two flavors of web server based searching depending on the EXTERNAL_SEARCH\n# setting. When disabled, doxygen will generate a PHP script for searching and\n# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing\n# and searching needs to be provided by external tools. See the section\n# \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSERVER_BASED_SEARCH    = NO\n\n# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP\n# script for searching. Instead the search results are written to an XML file\n# which needs to be processed by an external indexer. Doxygen will invoke an\n# external search engine pointed to by the SEARCHENGINE_URL option to obtain the\n# search results.\n#\n# Doxygen ships with an example indexer ( doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see: http://xapian.org/).\n#\n# See the section \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH        = NO\n\n# The SEARCHENGINE_URL should point to a search engine hosted by a web server\n# which will return the search results when EXTERNAL_SEARCH is enabled.\n#\n# Doxygen ships with an example indexer ( doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see: http://xapian.org/). See the section \"External Indexing and\n# Searching\" for details.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHENGINE_URL       = \n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed\n# search data is written to a file for indexing by an external tool. With the\n# SEARCHDATA_FILE tag the name of this file can be specified.\n# The default file is: searchdata.xml.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHDATA_FILE        = searchdata.xml\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the\n# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is\n# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple\n# projects and redirect the results back to the right project.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH_ID     = \n\n# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen\n# projects other than the one defined by this configuration file, but that are\n# all added to the same external search index. Each project needs to have a\n# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of\n# to a relative location where the documentation can be found. The format is:\n# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTRA_SEARCH_MAPPINGS  = \n\n#---------------------------------------------------------------------------\n# Configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.\n# The default value is: YES.\n\nGENERATE_LATEX         = YES\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked.\n#\n# Note that when enabling USE_PDFLATEX this option is only used for generating\n# bitmaps for formulas in the HTML output, but not in the Makefile that is\n# written to the output directory.\n# The default file is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate\n# index for LaTeX.\n# The default file is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used by the\n# printer.\n# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x\n# 14 inches) and executive (7.25 x 10.5 inches).\n# The default value is: a4.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPAPER_TYPE             = a4\n\n# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names\n# that should be included in the LaTeX output. To get the times font for\n# instance you can specify\n# EXTRA_PACKAGES=times\n# If left blank no extra packages will be included.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nEXTRA_PACKAGES         = \n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the\n# generated LaTeX document. The header should contain everything until the first\n# chapter. If it is left blank doxygen will generate a standard header. See\n# section \"Doxygen usage\" for information on how to let doxygen write the\n# default header to a separate file.\n#\n# Note: Only use a user-defined header if you know what you are doing! The\n# following commands have a special meaning inside the header: $title,\n# $datetime, $date, $doxygenversion, $projectname, $projectnumber,\n# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,\n# for the replacement values of the other commands the user is refered to\n# HTML_HEADER.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HEADER           = \n\n# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the\n# generated LaTeX document. The footer should contain everything after the last\n# chapter. If it is left blank doxygen will generate a standard footer. See\n# LATEX_HEADER for more information on how to generate a default footer and what\n# special commands can be used inside the footer.\n#\n# Note: Only use a user-defined footer if you know what you are doing!\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_FOOTER           = \n\n# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the LATEX_OUTPUT output\n# directory. Note that the files will be copied as-is; there are no commands or\n# markers available.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_FILES      = \n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is\n# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will\n# contain links (just like the HTML output) instead of page references. This\n# makes the output suitable for online browsing using a PDF viewer.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPDF_HYPERLINKS         = YES\n\n# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate\n# the PDF file directly from the LaTeX files. Set this option to YES to get a\n# higher quality PDF documentation.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nUSE_PDFLATEX           = YES\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode\n# command to the generated LaTeX files. This will instruct LaTeX to keep running\n# if errors occur, instead of asking the user for help. This option is also used\n# when generating formulas in HTML.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BATCHMODE        = NO\n\n# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the\n# index chapters (such as File Index, Compound Index, etc.) in the output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HIDE_INDICES     = NO\n\n# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source\n# code with syntax highlighting in the LaTeX output.\n#\n# Note that which sources are shown also depends on other settings such as\n# SOURCE_BROWSER.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_SOURCE_CODE      = NO\n\n# The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n# bibliography, e.g. plainnat, or ieeetr. See\n# http://en.wikipedia.org/wiki/BibTeX and \\cite for more info.\n# The default value is: plain.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BIB_STYLE        = plain\n\n#---------------------------------------------------------------------------\n# Configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The\n# RTF output is optimized for Word 97 and may not look too pretty with other RTF\n# readers/editors.\n# The default value is: NO.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: rtf.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will\n# contain hyperlink fields. The RTF file will contain links (just like the HTML\n# output) instead of page references. This makes the output suitable for online\n# browsing using Word or some other Word compatible readers that support those\n# fields.\n#\n# Note: WordPad (write) and others do not support links.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's config\n# file, i.e. a series of assignments. You only have to provide replacements,\n# missing definitions are set to their default value.\n#\n# See also section \"Doxygen usage\" for information on how to generate the\n# default style sheet that doxygen normally uses.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_STYLESHEET_FILE    = \n\n# Set optional variables used in the generation of an RTF document. Syntax is\n# similar to doxygen's config file. A template extensions file can be generated\n# using doxygen -e rtf extensionFile.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_EXTENSIONS_FILE    = \n\n#---------------------------------------------------------------------------\n# Configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for\n# classes and files.\n# The default value is: NO.\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it. A directory man3 will be created inside the directory specified by\n# MAN_OUTPUT.\n# The default directory is: man.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to the generated\n# man pages. In case the manual section does not start with a number, the number\n# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is\n# optional.\n# The default value is: .3.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_EXTENSION          = .3\n\n# The MAN_SUBDIR tag determines the name of the directory created within\n# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by\n# MAN_EXTENSION with the initial . removed.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_SUBDIR             = \n\n# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it\n# will generate one additional man file for each entity documented in the real\n# man page(s). These additional files only source the real man page, but without\n# them the man command would be unable to find the correct page.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that\n# captures the structure of the code including all documentation.\n# The default value is: NO.\n\nGENERATE_XML           = NO\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: xml.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_OUTPUT             = xml\n\n# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program\n# listings (including syntax highlighting and cross-referencing information) to\n# the XML output. Note that enabling this will significantly increase the size\n# of the XML output.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_PROGRAMLISTING     = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the DOCBOOK output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files\n# that can be used to generate PDF.\n# The default value is: NO.\n\nGENERATE_DOCBOOK       = NO\n\n# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in\n# front of it.\n# The default directory is: docbook.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_OUTPUT         = docbook\n\n# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the\n# program listings (including syntax highlighting and cross-referencing\n# information) to the DOCBOOK output. Note that enabling this will significantly\n# increase the size of the DOCBOOK output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_PROGRAMLISTING = NO\n\n#---------------------------------------------------------------------------\n# Configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen\n# Definitions (see http://autogen.sf.net) file that captures the structure of\n# the code including all documentation. Note that this feature is still\n# experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module\n# file that captures the structure of the code including all documentation.\n#\n# Note that this feature is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary\n# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI\n# output from the Perl module output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely\n# formatted so it can be parsed by a human reader. This is useful if you want to\n# understand what is going on. On the other hand, if this tag is set to NO the\n# size of the Perl module output will be much smaller and Perl will parse it\n# just the same.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file are\n# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful\n# so different doxyrules.make files included by the same Makefile don't\n# overwrite each other's variables.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_MAKEVAR_PREFIX = \n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all\n# C-preprocessor directives found in the sources and include files.\n# The default value is: YES.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names\n# in the source code. If set to NO only conditional compilation will be\n# performed. Macro expansion can be done in a controlled way by setting\n# EXPAND_ONLY_PREDEF to YES.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nMACRO_EXPANSION        = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then\n# the macro expansion is limited to the macros specified with the PREDEFINED and\n# EXPAND_AS_DEFINED tags.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES the includes files in the\n# INCLUDE_PATH will be searched if a #include is found.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by the\n# preprocessor.\n# This tag requires that the tag SEARCH_INCLUDES is set to YES.\n\nINCLUDE_PATH           = \n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will be\n# used.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nINCLUDE_FILE_PATTERNS  = \n\n# The PREDEFINED tag can be used to specify one or more macro names that are\n# defined before the preprocessor is started (similar to the -D option of e.g.\n# gcc). The argument of the tag is a list of macros of the form: name or\n# name=definition (no spaces). If the definition and the \"=\" are omitted, \"=1\"\n# is assumed. To prevent a macro definition from being undefined via #undef or\n# recursively expanded use the := operator instead of the = operator.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nPREDEFINED             = \n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this\n# tag can be used to specify a list of macro names that should be expanded. The\n# macro definition that is found in the sources will be used. Use the PREDEFINED\n# tag if you want to use a different macro definition that overrules the\n# definition found in the source code.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_AS_DEFINED      = \n\n# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will\n# remove all references to function-like macros that are alone on a line, have\n# an all uppercase name, and do not end with a semicolon. Such function macros\n# are typically used for boiler-plate code, and will confuse the parser if not\n# removed.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES tag can be used to specify one or more tag files. For each tag\n# file the location of the external documentation should be added. The format of\n# a tag file without this location is as follows:\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where loc1 and loc2 can be relative or absolute paths or URLs. See the\n# section \"Linking to external documentation\" for more information about the use\n# of tag files.\n# Note: Each tag file must have a unique name (where the name does NOT include\n# the path). If a tag file is not located in the directory in which doxygen is\n# run, you must also specify the path to the tagfile here.\n\nTAGFILES               = \n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create a\n# tag file that is based on the input files it reads. See section \"Linking to\n# external documentation\" for more information about the usage of tag files.\n\nGENERATE_TAGFILE       = \n\n# If the ALLEXTERNALS tag is set to YES all external class will be listed in the\n# class index. If set to NO only the inherited external classes will be listed.\n# The default value is: NO.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in\n# the modules index. If set to NO, only the current project's groups will be\n# listed.\n# The default value is: YES.\n\nEXTERNAL_GROUPS        = YES\n\n# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in\n# the related pages index. If set to NO, only the current project's pages will\n# be listed.\n# The default value is: YES.\n\nEXTERNAL_PAGES         = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script\n# interpreter (i.e. the result of 'which perl').\n# The default file (with absolute path) is: /usr/bin/perl.\n\nPERL_PATH              = /usr/bin/perl\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool\n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram\n# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to\n# NO turns the diagrams off. Note that this option also works with HAVE_DOT\n# disabled, but it is recommended to install and use dot, since it yields more\n# powerful graphs.\n# The default value is: YES.\n\nCLASS_DIAGRAMS         = YES\n\n# You can define message sequence charts within doxygen comments using the \\msc\n# command. Doxygen will then run the mscgen tool (see:\n# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the\n# documentation. The MSCGEN_PATH tag allows you to specify the directory where\n# the mscgen tool resides. If left empty the tool is assumed to be found in the\n# default search path.\n\nMSCGEN_PATH            = \n\n# You can include diagrams made with dia in doxygen documentation. Doxygen will\n# then run dia to produce the diagram and insert it in the documentation. The\n# DIA_PATH tag allows you to specify the directory where the dia binary resides.\n# If left empty dia is assumed to be found in the default search path.\n\nDIA_PATH               = \n\n# If set to YES, the inheritance and collaboration graphs will hide inheritance\n# and usage relations if the target is undocumented or is not a class.\n# The default value is: YES.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz (see:\n# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent\n# Bell Labs. The other options in this section have no effect if this option is\n# set to NO\n# The default value is: NO.\n\nHAVE_DOT               = NO\n\n# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed\n# to run in parallel. When set to 0 doxygen will base this on the number of\n# processors available in the system. You can set it explicitly to a value\n# larger than 0 to get control over the balance between CPU load and processing\n# speed.\n# Minimum value: 0, maximum value: 32, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NUM_THREADS        = 0\n\n# When you want a differently looking font in the dot files that doxygen\n# generates you can specify the font name using DOT_FONTNAME. You need to make\n# sure dot is able to find the font, which can be done by putting it in a\n# standard location or by setting the DOTFONTPATH environment variable or by\n# setting DOT_FONTPATH to the directory containing the font.\n# The default value is: Helvetica.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTNAME           = Helvetica\n\n# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of\n# dot graphs.\n# Minimum value: 4, maximum value: 24, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTSIZE           = 10\n\n# By default doxygen will tell dot to use the default font as specified with\n# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set\n# the path where dot can find it using this tag.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTPATH           = \n\n# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for\n# each documented class showing the direct and indirect inheritance relations.\n# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a\n# graph for each documented class showing the direct and indirect implementation\n# dependencies (inheritance, containment, and class references variables) of the\n# class with other documented classes.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for\n# groups, showing the direct groups dependencies.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LOOK               = NO\n\n# If the UML_LOOK tag is enabled, the fields and methods are shown inside the\n# class node. If there are many fields or methods and many nodes the graph may\n# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the\n# number of items for each type to make the size more manageable. Set this to 0\n# for no limit. Note that the threshold may be exceeded by 50% before the limit\n# is enforced. So when you set the threshold to 10, up to 15 fields may appear,\n# but if the number exceeds 15, the total amount of fields shown is limited to\n# 10.\n# Minimum value: 0, maximum value: 100, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LIMIT_NUM_FIELDS   = 10\n\n# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and\n# collaboration graphs will show the relations between templates and their\n# instances.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to\n# YES then doxygen will generate a graph for each documented file showing the\n# direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDE_GRAPH          = YES\n\n# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are\n# set to YES then doxygen will generate a graph for each documented file showing\n# the direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH tag is set to YES then doxygen will generate a call\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable call graphs for selected\n# functions only using the \\callgraph command.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALL_GRAPH             = NO\n\n# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable caller graphs for selected\n# functions only using the \\callergraph command.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALLER_GRAPH           = NO\n\n# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical\n# hierarchy of all classes instead of a textual one.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the\n# dependencies a directory has on other directories in a graphical way. The\n# dependency relations are determined by the #include relations between the\n# files in the directories.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDIRECTORY_GRAPH        = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot.\n# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order\n# to make the SVG files visible in IE 9+ (other browsers do not have this\n# requirement).\n# Possible values are: png, jpg, gif and svg.\n# The default value is: png.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_IMAGE_FORMAT       = png\n\n# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n# enable generation of interactive SVG images that allow zooming and panning.\n#\n# Note that this requires a modern browser other than Internet Explorer. Tested\n# and working are Firefox, Chrome, Safari, and Opera.\n# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make\n# the SVG files visible. Older versions of IE do not have SVG support.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINTERACTIVE_SVG        = NO\n\n# The DOT_PATH tag can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_PATH               = \n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the \\dotfile\n# command).\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOTFILE_DIRS           = \n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the \\mscfile\n# command).\n\nMSCFILE_DIRS           = \n\n# The DIAFILE_DIRS tag can be used to specify one or more directories that\n# contain dia files that are included in the documentation (see the \\diafile\n# command).\n\nDIAFILE_DIRS           = \n\n# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the\n# path where java can find the plantuml.jar file. If left blank, it is assumed\n# PlantUML is not used or called during a preprocessing step. Doxygen will\n# generate a warning when it encounters a \\startuml command in this case and\n# will not generate output for the diagram.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nPLANTUML_JAR_PATH      = \n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes\n# that will be shown in the graph. If the number of nodes in a graph becomes\n# larger than this value, doxygen will truncate the graph, which is visualized\n# by representing a node as a red box. Note that doxygen if the number of direct\n# children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that\n# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n# Minimum value: 0, maximum value: 10000, default value: 50.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_GRAPH_MAX_NODES    = 50\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs\n# generated by dot. A depth value of 3 means that only nodes reachable from the\n# root by following a path via at most 3 edges will be shown. Nodes that lay\n# further from the root node will be omitted. Note that setting this option to 1\n# or 2 may greatly reduce the computation time needed for large code bases. Also\n# note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n# Minimum value: 0, maximum value: 1000, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nMAX_DOT_GRAPH_DEPTH    = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent\n# background. This is disabled by default, because dot on Windows does not seem\n# to support this out of the box.\n#\n# Warning: Depending on the platform used, enabling this option may lead to\n# badly anti-aliased labels on the edges of a graph (i.e. they become hard to\n# read).\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_TRANSPARENT        = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10) support\n# this, this feature is disabled by default.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page\n# explaining the meaning of the various boxes and arrows in the dot generated\n# graphs.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot\n# files that are used to generate the various graphs.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_CLEANUP            = YES\n"
  },
  {
    "path": "SConstruct",
    "content": "import os, sys, commands\nenv = Environment(ENV = os.environ)\n\n# figure out a better way to configure this\nif os.environ.has_key('CXX'):\n    env['CXX'] = os.environ['CXX']\n\nif os.environ.has_key('DEBUG'):\n    env['DEBUG'] = os.environ['DEBUG']\n\nif os.environ.has_key('CXXFLAGS'):\n    #env['CXXFLAGS'] = os.environ['CXXFLAGS']\n    env.Append(CXXFLAGS = os.environ['CXXFLAGS'])\n\nif os.environ.has_key('LINKFLAGS'):\n    #env['LDFLAGS'] = os.environ['LDFLAGS']\n    env.Append(LINKFLAGS = os.environ['LINKFLAGS'])\n\n## Boost\n##\n## Note: You need to either set BOOSTROOT to the root of a stock Boost distribution\n## or set BOOST_INCLUDES and BOOST_LIBS if Boost comes with your OS distro e.g. and\n## needs BOOST_INCLUDES=/usr/include/boost and BOOST_LIBS=/usr/lib like Ubuntu.\n##\nif os.environ.has_key('BOOSTROOT'):\n    os.environ['BOOST_ROOT'] = os.environ['BOOSTROOT']\n\nif os.environ.has_key('BOOST_ROOT'):\n   env['BOOST_INCLUDES'] = os.environ['BOOST_ROOT']\n   env['BOOST_LIBS'] = os.path.join(os.environ['BOOST_ROOT'], 'stage', 'lib')\nelif os.environ.has_key('BOOST_INCLUDES') and os.environ.has_key('BOOST_LIBS'):\n   env['BOOST_INCLUDES'] = os.environ['BOOST_INCLUDES']\n   env['BOOST_LIBS'] = os.environ['BOOST_LIBS']\nelse:\n   raise SCons.Errors.UserError, \"Neither BOOST_ROOT, nor BOOST_INCLUDES + BOOST_LIBS was set!\"\n\n## Custom OpenSSL\nif os.environ.has_key('OPENSSL_PATH'):\n   env.Append(CPPPATH = os.path.join(os.environ['OPENSSL_PATH'], 'include'))\n   env.Append(LIBPATH = os.environ['OPENSSL_PATH'])\n\nif os.environ.has_key('WSPP_ENABLE_CPP11'):\n   env['WSPP_ENABLE_CPP11'] = True\nelse:\n   env['WSPP_ENABLE_CPP11'] = False\n\nboost_linkshared = False\n\ndef boostlibs(libnames,localenv):\n   if localenv['PLATFORM'].startswith('win'):\n      # Win/VC++ supports autolinking. nothing to do.\n      # http://www.boost.org/doc/libs/1_49_0/more/getting_started/windows.html#auto-linking\n      return []\n   else:\n      libs = []\n      prefix = localenv['SHLIBPREFIX'] if boost_linkshared else localenv['LIBPREFIX']\n      suffix = localenv['SHLIBSUFFIX'] if boost_linkshared else localenv['LIBSUFFIX']\n      for name in libnames:\n         lib = File(os.path.join(localenv['BOOST_LIBS'], '%sboost_%s%s' % (prefix, name, suffix)))\n         libs.append(lib)\n      return libs\n\nif env['PLATFORM'].startswith('win'):\n   env.Append(CPPDEFINES = ['WIN32',\n                            'NDEBUG',\n                            'WIN32_LEAN_AND_MEAN',\n                            '_WIN32_WINNT=0x0600',\n                            '_CONSOLE',\n                            'BOOST_TEST_DYN_LINK',\n                            'NOMINMAX',\n                            '_WEBSOCKETPP_CPP11_MEMORY_',\n                            '_WEBSOCKETPP_CPP11_FUNCTIONAL_'])\n   arch_flags  = '/arch:SSE2'\n   opt_flags   = '/Ox /Oi /fp:fast'\n   warn_flags  = '/W3 /wd4996 /wd4995 /wd4355'\n   env['CCFLAGS'] = '%s /EHsc /GR /GS- /MD /nologo %s %s' % (warn_flags, arch_flags, opt_flags)\n   env['LINKFLAGS'] = '/INCREMENTAL:NO /MANIFEST /NOLOGO /OPT:REF /OPT:ICF /MACHINE:X86'\nelif env['PLATFORM'] == 'posix':\n   if env.has_key('DEBUG'):\n      env.Append(CCFLAGS = ['-g', '-O0'])\n   else:\n      env.Append(CPPDEFINES = ['NDEBUG'])\n      env.Append(CCFLAGS = ['-O1', '-fomit-frame-pointer'])\n   env.Append(CCFLAGS = ['-Wall'])\n   #env['LINKFLAGS'] = ''\nelif env['PLATFORM'] == 'darwin':\n   if not os.environ.has_key('CXX'):\n      env['CXX'] = \"clang++\"\n   if env.has_key('DEBUG'):\n      env.Append(CCFLAGS = ['-g', '-O0'])\n   else:\n      env.Append(CPPDEFINES = ['NDEBUG'])\n      env.Append(CCFLAGS = ['-O1', '-fomit-frame-pointer'])\n   env.Append(CCFLAGS = ['-Wall'])\n   #env['LINKFLAGS'] = ''\n\nif env['PLATFORM'].startswith('win'):\n   #env['LIBPATH'] = env['BOOST_LIBS']\n   pass\nelse:\n   env.Append(LIBPATH = ['/usr/lib', '/usr/local/lib'])\n\n# Compiler specific warning flags\nif env['CXX'].startswith('g++'):\n   #env.Append(CCFLAGS = ['-Wconversion'])\n   env.Append(CCFLAGS = ['-Wcast-align'])\n   env.Append(CCFLAGS = ['-Wshadow'])\n   env.Append(CCFLAGS = ['-Wunused-parameter'])\nelif env['CXX'].startswith('clang++'):\n   #env.Append(CCFLAGS = ['-Wcast-align'])\n   #env.Append(CCFLAGS = ['-Wglobal-constructors'])\n   #env.Append(CCFLAGS = ['-Wconversion'])\n   env.Append(CCFLAGS = ['-Wno-padded'])\n   env.Append(CCFLAGS = ['-Wshadow'])\n   env.Append(CCFLAGS = ['-Wunused-parameter'])\n\n   env.Append(CCFLAGS = ['-Wsometimes-uninitialized'])\n   env.Append(CCFLAGS = ['-Wuninitialized'])\n\n   #env.Append(CCFLAGS = ['-Weverything'])\n   #env.Append(CCFLAGS = ['-Wno-documentation'])\n   #env.Append(CCFLAGS = ['-Wno-weak-vtables'])\n   #env.Append(CCFLAGS = ['-Wno-global-constructors'])\n   #env.Append(CCFLAGS = ['-Wno-sign-conversion'])\n   #env.Append(CCFLAGS = ['-Wno-exit-time-destructors'])\n\n\n\n\n   # Wpadded\n   # Wsign-conversion\n   #\n\nplatform_libs = []\ntls_libs = []\n\ntls_build = False\n\nif env['PLATFORM'] == 'posix':\n   platform_libs = ['pthread', 'rt']\n   tls_libs = ['ssl', 'crypto']\n   tls_build = True\nelif env['PLATFORM'] == 'darwin':\n   tls_libs = ['ssl', 'crypto']\n   tls_build = True\nelif env['PLATFORM'].startswith('win'):\n   # Win/VC++ supports autolinking. nothing to do.\n   pass\n\n## Append WebSocket++ path\nenv.Append(CPPPATH = ['#'])\n\n##### Set up C++11 environment\npolyfill_libs = [] # boost libraries used as drop in replacements for incomplete\n                   # C++11 STL implementations\nenv_cpp11 = env.Clone ()\n\nif env_cpp11['CXX'].startswith('g++'):\n   # TODO: check g++ version\n   GCC_VERSION = commands.getoutput(env_cpp11['CXX'] + ' -dumpversion')\n\n   if GCC_VERSION > \"4.4.0\":\n      print \"C++11 build environment partially enabled\"\n      env_cpp11.Append(WSPP_CPP11_ENABLED = \"true\",CXXFLAGS = ['-std=c++0x'],TOOLSET = ['g++'],CPPDEFINES = ['_WEBSOCKETPP_CPP11_STL_'])\n   else:\n      print \"C++11 build environment is not supported on this version of G++\"\nelif env_cpp11['CXX'].startswith('clang++'):\n   print \"C++11 build environment enabled\"\n   env.Append(CXXFLANGS = ['-stdlib=libc++'],LINKFLAGS=['-stdlib=libc++'])\n   env_cpp11.Append(WSPP_CPP11_ENABLED = \"true\",CXXFLAGS = ['-std=c++0x','-stdlib=libc++'],LINKFLAGS = ['-stdlib=libc++'],TOOLSET = ['clang++'],CPPDEFINES = ['_WEBSOCKETPP_CPP11_STL_'])\n\n   # look for optional second boostroot compiled with clang's libc++ STL library\n   # this prevents warnings/errors when linking code built with two different\n   # incompatible STL libraries.\n   if os.environ.has_key('BOOST_ROOT_CPP11'):\n      env_cpp11['BOOST_INCLUDES'] = os.environ['BOOST_ROOT_CPP11']\n      env_cpp11['BOOST_LIBS'] = os.path.join(os.environ['BOOST_ROOT_CPP11'], 'stage', 'lib')\n   elif os.environ.has_key('BOOST_INCLUDES_CPP11') and os.environ.has_key('BOOST_LIBS_CPP11'):\n      env_cpp11['BOOST_INCLUDES'] = os.environ['BOOST_INCLUDES_CPP11']\n      env_cpp11['BOOST_LIBS'] = os.environ['BOOST_LIBS_CPP11']\nelse:\n   print \"C++11 build environment disabled\"\n\n# if the build system is known to allow the isystem modifier for library include\n# values then use it for the boost libraries. Otherwise just add them to the\n# regular CPPPATH values.\nif env['CXX'].startswith('g++') or env['CXX'].startswith('clang'):\n    env.Append(CPPFLAGS = '-isystem ' + env['BOOST_INCLUDES'])\nelse:\n    env.Append(CPPPATH = [env['BOOST_INCLUDES']])\nenv.Append(LIBPATH = [env['BOOST_LIBS']])\n\n# if the build system is known to allow the isystem modifier for library include\n# values then use it for the boost libraries. Otherwise just add them to the\n# regular CPPPATH values.\nif env_cpp11['CXX'].startswith('g++') or env_cpp11['CXX'].startswith('clang'):\n    env_cpp11.Append(CPPFLAGS = '-isystem ' + env_cpp11['BOOST_INCLUDES'])\nelse:\n    env_cpp11.Append(CPPPATH = [env_cpp11['BOOST_INCLUDES']])\nenv_cpp11.Append(LIBPATH = [env_cpp11['BOOST_LIBS']])\n\nreleasedir = 'build/release/'\ndebugdir = 'build/debug/'\ntestdir = 'build/test/'\nbuilddir = releasedir\n\nExport('env')\nExport('env_cpp11')\nExport('platform_libs')\nExport('boostlibs')\nExport('tls_libs')\nExport('polyfill_libs')\n\n## END OF CONFIG !!\n\n## TARGETS:\n\nif not env['PLATFORM'].startswith('win'):\n    # Unit tests, add test folders with SConscript files to to_test list.\n    to_test = ['utility','http','logger','random','processors','message_buffer','extension','transport/iostream','transport/asio','roles','endpoint','connection','transport'] #,'http','processors','connection'\n\n    for t in to_test:\n       new_tests = SConscript('#/test/'+t+'/SConscript',variant_dir = testdir + t, duplicate = 0)\n       for a in new_tests:\n          new_alias = Alias('test', [a], a.abspath)\n          AlwaysBuild(new_alias)\n\n# Main test application\n#main = SConscript('#/examples/dev/SConscript',variant_dir = builddir + 'dev',duplicate = 0)\n\n# echo_server\necho_server = SConscript('#/examples/echo_server/SConscript',variant_dir = builddir + 'echo_server',duplicate = 0)\n\n# echo_client\necho_client = SConscript('#/examples/echo_client/SConscript',variant_dir = builddir + 'echo_client',duplicate = 0)\n\n# print_client\nprint_client = SConscript('#/examples/print_client/SConscript',variant_dir = builddir + 'print_client',duplicate = 0)\n\n# echo_server_tls\nif tls_build:\n    echo_server_tls = SConscript('#/examples/echo_server_tls/SConscript',variant_dir = builddir + 'echo_server_tls',duplicate = 0)\n    echo_server_both = SConscript('#/examples/echo_server_both/SConscript',variant_dir = builddir + 'echo_server_both',duplicate = 0)\n    print_client_tls = SConscript('#/examples/print_client_tls/SConscript',variant_dir = builddir + 'print_client_tls',duplicate = 0)\n\n# broadcast_server\nbroadcast_server = SConscript('#/examples/broadcast_server/SConscript',variant_dir = builddir + 'broadcast_server',duplicate = 0)\n\n# testee_server\ntestee_server = SConscript('#/examples/testee_server/SConscript',variant_dir = builddir + 'testee_server',duplicate = 0)\n\n# testee_client\ntestee_client = SConscript('#/examples/testee_client/SConscript',variant_dir = builddir + 'testee_client',duplicate = 0)\n\n# scratch_client\nscratch_client = SConscript('#/examples/scratch_client/SConscript',variant_dir = builddir + 'scratch_client',duplicate = 0)\n\n# scratch_server\nscratch_server = SConscript('#/examples/scratch_server/SConscript',variant_dir = builddir + 'scratch_server',duplicate = 0)\n\n\n# debug_client\ndebug_client = SConscript('#/examples/debug_client/SConscript',variant_dir = builddir + 'debug_client',duplicate = 0)\n\n# debug_server\ndebug_server = SConscript('#/examples/debug_server/SConscript',variant_dir = builddir + 'debug_server',duplicate = 0)\n\n# subprotocol_server\nsubprotocol_server = SConscript('#/examples/subprotocol_server/SConscript',variant_dir = builddir + 'subprotocol_server',duplicate = 0)\n\n# telemetry_server\ntelemetry_server = SConscript('#/examples/telemetry_server/SConscript',variant_dir = builddir + 'telemetry_server',duplicate = 0)\n\n# external_io_service\nexternal_io_service = SConscript('#/examples/external_io_service/SConscript',variant_dir = builddir + 'external_io_service',duplicate = 0)\n\nif not env['PLATFORM'].startswith('win'):\n    # iostream_server\n    iostream_server = SConscript('#/examples/iostream_server/SConscript',variant_dir = builddir + 'iostream_server',duplicate = 0)\n\n    # telemetry_client\n    telemetry_client = SConscript('#/examples/telemetry_client/SConscript',variant_dir = builddir + 'telemetry_client',duplicate = 0)\n\n    # print_server\n    print_server = SConscript('#/examples/print_server/SConscript',variant_dir = builddir + 'print_server',duplicate = 0)\n"
  },
  {
    "path": "changelog.md",
    "content": "HEAD\n\n0.8.2 - 2020-04-19\n- Examples: Update print_client_tls example to remove use of deprecated\n  OpenSSL functions.\n- Compatibility: Removes the use of make_shared in a number of cases where\n  it would be incompatible with newer versions of ASIO. Thank you Stefan\n  Floeren for the patch. #810 #814 #862 #843 #794 #808\n- CMake: Update cmake installer to better handle dependencies when using\n  g++ on MacOS. Thank you Luca Palano for reporting and a patch. #831\n- CMake: Update cmake installer to use a variable for the include directory\n  improving the ability of the install to be customized. THank you Schrijvers\n  Luc and Gianfranco Costamanga for reporting and a patch. #842\n\n0.8.1 - 2018-07-16\nNote: This release does not change library behavior. It only corrects issues\nin the installer and test system.\n- Test Suite: Adjust test suite to match behavior introduced in 0.8.0. Thank\n  you Gianfranco Costamagna for reporting and a patch. #731\n- CMake: Update cmake installer to only install library files globally.\n  Thank you Gianfraco Costamanga for reporting and a patch. #732\n\n0.8.0 - 2018-07-12\n- Examples: Add `print_client` example. This demonstrates a minimal non-TLS\n  client that connects to a server and prints out the messages it receives.\n- Examples: Add `print_client_tls` example. This demonstrates a minimal TLS\n  client, including basic support via Asio+OpenSSL for certificate chain\n  and hostname verification.\n- Feature: Add getter for all headers to the HTTP parsers. This allows a\n  wrapping library to enumerate all headers to send upstream. Thank you Jupp\n  Müller for reporting and an initial pull request.\n- Improvement: Move the `socket_init_handler` to execute as a part of `init_asio`\n  rather than connection `pre_init`. This allows setting of socket options prior\n  to the bind/listen/accept system calls. Thank you ChristianRobl3D for\n  reporting #530.\n- Improvement: Timers in transport integration tests should only fail if their\n  own test times out, rather than any test. #643 Thank you Alex Korotkin for\n  reporting and a patch.\n- Improvement: Preserve transport layer error codes in more cases, particularly\n  during calls to `endpoint::listen`. #652 Thank you vadz for reporting and\n  patches.\n- Compatibility: Make sure the chrono library used by Boost/Asio is in sync\n  with what the websocketpp is using. Thank you Flow86 for reporting and a\n  patch.\n- Compatibility: Update `telemetry_client` to use a slightly more cross platform\n  method of sleeping. Should work on windows now. Thank you Meir Yanovich for\n  reporting.\n- Compatibility: Updated permessage-deflate support to reflect that the zlib\n  library does not actually support a sliding window size of 256 bits. \n  WebSocket++ will no longer negotiate 256 bit deflate windows. If the user\n  of the library tries to request a 256 bit window a 512 bit window will be\n  specified instead (This was the previous behavior). #596 #653 Thank you \n  Vinnie Falco and Gianfranco Costamagna for reporting.\n- Compatibility: Better error handling and logging in cases where extension\n  requests parse correctly but negotiation fails.\n- Compatibility: Removed custom handling of `SSL_R_SHORT_READ` error condition.\n  This error code no longer exists in modern versions of OpenSSL and causes\n  a build error. It wasn't being used for anything particularly important\n  (slightly improving error reporting) and there isn't a great replacement.\n  #599 Thank you Gianfranco Costamagna for reporting.\n- Compatibility: Add missing `<stdint>` headers. Fixes issues with g++ 5.4.0.\n  #638 Thank you Alex Korotkin for reporting and a patch.\n- Compatibility: Remove the use of `std::auto_ptr` and `std::binary_function`\n  from builds with C++11 or later. These features are deprecated and were\n  removed entirely in C++17. This change allows building WebSocket++ on\n  C++17 compilers. #592 Thank you Michal Fojtak for reporting and a patch\n- Compatibility: Add 1014 close code and adds missing descriptions for codes\n  1012 and 1013. #589 Thank you jbwdevries and ronneke1996 for reporting and\n  patches.\n- Compatibility: Add hooks to support `mingw-std-threads` C++11 thread and mutex\n  polyfill library as an alternative to Boost. #608 Thank you Peter Taylor for\n  reporting and an initial patch.\n- Compatibility: Changed the handshake connection token to 'Upgrade' from\n  'upgrade'. Technically this header is supposed to be processed case\n  insensitively. In practice, there are browsers (such as Edge) that don't do\n  this and they tend to use the uppercase value used as an example in RFC6455.\n  Thank you Johann Bauer for reporting and a patch. #727\n- Bug: Store loggers in shared pointers to avoid crashes related to connections\n  trying to write logs entries after their respective endpoint has been\n  deallocated. Thank you Thalhammer for reporting and Jupp Müller for the \n  patch. #539 #501\n- Bug: Change default listen backlog from 0 to `socket_base::max_connections`.\n  #549. Thank you derwassi and zwelab for reporting and na1pir for providing\n  access to hardware to debug the issue.\n- Bug: Fix a crash in the accept loop when `get_connection` fails. #551 Thank you\n  Walter Gray for a patch.\n- Bug/Documentation: Fix incorrect example code that used \n  `websocketpp::lib::error_code` instead of `websocketpp::exception`. Thank you\n  heretic13 for reporting\n- Bug: Fix uninitialized shared pointer in Asio transport test suite. #647\n  Thank you Alex Korotkin for reporting and a patch.\n- Bug: Fix a thread safety issue in the permessage-deflate extension that\n  caused message corruption when sending compressed messages from a different\n  thread than the main I/O thread. #615 Thank you KyleNyenhuis and Pieter De \n  Gendt for reporting and a patch.\n- Bug: Fix an undefined behavior issue performing a 64 bit wide shift on a 64\n  bit value. #636 Thank you Gregor Jasny for reporting and a patch\n- Bug: Fix some compile issues with ASIO_STANDALONE. #662 #665 Thank you\n  chronoxor and Guillaume Egles for reporting and patches.\n\n0.7.0 - 2016-02-22\n- MINOR BREAKING SOCKET POLICY CHANGE: Asio transport socket policy method \n  `cancel_socket` will now return `lib::asio::error_code` instead of `void`.\n  Custom Asio transport socket policies will need to be updated accordingly.\n  This does not affect anyone using the bundled socket policies.\n- Feature: Basic support for the permessage-deflate extension. #344\n- Feature: Allow accessing the local endpoint when using the Asio transport.\n  This allows inspection of the address and port in cases where they are chosen\n  by the operating system rather than the user. Thank you Andreas Weis and \n  Muzahid Hussain for reporting and related code. #458\n- Feature: Add support for subprotocols in Hybi00. Thank you Lukas Obermann\n  for reporting and a patch. #518\n- Feature: Adds `tcp_pre_bind handler` to Asio transport. This allows setting\n  arbitrary socket options after the listen acceptor has been created but before\n  the socket bind has been performed. #634 #439 Thank you Gregor Jasny for\n  the patch.\n- Improvement: Better automatic std::chrono feature detection for Visual Studio\n- Improvement: Major refactoring to bundled CMake build system. CMake can now be\n  used to build all of the examples and the test suite. Thank you Thijs Wenker\n  for a significant portion of this code. #378, #435, #449\n- Improvement: In build environments where `lib::error_code` and \n  `lib::asio::error_code` match (such as using `boost::asio` with \n  `boost::system_error` or standalone asio with `std::system_error`, transport\n  errors are passed through natively rather than being reported as a translated \n  `pass_through` error type.\n- Improvement: Add a `get_transport_error` method to Asio transport connections\n  to allow retrieving a machine readable native transport error.\n- Improvement: Add `connection::get_response`, `connection::get_response_code`,\n  and `connection::get_response_msg` methods to allow accessing additional\n  information about the HTTP responses that WebSocket++ sends. #465 Thank you\n  Flow86 for reporting.\n- Improvement: Removes use of empty strings (\"\") in favor of `string::clear()`\n  and `string::empty()`. This avoids generating unnecessary temporary objects.\n  #468 Thank you Vladislav Yaroslavlev for reporting and a patch.\n- Documentation: Adds an example demonstrating the use of external `io_service`\n- Documentation: Adds a simple `echo_client` example.\n- Documentation: Begins migration of the web based user manual into Doxygen.\n- Bug: Fix memory leak when `init_asio` produces an error. #454 Thank you Mark \n  Grimes for reporting and fixing.\n- Bug: Fix crash when processing a specially crafted HTTP header. Thank you Eli \n  Fidler for reporting, test cases, and a patch. #456\n- Bug: Fix an issue where standalone Asio builds that use TLS would not compile\n  due to lingering boost code. #448 Thank you mjsp for reporting\n- Bug: Fix an issue where canceling a socket could throw an exception on some\n  older Windows XP platforms. It now prints an appropriate set of log messages\n  instead. Thank you Thijs Wenker for reporting and researching solutions. #460\n- Bug: Fix an issue where deferred HTTP connections that start sending a very \n  long response before their HTTP handler ends would result in a second set of\n  HTTP headers being injected into the output. Thank you Kevin Smith for\n  reporting and providing test case details. #443\n- Bug: Fix an issue where the wrong type of strand was being created. Thank you \n  Bastien Brunnenstein for reporting and a patch. #462\n- Bug: Fix an issue where TLS includes were broken for Asio Standalone builds.\n  Thank you giachi and Bastien Brunnenstein for reporting. #491\n- Bug: Remove the use of cached read and write handlers in the Asio transport.\n  This feature caused memory leaks when the `io_service` the connection was\n  running on was abruptly stopped. There isn't a clean and safe way of using\n  this optimization without global state and the associated locks. The locks\n  perform worse. Thank you Xavier Gibert for reporting, test cases, and code.\n  Fixes #490.\n- Bug: Fix a heap buffer overflow when checking very short URIs. Thank you \n  Xavier Gibert for reporting and a patch #524\n- Compatibility: Fixes a number of build & config issues on Visual Studio 2015\n- Compatibility: Removes non-standards compliant masking behavior. #395, #469\n- Compatibility: Replace deprecated use of `auto_ptr` on systems where \n  `unique_ptr` is available.\n\n0.6.0 - 2015-06-02\n- MINOR BREAKING TRANSPORT POLICY CHANGE: Custom transport policies will now be\n  required to include a new method `void set_uri(uri_ptr u)`. An implementation\n  is not required. The stub transport policy includes an example stub method\n  that can be added to any existing custom transport policy to fulfill this\n  requirement. This does not affect anyone using the bundled transports or\n  configs.\n- MINOR BREAKING SOCKET POLICY CHANGE: Custom asio transport socket policies \n  will now be required to include a new method `void set_uri(uri_ptr u)`. Like\n  with the transport layer, an implementation is not required. This does not \n  affect anyone using the bundled socket policies.\n- MINOR BREAKING DEPENDENCY CHANGE: When using Boost versions greater than or \n  equal to 1.49 in C++03 mode, `libboost-chrono` is needed now instead of \n  `libboost-date_time`. Users with C++11 compilers or using Boost versions 1.48\n  and earlier are not affected. Note: This change affects the bundled unit test\n  suite.\n- Feature: WebSocket++ Asio transport policy can now be used with the standalone\n  version of Asio (1.8.0+) when a C++11 compiler and standard library are \n  present. This means that it is possible now to use WebSocket++'s Asio\n  transport entirely without Boost. Thank you Robert Seiler for proof of concept\n  code that was used as a guide for this implementation. Fixes #324 \n- Feature: Adds a vectored/scatter-gather write handler to the iostream\n  transport.\n- Feature: Adds the ability to defer sending an HTTP response until sometime\n  after the `http_handler` is run. This allows processing of long running http\n  handlers to defer their response until it is ready without blocking the\n  network thread. references #425\n- Improvement: `echo_server_tls` has been update to demonstrate how to configure\n  it for Mozilla's recommended intermediate and modern TLS security profiles.\n- Improvement: `endpoint::set_timer` now uses a steady clock provided by \n  `boost::chrono` or `std::chrono` where available instead of the non-monotonic\n  system clock. Thank you breyed for reporting. fixes #241\n- Improvement: Outgoing TLS connections to servers using the SNI extension to\n  choose a certificate will now work. Thank you moozzyk for reporting. \n  Fixes #400\n- Improvement: Removes an unnecessary mutex lock in `get_con_from_hdl`.\n- Cleanup: Asio transport policy has been refactored to remove many Boost\n  dependencies. On C++03 compilers the `boost::noncopyable` dependency has been\n  removed and the `boost::date_time` dependency has been replaced with the newer\n  `boost::chrono` when possible. On C++11 compilers the `boost::aligned_storage`\n  and `boost::date_time` dependencies are gone, replaced with equivalent C++11\n  standard library features.\n- Bug: Fixes a potential dangling pointer and inconsistent error message\n  handling in `websocketpp::exception`. #432 Thank you Tom Swirly for the fix.\n\n0.5.1 - 2015-02-27\n- Bug: Fixes an issue where some frame data was counted against the max header\n  size limit, resulting in connections that included a lot of frame data\n  immediately after the opening handshake to fail.\n- Bug: Fix a typo in the name of the set method for `max_http_body_size`. #406\n  Thank you jplatte for reporting.\n\n0.5.0 - 2015-01-22\n- BREAKING UTILITY CHANGE: Deprecated methods `http::parser::parse_headers`,\n  `http::response::parse_complete`, and `http::request::parse_complete` have\n  been removed.\n- Security: Disabled SSLv3 in example servers.\n- Feature: Adds basic support for accessing HTTP request bodies in the http\n  handler. #181\n- Feature: Adds the ability to register a shutdown handler when using the\n  iostream transport. This provides a clean interface for triggering the shut\n  down of external sockets and other cleanup without hooking in to higher level\n  WebSocket handlers.\n- Feature: Adds the ability to register a write handler when using the iostream\n  transport. This handler can be used to handle transport output in place of\n  registering an ostream to write to.\n- Feature: Adds a new logging policy that outputs to syslog. #386 Thank you Tom\n  Hughes for submitting the initial version of this policy.\n- Improvement: Message payload logging now prints text for text messages rather\n  than binary.\n- Improvement: Overhaul of handshake state machine. Should make it impossible\n  for exceptions to bubble out of transport methods like `io_service::run`.\n- Improvement: Overhaul of handshake error reporting. Fail handler error codes\n  will be more detailed and precise. Adds new [fail] and [http] logging channels\n  that log failed websocket connections and successful HTTP connections\n  respectively. A new aggregate channel package, `alevel::access_core`, allows\n  enabling connect, disconnect, fail, and http together. Successful HTTP\n  connections will no longer trigger a fail handler.\n- Improvement: Ability to terminate connection during an http handler to cleanly\n  suppress the default outgoing HTTP response.\n- Documentation: Add Sending & Receiving Messages step to chapter one of the\n  `utility_client` tutorial. Update `utility_client` example to match.\n- Cleanup: Removes unused files & STL includes. Adds required STL includes.\n  Normalizes include order.\n- Bug: Fixes a fatal state error when a handshake response is completed\n  immediately after that handshake times out. #389\n- Bug: MinGW fixes; C++11 feature detection, localtime use. #393 Thank you\n  Schebb for reporting, code, and testing.\n- Bug: Fixes an issue where `websocketpp::exception::what()` could return an out\n  of scope pointer. #397 Thank you fabioang for reporting.\n- Bug: Fixes an issue where endpoints were not reset properly after a call to\n  `endpoint::listen` failed. #390 Thank you wyyqyl for reporting.\n\n0.4.0 - 2014-11-04\n- BREAKING API CHANGE: All WebSocket++ methods now throw an exception of type\n  `websocketpp::exception` which derives from `std::exception`. This normalizes\n  all exception types under the standard exception hierarchy and allows\n  WebSocket++ exceptions to be caught in the same statement as others. The error\n  code that was previously thrown is wrapped in the exception object and can be\n  accessed via the `websocketpp::exception::code()` method.\n- BREAKING API CHANGE: Custom logging policies have some new required\n  constructors that take generic config settings rather than pointers to\n  std::ostreams. This allows writing logging policies that do not involve the\n  use of std::ostream. This does not affect anyone using the built in logging\n  policies.\n- BREAKING UTILITY CHANGE: `websocketpp::lib::net::htonll` and\n  `websocketpp::lib::net::ntohll` have been prefixed with an underscore to avoid\n  conflicts with similarly named macros in some operating systems. If you are\n  using the WebSocket++ provided 64 bit host/network byte order functions you\n  will need to switch to the prefixed versions.\n- BREAKING UTILITY CHANGE: The signature of `base64_encode` has changed from\n  `websocketpp::base64_encode(unsigned char const *, unsigned int)` to\n  `websocketpp::base64_encode(unsigned char const *, size_t)`.\n- BREAKING UTILITY CHANGE: The signature of `sha1::calc` has changed from\n  `websocketpp::sha1::calc(void const *, int, unsigned char *)` to\n  `websocketpp::sha1::calc(void const *, size_t, unsigned char *)`\n- Feature: Adds incomplete `minimal_server` and `minimal_client` configs that\n  can be used to build custom configs without pulling in the dependencies of\n  `core` or `core_client`. These configs will offer a stable base config to\n  future-proof custom configs.\n- Improvement: Core library no longer has std::iostream as a dependency.\n  std::iostream is still required for the optional iostream logging policy and\n  iostream transport.\n- Bug: C++11 Chrono support was being incorrectly detected by the `boost_config`\n  header. Thank you Max Dmitrichenko for reporting and a patch.\n- Bug: use of `std::put_time` is now guarded by a unique flag rather than a\n  chrono library flag. Thank you Max Dmitrichenko for reporting.\n- Bug: Fixes non-thread safe use of std::localtime. #347 #383\n- Compatibility: Adjust usage of std::min to be more compatible with systems\n  that define a min(...) macro.\n- Compatibility: Removes unused parameters from all library, test, and example\n  code. This assists with those developing with -Werror and -Wunused-parameter\n  #376\n- Compatibility: Renames ntohll and htonll methods to avoid conflicts with\n  platform specific macros. #358 #381, #382 Thank you logotype, unphased,\n  svendjo\n- Cleanup: Removes unused functions, fixes variable shadow warnings, normalizes\n  all whitespace in library, examples, and tests to 4 spaces. #376\n\n0.3.0 - 2014-08-10\n- Feature: Adds `start_perpetual` and `stop_perpetual` methods to asio transport\n  These may be used to replace manually managed `asio::io_service::work` objects\n- Feature: Allow setting pong and handshake timeouts at runtime.\n- Feature: Allows changing the listen backlog queue length.\n- Feature: Split tcp init into pre and post init.\n- Feature: Adds URI method to extract query string from URI. Thank you Banaan\n  for code. #298\n- Feature: Adds a compile time switch to asio transport config to disable\n  certain multithreading features (some locks, asio strands)\n- Feature: Adds the ability to pause reading on a connection. Paused connections\n  will not read more data from their socket, allowing TCP flow control to work\n  without blocking the main thread.\n- Feature: Adds the ability to specify whether or not to use the `SO_REUSEADDR`\n  TCP socket option. The default for this value has been changed from `true` to\n  `false`.\n- Feature: Adds the ability to specify a maximum message size.\n- Feature: Adds `close::status::get_string(...)` method to look up a human\n  readable string given a close code value.\n- Feature: Adds `connection::read_all(...)` method to iostream transport as a\n  convenience method for reading all data into the connection buffer without the\n  end user needing to manually loop on `read_some`.\n- Improvement: Open, close, and pong timeouts can be disabled entirely by\n  setting their duration to 0.\n- Improvement: Numerous performance improvements. Including: tuned default\n  buffer sizes based on profiling, caching of handler binding for async\n  reads/writes, non-malloc allocators for read/write handlers, disabling of a\n  number of questionably useful range sanity checks in tight inner loops.\n- Improvement: Cleaned up the handling of TLS related errors. TLS errors will\n  now be reported with more detail on the info channel rather than all being\n  `tls_short_read` or `pass_through`. In addition, many cases where a TLS short\n  read was in fact expected are no longer classified as errors. Expected TLS\n  short reads and quasi-expected socket shutdown related errors will no longer\n  be reported as unclean WebSocket shutdowns to the application. Information\n  about them will remain in the info error channel for debugging purposes.\n- Improvement: `start_accept` and `listen` errors are now reported to the caller\n  either via an exception or an ec parameter.\n- Improvement: Outgoing writes are now batched for improved message throughput\n  and reduced system call and TCP frame overhead.\n- Bug: Fix some cases of calls to empty lib::function objects.\n- Bug: Fix memory leak of connection objects due to cached handlers holding on to\n  reference counted pointers. #310 Thank you otaras for reporting.\n- Bug: Fix issue with const endpoint accessors (such as `get_user_agent`) not\n  compiling due to non-const mutex use. #292 Thank you logofive for reporting.\n- Bug: Fix handler allocation crash with multithreaded `io_service`.\n- Bug: Fixes incorrect whitespace handling in header parsing. #301 Thank you\n  Wolfram Schroers for reporting\n- Bug: Fix a crash when parsing empty HTTP headers. Thank you Thingol for\n  reporting.\n- Bug: Fix a crash following use of the `stop_listening` function. Thank you\n  Thingol for reporting.\n- Bug: Fix use of variable names that shadow function parameters. The library\n  should compile cleanly with -Wshadow now. Thank you giszo for reporting. #318\n- Bug: Fix an issue where `set_open_handshake_timeout` was ignored by server\n  code. Thank you Robin Rowe for reporting.\n- Bug: Fix an issue where custom timeout values weren't being propagated from\n  endpoints to new connections.\n- Bug: Fix a number of memory leaks related to server connection failures. #323\n  #333 #334 #335 Thank you droppy and aydany for reporting and patches.\n  reporting.\n- Compatibility: Fix compile time conflict with Visual Studio's MIN/MAX macros.\n  Thank you Robin Rowe for reporting.\n- Documentation: Examples and test suite build system now defaults to clang on\n  OS X\n\n0.3.0-alpha4 - 2013-10-11\n- HTTP requests ending normally are no longer logged as errors. Thank you Banaan\n  for reporting. #294\n- Eliminates spurious expired timers in certain error conditions. Thank you\n  Banaan for reporting. #295\n- Consolidates all bundled library licenses into the COPYING file. #294\n- Updates bundled sha1 library to one with a cleaner interface and more\n  straight-forward license. Thank you lotodore for reporting and Evgeni Golov\n  for reviewing. #294\n- Re-introduces strands to asio transport, allowing `io_service` thread pools to\n  be used (with some limitations).\n- Removes endpoint code that kept track of a connection list that was never used\n  anywhere. Removes a lock and reduces connection creation/deletion complexity\n  from O(log n) to O(1) in the number of connections.\n- A number of internal changes to transport APIs\n- Deprecates iostream transport `readsome` in favor of `read_some` which is more\n  consistent with the naming of the rest of the library.\n- Adds preliminary signaling to iostream transport of eof and fatal transport\n  errors\n- Updates transport code to use shared pointers rather than raw pointers to\n  prevent asio from retaining pointers to connection methods after the\n  connection goes out of scope. #293 Thank you otaras for reporting.\n- Fixes an issue where custom headers couldn't be set for client connections\n  Thank you Jerry Win and Wolfram Schroers for reporting.\n- Fixes a compile error on visual studio when using interrupts. Thank you Javier\n  Rey Neira for reporting this.\n- Adds new 1012 and 1013 close codes per IANA registry\n- Add `set_remote_endpoint` method to iostream transport.\n- Add `set_secure` method to iostream transport.\n- Fix typo in .gitattributes file. Thank you jstarasov for reporting this. #280\n- Add missing locale include. Thank you Toninoso for reporting this. #281\n- Refactors `asio_transport` endpoint and adds full documentation and exception\n  free varients of all methods.\n- Removes `asio_transport` endpoint method cancel(). Use `stop_listen()` instead\n- Wrap internal `io_service` `run_one()` method\n- Suppress error when trying to shut down a connection that was already closed\n\n0.3.0-alpha3 - 2013-07-16\n- Minor refactor to bundled sha1 library\n- HTTP header comparisons are now case insensitive. #220, #275\n- Refactors URI to be exception free and not use regular expressions. This\n  eliminates the dependency on boost or C++11 regex libraries allowing native\n  C++11 usage on GCC 4.4 and higher and significantly reduces staticly built\n  binary sizes.\n- Updates handling of Server and User-Agent headers to better handle custom\n  settings and allow suppression of these headers for security purposes.\n- Fix issue where pong timeout handler always fired. Thank you Steven Klassen\n  for reporting this bug.\n- Add ping and pong endpoint wrapper methods\n- Add `get_request()` pass through method to connection to allow calling methods\n  specific to the HTTP policy in use.\n- Fix issue compile error with `WEBSOCKETPP_STRICT_MASKING` enabled and another\n  issue where `WEBSOCKETPP_STRICT_MASKING` was not applied to incoming messages.\n  Thank you Petter Norby for reporting and testing these bugs. #264\n- Add additional macro guards for use with boost_config. Thank you breyed\n  for testing and code. #261\n\n0.3.0-alpha2 - 2013-06-09\n- Fix a regression that caused servers being sent two close frames in a row\n  to end a connection uncleanly. #259\n- Fix a regression that caused spurious frames following a legitimate close\n  frames to erroneously trigger handlers. #258\n- Change default HTTP response error code when no http_handler is defined from\n  500/Internal Server Error to 426/Upgrade Required\n- Remove timezone from logger timestamp to work around issues with the Windows\n  implementation of strftime. Thank you breyed for testing and code. #257\n- Switch integer literals to char literals to improve VCPP compatibility.\n  Thank you breyed for testing and code. #257\n- Add MSVCPP warning suppression for the bundled SHA1 library. Thank you breyed\n  for testing and code. #257\n\n0.3.0-alpha1 - 2013-06-09\n- Initial Release\n"
  },
  {
    "path": "docs/config.dox",
    "content": "/** \\page reference.config Config Reference\n\nWebSocket++ uses a config template parameter to supply a number of compile type policy types and default numerical values for buffer sizes, timeouts, security behavior, etc. Swapping policies allows changing certain core library behavior designed to be pluggable.\n\nA custom config can be made standalone or can subclass one of the bundled configs and just override a few things.\n\n__Example__\n```\n// some config options may require additional includes or dependencies.\n// syslog logging policy, for example, requires <syslog.h>, \n// the permessage deflate settings require zlib.\n#include <websocketpp/logger/syslog.hpp>\n#include <websocketpp/extensions/permessage_deflate/enabled.hpp>\n\n// Custom server config based on bundled asio config\nstruct custom_server_config : public websocketpp::config::asio {\n\t// Replace default stream logger with a syslog logger\n\ttypedef websocketpp::log::syslog<concurrency_type, websocketpp::log::elevel> elog_type;\n\ttypedef websocketpp::log::syslog<concurrency_type, websocketpp::log::alevel> alog_type;\n\n\t// Reduce read buffer size to optimize for small messages\n\tstatic const size_t connection_read_buffer_size = 1024;\n\n\t// enable permessage_compress extension\n    struct permessage_deflate_config {};\n\n    typedef websocketpp::extensions::permessage_deflate::enabled\n        <permessage_deflate_config> permessage_deflate_type;\n};\n\ntypedef websocketpp::server<custom_server_config> server_endpoint_type;\n```\n\nCore Config Options\n-------------------\n\n### Policies\n\nPolicies are classes used to allow clean swapping of behavior without changing the core library\n\n| Typedef Name              | Effect                                 |\n| ------------------------- | -------------------------------------- |\n| concurrency_type          | Concurrency policy                     |\n| elog_type                 | Error logger type                      |\n| alog_type                 | Access logger type                     |\n| request_type              | HTTP request type                      |\n| response_type             | HTTP response type                     |\n| message_type              | Type to deliver recieved messages      |\n| con_msg_manager_type      | Connection level message manager       |\n| endpoint_msg_manager_type | Endpoint level message manager         |\n| rng_type                  | Random Number Generation policy        |\n| transport_type            | Transport policy to use                |\n| endpoint_base             | User overridable Endpoint base class   |\n| connection_base           | User overridable Connection base class |\n\n### Timeouts Values\n\nThese represent the length of time (in ms) before the given operation is aborted\n\n| Field                   | Type | Default | Operation                   |\n| ----------------------- | ---- | ------- | --------------------------- |\n| timeout_open_handshake  | long | 5000    | Opening handshake           |\n| timeout_close_handshake | long | 5000    | Closing handshake           |\n| timeout_pong            | long | 5000    | No pong recieved after ping |\n\n### Performance tuning\n\n| Field                       | Type   | Default  | Meaning                                                            |\n| --------------------------- | ------ | -------- | ------------------------------------------------------------------ |\n| connection_read_buffer_size | size_t | 16384    | Size of the per-connection read buffer                             |\n| enable_multithreading       | bool   | true     | Disabling may reduce locking overhead for single threaded programs |\n\n#### Connection Read Buffer\n\nEach connection has an internal buffer of this size. A larger value will result in fewer trips through the library and less CPU overhead at the expense of increased memory usage per connection.\n\nIf your application primarily deals in very large messages you may want to try setting this value higher.\n\nIf your application has a lot of connections or primarily deals in small messages you may want to try setting this smaller.\n\n### Security settings\n\n| Field                  | Type   | Default | Effect                                 |\n| ---------------------- | ------ | ------- | -------------------------------------- |\n| drop_on_protocol_error | bool   | false   | Omit close handshake on protocol error |\n| silent_close           | bool   | false   | Don't return close codes or reasons    |\n| max_message_size       | size_t | 32MB    | WebSocket max message size limit       |\n| max_http_body_size     | size_t | 32MB    | HTTP Parser's max body size limit      |\n\n#### Drop on protocol error\nDrop connections on protocol error rather than sending a close frame. Off by default. This may result in legitimate messages near the error being dropped as well. It may free up resources otherwise spent dealing with misbehaving clients.\n\n#### Silent Close\nSilence close suppresses the return of detailed connection close information during the closing handshake. This information is useful for debugging and presenting useful errors to end users but may be undesirable for security reasons in some production environments. Close reasons could be used by an attacker to confirm that the endpoint is out of resources or be used to identify the WebSocket implementation in use.\n\nNote: this will suppress *all* close codes, including those explicitly sent by local applications.\n\n#### Max message size\nDefault value for the processor's maximum message size. Maximum message size determines the point at which the library will drop a connection with the message_too_big protocol error.\n\n#### Max HTTP header size\nMaximum body size determines the point at which the library will abort reading an HTTP message body and return the 413/request entity too large error.\n\nTransport Config Options\n------------------------\n\n### Policies\n\nPolicies are classes used to allow clean swapping of behavior without changing the core library\n\n| Typedef Name     | Effect             |\n| ---------------- | ------------------ |\n| concurrency_type | Concurrency Policy |\n| elog_type        | Error logger type  |\n| alog_type        | Access logger type |\n| request_type     | HTTP request type  |\n| response_type    | HTTP response type |\n\n### Timeouts Values\n\nThese represent the length of time (in ms) before the given operation is aborted\n\n| Field                    | Type | Default | Operation                                     |\n| ------------------------ | ---- | ------- | --------------------------------------------- |\n| timeout_socket_pre_init  | long | 5000    | Transport dependent                           |\n| timeout_proxy            | long | 5000    | Proxy handshake                               |\n| timeout_socket_post_init | long | 5000    | Transport dependent (commonly: TLS handshake) |\n| timeout_dns_resolve      | long | 5000    | DNS resolution                                |\n| timeout_connect          | long | 5000    | TCP Connect                                   |\n| timeout_socket_shutdown  | long | 5000    | Socket shutdown                               |\n\n### Performance tuning\n\n| Field                       | Type   | Default  | Meaning                                                            |\n| --------------------------- | ------ | -------- | ------------------------------------------------------------------ |\n| enable_multithreading       | bool   | true     | Disabling may reduce locking overhead for single threaded programs |\n\n*/\n"
  },
  {
    "path": "docs/faq.dox",
    "content": "/** \\page faq FAQ\n\n## General Library Usage\n\n### Can a handler be changed after a connection is established? Can one be removed?\nYes, but not globally.\n\nHandlers assigned to endpoints will be automatically copied to the connections created by that endpoint. Changing a handler on an endpoint will only affect future connections.\n\nOnce a particular connection is created, it's handlers can be changed individually by calling the `set_*_handler` methods. Once changed, all future events of that type for that connection will use the new handler.\n\nTo remove a handler that was previously set, call the set method with `nullptr` or `NULL`.\n\n### Can I reject or conditionally accept a connection\nYes. The `validate` handler is called after the initial handshake has been recieved but before WebSocket++ has responded. This gives you the opportunity to inspect the incoming connection request, its headers, origin, subprotocols, and the remote endpoint IP. Return `true` from the validate handler to accept the connection and `false` to reject it.\n\nTo set a custom HTTP error message for your rejection, use `websocketpp::connection::set_status` and (optionally) `websocketpp::connection::set_body()` to set the HTTP status code and error message body text. If you do not set body text a message will be generated automatically based on the status code.\n\n### How do I negotiate subprotocols?\nWebSocket connections may offer a particular subprotocol they want to use. The WebSocket protocol does not define the meaning or interpretation of the subprotocol. This interpretation is left up to the individual application endpoints.\n\nWebSocket++ servers can read the requested subprotocols during the `validate` handler by calling `websocketpp::connection::get_requested_subprotocols`. The list is ordered by client priority. You may optionally choose one of these subprotocols with `websocketpp::connection::select_subprotocol`. The handshake will then complete and let the client know which one was chosen. If you do not choose any, the \"blank\"/empty/none subprotocol will be used.\n\nWebSocket++ clients can add a subprotocol to an outgoing connection by calling `websocketpp::connection::add_subprotocol` before calling `websocketpp::client::connect`. The order of adding will be interpreted as the order of preference.\n\nIn both caases, after the connection has been established, the selected subprotocol is available via the `websocketpp::connection::get_subprotocol` method.\n\nNote: some browsers will allow the connection to continue if they requested a subprotocol and your server doesn't select one. Others will reject the connection. \n\n### How do I cleanly exit an Asio transport based program\n\nThe Asio transport based clients and servers use the Asio library's underlying `io_service` to handle asyncronous networking operations. The standard behavior of the io_service is to run until there are no async operations left and then return. WebSocket++, when using the Asio transport, behaves like a standard Asio application. If you want your WebSocket++/Asio based program to stop network operations and cleanly close all sockets you will want to do the following:\n\n- For servers, call `websocketpp::transport::asio::endpoint::stop_listening` to initiate the closing of the server listening socket.\n- For clients, if you have engaged perpetual mode with `websocketpp::transport::asio::endpoint::start_perpetual`, disable it with `websocketpp::transport::asio::endpoint::stop_perpetual`.\n- For both, run `websocketpp::endpoint::close` or `websocketpp::connection::close` on all currently outstanding connections. This will initiate the WebSocket closing handshake for these connections\n- Wait. Asio is asyncronous. When the calls to the above methods (stop_listening, close, etc) complete the server *will still be listening*, the connections *will still be active* until the io_service gets around to asyncronously processing the socket and WebSocket protocol closing handshakes. The `io_service::run` method will exit cleanly and automatically when all operations are complete.\n\n__WARNING__: Asio's `io_service` has a method called `stop`. WebSocket++ wraps this method as `websocketpp::transport::asio::endpoint::stop`. While this operation has a benign sounding name, it is a powerful and destructive operation that should only be used in special cases. If you are using `io_service::stop` or `endpoint::stop` without a very good reason your program is likely broken and may exhibit erratic behavior. Specifically, `io_service::stop` stops the processing of events entirely. This does not give current operations (such as socket closing handshakes) the opportunity to finish. It will leave your sockets in a dangling state that may invoke operating system level timeouts or other errors.\n\n__Special cases__:\n- If your client uses the `start_perpetual` method it will prevent the io_service from exiting even if it has nothing to do. This is useful if you want a client endpoint to idle in the background to allow new connections to be formed on demand rather than generating a new endpoint for each.\n- If you are using an external io_service and/or are placing non-WebSocket++ operations on the `io_service` those operations may keep the `io_service` open even after all WebSocket++ operations have completed.\n- If you are using `poll`/`poll_one`/`run_one` or otherwise manually driving the `io_service` event loop you may need to adjust usage to make sure you are correctly recognizing the \"done with work\" and \"not done but idling / `io_service::work`\" cases.\n\n### Is there a way to check the validity of a `connection_hdl`?\n\nSometimes, not generally though, because there isn’t a way to check if a TCP connection is valid.\n\nYou can try upgrading your hdl to a full connection_ptr using `websocketpp::endpoint::get_con_from_hdl`. If this fails, the hdl is definitely invalid. If it succeeds it may or may not be. The only way to tell definitively is to try and send something (either a message or a ping).\n\nIf you handle errors from methods like send, ping, close, etc correctly then you shouldn’t have to worry about accidentally sending to dead connections. The send/ping/pong/close methods will set or throw a specific error in the case that you tried to send something but the connection was closed/gone/etc.\n\n### How do I fix the \"address is in use\" error when trying to restart my server?\n\nNormally, for security purposes, operating systems prevent programs from listening on sockets created by other programs. When your program crashes and restarts, the new instance is a different program from the perspective of the operating system. As such it can’t listen on the socket address/port that the previous program was using until after a timeout occurs to make sure the old program was done with it.\n\nThe first step for handling this is to make sure that you provide a method (signal handler, admin websocket message, etc) to perform a clean server shutdown. There is a question elsewhere in this FAQ that describes the steps necessary for this.\n\nThe clean close strategy won't help in the case of crashes or other abnormal closures. An option to consider for these cases is the use of the SO_REUSEADDR socket option. This instructs the OS to not request an exclusive lock on the socket. This means that after your program crashes the replacement you start can immediately listen on that address/port combo again.\n\n__Please note__: how this works exactly depends on your operating system. Additionally, not exclusively locking your listening socket could allow hijacking by other programs if you are running in a shared resource environment. For development this is generally no problem. For a production environment, think carefully about the security model. `websocketpp::transport::asio::endpoint::set_reuse_addr` is the method to do this. You must specify this setting before calling `websocketpp::transport::asio::endpoint::listen`.\n\n### How do I send and recieve binary messages?\n\nWhen supported by the remote endpoint, WebSocket++ allows reading and sending messages in the two formats specified in RFC6455, UTF8 text and binary. WebSocket++ performs UTF8 validation on all outgoing text messages to ensure that they meet the specification. Binary messages do not have any additional processing and their interpretation is left entirely to the library user.\n\nTo determine the type of an incoming message, use `websocketpp::message_buffer::message::get_opcode`. The relevant return values are `websocketpp::frame::opcode::text` and `websocketpp::frame::opcode::binary`. There is no difference in how payloads are retrieved between these modes, only in how WebSocket++ validated the contents and how the library user is to interpret the data.\n\nTo specify the type of an outgoing message, use the frame opcode values listed above as the second op parameter for `websocketpp::connection::send`. There are two relevant overloads of send. One that takes a `std::string` and defaults to op=text. The other that takes a `void const *` and a `size_t` length and defaults to op=binary. Note: You can send binary messages via the string overload and text messages via the void * overload. In the case that you are manually building a message buffer rather than using the automatic send member functions, you can pass the opcode in as a parameter to the message buffer constructor or user the `websocketpp::message_buffer::message::set_opcode` member function to set or re-set it later.\n\n## Dependency Management\n\n### Can WebSocket++ be used without Boost?\nYes. WebSocket++ only uses Boost features as polyfills for C++11 language features and libraries. If you have a C++11 compiler and standard library you can use WebSocket++ without Boost. In most cases setting your build environment to use the C++11 (or later) language dialect is sufficient to enable this mode of use.\n\nWith less common compilers (and sometimes very recently release compilers) there may be specific issues with certain libraries that aren't automatically detected by the library. For these situations there are additional defines available to fine tune which C++11 libraries and features are used. TODO: more details about them.\n\nFor the iostream/raw transport the C++11 standard library is sufficient. For the Asio based transports, there is no C++11 library that provides the networking capabilaties that Asio does. As such even with a C++11 build system, you will need a standalone copy of Asio to use if Boost Asio is not available.\n\nMinGW users who want to avoid Boost should also consult the nearby question about MinGW compatibility.\n\n### Can WebSocket++ be used with standalone Asio\nYes. The process is the same as used with standalone Asio itself. Define `ASIO_STANDALONE` before including Asio or WebSocket++ headers. You will need to download a copy of the Asio headers separately (http://www.think-async.com) and make sure they are in your build system's include path.\n\n### Can WebSocket++ be used without TLS or OpenSSL?\nYes. When using the iostream/raw transport, there are no TLS features and OpenSSL is not required. When using the Asio transport TLS features are optional. You only need OpenSSL if you want to use TLS. You can only make or recieve encrypted connections (https/wss) if you have enabled TLS features.\n\nWhether an Asio endpoint uses TLS or not is determined by its config template parameter. The default bundled `websocketpp::config::asio` and `websocketpp::config::asio_client` configs do not support TLS, the `websocketpp::config::asio_tls` and `websocketpp::config::asio_tls_client` do.\n\nThe `<websocketpp/config/asio.hpp>` and `<websocketpp/config/asio_client.hpp>` headers will include both the TLS and non-TLS varients of their respective configs and require the presence of OpenSSL. The `<websocketpp/config/asio_no_tls.hpp>` and `<websocketpp/config/asio_no_tls_client.hpp>` headers will include only the non-TLS configs and do not require OpenSSL.\n\n### Build issues with TLS on recent versions of OS X\nMac OS X ships a severely outdated version of the OpenSSL library. To securely use TLS with WebSocket++ on OS X you will need to install a modern version of OpenSSL via homebrew or compiling from source.\n\n### Can WebSocket++ be used with MinGW\nGenerally, yes. Note that in C++11 mode MinGW does not currently support the C++11 STL `<thread>` library. WebSocket++ requires a thread/mutex library. Options include Boost thread (the default when a compatible C++11 `<thread>` can't be found) or `mingw-std-threads` (https://github.com/meganz/mingw-std-threads) by including those headers and defining `_WEBSOCKETPP_MINGW_THREAD_`.\n\n## Compression\n\n### How do I use permessage-deflate in version 0.6.0-permessagedeflate and 0.7.0?\n\nThese versions of the library require a custom config to use the permessage-deflate extension. Here is a minimal example of such a custom config. You can also integrate these lines into an existing custom config.\n\nNote that in these versions there is no fine grained control over which connections are compressed or not. Clients will request compression with the default settings and use it if the server supports it. Servers will accept whatever parameters clients request.\n\nOutgoing messages by default will be compressed if compression was auto-negotiated during the handshake. There is an option to force a specific message to be sent uncompressed even if compression was negotiated. This may be useful for sending data that you know to be compressed already (images, zip files, etc).\n\n\n__Server Example__\n```\n#include <websocketpp/extensions/permessage_deflate/enabled.hpp>\n\nstruct deflate_server_config : public websocketpp::config::asio {\n\t// ... additional custom config if you need it for other things\n\n\t/// permessage_compress extension\n    struct permessage_deflate_config {};\n\n    typedef websocketpp::extensions::permessage_deflate::enabled\n        <permessage_deflate_config> permessage_deflate_type;\n};\n\ntypedef websocketpp::server<deflate_server_config> server_endpoint_type;\n```\n\n__Client Example__\n```\n#include <websocketpp/extensions/permessage_deflate/enabled.hpp>\n\nstruct deflate_client_config : public websocketpp::config::asio_client {\n\t// ... additional custom config if you need it for other things\n\n\t/// permessage_compress extension\n    struct permessage_deflate_config {};\n\n    typedef websocketpp::extensions::permessage_deflate::enabled\n        <permessage_deflate_config> permessage_deflate_type;\n};\n\ntypedef websocketpp::client<deflate_client_config> client_endpoint_type;\n```\n\n## Security\n\n### Is it possible to terminate a malicious connection quickly, without tying up resources performing clean close steps, \n\nYes. The library will automatically detect and terminate connections that violate the WebSocket protocol. In cases where the library believes the remote endpoint to be malicious or sufficiently broken to be unlikely to understand or process the closing handshake, it will be omited.\n\nIf your application detects conditions above the protocol level that you believe to be malicious, for example, if you recognize an IP from a known denial of service attack, you can close the connection with two different levels of urgency. Use the standard `websocketpp::endpoint::close` or `websocketpp::connection::close` methods with one of the following special close codes:\n- `websocketpp::close::status::omit_handshake`: Omits the closing handshake, but cleanly closes the TCP connection.\n- `websocketpp::close::status::force_tcp_drop`: Forcibly drop the TCP connection.\n\nPlease note that usage of these disconnect methods results in a violation of the WebSocket protocol and may have negative reprocusions for the remote endpoint with respect to network timeouts. Please use caution when using them.\n\n## Build Issues\n\n### Getting compile errors related to `std::chrono`, `boost::chrono`, `waitable_timer`, or `steady_clock`\n\nYour build system may be confused about whether it is supposed to be using `boost::chrono` or `std::chrono`. Boost automatically detects this setup on some compilers but not others. Defining `BOOST_ASIO_HAS_STD_CHRONO` can help. See http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/overview/cpp2011/chrono.html for more details.\n\n*/\n"
  },
  {
    "path": "docs/getting_started.dox",
    "content": "/** \\page getting_started Getting Started\n\nWebSocket++ code is available on github at https://github.com/zaphoyd/websocketpp\nThe official project homepage lives at http://www.zaphoyd.com/websocketpp\n\nThe git repository is organized into several directories:\n\n- **docs**: This documentation\n- **examples**: Example programs that demonstrate how to build basic versions of some commonly used patterns for WebSocket clients and servers.\n- **test**: Unit tests that confirm that the code you have works properly and help detect platform specific issues.\n- **tutorials**: Detailed walkthroughs of a select set of the example programs.\n- **websocketpp**: All of the library code and default configuration files.\n\nWebSocket++ is a header only library. You can start using it by including the websocketpp source directory in your project's include path and including the appropriate WebSocket++ headers in your program. You may also need to include and/or link to appropriate Boost/system libraries. TODO: More information: Building a program with WebSocket++, Walkthroughs of the example programs\n\nWebSocket++ includes cmake and scons scripts for building the examples and unit tests. Neither system is needed unless you want to build tests or examples in an automated fashion.\n\n__Usage questions__ should be posted to the project mailing list at http://groups.google.com/group/websocketpp/ or the IRC channel (\\#websocketpp on freenode).\n\n__Bugs and issues__ should be posted to the project GitHub issues queue: https://github.com/zaphoyd/websocketpp/issues.\n\n__Pull requests__ on GitHub are welcome. Please make them against the `develop` branch.\n\nWebSocket++ is written and maintained by Peter Thorson. You can contact me via GitHub messaging, IRC, or via email at websocket@zaphoyd.com.\n\n*/\n\n"
  },
  {
    "path": "docs/handlers.dox",
    "content": "/** \\page reference.handlers Handler Reference\n\nHandlers allow WebSocket++ programs to receive notifications about events\nthat happen in relation to their connections. Some handlers also behave as\nhooks that give the program a chance to modify state or adjust settings before\nthe connection continues.\n\nHandlers are registered by calling the appropriate `set_*_handler` method on either an\nendpoint or connection. The * refers to the name of the handler (as \nspecified in the signature field below). For example, to set the open handler,\ncall `set_open_handler(...)`.\n\nSetting handlers on an endpoint will result in them being copied as the default\nhandler to all new connections created by that endpoint. Changing an endpoint's\nhandlers will not affect connections that are already in progress. This includes\nconnections that are in the listening state. As such, it is important to set any\nendpoint handlers before you call `endpoint::start_accept` or else the handlers\nwill not be attached to your first connection.\n\nSetting handlers on a connection will result in the handler being changed for\nthat connection only, starting at the next time that handler is called. This can\nbe used to change the handler during a connection.\n\nConnection Handlers\n-------------------\n\nThese handlers will be called at most once per connection in the order specified below.\n\n### Socket Init Handler\n\n| Event                 | Signature                                             | Availability         |\n| --------------------- | ----------------------------------------------------- | -------------------- |\n| Socket initialization | `socket_init(connection_hdl, asio::ip::tcp::socket&)` | 0.3.0 Asio Transport |\n\nThis hook is triggered after the socket has been initialized but before a connection is established. \nIt allows setting arbitrary socket options before connections are sent/recieved.\n\n### TCP Pre-init Handler\n\n| Event                         | Signature                      | Availability         |\n| ----------------------------- | ------------------------------ | -------------------- |\n| TCP established, no data sent | `tcp_pre_init(connection_hdl)` | 0.3.0 Asio Transport |\n\nThis hook is triggered after the TCP connection is established, but before any pre-WebSocket-handshake \noperations have been run. Common pre-handshake operations include TLS handshakes and proxy connections.\n\n### TCP Post-init Handler\n\n| Event                   | Signature                                  | Availability                  |\n| ----------------------- | ------------------------------------------ | ----------------------------- |\n| Request for TLS context | `tls_context_ptr tls_init(connection_hdl)` | 0.3.0 Asio Transport with TLS |\n\nThis hook is triggered before the TLS handshake to request the TLS context to use. You must \nreturn a pointer to a configured TLS conext to continue. This provides the opportuinity to \nset up the TLS settings, certificates, etc.\n\n### Validate Handler\n\n| Event                                 | Signature                       | Availability                 |\n| ------------------------------------- | ------------------------------- | ---------------------------- |\n| Hook to accept or reject a connection | `bool validate(connection_hdl)` | 0.3.0 Core, Server role only |\n\nThis hook is triggered for servers during the opening handshake after the request has been \nprocessed but before the response has been sent. It gives a program the opportunity to inspect\nheaders and other connection details and either accept or reject the connection. Validate happens\nbefore the open or fail handler.\n\nReturn true to accept the connection, false to reject. If no validate handler is registered, \nall connections will be accepted.\n\n### Open Connection Handler\n\n| Event                     | Signature              | Availability |\n| ------------------------- | ---------------------- | ------------ |\n| Successful new connection | `open(connection_hdl)` | 0.3.0 Core   |\n\nEither open or fail will be called for each connection. Never both. All\nconnections that begin with an open handler call will also have a matching\nclose handler call when the connection ends.\n\n### Fail Connection Handler\n\n| Event                               | Signature              | Availability |\n| ----------------------------------- | ---------------------- | ------------ |\n| Connection failed (before opening)  | `fail(connection_hdl)` | 0.3.0 Core   |\n\nEither open or fail will be called for each connection. Never both. Connections\nthat fail will never have a close handler called.\n\n### Close Connection Handler\n\n| Event                             | Signature               | Availability |\n| --------------------------------- | ----------------------- | ------------ |\n| Connection closed (after opening) | `close(connection_hdl)` | 0.3.0 Core   |\n\nClose will be called exactly once for every connection that open was called for.\nClose is not called for failed connections.\n\nMessage Handlers\n----------------\n\nThese handers are called in response to incoming messages or message like events. They only will be called while the connection is in the open state.\n\n### Message Handler\n\n| Event                 | Signature                              | Availability |\n| --------------------- | -------------------------------------- | ------------ |\n| Data message recieved | `message(connection_hdl, message_ptr)` | 0.3.0 Core   |\n\nApplies to all non-control messages, including both text and binary opcodes. The\n`message_ptr` type and its API depends on your endpoint type and its config.\n\n### Ping Handler\n\n| Event         | Signature                                | Availability |\n| ------------- | ---------------------------------------- | ------------ |\n| Ping recieved | `bool ping(connection_hdl, std::string)` | 0.3.0 Core   |\n\nSecond (string) argument is the binary ping payload. Handler return value\nindicates whether or not to respond to the ping with a pong. If no ping handler\nis set, WebSocket++ will respond with a pong containing the same binary data as\nthe ping (Per requirements in RFC6455).\n\n### Pong Handler\n\n| Event         | Signature                           | Availability |\n| ------------- | ----------------------------------- | ------------ |\n| Pong recieved | `pong(connection_hdl, std::string)` | 0.3.0 Core   |\n\nSecond (string) argument is the binary pong payload.\n\n### Pong Timeout Handler\n\n| Event                              | Signature                                   | Availability                             |\n| ---------------------------------- | ------------------------------------------- | ---------------------------------------- |\n| Timed out while waiting for a pong | `pong_timeout(connection_hdl, std::string)` | 0.3.0 Core, transport with timer support |\n\nTriggered if there is no response to a ping after the configured duration. The second\n(string) argument is the binary payload of the unanswered ping.\n\n### HTTP Handler\n\n| Event                 | Signature             | Availability                 |\n| --------------------- | --------------------- | ---------------------------- |\n| HTTP request recieved | `http(connection_hdl` | 0.3.0 Core, Server role only |\n\nCalled when HTTP requests that are not WebSocket handshake upgrade requests are\nrecieved. Allows responding to regular HTTP requests. If no handler is registered\na 426/Upgrade Required error is returned.\n\n### Interrupt Handler\n\n| Event                               | Signature                   | Availability |\n| ----------------------------------- | --------------------------- | ------------ |\n| Connection was manually interrupted | `interrupt(connection_hdl)` | 0.3.0 Core   |\n\nInterrupt events can be triggered by calling `endpoint::interrupt` or `connection::interrupt`. \nInterrupt is similar to a timer event with duration zero but with lower overhead. It is useful\nfor single threaded programs to allow breaking up a very long handler into multiple parts and \nfor multi threaded programs as a way for worker threads to signale to the main/network thread \nthat an event is ready.\n\ntodo: write low and high watermark handlers\n\n*/\n"
  },
  {
    "path": "docs/logging.dox",
    "content": "/** \\page reference.logging Logging Reference\n\nWebSocket++ has the capability of logging events during the lifetime of the connections that it processes. Each endpoint has two independent logging interfaces that are used by all connections created by that endpoint. The first is an access interface that allows logging routine events in the life of a connection (such as connect/disconnect and receipt of messages). The other is an error interface that allows logging non-routine problems or errors. Each interface has a number of different named channels that can be toggled on and off independently.\n\nExactly how these logs are processed and where they are written to depends on which logging policy is in use. Several logging policies are included by default and you can write your own policy if you need something more specialized. Selecting a policy is done via the  \\subpage reference.config \"endpoint config\".\n\nCommon functionality (all policies)\n-----------------------------------\n\n### Logging Channels\n\nEach logging interface is divided into 32 named channels. Log messages are written to a specific interface on a specific channel. Which log messages are actually printed is determined by which channels are enabled or not. Channels can be enabled or disabled either at compile time or at runtime.\n\n### Enabling and Disabling Channels\n\nChannels disabled at compile time are removed from the code entirely (assuming correct compiler optimization settings) and are not available for runtime enabling or disabling. To disable channels at compile time, use the `alog_level` and `elog_level` values within your \\subpage reference.config \"endpoint config\". Channels not disabled at compile time can be enabled or disabled at runtime using the `websocketpp::endpoint::set_access_channels()`, `websocketpp::endpoint::clear_access_channels()`, `websocketpp::endpoint::set_error_channels()`, and `websocketpp::endpoint::clear_error_channels()` methods.\n\nThe set and clear functions act only on the channels specified. `set_access_channels(log::alevel::connect)` will enable logging of new connections. Following this with `set_access_channels(log::alevel::disconnect)` will enable logging of disconnections in addition to connections. Use `clear*` functions to disable a specific channel. Channels may be combined using bitwise operations to create aggregate packages of channels that may be set or cleared at once. Default packages include `websocketpp::log::alevel::all`, `websocketpp::log::elevel::all`, `websocketpp::log::alevel::none`, `websocketpp::log::elevel::none`. These represent all possible access/error channels and no access/error channels respectively. For convenience, setting none is aliased to clearing all.\n\n### Examples\n\n__Disable all__\n\n`clear_access_channels(log::alevel::all)`\n\n__Disable all (alternative method)__\n\n`set_access_channels(log::alevel::none)`\n\n__Multiple channels at once__\n\n`log::alevel::message_payload | log::alevel::message_payload`\n\n__All except one__\n\n`log::alevel::all ^ log::alevel::message_payload`\n\n__Default settings__\n\nBy default, only debug/development logging is disabled.\n\n### Access to underlying loggers\n\nLogging interfaces may be directly accessed via their associated endpoint or connection using get_alog() and get_elog(). This allows access to methods specific to the chosen logging policy. \n\nBasic Logging (Default Policy)\n------------------------------\n\nThe basic logging policy (`websocketpp::log::basic`) writes logs to a std::ostream. By default, access logs are written to stdout and error logs are written to stderr. Each logging interface may be optionally redirected to an arbitrary C++ stream (including file streams) using the `websocketpp::log::basic::set_ostream()` method.\n\nSyslog Logging\n--------------\n\nThe syslog logging policy (`websocketpp::log::syslog`) logs to POSIX syslog. It is included in the header `<websocketpp/logger/syslog.hpp>`. It requires a system with `<syslog.h>`.\n\nStub Logging\n------------\n\nThe stub logging policy (`websocketpp::log::stub`) implements the logging policy interface but ignores all input and provides no output. It can be used to stub out the logging system in tests or to completely disable and remove nearly all logging related code. \n\nThe stub logger also provides documentation for the minimal required interface to build a custom logging policy.\n\nLog level reference\n-------------------\n\n### Error Logging Levels\n\nEach of these channels is in the namespace `websocketpp::log::elevel`\n\n| Level   | Description                                                                                                                |\n| ------- | -------------------------------------------------------------------------------------------------------------------------- |\n| none    | Special aggregate value representing \"no levels\"                                                                           |\n| devel   | Low level debugging information (warning: very chatty). Requires debug or custom config.                                   |\n| library | Information about unusual system states or other minor internal library problems, less chatty than devel.                  |\n| info    | Information about minor configuration problems or additional information about other warnings.                             |\n| warn    | Information about important problems not severe enough to terminate connections.                                           |\n| rerror  | Recoverable error. Recovery may mean cleanly closing the connection with an appropriate error code to the remote endpoint. |\n| fatal   | Unrecoverable error. This error will trigger immediate unclean termination of the connection or endpoint.                  |\n| all     | Special aggregate value representing \"all levels\"                                                                          |\n\n### Access Logging Levels\n\nEach of these channels is in the namespace `websocketpp::log::alevel`\n\n| Level           | Description                                                                                        |\n| --------------- | -------------------------------------------------------------------------------------------------- |\n| none            | Special aggregate value representing \"no levels\"                                                   |\n| connect         | One line for each new connection that includes a host of information including: the remote address, websocket version, requested resource, http code, remote user agent |\n| disconnect      | One line for each connection that is closed. Includes closing codes and reasons                    |\n| control         | One line per control message                                                                       |\n| frame_header    | One line per frame, includes the full frame header                                                 |\n| frame_payload   | One line per frame, includes the full message payload (warning: lots of output for large messages) |\n| message_header  | Reserved                                                                                           |\n| message_payload | Reserved                                                                                           |\n| endpoint        | Reserved                                                                                           |\n| debug_handshake | Extra information about opening handshakes                                                         |\n| debug_close     | Extra information about closing handshakes                                                         |\n| devel           | Development messages (warning: very chatty). Requires debug or custom config.                      |\n| app             | Special channel for application specific logs. Not used by the library.                            |\n| all             | Special aggregate value representing \"all levels\"                                                  |\n\n*/\n"
  },
  {
    "path": "docs/manual.css",
    "content": ".tabs, .tabs2, .tabs3, .navpath ul {\n    background-image: none;\n    background-color: #333;\n    border: none;\n    border-bottom: 1px solid #575757;\n}\n\n.tablist li, .navpath li {\n    background-image: none;\n    background-color: #333;\n}\n\n.tablist a, .navpath li.navelem a {\n    color: #ccc;\n    text-shadow: 0px 1px 1px black;\n}\n\n.tablist a:hover, .navpath li.navelem a:hover {\n    background-image: none;\n    background-color: #444;\n    color: #ccc;\n}\n"
  },
  {
    "path": "docs/manual.dox",
    "content": "/** \\mainpage\n\nWebSocket++ is a C++ library that can be used to implement WebSocket functionality. The goals of the project are to provide a WebSocket implementation that is portable, flexible, lightweight, low level, and high performance.\n\nWebSocket++ does not intend to be used alone as a web application framework or full featured web services platform. As such the components, examples, and performance tuning are geared towards operation as a WebSocket client or server. There are some minimal convenience features that stray from this (for example the ability to respond to HTTP requests other than WebSocket Upgrades) but these are not the focus of the project. In particular WebSocket++ does not intend to implement any non-WebSocket related fallback options (ajax / long polling / comet / etc).\n\nIn order to remain compact and improve portability, the WebSocket++ project strives to reduce or eliminate external dependencies where possible and appropriate. WebSocket++ core has no dependencies other than the C++11 standard library. For non-C++11 compilers the Boost libraries provide drop in polyfills for the C++11 functionality used.\n\nWebSocket++ implements a pluggable data transport component. The default component allows reduced functionality by using STL iostream or raw byte shuffling via reading and writing char buffers. This component has no non-STL dependencies and can be used in a C++11 environment without Boost. Also included is an Asio based transport component that provides full featured network client/server functionality. This component requires either Boost Asio or a C++11 compiler and standalone Asio. As an advanced option, WebSocket++ supports custom transport layers if you want to provide your own using another library.\n\nIn order to accommodate the wide variety of use cases WebSocket++ has collected, the library is built in a way that most of the major components are loosely coupled and can be swapped out and replaced. WebSocket++ will attempt to track the future development of the WebSocket protocol and any extensions as they are developed.\n\n- \\subpage getting_started \"Getting Started\"\n- \\subpage faq \"FAQ\"\n- \\subpage tutorials \"Tutorials\"\n- \\subpage md_changelog \"Change Log / Version History\"\n- Reference\n - \\subpage reference.handlers \"Handler Reference\"\n - \\subpage reference.config \"Config Reference\"\n - \\subpage reference.logging \"Logging Reference\"\n\n*/\n\n"
  },
  {
    "path": "docs/simple_broadcast_server.cpp",
    "content": "#include <set>\n\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nusing websocketpp::connection_hdl;\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\nclass broadcast_server {\npublic:\n    broadcast_server() {\n        m_server.init_asio();\n                \n        m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));\n        m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));\n        m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));\n    }\n    \n    void on_open(connection_hdl hdl) {\n        m_connections.insert(hdl);\n    }\n    \n    void on_close(connection_hdl hdl) {\n        m_connections.erase(hdl);\n    }\n    \n    void on_message(connection_hdl hdl, server::message_ptr msg) {\n        for (auto it : m_connections) {\n            m_server.send(it,msg);\n        }\n    }\n\n    void run(uint16_t port) {\n        m_server.listen(port);\n        m_server.start_accept();\n        m_server.run();\n    }\nprivate:\n    typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;\n\n    server m_server;\n    con_list m_connections;\n};\n\nint main() {\n    broadcast_server server;\n    server.run(9002);\n}"
  },
  {
    "path": "docs/simple_count_server_thread.cpp",
    "content": "#include <functional>\n#include <mutex>\n#include <set>\n#include <thread>\n\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nusing websocketpp::connection_hdl;\n\nclass count_server {\npublic:\n    count_server() : m_count(0) {\n        m_server.init_asio();\n                \n        m_server.set_open_handler(bind(&count_server::on_open,this,_1));\n        m_server.set_close_handler(bind(&count_server::on_close,this,_1));\n    }\n    \n    void on_open(connection_hdl hdl) {\n        std::lock_guard<std::mutex> lock(m_mutex);\n        m_connections.insert(hdl);\n    }\n    \n    void on_close(connection_hdl hdl) {\n        std::lock_guard<std::mutex> lock(m_mutex);\n        m_connections.erase(hdl);\n    }\n    \n    void count() {\n        while (1) {\n            sleep(1);\n            m_count++;\n            \n            std::stringstream ss;\n            ss << m_count;\n            \n            std::lock_guard<std::mutex> lock(m_mutex);    \n            for (auto it : m_connections) {\n                m_server.send(it,ss.str(),websocketpp::frame::opcode::text);\n            }\n        }\n    }\n    \n    void run(uint16_t port) {\n        m_server.listen(port);\n        m_server.start_accept();\n        m_server.run();\n    }\nprivate:\n    typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;\n    \n    int m_count;\n    server m_server;\n    con_list m_connections;\n    std::mutex m_mutex;\n};\n\nint main() {\n    count_server server;\n    std::thread t(std::bind(&count_server::count,&server));\n    server.run(9002);\n}"
  },
  {
    "path": "docs/tutorials.dox",
    "content": "/** \\page tutorials Tutorials\n\nThese tutorials are works in progress, some are more complete than others.\n\n- \\subpage md_tutorials_utility_client_utility_client\n- \\subpage md_tutorials_utility_server_utility_server\n- \\subpage md_tutorials_broadcast_tutorial_broadcast_tutorial\n- \\subpage md_tutorials_chat_tutorial_chat_tutorial\n\n*/\n"
  },
  {
    "path": "examples/associative_storage/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (associative_storage)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/associative_storage/associative_storage.cpp",
    "content": "#include <iostream>\n#include <map>\n#include <exception>\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nusing websocketpp::connection_hdl;\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\nstruct connection_data {\n    int sessionid;\n    std::string name;\n};\n\nclass print_server {\npublic:\n    print_server() : m_next_sessionid(1) {\n        m_server.init_asio();\n\n        m_server.set_open_handler(bind(&print_server::on_open,this,::_1));\n        m_server.set_close_handler(bind(&print_server::on_close,this,::_1));\n        m_server.set_message_handler(bind(&print_server::on_message,this,::_1,::_2));\n    }\n\n    void on_open(connection_hdl hdl) {\n        connection_data data;\n\n        data.sessionid = m_next_sessionid++;\n        data.name.clear();\n\n        m_connections[hdl] = data;\n    }\n\n    void on_close(connection_hdl hdl) {\n        connection_data& data = get_data_from_hdl(hdl);\n\n        std::cout << \"Closing connection \" << data.name\n                  << \" with sessionid \" << data.sessionid << std::endl;\n\n        m_connections.erase(hdl);\n    }\n\n    void on_message(connection_hdl hdl, server::message_ptr msg) {\n        connection_data& data = get_data_from_hdl(hdl);\n\n        if (data.name.empty()) {\n            data.name = msg->get_payload();\n            std::cout << \"Setting name of connection with sessionid \"\n                      << data.sessionid << \" to \" << data.name << std::endl;\n        } else {\n            std::cout << \"Got a message from connection \" << data.name\n                      << \" with sessionid \" << data.sessionid << std::endl;\n        }\n    }\n\n    connection_data& get_data_from_hdl(connection_hdl hdl) {\n        auto it = m_connections.find(hdl);\n\n        if (it == m_connections.end()) {\n            // this connection is not in the list. This really shouldn't happen\n            // and probably means something else is wrong.\n            throw std::invalid_argument(\"No data available for session\");\n        }\n\n        return it->second;\n    }\n\n    void run(uint16_t port) {\n        m_server.listen(port);\n        m_server.start_accept();\n        m_server.run();\n    }\nprivate:\n    typedef std::map<connection_hdl,connection_data,std::owner_less<connection_hdl>> con_list;\n\n    int m_next_sessionid;\n    server m_server;\n    con_list m_connections;\n};\n\nint main() {\n    print_server server;\n    server.run(9002);\n}\n"
  },
  {
    "path": "examples/broadcast_server/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (broadcast_server)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/broadcast_server/SConscript",
    "content": "## Broadcast Server example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('broadcast_server', [\"broadcast_server.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system','thread'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('broadcast_server', [\"broadcast_server.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/broadcast_server/broadcast_server.cpp",
    "content": "#include <websocketpp/config/asio_no_tls.hpp>\n\n#include <websocketpp/server.hpp>\n\n#include <iostream>\n#include <set>\n\n/*#include <boost/thread.hpp>\n#include <boost/thread/mutex.hpp>\n#include <boost/thread/condition_variable.hpp>*/\n#include <websocketpp/common/thread.hpp>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nusing websocketpp::connection_hdl;\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\nusing websocketpp::lib::thread;\nusing websocketpp::lib::mutex;\nusing websocketpp::lib::lock_guard;\nusing websocketpp::lib::unique_lock;\nusing websocketpp::lib::condition_variable;\n\n/* on_open insert connection_hdl into channel\n * on_close remove connection_hdl from channel\n * on_message queue send to all channels\n */\n\nenum action_type {\n    SUBSCRIBE,\n    UNSUBSCRIBE,\n    MESSAGE\n};\n\nstruct action {\n    action(action_type t, connection_hdl h) : type(t), hdl(h) {}\n    action(action_type t, connection_hdl h, server::message_ptr m)\n      : type(t), hdl(h), msg(m) {}\n\n    action_type type;\n    websocketpp::connection_hdl hdl;\n    server::message_ptr msg;\n};\n\nclass broadcast_server {\npublic:\n    broadcast_server() {\n        // Initialize Asio Transport\n        m_server.init_asio();\n\n        // Register handler callbacks\n        m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));\n        m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));\n        m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));\n    }\n\n    void run(uint16_t port) {\n        // listen on specified port\n        m_server.listen(port);\n\n        // Start the server accept loop\n        m_server.start_accept();\n\n        // Start the ASIO io_service run loop\n        try {\n            m_server.run();\n        } catch (const std::exception & e) {\n            std::cout << e.what() << std::endl;\n        }\n    }\n\n    void on_open(connection_hdl hdl) {\n        {\n            lock_guard<mutex> guard(m_action_lock);\n            //std::cout << \"on_open\" << std::endl;\n            m_actions.push(action(SUBSCRIBE,hdl));\n        }\n        m_action_cond.notify_one();\n    }\n\n    void on_close(connection_hdl hdl) {\n        {\n            lock_guard<mutex> guard(m_action_lock);\n            //std::cout << \"on_close\" << std::endl;\n            m_actions.push(action(UNSUBSCRIBE,hdl));\n        }\n        m_action_cond.notify_one();\n    }\n\n    void on_message(connection_hdl hdl, server::message_ptr msg) {\n        // queue message up for sending by processing thread\n        {\n            lock_guard<mutex> guard(m_action_lock);\n            //std::cout << \"on_message\" << std::endl;\n            m_actions.push(action(MESSAGE,hdl,msg));\n        }\n        m_action_cond.notify_one();\n    }\n\n    void process_messages() {\n        while(1) {\n            unique_lock<mutex> lock(m_action_lock);\n\n            while(m_actions.empty()) {\n                m_action_cond.wait(lock);\n            }\n\n            action a = m_actions.front();\n            m_actions.pop();\n\n            lock.unlock();\n\n            if (a.type == SUBSCRIBE) {\n                lock_guard<mutex> guard(m_connection_lock);\n                m_connections.insert(a.hdl);\n            } else if (a.type == UNSUBSCRIBE) {\n                lock_guard<mutex> guard(m_connection_lock);\n                m_connections.erase(a.hdl);\n            } else if (a.type == MESSAGE) {\n                lock_guard<mutex> guard(m_connection_lock);\n\n                con_list::iterator it;\n                for (it = m_connections.begin(); it != m_connections.end(); ++it) {\n                    m_server.send(*it,a.msg);\n                }\n            } else {\n                // undefined.\n            }\n        }\n    }\nprivate:\n    typedef std::set<connection_hdl,std::owner_less<connection_hdl> > con_list;\n\n    server m_server;\n    con_list m_connections;\n    std::queue<action> m_actions;\n\n    mutex m_action_lock;\n    mutex m_connection_lock;\n    condition_variable m_action_cond;\n};\n\nint main() {\n    try {\n    broadcast_server server_instance;\n\n    // Start a thread to run the processing loop\n    thread t(bind(&broadcast_server::process_messages,&server_instance));\n\n    // Run the asio loop with the main thread\n    server_instance.run(9002);\n\n    t.join();\n\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/debug_client/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\nif (OPENSSL_FOUND)\n\ninit_target (debug_client)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nlink_openssl()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n\nendif()"
  },
  {
    "path": "examples/debug_client/SConscript",
    "content": "## Debug client example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\nImport('tls_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   prgs += env_cpp11.Program('debug_client', [\"debug_client.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   prgs += env.Program('debug_client', [\"debug_client.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/debug_client/debug_client.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/** ====== WARNING ========\n * This example is presently used as a scratch space. It may or may not be broken\n * at any given time.\n */\n\n#include <websocketpp/config/asio_client.hpp>\n\n#include <websocketpp/client.hpp>\n\n#include <iostream>\n#include <chrono>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n// pull out the type of messages sent by our config\ntypedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr;\ntypedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;\ntypedef client::connection_ptr connection_ptr;\n\n\n\nclass perftest {\npublic:\n    typedef perftest type;\n    typedef std::chrono::duration<int,std::micro> dur_type;\n\n    perftest () {\n        m_endpoint.set_access_channels(websocketpp::log::alevel::all);\n        m_endpoint.set_error_channels(websocketpp::log::elevel::all);\n\n        // Initialize ASIO\n        m_endpoint.init_asio();\n\n        // Register our handlers\n        m_endpoint.set_socket_init_handler(bind(&type::on_socket_init,this,::_1));\n        //m_endpoint.set_tls_init_handler(bind(&type::on_tls_init,this,::_1));\n        m_endpoint.set_message_handler(bind(&type::on_message,this,::_1,::_2));\n        m_endpoint.set_open_handler(bind(&type::on_open,this,::_1));\n        m_endpoint.set_close_handler(bind(&type::on_close,this,::_1));\n        m_endpoint.set_fail_handler(bind(&type::on_fail,this,::_1));\n    }\n\n    void start(std::string uri) {\n        websocketpp::lib::error_code ec;\n        client::connection_ptr con = m_endpoint.get_connection(uri, ec);\n\n        if (ec) {\n            m_endpoint.get_alog().write(websocketpp::log::alevel::app,ec.message());\n            return;\n        }\n\n        //con->set_proxy(\"http://humupdates.uchicago.edu:8443\");\n\n        m_endpoint.connect(con);\n\n        // Start the ASIO io_service run loop\n        m_start = std::chrono::high_resolution_clock::now();\n        m_endpoint.run();\n    }\n\n    void on_socket_init(websocketpp::connection_hdl) {\n        m_socket_init = std::chrono::high_resolution_clock::now();\n    }\n\n    context_ptr on_tls_init(websocketpp::connection_hdl) {\n        m_tls_init = std::chrono::high_resolution_clock::now();\n        context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);\n\n        try {\n            ctx->set_options(boost::asio::ssl::context::default_workarounds |\n                             boost::asio::ssl::context::no_sslv2 |\n                             boost::asio::ssl::context::no_sslv3 |\n                             boost::asio::ssl::context::single_dh_use);\n        } catch (std::exception& e) {\n            std::cout << e.what() << std::endl;\n        }\n        return ctx;\n    }\n\n    void on_fail(websocketpp::connection_hdl hdl) {\n        client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl);\n        \n        std::cout << \"Fail handler\" << std::endl;\n        std::cout << con->get_state() << std::endl;\n        std::cout << con->get_local_close_code() << std::endl;\n        std::cout << con->get_local_close_reason() << std::endl;\n        std::cout << con->get_remote_close_code() << std::endl;\n        std::cout << con->get_remote_close_reason() << std::endl;\n        std::cout << con->get_ec() << \" - \" << con->get_ec().message() << std::endl;\n    }\n\n    void on_open(websocketpp::connection_hdl hdl) {\n        m_open = std::chrono::high_resolution_clock::now();\n        m_endpoint.send(hdl, \"\", websocketpp::frame::opcode::text);\n    }\n    void on_message(websocketpp::connection_hdl hdl, message_ptr) {\n        m_message = std::chrono::high_resolution_clock::now();\n        m_endpoint.close(hdl,websocketpp::close::status::going_away,\"\");\n    }\n    void on_close(websocketpp::connection_hdl) {\n        m_close = std::chrono::high_resolution_clock::now();\n\n        std::cout << \"Socket Init: \" << std::chrono::duration_cast<dur_type>(m_socket_init-m_start).count() << std::endl;\n        std::cout << \"TLS Init: \" << std::chrono::duration_cast<dur_type>(m_tls_init-m_start).count() << std::endl;\n        std::cout << \"Open: \" << std::chrono::duration_cast<dur_type>(m_open-m_start).count() << std::endl;\n        std::cout << \"Message: \" << std::chrono::duration_cast<dur_type>(m_message-m_start).count() << std::endl;\n        std::cout << \"Close: \" << std::chrono::duration_cast<dur_type>(m_close-m_start).count() << std::endl;\n    }\nprivate:\n    client m_endpoint;\n\n    std::chrono::high_resolution_clock::time_point m_start;\n    std::chrono::high_resolution_clock::time_point m_socket_init;\n    std::chrono::high_resolution_clock::time_point m_tls_init;\n    std::chrono::high_resolution_clock::time_point m_open;\n    std::chrono::high_resolution_clock::time_point m_message;\n    std::chrono::high_resolution_clock::time_point m_close;\n};\n\nint main(int argc, char* argv[]) {\n    std::string uri = \"wss://echo.websocket.org\";\n\n    if (argc == 2) {\n        uri = argv[1];\n    }\n\n    try {\n        perftest endpoint;\n        endpoint.start(uri);\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    } catch (std::exception const & e) {\n        std::cout << e.what() << std::endl;\n    } catch (...) {\n        std::cout << \"other exception\" << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/debug_server/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (debug_server)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/debug_server/SConscript",
    "content": "## Debug server example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('debug_server', [\"debug_server.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('debug_server', [\"debug_server.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/debug_server/debug_server.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/** ====== WARNING ========\n * This example is presently used as a scratch space. It may or may not be broken\n * at any given time.\n */\n\n#include <websocketpp/config/debug_asio_no_tls.hpp>\n\n// Custom logger\n#include <websocketpp/logger/syslog.hpp>\n\n#include <websocketpp/server.hpp>\n\n#include <iostream>\n\n////////////////////////////////////////////////////////////////////////////////\n///////////////// Custom Config for debugging custom policies //////////////////\n////////////////////////////////////////////////////////////////////////////////\n\nstruct debug_custom : public websocketpp::config::debug_asio {\n    typedef debug_custom type;\n    typedef debug_asio base;\n\n    typedef base::concurrency_type concurrency_type;\n\n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    /// Custom Logging policies\n    /*typedef websocketpp::log::syslog<concurrency_type,\n        websocketpp::log::elevel> elog_type;\n    typedef websocketpp::log::syslog<concurrency_type,\n        websocketpp::log::alevel> alog_type;\n    */\n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n\n    typedef base::rng_type rng_type;\n\n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::basic_socket::endpoint\n            socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config>\n        transport_type;\n    \n    static const long timeout_open_handshake = 0;\n};\n\n////////////////////////////////////////////////////////////////////////////////\n\ntypedef websocketpp::server<debug_custom> server;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n// pull out the type of messages sent by our config\ntypedef server::message_ptr message_ptr;\n\nbool validate(server *, websocketpp::connection_hdl) {\n    //sleep(6);\n    return true;\n}\n\nvoid on_http(server* s, websocketpp::connection_hdl hdl) {\n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n\n    std::string res = con->get_request_body();\n\n    std::stringstream ss;\n    ss << \"got HTTP request with \" << res.size() << \" bytes of body data.\";\n\n    con->set_body(ss.str());\n    con->set_status(websocketpp::http::status_code::ok);\n}\n\nvoid on_fail(server* s, websocketpp::connection_hdl hdl) {\n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n    \n    std::cout << \"Fail handler: \" << con->get_ec() << \" \" << con->get_ec().message()  << std::endl;\n}\n\nvoid on_close(websocketpp::connection_hdl) {\n    std::cout << \"Close handler\" << std::endl;\n}\n\n// Define a callback to handle incoming messages\nvoid on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {\n    std::cout << \"on_message called with hdl: \" << hdl.lock().get()\n              << \" and message: \" << msg->get_payload()\n              << std::endl;\n\n    try {\n        s->send(hdl, msg->get_payload(), msg->get_opcode());\n    } catch (websocketpp::exception const & e) {\n        std::cout << \"Echo failed because: \" \n                  << \"(\" << e.what() << \")\" << std::endl;\n    }\n}\n\nint main() {\n    // Create a server endpoint\n    server echo_server;\n\n    try {\n        // Set logging settings\n        echo_server.set_access_channels(websocketpp::log::alevel::all);\n        echo_server.clear_access_channels(websocketpp::log::alevel::frame_payload);\n\n        // Initialize ASIO\n        echo_server.init_asio();\n        echo_server.set_reuse_addr(true);\n\n        // Register our message handler\n        echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));\n\n        echo_server.set_http_handler(bind(&on_http,&echo_server,::_1));\n        echo_server.set_fail_handler(bind(&on_fail,&echo_server,::_1));\n        echo_server.set_close_handler(&on_close);\n\n        echo_server.set_validate_handler(bind(&validate,&echo_server,::_1));\n\n        // Listen on port 9012\n        echo_server.listen(9012);\n\n        // Start the server accept loop\n        echo_server.start_accept();\n\n        // Start the ASIO io_service run loop\n        echo_server.run();\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    } catch (const std::exception & e) {\n        std::cout << e.what() << std::endl;\n    } catch (...) {\n        std::cout << \"other exception\" << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/dev/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\n#init_target (dev)\n\n#build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\n#link_boost ()\n#final_target ()\n\n#set_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/dev/SConscript",
    "content": "## Main development example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system','timer','chrono'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('main', [\"main.cpp\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/dev/main.cpp",
    "content": "//#ifndef _WEBSOCKETPP_CPP11_STL_\n//    #define _WEBSOCKETPP_CPP11_STL_\n//#endif\n\n#include <random>\n#include <boost/timer/timer.hpp>\n\n#include <websocketpp/config/core.hpp>\n\n//#include <websocketpp/security/none.hpp>\n\n//#include <websocketpp/concurrency/none.hpp>\n//#include <websocketpp/concurrency/stl.hpp>\n\n//#include <websocketpp/transport/iostream.hpp>\n#include <websocketpp/server.hpp>\n\n#include <iostream>\n#include <sstream>\n\n//typedef websocketpp::concurrency::stl concurrency;\n//typedef websocketpp::transport::iostream<concurrency> transport;\n//typedef websocketpp::server<concurrency,transport> server;\ntypedef websocketpp::server<websocketpp::config::core> server;\n\n/*class handler : public server::handler {\n    bool validate(connection_ptr con) {\n        std::cout << \"handler validate\" << std::endl;\n        if (con->get_origin() != \"http://www.example.com\") {\n            con->set_status(websocketpp::http::status_code::FORBIDDEN);\n            return false;\n        }\n        return true;\n    }\n\n    void http(connection_ptr con) {\n        std::cout << \"handler http\" << std::endl;\n    }\n\n    void on_load(connection_ptr con, ptr old_handler) {\n        std::cout << \"handler on_load\" << std::endl;\n    }\n    void on_unload(connection_ptr con, ptr new_handler) {\n        std::cout << \"handler on_unload\" << std::endl;\n    }\n\n    void on_open(connection_ptr con) {\n        std::cout << \"handler on_open\" << std::endl;\n    }\n    void on_fail(connection_ptr con) {\n        std::cout << \"handler on_fail\" << std::endl;\n    }\n\n    void on_message(connection_ptr con, message_ptr msg) {\n        std::cout << \"handler on_message\" << std::endl;\n\n\n    }\n\n    void on_close(connection_ptr con) {\n        std::cout << \"handler on_close\" << std::endl;\n    }\n};*/\n\nint main() {\n    typedef websocketpp::message_buffer::message<websocketpp::message_buffer::alloc::con_msg_manager>\n        message_type;\n    typedef websocketpp::message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_man_type;\n\n    con_msg_man_type::ptr manager = websocketpp::lib::make_shared<con_msg_man_type>();\n\n    size_t foo = 1024;\n\n    message_type::ptr input = manager->get_message(websocketpp::frame::opcode::TEXT,foo);\n    message_type::ptr output = manager->get_message(websocketpp::frame::opcode::TEXT,foo);\n    websocketpp::frame::masking_key_type key;\n\n    std::random_device dev;\n\n\n\n    key.i = 0x12345678;\n\n    double m = 18094238402394.0824923;\n\n    /*std::cout << \"Some Math\" << std::endl;\n    {\n        boost::timer::auto_cpu_timer t;\n\n        for (int i = 0; i < foo; i++) {\n            m /= 1.001;\n        }\n\n    }*/\n\n    std::cout << m << std::endl;\n\n    std::cout << \"Random Gen\" << std::endl;\n    {\n        boost::timer::auto_cpu_timer t;\n\n        input->get_raw_payload().replace(0,foo,foo,'\\0');\n        output->get_raw_payload().replace(0,foo,foo,'\\0');\n    }\n\n    std::cout << \"Out of place accelerated\" << std::endl;\n    {\n        boost::timer::auto_cpu_timer t;\n\n        websocketpp::frame::word_mask_exact(reinterpret_cast<uint8_t*>(const_cast<char*>(input->get_raw_payload().data())), reinterpret_cast<uint8_t*>(const_cast<char*>(output->get_raw_payload().data())), foo, key);\n    }\n\n    std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;\n    std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;\n\n    input->get_raw_payload().replace(0,foo,foo,'\\0');\n    output->get_raw_payload().replace(0,foo,foo,'\\0');\n\n    std::cout << \"In place accelerated\" << std::endl;\n    {\n        boost::timer::auto_cpu_timer t;\n\n        websocketpp::frame::word_mask_exact(reinterpret_cast<uint8_t*>(const_cast<char*>(input->get_raw_payload().data())), reinterpret_cast<uint8_t*>(const_cast<char*>(input->get_raw_payload().data())), foo, key);\n    }\n\n    std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;\n    std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;\n\n    input->get_raw_payload().replace(0,foo,foo,'\\0');\n    output->get_raw_payload().replace(0,foo,foo,'\\0');\n    std::cout << \"Out of place byte by byte\" << std::endl;\n    {\n        boost::timer::auto_cpu_timer t;\n\n        websocketpp::frame::byte_mask(input->get_raw_payload().begin(), input->get_raw_payload().end(), output->get_raw_payload().begin(), key);\n    }\n\n    std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;\n    std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;\n\n    input->get_raw_payload().replace(0,foo,foo,'\\0');\n    output->get_raw_payload().replace(0,foo,foo,'\\0');\n    std::cout << \"In place byte by byte\" << std::endl;\n    {\n        boost::timer::auto_cpu_timer t;\n\n        websocketpp::frame::byte_mask(input->get_raw_payload().begin(), input->get_raw_payload().end(), input->get_raw_payload().begin(), key);\n    }\n\n    std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;\n    std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;\n\n    input->get_raw_payload().replace(0,foo,foo,'a');\n    output->get_raw_payload().replace(0,foo,foo,'b');\n    std::cout << \"Copy\" << std::endl;\n    {\n        boost::timer::auto_cpu_timer t;\n\n        std::copy(input->get_raw_payload().begin(), input->get_raw_payload().end(), output->get_raw_payload().begin());\n    }\n\n    std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;\n    std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;\n\n    /*server::handler::ptr h(new handler());\n\n    server test_server(h);\n    server::connection_ptr con;\n\n    std::stringstream output;\n\n    test_server.register_ostream(&output);\n\n    con = test_server.get_connection();\n\n    con->start();\n\n    //foo.handle_accept(con,true);\n\n    std::stringstream input;\n    input << \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n    //input << \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\n\\r\\n\";\n    input >> *con;\n\n    std::stringstream input2;\n    input2 << \"messageabc2\";\n    input2 >> *con;\n\n    std::stringstream input3;\n    input3 << \"messageabc3\";\n    input3 >> *con;\n\n    std::stringstream input4;\n    input4 << \"close\";\n    input4 >> *con;\n\n    std::cout << \"connection output:\" << std::endl;\n    std::cout << output.str() << std::endl;*/\n}\n"
  },
  {
    "path": "examples/echo_client/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (echo_client)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/echo_client/SConscript",
    "content": "## echo_client example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']\n   prgs += env_cpp11.Program('echo_client', [\"echo_client.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + ['z']\n   prgs += env.Program('echo_client', [\"echo_client.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/echo_client/echo_client.cpp",
    "content": "/*\n * Copyright (c) 2016, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <iostream>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n// pull out the type of messages sent by our config\ntypedef websocketpp::config::asio_client::message_type::ptr message_ptr;\n\n// This message handler will be invoked once for each incoming message. It\n// prints the message and then sends a copy of the message back to the server.\nvoid on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) {\n    std::cout << \"on_message called with hdl: \" << hdl.lock().get()\n              << \" and message: \" << msg->get_payload()\n              << std::endl;\n\n\n    websocketpp::lib::error_code ec;\n\n    c->send(hdl, msg->get_payload(), msg->get_opcode(), ec);\n    if (ec) {\n        std::cout << \"Echo failed because: \" << ec.message() << std::endl;\n    }\n}\n\nint main(int argc, char* argv[]) {\n    // Create a client endpoint\n    client c;\n\n    std::string uri = \"ws://localhost:9002\";\n\n    if (argc == 2) {\n        uri = argv[1];\n    }\n\n    try {\n        // Set logging to be pretty verbose (everything except message payloads)\n        c.set_access_channels(websocketpp::log::alevel::all);\n        c.clear_access_channels(websocketpp::log::alevel::frame_payload);\n\n        // Initialize ASIO\n        c.init_asio();\n\n        // Register our message handler\n        c.set_message_handler(bind(&on_message,&c,::_1,::_2));\n\n        websocketpp::lib::error_code ec;\n        client::connection_ptr con = c.get_connection(uri, ec);\n        if (ec) {\n            std::cout << \"could not create connection because: \" << ec.message() << std::endl;\n            return 0;\n        }\n\n        // Note that connect here only requests a connection. No network messages are\n        // exchanged until the event loop starts running in the next line.\n        c.connect(con);\n\n        // Start the ASIO io_service run loop\n        // this will cause a single connection to be made to the server. c.run()\n        // will exit when this connection is closed.\n        c.run();\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/echo_server/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (echo_server)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/echo_server/SConscript",
    "content": "## Main development example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('echo_server', [\"echo_server.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('echo_server', [\"echo_server.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/echo_server/echo_handler.hpp",
    "content": "/*\n * Copyright (c) 2012, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP\n#define WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP\n\nclass echo_handler : public server::handler {\n    void on_message(connection_ptr con, std::string msg) {\n        con->write(msg);\n    }\n};\n\n#endif // WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP\n"
  },
  {
    "path": "examples/echo_server/echo_server.cpp",
    "content": "#include <websocketpp/config/asio_no_tls.hpp>\n\n#include <websocketpp/server.hpp>\n\n#include <iostream>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n// pull out the type of messages sent by our config\ntypedef server::message_ptr message_ptr;\n\n// Define a callback to handle incoming messages\nvoid on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {\n    std::cout << \"on_message called with hdl: \" << hdl.lock().get()\n              << \" and message: \" << msg->get_payload()\n              << std::endl;\n\n    // check for a special command to instruct the server to stop listening so\n    // it can be cleanly exited.\n    if (msg->get_payload() == \"stop-listening\") {\n        s->stop_listening();\n        return;\n    }\n\n    try {\n        s->send(hdl, msg->get_payload(), msg->get_opcode());\n    } catch (websocketpp::exception const & e) {\n        std::cout << \"Echo failed because: \"\n                  << \"(\" << e.what() << \")\" << std::endl;\n    }\n}\n\nint main() {\n    // Create a server endpoint\n    server echo_server;\n\n    try {\n        // Set logging settings\n        echo_server.set_access_channels(websocketpp::log::alevel::all);\n        echo_server.clear_access_channels(websocketpp::log::alevel::frame_payload);\n\n        // Initialize Asio\n        echo_server.init_asio();\n\n        // Register our message handler\n        echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));\n\n        // Listen on port 9002\n        echo_server.listen(9002);\n\n        // Start the server accept loop\n        echo_server.start_accept();\n\n        // Start the ASIO io_service run loop\n        echo_server.run();\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    } catch (...) {\n        std::cout << \"other exception\" << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/echo_server_both/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\n\nif (OPENSSL_FOUND)\n\ninit_target (echo_server_both)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nlink_openssl()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n\nendif()\n"
  },
  {
    "path": "examples/echo_server_both/SConscript",
    "content": "## Combo plain+tls echo server\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\nImport('tls_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   prgs += env_cpp11.Program('echo_server_both', [\"echo_server_both.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   prgs += env.Program('echo_server_both', [\"echo_server_both.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/echo_server_both/echo_server_both.cpp",
    "content": "#include <websocketpp/config/asio.hpp>\n#include <websocketpp/server.hpp>\n\n#include <iostream>\n\n// define types for two different server endpoints, one for each config we are\n// using\ntypedef websocketpp::server<websocketpp::config::asio> server_plain;\ntypedef websocketpp::server<websocketpp::config::asio_tls> server_tls;\n\n// alias some of the bind related functions as they are a bit long\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n// type of the ssl context pointer is long so alias it\ntypedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;\n\n// The shared on_message handler takes a template parameter so the function can\n// resolve any endpoint dependent types like message_ptr or connection_ptr\ntemplate <typename EndpointType>\nvoid on_message(EndpointType* s, websocketpp::connection_hdl hdl,\n    typename EndpointType::message_ptr msg)\n{\n    std::cout << \"on_message called with hdl: \" << hdl.lock().get()\n              << \" and message: \" << msg->get_payload()\n              << std::endl;\n\n    try {\n        s->send(hdl, msg->get_payload(), msg->get_opcode());\n    } catch (websocketpp::exception const & e) {\n        std::cout << \"Echo failed because: \"\n                  << \"(\" << e.what() << \")\" << std::endl;\n    }\n}\n\n// No change to TLS init methods from echo_server_tls\nstd::string get_password() {\n    return \"test\";\n}\n\ncontext_ptr on_tls_init(websocketpp::connection_hdl hdl) {\n    std::cout << \"on_tls_init called with hdl: \" << hdl.lock().get() << std::endl;\n    context_ptr ctx(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));\n\n    try {\n        ctx->set_options(boost::asio::ssl::context::default_workarounds |\n                         boost::asio::ssl::context::no_sslv2 |\n                         boost::asio::ssl::context::no_sslv3 |\n                         boost::asio::ssl::context::single_dh_use);\n        ctx->set_password_callback(bind(&get_password));\n        ctx->use_certificate_chain_file(\"server.pem\");\n        ctx->use_private_key_file(\"server.pem\", boost::asio::ssl::context::pem);\n    } catch (std::exception& e) {\n        std::cout << e.what() << std::endl;\n    }\n    return ctx;\n}\n\nint main() {\n    // set up an external io_service to run both endpoints on. This is not\n    // strictly necessary, but simplifies thread management a bit.\n    boost::asio::io_service ios;\n\n    // set up plain endpoint\n    server_plain endpoint_plain;\n    // initialize asio with our external io_service rather than an internal one\n    endpoint_plain.init_asio(&ios);\n    endpoint_plain.set_message_handler(\n        bind(&on_message<server_plain>,&endpoint_plain,::_1,::_2));\n    endpoint_plain.listen(80);\n    endpoint_plain.start_accept();\n\n    // set up tls endpoint\n    server_tls endpoint_tls;\n    endpoint_tls.init_asio(&ios);\n    endpoint_tls.set_message_handler(\n        bind(&on_message<server_tls>,&endpoint_tls,::_1,::_2));\n    // TLS endpoint has an extra handler for the tls init\n    endpoint_tls.set_tls_init_handler(bind(&on_tls_init,::_1));\n    // tls endpoint listens on a different port\n    endpoint_tls.listen(443);\n    endpoint_tls.start_accept();\n\n    // Start the ASIO io_service run loop running both endpoints\n    ios.run();\n}\n"
  },
  {
    "path": "examples/echo_server_both/server.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,A0ED66EF872A48A9\n\ngXuvKojXzApVhhPVNdRliiajbC4PtwQG5c8TA7JADLgwOR7o9t6KtXEr37bDRpvB\n9aO9P+SJaK5OOp3XKPGthOdqv+tvCRTlmzmC8GjPLBX389DWT2xoGu7JkGwDtdSm\nrnF49Rlp5bfjpACk5xKNiKeDo1CWfeEJzw9Kto0g+5eMaEdors64oPzjXs3geA2g\nTxCJSHv9qSX6++pCLKKCUTbyzidAxV/Zb0AAubt5V40QKqX4HhSwwstFnTaX3tlb\n3QOdY+y04VIkM6d7qN5W8M7NzRkMpZ1qBpQcUMpkhQcRzWP2wub5AAff9D2GntRd\n4Dz1vn3u41U3Okdr0CNj+iH7byCzuokoAhk6ZQEN6WB+GTpGgfBXdtUZrfpb0MKm\nUNYP5AF2AmUqJRXhViTDVtu/V2tHF3LGuNT+W2Dz+spFZEq0byEO0N858eR0dikc\n6jOASvNQbSwD0+mkgBC1gXKKU3ngj2gpJUwljeACdWFd8N2egrZfyI05CmX7vPNC\nNXbs7k2buWNdjP4/D8IM+HDVidWzQa/kG/qokXKqllem9Egg37lUucwnP3cX2/Hw\nU2mfaBWzeZtqc+GqRp08rYIql+Reai3sUYlQMnNk01prVY47UQb+dxuqjaxGV5Xx\nXkx0s2mfQnNRjL4S7Hjhqelufi6GpkCQ2EGsPpA+6K1ztZ0ame9Q2BE1SXeM/6vU\nrxT5nRrCxueyXAyQSGcqMX9//gSeK8WWBqG/c1IAMVDa0NWrJeOJhSziE+ta3B0m\nbHAPBY6vh0iB3lLdRlbUOPbC6R1TpxMOs+6Vbs2+OTifFpvOVymEoZq/nroyg68P\nvn5uCKogwWA7o8EArf/UTlIwWJmH9bgILdZKld4wMel2HQg16RDzm+mEXAJi52a/\nFC+fgfphdxltmUJ+rqOyR4AHULjaTWUQqTIB6sdlzgmES1nXAiE71zX//KFqomar\nO60SPPk3C1bs0x5DsvmGJa8SIfDhyd+D7NPyqwEKqrZsaotYGklNkfqxa6pa8mrc\nejxquW1PK4FvBk26+osu5a90Jih0PcQM7DUMMr2WHdTiMSXWAiK2ToYF8Itt25Qv\nCd0CsSYw9CJkXNr1u1+mObheaY9QYOmztnSJLy4ZO2JsMhqNwuAueIcwmhXOREq7\nkzlnGMgJcuSeAS/OBNj8Zgx0c7QQ0kzc+YmnOCsqoMtPsu/CsXJ4iJiM3Tki/2jT\nbywrTiQwE6R3a/87GREOREX+WLicZBWX3k9/4tBL5XSe1p5wPpuIRQUDvAGNfNHP\nJN7kujDF4SehilF1qtvCygAwvxHFDj+EwhXKNDKJzoZZIM15rAk3k92n2j6nz1qH\na3xOU05yydOlO6F6w51I1QoDddmkzCRNB0TeO3D6rekHsCK1aDWmC+qRcm2ZFtVz\nsY6fdZN2NEmMQokIh9Opi1f8CSYSizPESMzdu2SF0xVO9n/IGIkn1ksK04O2BZo0\nX3LBPHLfCRsQNY1eF17bj07fYU2oPZKs/XzJiwxkqK6LFvpeAVaYrtg9fqRO/UVe\nQhUIj3BL550ocEpa15xLehLrmwzYiW5zwGjSHQ4EgZluGLCwyKGTh4QswEJRA9Rt\n-----END RSA PRIVATE KEY-----\n-----BEGIN CERTIFICATE-----\nMIIE0DCCA7igAwIBAgIJAM5MuKJezXq0MA0GCSqGSIb3DQEBBQUAMIGgMQswCQYD\nVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xGDAW\nBgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0KysxFjAU\nBgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3RlckB6\nYXBob3lkLmNvbTAeFw0xMTExMTUyMTIwMDZaFw0xMjExMTQyMTIwMDZaMIGgMQsw\nCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28x\nGDAWBgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0Kysx\nFjAUBgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3Rl\nckB6YXBob3lkLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANR0\ntdwAnIB8I9qRZ7QbzEWY95RpM7GIn0u/9oH90PzdHiE0rXSkKT+yw3XUzH0iw5t0\n5dEwSC+srSP5Vm4cA6kXc94agVVaPW89tGcdP4fHptCruSrzQsDXELCPl5UUvMpA\nYUcGisdXYPN/EeOoqb9wKWxoW5mREsyyeWWS89fYN5qU/d0QpbSvEWghqLbL/ZS2\nhOlXT9LufOeA+vHiV1/T/h5xC7ecIH02YDQw1EnqxbPmkLPcWThztLS9FiufNDRM\nRhcoaj2b9VDHvDwdbeA0T5v5qNdG34LaapYOelxzQMOtM0f9Dgqehodyxl2qm9mR\nlq432dlOEzDnVCPNHwECAwEAAaOCAQkwggEFMB0GA1UdDgQWBBTTPKfNMnKOykhv\n+vKS7vql5JsMyzCB1QYDVR0jBIHNMIHKgBTTPKfNMnKOykhv+vKS7vql5JsMy6GB\npqSBozCBoDELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQH\nEwdDaGljYWdvMRgwFgYDVQQKEw9aYXBob3lkIFN0dWRpb3MxFDASBgNVBAsTC1dl\nYlNvY2tldCsrMRYwFAYDVQQDEw1QZXRlciBUaG9yc29uMSQwIgYJKoZIhvcNAQkB\nFhV3ZWJtYXN0ZXJAemFwaG95ZC5jb22CCQDOTLiiXs16tDAMBgNVHRMEBTADAQH/\nMA0GCSqGSIb3DQEBBQUAA4IBAQB+SH0s/hrv5VYqgX6SNLzxdSLvCVsUkCdTpxwY\nwOJ84XmYcXDMhKDtZqLtOtN6pfEwVusFlC9mkieuunztCnWNmsSG83RuljJPjFSi\n1d4Id4bKEQkQ4cfnjoHKivRrViWLnxuNnLzC6tpyGH/35kKWhhr6T58AXerFgVw3\nmHvLPTr1DuhdAZA0ZuvuseVAFFAjI3RetSySwHJE3ak8KswDVfLi6E3XxMVsIWTS\n/iFsC2WwoZQlljya2V/kRYIhu+uCdqJ01wunn2BvmURPSgr4GTBF0FQ9JGpNbXxM\nTAU7oQJgyFc5sCcuEgPTO0dWVQTvdZVgay4tkmduKDRkmJBF\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/echo_server_tls/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\n\nif (OPENSSL_FOUND)\n\ninit_target (echo_server_tls)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nlink_openssl()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n\nendif()\n"
  },
  {
    "path": "examples/echo_server_tls/SConscript",
    "content": "## Main development example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\nImport('tls_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   prgs += env_cpp11.Program('echo_server_tls', [\"echo_server_tls.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   prgs += env.Program('echo_server_tls', [\"echo_server_tls.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/echo_server_tls/dh.pem",
    "content": "-----BEGIN DH PARAMETERS-----\nMIIBCAKCAQEAqxMGKZB8YNV8WQnbJWwwwmifc+PfVRtd1FN5v5aQSsf6dpjX3Zlh\nN1NmgecsQyg4u2EWe4Umta10QzCgYaxf6QdTCg7iprLzFNw7IvWYbQ6du12NMGDr\nhmwA6KQKwbTgPL6mSlSlcK2wTP2FzxDTNffFu10cB/6Fj4kdQjPG0c1Koz/z7OOq\nBuDElJLClS8rjp3z1xvrc7gX95dFa2KaKgOAYDkpe8tfHRhHfJeIVS/whH9hzx6r\nOBg+E5K9JyvayrUoKgPeptRKCqo8A4YevtMLpRxMup0nMUgAIv6+BGTwPAFpwgl/\n8UIVcvjh1v95PwGDM/Q8yvIBJznBYk/e2wIBAg==\n-----END DH PARAMETERS-----\n"
  },
  {
    "path": "examples/echo_server_tls/echo_server_tls.cpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n /**\n  * NOTES\n  *\n  * This example uses a number of standard classes through the websocketpp::lib\n  * namespace. This is to allow easy switching between Boost, the C++11 STL, and \n  * the standalone Asio library. Your program need not use these namespaces if\n  * you do not need this sort of flexibility.\n  */\n\n#include <websocketpp/config/asio.hpp>\n\n#include <websocketpp/server.hpp>\n\n#include <iostream>\n\ntypedef websocketpp::server<websocketpp::config::asio_tls> server;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n// pull out the type of messages sent by our config\ntypedef websocketpp::config::asio::message_type::ptr message_ptr;\ntypedef websocketpp::lib::shared_ptr<websocketpp::lib::asio::ssl::context> context_ptr;\n\nvoid on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {\n    std::cout << \"on_message called with hdl: \" << hdl.lock().get()\n              << \" and message: \" << msg->get_payload()\n              << std::endl;\n\n    try {\n        s->send(hdl, msg->get_payload(), msg->get_opcode());\n    } catch (websocketpp::exception const & e) {\n        std::cout << \"Echo failed because: \"\n                  << \"(\" << e.what() << \")\" << std::endl;\n    }\n}\n\nvoid on_http(server* s, websocketpp::connection_hdl hdl) {\n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n    \n    con->set_body(\"Hello World!\");\n    con->set_status(websocketpp::http::status_code::ok);\n}\n\nstd::string get_password() {\n    return \"test\";\n}\n\n// See https://wiki.mozilla.org/Security/Server_Side_TLS for more details about\n// the TLS modes. The code below demonstrates how to implement both the modern\nenum tls_mode {\n    MOZILLA_INTERMEDIATE = 1,\n    MOZILLA_MODERN = 2\n};\n\ncontext_ptr on_tls_init(tls_mode mode, websocketpp::connection_hdl hdl) {\n    namespace asio = websocketpp::lib::asio;\n\n    std::cout << \"on_tls_init called with hdl: \" << hdl.lock().get() << std::endl;\n    std::cout << \"using TLS mode: \" << (mode == MOZILLA_MODERN ? \"Mozilla Modern\" : \"Mozilla Intermediate\") << std::endl;\n\n    context_ptr ctx = websocketpp::lib::make_shared<asio::ssl::context>(asio::ssl::context::sslv23);\n\n    try {\n        if (mode == MOZILLA_MODERN) {\n            // Modern disables TLSv1\n            ctx->set_options(asio::ssl::context::default_workarounds |\n                             asio::ssl::context::no_sslv2 |\n                             asio::ssl::context::no_sslv3 |\n                             asio::ssl::context::no_tlsv1 |\n                             asio::ssl::context::single_dh_use);\n        } else {\n            ctx->set_options(asio::ssl::context::default_workarounds |\n                             asio::ssl::context::no_sslv2 |\n                             asio::ssl::context::no_sslv3 |\n                             asio::ssl::context::single_dh_use);\n        }\n        ctx->set_password_callback(bind(&get_password));\n        ctx->use_certificate_chain_file(\"server.pem\");\n        ctx->use_private_key_file(\"server.pem\", asio::ssl::context::pem);\n        \n        // Example method of generating this file:\n        // `openssl dhparam -out dh.pem 2048`\n        // Mozilla Intermediate suggests 1024 as the minimum size to use\n        // Mozilla Modern suggests 2048 as the minimum size to use.\n        ctx->use_tmp_dh_file(\"dh.pem\");\n        \n        std::string ciphers;\n        \n        if (mode == MOZILLA_MODERN) {\n            ciphers = \"ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK\";\n        } else {\n            ciphers = \"ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA\";\n        }\n        \n        if (SSL_CTX_set_cipher_list(ctx->native_handle() , ciphers.c_str()) != 1) {\n            std::cout << \"Error setting cipher list\" << std::endl;\n        }\n    } catch (std::exception& e) {\n        std::cout << \"Exception: \" << e.what() << std::endl;\n    }\n    return ctx;\n}\n\nint main() {\n    // Create a server endpoint\n    server echo_server;\n\n    // Initialize ASIO\n    echo_server.init_asio();\n\n    // Register our message handler\n    echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));\n    echo_server.set_http_handler(bind(&on_http,&echo_server,::_1));\n    echo_server.set_tls_init_handler(bind(&on_tls_init,MOZILLA_INTERMEDIATE,::_1));\n\n    // Listen on port 9002\n    echo_server.listen(9002);\n\n    // Start the server accept loop\n    echo_server.start_accept();\n\n    // Start the ASIO io_service run loop\n    echo_server.run();\n\n}\n"
  },
  {
    "path": "examples/echo_server_tls/server.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDMYjHlTUeUGSys\nFz5PZcvgS3gojBlEAOu2gXFQDcJ7kq6dJ4jKsPaH1Q5jAtEDkU/el8otzfacOgyp\n2ZxioRimpmcORWGU0bKJcenh4ZQ1oK1CQObjeYk1YgE7H8/sBetSdtL4n1rB8LIz\nAV/k6kwSZFu3/lSmc6g09H4efSKGKVBcVOjBamcvFGVH4KhM2NyL+ffeV5H2Ucxk\nipyhpr4uxEoC3EV60sQxloqZb+upBM0LS4kVvaYMcn39XkUx3Z8FwN5+hFGwsWda\ntU8zDxEuRMrZxG7mwDXLBGehtQvoJIVMQbOuwBQcgAbsVyy1dxV3aczbLX0iGEuG\neBhdFE+BAgMBAAECggEAQaPn0nUXYAEVz89HO8i9ybNzS9Jy6txA18SK1+MTawyY\n9/AShsZ+5vEORc5JwpOQyzSEwmE7qsEaABLbnvGOMTeQMY0m4dzXMj1bmCgSqYaJ\nHpYpkTUfU/2913dIF81u3nU7HI5RX6gmEyuF2MdG10FUE6ujFDJg+2DqgHA//kYD\nhkXFinVS2PuZs8d5xdzpF0aCIWTuOc+Fgsyhdm/lZRIzFdID45YUVuPIN2uh+GkM\nENp/r1x7dPlDRqiL1ufP0mTQGs26S5kQSF8W0BClkOIOgmrhSON4+Vqhqx+ki/7w\nRY+7mmgdvt0uzYT+Lk2cDw4f89Rsh7rR1EieBpQ2YQKBgQDq6zAHWfweJmkugT0w\nHzI0UKfcOdzlJBwMu6tSgSHU99dnXlTwQY8sG7vtfRekokoo7XY4JsSk1n6E9OVy\n4UKuEvU1+llDGxtvHxEEGOAgwB8wxMuY4uNYgDVhTlUzr2ERcet7FOIGzxEWzSsg\n5vgnTQfyMzAh5/6k8CsHVI4u2wKBgQDeuYVCgg555lcc5rvTFxfU15d3fweSd78+\nakgIBaXAlFbxI+5znGPmKG/ii4N2XObC8B568fA2nIxw6M1xgbKyvvmN3ECYiqWv\nbx8x6Vg5Slg0vJr+DrPgvIKbOWEEKF/cfpTeeVLP0gUBT63mA3qezuRx1r0JJr7A\nk9a4Td9j0wKBgDmRQMfMaVgKGaRnz1LHkkn3qerx0wvj+Wu1YZpqQpwp0ANovm/R\n4P/yG+9qxCx4CKxW5K2F8pJibcavLLsmMGzwAF8l5lHnhqWIe2cBoYrlCb+tuibR\nEt1RLcOWqpJr2+GmhQo4Z9s7SvjHdlYtw4n9+oCDwrvMWj6ZDDJTqjQZAoGAEhRt\nRODZ2/texvHT/Wa6gISfvwuIydL+q0plXoFW2zMve5O3H5tqYJyXuIQqv8j60og7\ncS+CmGxM2j2Lr9MfdnMaPvHKLJfUq1ER7zNJ/hyS3HUS/9yhrXSgBYm63mOIpJWB\n8C1ZE5Ww4lJdg3Z01b9lu/f6kGucwHU/0OZBZBECgYAQ+dl2kKKd+lQ9O/LVz7oD\ngoQMPYF+QZcEhY4vlYKkWVtR2A0CiY6XeTi6vO/qVUt/ht+UO3XIJFOjGV1VyORQ\nBhibfstxl5s59jGlns5y5QqcRKzCiX74BKG0xQUtHgga7Od6L+GJKbJAPBfncYwW\nU7Tfwwi0WbbgQoy5Xr/5gg==\n-----END PRIVATE KEY-----\n-----BEGIN CERTIFICATE-----\nMIIFBTCCAu2gAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVT\nMQswCQYDVQQIDAJJTDEUMBIGA1UECgwLV2ViU29ja2V0KysxKjAoBgNVBAsMIVdl\nYlNvY2tldCsrIENlcnRpZmljYXRlIEF1dGhvcml0eTEkMCIGA1UEAwwbV2ViU29j\na2V0KysgSW50ZXJtZWRpYXRlIENBMB4XDTE2MDYwODEyNDUxMloXDTI2MDYwNjEy\nNDUxMlowfjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAklMMRAwDgYDVQQHDAdDaGlj\nYWdvMRQwEgYDVQQKDAtXZWJTb2NrZXQrKzEgMB4GA1UECwwXV2ViU29ja2V0Kysg\nVExTIEV4YW1wbGUxGDAWBgNVBAMMD3dlYnNvY2tldHBwLm9yZzCCASIwDQYJKoZI\nhvcNAQEBBQADggEPADCCAQoCggEBAMxiMeVNR5QZLKwXPk9ly+BLeCiMGUQA67aB\ncVANwnuSrp0niMqw9ofVDmMC0QORT96Xyi3N9pw6DKnZnGKhGKamZw5FYZTRsolx\n6eHhlDWgrUJA5uN5iTViATsfz+wF61J20vifWsHwsjMBX+TqTBJkW7f+VKZzqDT0\nfh59IoYpUFxU6MFqZy8UZUfgqEzY3Iv5995XkfZRzGSKnKGmvi7ESgLcRXrSxDGW\niplv66kEzQtLiRW9pgxyff1eRTHdnwXA3n6EUbCxZ1q1TzMPES5EytnEbubANcsE\nZ6G1C+gkhUxBs67AFByABuxXLLV3FXdpzNstfSIYS4Z4GF0UT4ECAwEAAaOBhzCB\nhDALBgNVHQ8EBAMCBDAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwYAYDVR0RBFkwV4IP\nd2Vic29ja2V0cHAub3JnghN3d3cud2Vic29ja2V0cHAub3Jnghl1dGlsaXRpZXMu\nd2Vic29ja2V0cHAub3JnghRkb2NzLndlYnNvY2tldHBwLm9yZzANBgkqhkiG9w0B\nAQsFAAOCAgEAelJvIWFikBU3HVoP0icuoezTHGqABPLCeooTC/GELq7lHCFEjiqW\np96Zc3vrk+0Z0tkYy3E0fpuzPtlTUhBzO3fMF41FpB5ix3W/tH9YJvrozlIuDD1I\nIEusxomeeiMRbyYpX/gkSOO74ylCzMEQVzleMNdpzpeXOg0Kp5z2JNShdEoT7eMR\nqkJQJjMdL6QeXUqWNvX1Zqb8v6VeWGWjuu/cl374P8D8bjn89VwZQ5HFqoLOhI5v\nXEYsMViZWwLSMcfWTU2Rdi0RxUZQVciLP/3GQROR1/0/e1J1kd7GsRWQMZcU20Vy\njXBVAiWhW1bgd0XOrrFILsAmnBtinEJiE+h5UC4ksZtwWf9x1IhXGlpb9bmD4+Ud\n93wmqytPXBFL6wwlj4IYjjy0gU6xP6h7nwhHXnBlwFWGDpe8Cco9qgyJxJxBTtj9\nMbBv+BSLXJoniDASdk6RIqCjPWZtWbQ7j5mIKV0bdJQZpBX553QOy8AoIpJE32An\nFzR0SSCHOCgSAbqtM8CvLO6mquEJunmwKQx6xfos5N6ee+D+JtUFTw04TrjZUzFs\nZ7v3SN/N4Hd13iTBDSu4XY/tJYICvTRLYNrzQRh/XEVbEEVxXhL8rxNn5aL1pqrV\nyEnvHXrnSXWxTif1K+hS2HfTkQ6d1GjglvmwkoBqBHuRH0OJ1VguTqM=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/enriched_storage/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (enriched_storage)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/enriched_storage/enriched_storage.cpp",
    "content": "#include <iostream>\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\nstruct connection_data {\n    int sessionid;\n    std::string name;\n};\n\nstruct custom_config : public websocketpp::config::asio {\n    // pull default settings from our core config\n    typedef websocketpp::config::asio core;\n    \n    typedef core::concurrency_type concurrency_type;\n    typedef core::request_type request_type;\n    typedef core::response_type response_type;\n    typedef core::message_type message_type;\n    typedef core::con_msg_manager_type con_msg_manager_type;\n    typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;\n    typedef core::alog_type alog_type;\n    typedef core::elog_type elog_type;\n    typedef core::rng_type rng_type;\n    typedef core::transport_type transport_type;\n    typedef core::endpoint_base endpoint_base;\n    \n    // Set a custom connection_base class\n    typedef connection_data connection_base;\n};\n\ntypedef websocketpp::server<custom_config> server;\ntypedef server::connection_ptr connection_ptr;\n\nusing websocketpp::connection_hdl;\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\nclass print_server {\npublic:\n    print_server() : m_next_sessionid(1) {\n        m_server.init_asio();\n                \n        m_server.set_open_handler(bind(&print_server::on_open,this,::_1));\n        m_server.set_close_handler(bind(&print_server::on_close,this,::_1));\n        m_server.set_message_handler(bind(&print_server::on_message,this,::_1,::_2));\n    }\n    \n    void on_open(connection_hdl hdl) {\n        connection_ptr con = m_server.get_con_from_hdl(hdl);\n        \n        con->sessionid = m_next_sessionid++;\n    }\n    \n    void on_close(connection_hdl hdl) {\n        connection_ptr con = m_server.get_con_from_hdl(hdl);\n        \n        std::cout << \"Closing connection \" << con->name \n                  << \" with sessionid \" << con->sessionid << std::endl;\n    }\n    \n    void on_message(connection_hdl hdl, server::message_ptr msg) {\n        connection_ptr con = m_server.get_con_from_hdl(hdl);\n        \n        if (con->name.empty()) {\n            con->name = msg->get_payload();\n            std::cout << \"Setting name of connection with sessionid \" \n                      << con->sessionid << \" to \" << con->name << std::endl;\n        } else {\n            std::cout << \"Got a message from connection \" << con->name \n                      << \" with sessionid \" << con->sessionid << std::endl;\n        }\n    }\n    \n    void run(uint16_t port) {\n        m_server.listen(port);\n        m_server.start_accept();\n        m_server.run();\n    }\nprivate:\n    int m_next_sessionid;\n    server m_server;\n};\n\nint main() {\n    print_server server;\n    server.run(9002);\n}"
  },
  {
    "path": "examples/external_io_service/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (external_io_service)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/external_io_service/SConscript",
    "content": "## Main development example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('external_io_service', [\"external_io_service.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('external_io_service', [\"external_io_service.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/external_io_service/external_io_service.cpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include \"tcp_echo_server.hpp\"\n\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\n#include <iostream>\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\ntypedef websocketpp::server<websocketpp::config::asio> ws_echo_server;\n\n// Define a callback to handle incoming messages\nvoid on_message(ws_echo_server* s, websocketpp::connection_hdl hdl, ws_echo_server::message_ptr msg) {\n    std::cout << \"on_message called with hdl: \" << hdl.lock().get()\n              << \" and message: \" << msg->get_payload()\n              << std::endl;\n\n    // check for a special command to instruct the server to stop listening so\n    // it can be cleanly exited.\n    if (msg->get_payload() == \"stop-listening\") {\n        s->stop_listening();\n        return;\n    }\n\n    try {\n        s->send(hdl, msg->get_payload(), msg->get_opcode());\n    } catch (websocketpp::exception const & e) {\n        std::cout << \"Echo failed because: \"\n                  << \"(\" << e.what() << \")\" << std::endl;\n    }\n}\n\nint main() {\n    asio::io_service service;\n\n    // Add a TCP echo server on port 9003\n    tcp_echo_server custom_http_server(service, 9003);\n\n    // Add a WebSocket echo server on port 9002\n    ws_echo_server ws_server;\n    ws_server.set_access_channels(websocketpp::log::alevel::all);\n    ws_server.clear_access_channels(websocketpp::log::alevel::frame_payload);\n\n    // The only difference in this code between an internal and external\n    // io_service is the different constructor to init_asio\n    ws_server.init_asio(&service);\n\n    // Register our message handler\n    ws_server.set_message_handler(bind(&on_message,&ws_server,::_1,::_2));\n    ws_server.listen(9002);\n    ws_server.start_accept();\n\n    // TODO: add a timer?\n\n    // Start the Asio io_service run loop for all\n    service.run();\n}"
  },
  {
    "path": "examples/external_io_service/tcp_echo_server.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n \n/**\n * TCP Echo Server\n *\n * This file defines a simple TCP Echo Server. It is adapted from the Asio\n * example: cpp03/echo/async_tcp_echo_server.cpp\n */ \n\n#include <websocketpp/common/asio.hpp>\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/common/functional.hpp>\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\nnamespace asio = websocketpp::lib::asio;\n\nstruct tcp_echo_session : websocketpp::lib::enable_shared_from_this<tcp_echo_session> {\n    typedef websocketpp::lib::shared_ptr<tcp_echo_session> ptr;\n    \n    tcp_echo_session(asio::io_service & service) : m_socket(service) {}\n\n    void start() {\n        m_socket.async_read_some(asio::buffer(m_buffer, sizeof(m_buffer)),\n            websocketpp::lib::bind(\n                &tcp_echo_session::handle_read, shared_from_this(), _1, _2));\n    }\n    \n    void handle_read(const asio::error_code & ec, size_t transferred) {\n        if (!ec) {\n            asio::async_write(m_socket,\n                asio::buffer(m_buffer, transferred),\n                    bind(&tcp_echo_session::handle_write, shared_from_this(), _1));\n        }\n    }\n    \n    void handle_write(const asio::error_code & ec) {\n        if (!ec) {\n            m_socket.async_read_some(asio::buffer(m_buffer, sizeof(m_buffer)),\n                bind(&tcp_echo_session::handle_read, shared_from_this(), _1, _2));\n        }\n    }\n\n    asio::ip::tcp::socket m_socket;\n    char m_buffer[1024];\n};\n\nstruct tcp_echo_server {\n    tcp_echo_server(asio::io_service & service, short port)\n        : m_service(service)\n        , m_acceptor(service, asio::ip::tcp::endpoint(asio::ip::tcp::v6(), port))\n    {\n        this->start_accept();\n    }\n    \n    void start_accept() {\n        tcp_echo_session::ptr new_session(new tcp_echo_session(m_service));\n        m_acceptor.async_accept(new_session->m_socket,\n            bind(&tcp_echo_server::handle_accept, this, new_session, _1));\n    }\n    \n    void handle_accept(tcp_echo_session::ptr new_session, const asio::error_code & ec) {\n        if (!ec) {\n            new_session->start();\n        }\n        start_accept();\n    }\n\n    asio::io_service & m_service;\n    asio::ip::tcp::acceptor m_acceptor;\n};\n"
  },
  {
    "path": "examples/handler_switch/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (handler_switch)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/handler_switch/handler_switch.cpp",
    "content": "#include <iostream>\n\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nusing websocketpp::connection_hdl;\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\nusing websocketpp::lib::ref;\n\nvoid custom_on_msg(server & s, connection_hdl hdl, server::message_ptr msg) {\n        std::cout << \"Message sent to custom handler\" << std::endl;\n}\n\nvoid default_on_msg(server & s, connection_hdl hdl, server::message_ptr msg) {\n    std::cout << \"Message sent to default handler\" << std::endl;\n\n    if (msg->get_payload() == \"upgrade\") {\n        // Upgrade our connection_hdl to a full connection_ptr\n        server::connection_ptr con = s.get_con_from_hdl(hdl);\n\n        // Change the on message handler for this connection only to\n        // custom_on_mesage\n        con->set_message_handler(bind(&custom_on_msg,ref(s),::_1,::_2));\n        std::cout << \"Upgrading connection to custom handler\" << std::endl;\n    }\n}\n\nint main() {\n    server s;\n\n    s.set_message_handler(bind(&default_on_msg,ref(s),::_1,::_2));\n\n    s.init_asio();\n    s.listen(9002);\n    s.start_accept();\n\n    s.run();\n}\n"
  },
  {
    "path": "examples/iostream_server/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (iostream_server)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/iostream_server/SConscript",
    "content": "## iostream server example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('iostream_server', [\"iostream_server.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('iostream_server', [\"iostream_server.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/iostream_server/iostream_server.cpp",
    "content": "#include <websocketpp/config/core.hpp>\n\n#include <websocketpp/server.hpp>\n\n#include <iostream>\n#include <fstream>\n\ntypedef websocketpp::server<websocketpp::config::core> server;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n// pull out the type of messages sent by our config\ntypedef server::message_ptr message_ptr;\n\n// Define a callback to handle incoming messages\nvoid on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {\n    if (msg->get_opcode() == websocketpp::frame::opcode::text) {\n        s->get_alog().write(websocketpp::log::alevel::app,\n                    \"Text Message Received: \"+msg->get_payload());\n    } else {\n        s->get_alog().write(websocketpp::log::alevel::app,\n                    \"Binary Message Received: \"+websocketpp::utility::to_hex(msg->get_payload()));\n    }\n\n    try {\n        s->send(hdl, msg->get_payload(), msg->get_opcode());\n    } catch (websocketpp::exception const & e) {\n        s->get_alog().write(websocketpp::log::alevel::app,\n                    std::string(\"Echo Failed: \")+e.what());\n    }\n}\n\nint main() {\n    server s;\n    std::ofstream log;\n\n    try {\n        // set up access channels to only log interesting things\n        s.clear_access_channels(websocketpp::log::alevel::all);\n        s.set_access_channels(websocketpp::log::alevel::connect);\n        s.set_access_channels(websocketpp::log::alevel::disconnect);\n        s.set_access_channels(websocketpp::log::alevel::app);\n\n        // Log to a file rather than stdout, as we are using stdout for real\n        // output\n        log.open(\"output.log\");\n        s.get_alog().set_ostream(&log);\n        s.get_elog().set_ostream(&log);\n\n        // print all output to stdout\n        s.register_ostream(&std::cout);\n\n        // Register our message handler\n        s.set_message_handler(bind(&on_message,&s,::_1,::_2));\n\n        server::connection_ptr con = s.get_connection();\n\n        con->start();\n\n        // C++ iostream's don't support the idea of asynchronous i/o. As such\n        // there are two input strategies demonstrated here. Buffered I/O will\n        // read from stdin in chunks until EOF. This works very well for\n        // replaying canned connections as would be done in automated testing.\n        //\n        // If the server is being used live however, assuming input is being\n        // piped from elsewhere in realtime, this strategy will result in small\n        // messages being buffered forever. The non-buffered strategy below\n        // reads characters from stdin one at a time. This is inefficient and\n        // for more serious uses should be replaced with a platform specific\n        // asyncronous i/o technique like select, poll, IOCP, etc\n        bool buffered_io = false;\n\n        if (buffered_io) {\n            std::cin >> *con;\n            con->eof();\n        } else {\n            char a;\n            while(std::cin.get(a)) {\n                con->read_some(&a,1);\n            }\n            con->eof();\n        }\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    }\n    log.close();\n}\n"
  },
  {
    "path": "examples/print_client/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (print_client)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/print_client/SConscript",
    "content": "## Print client example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('print_client', [\"print_client.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('print_client', [\"print_client.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/print_client/print_client.cpp",
    "content": "/*\n * Copyright (c) 2016, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <iostream>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nvoid on_message(websocketpp::connection_hdl, client::message_ptr msg) {\n\tstd::cout << msg->get_payload() << std::endl;\n}\n\nint main(int argc, char* argv[]) {\n    client c;\n\n    std::string uri = \"ws://localhost:9002\";\n\n    if (argc == 2) {\n        uri = argv[1];\n    }\n\n\ttry {\n        // Set logging to be pretty verbose (everything except message payloads)\n        c.set_access_channels(websocketpp::log::alevel::all);\n        c.clear_access_channels(websocketpp::log::alevel::frame_payload);\n        c.set_error_channels(websocketpp::log::elevel::all);\n\n        // Initialize ASIO\n        c.init_asio();\n\n        // Register our message handler\n        c.set_message_handler(&on_message);\n\n        websocketpp::lib::error_code ec;\n        client::connection_ptr con = c.get_connection(uri, ec);\n        if (ec) {\n            std::cout << \"could not create connection because: \" << ec.message() << std::endl;\n            return 0;\n        }\n\n        // Note that connect here only requests a connection. No network messages are\n        // exchanged until the event loop starts running in the next line.\n        c.connect(con);\n\n        // Start the ASIO io_service run loop\n        // this will cause a single connection to be made to the server. c.run()\n        // will exit when this connection is closed.\n        c.run();\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/print_client_tls/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\nif (OPENSSL_FOUND)\n\ninit_target (print_client_tls)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nlink_openssl()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n\nendif()"
  },
  {
    "path": "examples/print_client_tls/SConscript",
    "content": "## Print client tls example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\nImport('tls_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   prgs += env_cpp11.Program('print_client_tls', [\"print_client_tls.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   prgs += env.Program('print_client_tls', [\"print_client_tls.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/print_client_tls/ca-chain.cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFxTCCA62gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UEBhMCVVMx\nCzAJBgNVBAgMAklMMRAwDgYDVQQHDAdDaGljYWdvMRQwEgYDVQQKDAtXZWJTb2Nr\nZXQrKzEcMBoGA1UEAwwTV2ViU29ja2V0KysgUm9vdCBDQTAeFw0xNjA1MjUxMzU4\nMjdaFw0yNjA1MjMxMzU4MjdaMIGCMQswCQYDVQQGEwJVUzELMAkGA1UECAwCSUwx\nFDASBgNVBAoMC1dlYlNvY2tldCsrMSowKAYDVQQLDCFXZWJTb2NrZXQrKyBDZXJ0\naWZpY2F0ZSBBdXRob3JpdHkxJDAiBgNVBAMMG1dlYlNvY2tldCsrIEludGVybWVk\naWF0ZSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMNaFAzlx0KJ\ngG15yRHI3xn9+B1woHG4uuOr124Sk1JllPcO3enusgIYTMl0FiYYW9CsyPoe4L0P\nwflbz20vDDjxmXG+NPgjuYmnPaq7q2JXYz+cShv9+o60EIwEIe+EWk1ZQs9YSdQ0\nr4UOxGVq6eEuWJi8Wh02cbnxdjwvrk7lTMFVY+z5EX8cCj6Tbrd0lyIf/0X8OkOb\nq2HOqqzTgT2apBCWCEW6grW6rtMOoDx93BOZDBEGz39sJ5i8AQ8XIdYCdUcOMdJU\nSCAw/MMyFTHXhv8hJdG5GcDSfc7woB9xRUf8UHuCH0nYkTb260TWvyDCYJy001ko\nSWoRbh2hVgPqQ9FTDMzMTY8T8C5u3BRfGN5PHuSPhwfHv/p1g4uPnltDBe4CNtOs\nwu8w1wbrr3uI7qETnqOzbXlcT7o4rCrrRQqLbNOssf2mMH+Phq6dINjXpZjiAhO0\nSURtBMmQdAZcQkGStzFitEkb2Py5LEIxQ068i8RCowTyD9+/jbO1fZyxJ4X8TDUe\nXx48xWnu0i4f8/9ldnWLwX9h3ilaZVsr7buNYJoMlz+v73TQoWKSybJ2SMe/Cddj\nOZCy5r1UakuZhX6n1ScD/hbO8FEfmQRpAywYajyU4dZ9XMbf5bo6OAUqlJ2f4yYh\nVAy5mi1JHfD5PiJN90j79GXXvtBTJc4hAgMBAAGjZjBkMB0GA1UdDgQWBBTKMn5O\n3NUPpztL1bAz8UCsOBLpkjAfBgNVHSMEGDAWgBTNBBKZQN694xplMGyMruXFv27o\neTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0B\nAQsFAAOCAgEAyNkZUEAdP73th4/RLu0d2foMiIqKlcvw3JsW0tto3MT5lvQ5UugH\nOwluhWhnMLE0KsknQd7/p4ZwyZugWAYjGcDydp0GDIDfNBBEOQkOAL23KkYiRFqt\nVPBTZi9S7P2MJLY0j94liIg94nikhz/0q7JxxWFlvSHUjwZxXrbFjfZRPOS1vIq/\n/VK2QjUsdIXE3NOPYfQwd9FpG2YS8ZcMeipwNYVAs2FBEeWzGH1j6i2hP8FFBDYP\n0LTvJYOJvlCeyIvPBjKk9461/Z4CPJcKtKC59onQmiqSK/Juak/bpPoY7jJ228KG\nbEBzClIEHgbDiBewFTHbyOWhW2ySRLOGsPeqKDSbm4J1N5rfKnrSQB9PfOmWoRfJ\nvqPlXFSlpdgD4j/WnEumpvt78fT+cn+AkRG8tE5DQrCWZTK47TSWn902Fm0A19Rl\npSbE9qsulXurOqEuOOayrzcUmbZ/jkU+wj+/tN4Gl8K98WbjcXvwz0sRL3SgRRrI\nawUdaGWKQHrTJNEOTisepUAuHVDmvuQz0j/Ru+PbB9K3GcKY6X6+o1c2JBC1V6KX\naHHZQ+xPm+VEa1pG/QVHGpt2AbGUQlXwDYtOIRwEhO27tFbH8Q68s2cMLYjsF5gd\nMWuMYCPkFv10/V2f2lAIPSEzw2pldIGERcb4VG4xuD0qU+HH/aAID7k=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFpjCCA46gAwIBAgIJAL42eqbfw976MA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIDAJJTDEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIGA1UECgwL\nV2ViU29ja2V0KysxHDAaBgNVBAMME1dlYlNvY2tldCsrIFJvb3QgQ0EwHhcNMTYw\nNTI1MTM1MTUzWhcNMzYwNTIwMTM1MTUzWjBgMQswCQYDVQQGEwJVUzELMAkGA1UE\nCAwCSUwxEDAOBgNVBAcMB0NoaWNhZ28xFDASBgNVBAoMC1dlYlNvY2tldCsrMRww\nGgYDVQQDDBNXZWJTb2NrZXQrKyBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOC\nAg8AMIICCgKCAgEA4QjJ0v5yri+pAN67I/XPz88D8oIczCW96CIuwc44aDC9Kptb\n9iY8xwbGCyQsFZ/1IQ74QfnXZSwq8EwedcBIdcyHdBu6qtNkCVKeDIZAMBef6Hx+\ntWSe1op3sDbUlT8NHiTxZCZWk/2/yIi8yPzQTi4y1vF04vvrQS5RFomCz17kdyOa\nNdxO5p+I4afdoVKtzA1aHoBqdTe7vzM3eww4AxKfgIEDdIuOGDiglI/b/frlwiOi\nSfTOsPzu52TOPW2d1Ad5BG4GuMpnTUOVnc8j18w9LdeXO0J10oVyCmwiPuzFCcDB\ng1xvVr5TXzIZ5J+qlso7+mUfZGH+nxOT7Tc78o1EvX6JbfQAI2PrpcksmJfFnN4l\n4XnXDW/eKl8AlLUr/cW5axAfql4QHJoBCZcfYldQpMoL5R1ikLtY53cOJpycFoWm\n1IEfkLBZ4C1old+KoaErG0+Aur8/kwAJGMnmMvZqGZ5pgXtVipOLy5TKuS6ZKO8g\nMRzalaF/naiu3pF+/sctaqkAPvOr65WrANNGxTQ93ePdyuT6sOEUKXxaXcTtAOOM\n5FCgX8dPxkOACxTrxppvb+bYmYL9GIuYDGYxSRu3Fm+04eXIh+uCqcuWPQuRPc5t\nVXvk/M0fPaJvKfP6lRAoE5Dp4qPRvL6tRVtOXfP6d+O+yGnxRoLKAW7ejoMCAwEA\nAaNjMGEwHQYDVR0OBBYEFM0EEplA3r3jGmUwbIyu5cW/buh5MB8GA1UdIwQYMBaA\nFM0EEplA3r3jGmUwbIyu5cW/buh5MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/\nBAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQAQ4eY4LhW795wl9XuDVg2vOFTYmIS0\nOxrunFX4f3RjddbIbXzYmQ0cJ8pJ5l7eGYcg/DYQRY4Tk6LjXMs9VhIU10akqLS4\nqGE+Bmp3Jhu5NxZbKkY+k+kTAA1LYxFCjGjSV0v5QNLFULDAmGer2zWwU5DcDwwq\n8yWyBuI974UyE/49/TeckfqwBrb90LL2lFEwoL86XZK2IZMPyMBC/S1X5P/Kc15Q\nd8lwOPS5AirFkkrzs/px+mRia5U1uWKIPRLq9Medvjf8HR8SFWq9eRtkxiLaWyRv\nHBVyVRKCubCZR8psVLK/zrF+Bc+Hr9aAi3TuqTKjIOI7hrq5oJcJpebZDNoBIqoj\nkab13WcRwG+BQvuK1CEkd1aq8Nh2GX6Reb2Zv82/WntgP1a0sztbIGgrUBYQryb5\nHF79v4e2byY613SiQ3lz+g/AWxaZsYH80/Zl+hEwEtU4fFz34Jcv9Kvda1JpknBT\nFi63ugfoNeNriO02AReMmDvuBG3X8RF1UQyBoTU3uZuW7X26MizEjiVCK9qaOLED\nWDSEoyKLe4JKd387CVlsCY8K/6fBlFTI/hJhggDz8pZFj3n2irUI44kjgOmoxOrW\nJY2jgY89AEMN9yOKkyQGara8pF9IJxTQ7jurYnWcUbompWeybJRwvWN0h+tGV+bd\nl/aq/5LwL3fVpg==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/print_client_tls/print_client_tls.cpp",
    "content": "/*\n * Copyright (c) 2016, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#include <websocketpp/config/asio_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <iostream>\n\ntypedef websocketpp::client<websocketpp::config::asio_tls_client> client;\ntypedef websocketpp::lib::shared_ptr<websocketpp::lib::asio::ssl::context> context_ptr;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\nvoid on_message(websocketpp::connection_hdl, client::message_ptr msg) {\n    std::cout << msg->get_payload() << std::endl;\n}\n\n/// Verify that one of the subject alternative names matches the given hostname\nbool verify_subject_alternative_name(const char * hostname, X509 * cert) {\n    STACK_OF(GENERAL_NAME) * san_names = NULL;\n    \n    san_names = (STACK_OF(GENERAL_NAME) *) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);\n    if (san_names == NULL) {\n        return false;\n    }\n    \n    int san_names_count = sk_GENERAL_NAME_num(san_names);\n    \n    bool result = false;\n    \n    for (int i = 0; i < san_names_count; i++) {\n        const GENERAL_NAME * current_name = sk_GENERAL_NAME_value(san_names, i);\n        \n        if (current_name->type != GEN_DNS) {\n            continue;\n        }\n        \n        char const * dns_name = (char const *) ASN1_STRING_get0_data(current_name->d.dNSName);\n        \n        // Make sure there isn't an embedded NUL character in the DNS name\n        if (ASN1_STRING_length(current_name->d.dNSName) != strlen(dns_name)) {\n            break;\n        }\n        // Compare expected hostname with the CN\n        result = (strcasecmp(hostname, dns_name) == 0);\n    }\n    sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);\n    \n    return result;\n}\n\n/// Verify that the certificate common name matches the given hostname\nbool verify_common_name(char const * hostname, X509 * cert) {\n    // Find the position of the CN field in the Subject field of the certificate\n    int common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name(cert), NID_commonName, -1);\n    if (common_name_loc < 0) {\n        return false;\n    }\n    \n    // Extract the CN field\n    X509_NAME_ENTRY * common_name_entry = X509_NAME_get_entry(X509_get_subject_name(cert), common_name_loc);\n    if (common_name_entry == NULL) {\n        return false;\n    }\n    \n    // Convert the CN field to a C string\n    ASN1_STRING * common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);\n    if (common_name_asn1 == NULL) {\n        return false;\n    }\n    \n    char const * common_name_str = (char const *) ASN1_STRING_get0_data(common_name_asn1);\n    \n    // Make sure there isn't an embedded NUL character in the CN\n    if (ASN1_STRING_length(common_name_asn1) != strlen(common_name_str)) {\n        return false;\n    }\n    \n    // Compare expected hostname with the CN\n    return (strcasecmp(hostname, common_name_str) == 0);\n}\n\n/**\n * This code is derived from examples and documentation found ato00po\n * http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/example/cpp03/ssl/client.cpp\n * and\n * https://github.com/iSECPartners/ssl-conservatory\n */\nbool verify_certificate(const char * hostname, bool preverified, boost::asio::ssl::verify_context& ctx) {\n    // The verify callback can be used to check whether the certificate that is\n    // being presented is valid for the peer. For example, RFC 2818 describes\n    // the steps involved in doing this for HTTPS. Consult the OpenSSL\n    // documentation for more details. Note that the callback is called once\n    // for each certificate in the certificate chain, starting from the root\n    // certificate authority.\n\n    // Retrieve the depth of the current cert in the chain. 0 indicates the\n    // actual server cert, upon which we will perform extra validation\n    // (specifically, ensuring that the hostname matches. For other certs we\n    // will use the 'preverified' flag from Asio, which incorporates a number of\n    // non-implementation specific OpenSSL checking, such as the formatting of\n    // certs and the trusted status based on the CA certs we imported earlier.\n    int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());\n\n    // if we are on the final cert and everything else checks out, ensure that\n    // the hostname is present on the list of SANs or the common name (CN).\n    if (depth == 0 && preverified) {\n        X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());\n        \n        if (verify_subject_alternative_name(hostname, cert)) {\n            return true;\n        } else if (verify_common_name(hostname, cert)) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    return preverified;\n}\n\n/// TLS Initialization handler\n/**\n * WebSocket++ core and the Asio Transport do not handle TLS context creation\n * and setup. This callback is provided so that the end user can set up their\n * TLS context using whatever settings make sense for their application.\n *\n * As Asio and OpenSSL do not provide great documentation for the very common\n * case of connect and actually perform basic verification of server certs this\n * example includes a basic implementation (using Asio and OpenSSL) of the\n * following reasonable default settings and verification steps:\n *\n * - Disable SSLv2 and SSLv3\n * - Load trusted CA certificates and verify the server cert is trusted.\n * - Verify that the hostname matches either the common name or one of the\n *   subject alternative names on the certificate.\n *\n * This is not meant to be an exhaustive reference implimentation of a perfect\n * TLS client, but rather a reasonable starting point for building a secure\n * TLS encrypted WebSocket client.\n *\n * If any TLS, Asio, or OpenSSL experts feel that these settings are poor\n * defaults or there are critically missing steps please open a GitHub issue\n * or drop a line on the project mailing list.\n *\n * Note the bundled CA cert ca-chain.cert.pem is the CA cert that signed the\n * cert bundled with echo_server_tls. You can use print_client_tls with this\n * CA cert to connect to echo_server_tls as long as you use /etc/hosts or\n * something equivilent to spoof one of the names on that cert \n * (websocketpp.org, for example).\n */\ncontext_ptr on_tls_init(const char * hostname, websocketpp::connection_hdl) {\n    context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);\n\n    try {\n        ctx->set_options(boost::asio::ssl::context::default_workarounds |\n                         boost::asio::ssl::context::no_sslv2 |\n                         boost::asio::ssl::context::no_sslv3 |\n                         boost::asio::ssl::context::single_dh_use);\n\n\n        ctx->set_verify_mode(boost::asio::ssl::verify_peer);\n        ctx->set_verify_callback(bind(&verify_certificate, hostname, ::_1, ::_2));\n\n        // Here we load the CA certificates of all CA's that this client trusts.\n        ctx->load_verify_file(\"ca-chain.cert.pem\");\n    } catch (std::exception& e) {\n        std::cout << e.what() << std::endl;\n    }\n    return ctx;\n}\n\nint main(int argc, char* argv[]) {\n    client c;\n\n    std::string hostname = \"localhost\";\n    std::string port = \"9002\";\n\n\n    if (argc == 3) {\n        hostname = argv[1];\n        port = argv[2];\n    } else {\n        std::cout << \"Usage: print_server_tls <hostname> <port>\" << std::endl;\n        return 1;\n    }\n    \n    std::string uri = \"wss://\" + hostname + \":\" + port;\n\n    try {\n        // Set logging to be pretty verbose (everything except message payloads)\n        c.set_access_channels(websocketpp::log::alevel::all);\n        c.clear_access_channels(websocketpp::log::alevel::frame_payload);\n        c.set_error_channels(websocketpp::log::elevel::all);\n\n        // Initialize ASIO\n        c.init_asio();\n\n        // Register our message handler\n        c.set_message_handler(&on_message);\n        c.set_tls_init_handler(bind(&on_tls_init, hostname.c_str(), ::_1));\n\n        websocketpp::lib::error_code ec;\n        client::connection_ptr con = c.get_connection(uri, ec);\n        if (ec) {\n            std::cout << \"could not create connection because: \" << ec.message() << std::endl;\n            return 0;\n        }\n\n        // Note that connect here only requests a connection. No network messages are\n        // exchanged until the event loop starts running in the next line.\n        c.connect(con);\n\n        c.get_alog().write(websocketpp::log::alevel::app, \"Connecting to \" + uri);\n\n        // Start the ASIO io_service run loop\n        // this will cause a single connection to be made to the server. c.run()\n        // will exit when this connection is closed.\n        c.run();\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/print_server/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (print_server)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/print_server/SConscript",
    "content": "## Print server example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('print_server', [\"print_server.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('print_server', [\"print_server.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/print_server/print_server.cpp",
    "content": "#include <iostream>\n\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nvoid on_message(websocketpp::connection_hdl, server::message_ptr msg) {\n        std::cout << msg->get_payload() << std::endl;\n}\n\nint main() {\n    server print_server;\n\n    print_server.set_message_handler(&on_message);\n    print_server.set_access_channels(websocketpp::log::alevel::all);\n    print_server.set_error_channels(websocketpp::log::elevel::all);\n\n    print_server.init_asio();\n    print_server.listen(9002);\n    print_server.start_accept();\n\n    print_server.run();\n}\n"
  },
  {
    "path": "examples/scratch_client/SConscript",
    "content": "## Scratch client example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\nImport('tls_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   prgs += env_cpp11.Program('scratch_client', [\"scratch_client.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('utility_client', [\"utility_client.cpp\"], LIBS = ALL_LIBS)\n   \nReturn('prgs')\n"
  },
  {
    "path": "examples/scratch_client/scratch_client.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial.\n// Additional related material can be found in the tutorials/utility_client\n// directory of the WebSocket++ repository.\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <websocketpp/common/thread.hpp>\n#include <websocketpp/common/memory.hpp>\n\n#include <cstdlib>\n#include <iostream>\n#include <map>\n#include <string>\n#include <sstream>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nclass connection_metadata {\npublic:\n    typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;\n\n    connection_metadata(int id, websocketpp::connection_hdl hdl, std::string uri)\n      : m_id(id)\n      , m_hdl(hdl)\n      , m_status(\"Connecting\")\n      , m_uri(uri)\n      , m_server(\"N/A\")\n    {}\n\n    void on_open(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Open\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n    }\n\n    void on_fail(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Failed\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n        m_error_reason = con->get_ec().message();\n    }\n    \n    void on_close(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Closed\";\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        std::stringstream s;\n        s << \"close code: \" << con->get_remote_close_code() << \" (\" \n          << websocketpp::close::status::get_string(con->get_remote_close_code()) \n          << \"), close reason: \" << con->get_remote_close_reason();\n        m_error_reason = s.str();\n    }\n\n    websocketpp::connection_hdl get_hdl() const {\n        return m_hdl;\n    }\n    \n    int get_id() const {\n        return m_id;\n    }\n    \n    std::string get_status() const {\n        return m_status;\n    }\n\n    friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);\nprivate:\n    int m_id;\n    websocketpp::connection_hdl m_hdl;\n    std::string m_status;\n    std::string m_uri;\n    std::string m_server;\n    std::string m_error_reason;\n};\n\nstd::ostream & operator<< (std::ostream & out, connection_metadata const & data) {\n    out << \"> URI: \" << data.m_uri << \"\\n\"\n        << \"> Status: \" << data.m_status << \"\\n\"\n        << \"> Remote Server: \" << (data.m_server.empty() ? \"None Specified\" : data.m_server) << \"\\n\"\n        << \"> Error/close reason: \" << (data.m_error_reason.empty() ? \"N/A\" : data.m_error_reason);\n\n    return out;\n}\n\nclass websocket_endpoint {\npublic:\n    websocket_endpoint () : m_next_id(0) {\n        m_endpoint.clear_access_channels(websocketpp::log::alevel::all);\n        m_endpoint.clear_error_channels(websocketpp::log::elevel::all);\n\n        m_endpoint.init_asio();\n        m_endpoint.start_perpetual();\n\n        m_thread.reset(new websocketpp::lib::thread(&client::run, &m_endpoint));\n    }\n\n    ~websocket_endpoint() {\n        m_endpoint.stop_perpetual();\n        \n        for (con_list::const_iterator it = m_connection_list.begin(); it != m_connection_list.end(); ++it) {\n            if (it->second->get_status() != \"Open\") {\n                // Only close open connections\n                continue;\n            }\n            \n            std::cout << \"> Closing connection \" << it->second->get_id() << std::endl;\n            \n            websocketpp::lib::error_code ec;\n            m_endpoint.close(it->second->get_hdl(), websocketpp::close::status::going_away, \"\", ec);\n            if (ec) {\n                std::cout << \"> Error closing connection \" << it->second->get_id() << \": \"  \n                          << ec.message() << std::endl;\n            }\n        }\n        \n        m_thread->join();\n    }\n\n    int connect(std::string const & uri) {\n        websocketpp::lib::error_code ec;\n\n        client::connection_ptr con = m_endpoint.get_connection(uri, ec);\n\n        if (ec) {\n            std::cout << \"> Connect initialization error: \" << ec.message() << std::endl;\n            return -1;\n        }\n\n        int new_id = m_next_id++;\n        connection_metadata::ptr metadata_ptr(new connection_metadata(new_id, con->get_handle(), uri));\n        m_connection_list[new_id] = metadata_ptr;\n\n        con->set_open_handler(websocketpp::lib::bind(\n            &connection_metadata::on_open,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_fail_handler(websocketpp::lib::bind(\n            &connection_metadata::on_fail,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_close_handler(websocketpp::lib::bind(\n            &connection_metadata::on_close,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n\n        m_endpoint.connect(con);\n\n        return new_id;\n    }\n\n    void close(int id, websocketpp::close::status::value code, std::string reason) {\n        websocketpp::lib::error_code ec;\n        \n        con_list::iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            std::cout << \"> No connection found with id \" << id << std::endl;\n            return;\n        }\n        \n        m_endpoint.close(metadata_it->second->get_hdl(), code, reason, ec);\n        if (ec) {\n            std::cout << \"> Error initiating close: \" << ec.message() << std::endl;\n        }\n    }\n\n    connection_metadata::ptr get_metadata(int id) const {\n        con_list::const_iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            return connection_metadata::ptr();\n        } else {\n            return metadata_it->second;\n        }\n    }\nprivate:\n    typedef std::map<int,connection_metadata::ptr> con_list;\n\n    client m_endpoint;\n    websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;\n\n    con_list m_connection_list;\n    int m_next_id;\n};\n\nint main() {\n    bool done = false;\n    std::string input;\n    websocket_endpoint endpoint;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout\n                << \"\\nCommand List:\\n\"\n                << \"connect <ws uri>\\n\"\n                << \"close <connection id> [<close code:default=1000>] [<close reason>]\\n\"\n                << \"show <connection id>\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else if (input.substr(0,7) == \"connect\") {\n            int id = endpoint.connect(input.substr(8));\n            if (id != -1) {\n                std::cout << \"> Created connection with id \" << id << std::endl;\n            }\n        } else if (input.substr(0,5) == \"close\") {\n            std::stringstream ss(input);\n            \n            std::string cmd;\n            int id;\n            int close_code = websocketpp::close::status::normal;\n            std::string reason;\n            \n            ss >> cmd >> id >> close_code;\n            std::getline(ss,reason);\n            \n            endpoint.close(id, close_code, reason);\n        }  else if (input.substr(0,4) == \"show\") {\n            int id = atoi(input.substr(5).c_str());\n\n            connection_metadata::ptr metadata = endpoint.get_metadata(id);\n            if (metadata) {\n                std::cout << *metadata << std::endl;\n            } else {\n                std::cout << \"> Unknown connection id \" << id << std::endl;\n            }\n        } else {\n            std::cout << \"> Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/scratch_server/SConscript",
    "content": "## Scratch server example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\nImport('tls_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs] + ['z']\n   prgs += env_cpp11.Program('scratch_server', [\"scratch_server.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system','regex','random'],env) + [platform_libs] + [polyfill_libs] + [tls_libs] + ['z']\n   prgs += env.Program('scratch_server', [\"scratch_server.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/scratch_server/scratch_server.cpp",
    "content": "/**\n * This example is presently used as a scratch space. It may or may not be broken\n * at any given time.\n */\n\n#include <iostream>\n\n#include <websocketpp/config/debug_asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\n#include <websocketpp/extensions/permessage_deflate/enabled.hpp>\n\nstruct deflate_config : public websocketpp::config::debug_core {\n    typedef deflate_config type;\n    typedef debug_core base;\n    \n    typedef base::concurrency_type concurrency_type;\n    \n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n    \n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n    \n    typedef base::rng_type rng_type;\n    \n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::basic_socket::endpoint \n            socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config> \n        transport_type;\n        \n    /// permessage_compress extension\n    struct permessage_deflate_config {};\n\n    typedef websocketpp::extensions::permessage_deflate::enabled\n        <permessage_deflate_config> permessage_deflate_type;\n};\n\ntypedef websocketpp::server<deflate_config> server;\n\ntypedef server::message_ptr message_ptr;\n\n// Define a callback to handle incoming messages\nvoid on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {\n    /*std::cout << \"on_message called with hdl: \" << hdl.lock().get() \n              << \" and message (\" << msg->get_payload().size() << \"): \" << msg->get_payload()\n              << std::endl;\n    */\n    try {\n        s->send(hdl, msg->get_payload(), msg->get_opcode());\n    } catch (websocketpp::exception const & e) {\n        std::cout << \"Echo failed because: \" \n                  << \"(\" << e.what() << \")\" << std::endl;\n    }\n}\n\nint main(int argc, char * argv[]) {\n\t// Create a server endpoint\n    server echo_server;\n\t\n\ttry {\n        // Set logging settings        \n        if (argc > 1 && std::string(argv[1]) == \"-d\") {\n            echo_server.set_access_channels(websocketpp::log::alevel::all);\n            echo_server.set_error_channels(websocketpp::log::elevel::all);\n        } else {\n            echo_server.set_access_channels(websocketpp::log::alevel::none);\n            echo_server.set_error_channels(websocketpp::log::elevel::none);\n        }\n        \n        // Initialize ASIO\n        echo_server.init_asio();\n        \n        // Register our message handler\n        using websocketpp::lib::placeholders::_1;\n        using websocketpp::lib::placeholders::_2;\n        echo_server.set_message_handler(bind(&on_message,&echo_server,_1,_2));\n        \n        // Listen on port 9002\n        echo_server.listen(9002);\n        \n        // Start the server accept loop\n        echo_server.start_accept();\n\t    \n\t    // Start the ASIO io_service run loop\n        echo_server.run();\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    } catch (const std::exception & e) {\n        std::cout << e.what() << std::endl;\n    } catch (...) {\n        std::cout << \"other exception\" << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/simple_broadcast_server/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (simple_broadcast_server)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/simple_broadcast_server/simple_broadcast_server.cpp",
    "content": "#include <set>\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nusing websocketpp::connection_hdl;\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\nclass broadcast_server {\npublic:\n    broadcast_server() {\n        m_server.init_asio();\n\n        m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));\n        m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));\n        m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));\n    }\n\n    void on_open(connection_hdl hdl) {\n        m_connections.insert(hdl);\n    }\n\n    void on_close(connection_hdl hdl) {\n        m_connections.erase(hdl);\n    }\n\n    void on_message(connection_hdl hdl, server::message_ptr msg) {\n        for (auto it : m_connections) {\n            m_server.send(it,msg);\n        }\n    }\n\n    void run(uint16_t port) {\n        m_server.listen(port);\n        m_server.start_accept();\n        m_server.run();\n    }\nprivate:\n    typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;\n\n    server m_server;\n    con_list m_connections;\n};\n\nint main() {\n    broadcast_server server;\n    server.run(9002);\n}\n"
  },
  {
    "path": "examples/sip_client/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (sip_client)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/sip_client/README.txt",
    "content": "\n\nCheckout the project from git\n\nAt the top level, run cmake:\n\n  cmake -G 'Unix Makefiles' \\\n     -D BUILD_EXAMPLES=ON \\\n     -D WEBSOCKETPP_ROOT=/tmp/cm1 \\\n     -D ENABLE_CPP11=OFF .\n\nand then make the example:\n\n  make -C examples/sip_client\n\nNow run it:\n\n  bin/sip_client ws://ws-server:80\n\nIt has been tested against the repro SIP proxy from reSIProcate\n\n  http://www.resiprocate.org/WebRTC_and_SIP_Over_WebSockets\n"
  },
  {
    "path": "examples/sip_client/SConscript",
    "content": "## SIP client example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('sip_client', [\"sip_client.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('sip_client', [\"sip_client.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/sip_client/sip_client.cpp",
    "content": "#include <condition_variable>\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n\n#include <websocketpp/client.hpp>\n\n#include <iostream>\n\n#include <boost/thread/thread.hpp>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n// pull out the type of messages sent by our config\ntypedef websocketpp::config::asio_client::message_type::ptr message_ptr;\n\n// Create a server endpoint\nclient sip_client;\n\n\nbool received;\n\nvoid on_open(client* c, websocketpp::connection_hdl hdl) {\n    // now it is safe to use the connection\n    std::cout << \"connection ready\" << std::endl;\n\n    received=false;\n    // Send a SIP OPTIONS message to the server:\n    std::string SIP_msg=\"OPTIONS sip:carol@chicago.com SIP/2.0\\r\\nVia: SIP/2.0/WS df7jal23ls0d.invalid;rport;branch=z9hG4bKhjhs8ass877\\r\\nMax-Forwards: 70\\r\\nTo: <sip:carol@chicago.com>\\r\\nFrom: Alice <sip:alice@atlanta.com>;tag=1928301774\\r\\nCall-ID: a84b4c76e66710\\r\\nCSeq: 63104 OPTIONS\\r\\nContact: <sip:alice@pc33.atlanta.com>\\r\\nAccept: application/sdp\\r\\nContent-Length: 0\\r\\n\\r\\n\";\n    sip_client.send(hdl, SIP_msg.c_str(), websocketpp::frame::opcode::text);\n}\n\nvoid on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) {\n    client::connection_ptr con = sip_client.get_con_from_hdl(hdl);\n\n    std::cout << \"Received a reply:\" << std::endl;\n    fwrite(msg->get_payload().c_str(), msg->get_payload().size(), 1, stdout);\n    received=true;\n}\n\nint main(int argc, char* argv[]) {\n\n    std::string uri = \"ws://localhost:9001\";\n\n    if (argc == 2) {\n        uri = argv[1];\n    }\n\n    try {\n        // We expect there to be a lot of errors, so suppress them\n        sip_client.clear_access_channels(websocketpp::log::alevel::all);\n        sip_client.clear_error_channels(websocketpp::log::elevel::all);\n\n        // Initialize ASIO\n        sip_client.init_asio();\n\n        // Register our handlers\n        sip_client.set_open_handler(bind(&on_open,&sip_client,::_1));\n        sip_client.set_message_handler(bind(&on_message,&sip_client,::_1,::_2));\n\n        websocketpp::lib::error_code ec;\n        client::connection_ptr con = sip_client.get_connection(uri, ec);\n\n        // Specify the SIP subprotocol:\n        con->add_subprotocol(\"sip\");\n\n        sip_client.connect(con);\n\n        // Start the ASIO io_service run loop\n        sip_client.run();\n\n        while(!received) {\n            boost::this_thread::sleep(boost::posix_time::milliseconds(100));\n        }\n\n        std::cout << \"done\" << std::endl;\n\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/subprotocol_server/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (subprotocol_server)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/subprotocol_server/SConscript",
    "content": "## Main development example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('subprotocol_server', [\"subprotocol_server.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('subprotocol_server', [\"subprotocol_server.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/subprotocol_server/subprotocol_server.cpp",
    "content": "#include <iostream>\n\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nusing websocketpp::connection_hdl;\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\nusing websocketpp::lib::ref;\n\n\nbool validate(server & s, connection_hdl hdl) {\n    server::connection_ptr con = s.get_con_from_hdl(hdl);\n\n    std::cout << \"Cache-Control: \" << con->get_request_header(\"Cache-Control\") << std::endl;\n\n    const std::vector<std::string> & subp_requests = con->get_requested_subprotocols();\n    std::vector<std::string>::const_iterator it;\n\n    for (it = subp_requests.begin(); it != subp_requests.end(); ++it) {\n        std::cout << \"Requested: \" << *it << std::endl;\n    }\n\n    if (subp_requests.size() > 0) {\n        con->select_subprotocol(subp_requests[0]);\n    }\n\n    return true;\n}\n\nint main() {\n    try {\n        server s;\n\n        s.set_validate_handler(bind(&validate,ref(s),::_1));\n\n        s.init_asio();\n        s.listen(9005);\n        s.start_accept();\n\n        s.run();\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/telemetry_client/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (telemetry_client)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/telemetry_client/SConscript",
    "content": "## Telemetry client example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('telemetry_client', [\"telemetry_client.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('telemetry_client', [\"telemetry_client.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/telemetry_client/telemetry_client.cpp",
    "content": "#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n// This header pulls in the WebSocket++ abstracted thread support that will\n// select between boost::thread and std::thread based on how the build system\n// is configured.\n#include <websocketpp/common/thread.hpp>\n\n/**\n * Define a semi-cross platform helper method that waits/sleeps for a bit.\n */\nvoid wait_a_bit() {\n#ifdef WIN32\n    Sleep(1000);\n#else\n    sleep(1);\n#endif\n}\n\n/**\n * The telemetry client connects to a WebSocket server and sends a message every\n * second containing an integer count. This example can be used as the basis for\n * programs where a client connects and pushes data for logging, stress/load\n * testing, etc.\n */\nclass telemetry_client {\npublic:\n    typedef websocketpp::client<websocketpp::config::asio_client> client;\n    typedef websocketpp::lib::lock_guard<websocketpp::lib::mutex> scoped_lock;\n\n    telemetry_client() : m_open(false),m_done(false) {\n        // set up access channels to only log interesting things\n        m_client.clear_access_channels(websocketpp::log::alevel::all);\n        m_client.set_access_channels(websocketpp::log::alevel::connect);\n        m_client.set_access_channels(websocketpp::log::alevel::disconnect);\n        m_client.set_access_channels(websocketpp::log::alevel::app);\n\n        // Initialize the Asio transport policy\n        m_client.init_asio();\n\n        // Bind the handlers we are using\n        using websocketpp::lib::placeholders::_1;\n        using websocketpp::lib::bind;\n        m_client.set_open_handler(bind(&telemetry_client::on_open,this,_1));\n        m_client.set_close_handler(bind(&telemetry_client::on_close,this,_1));\n        m_client.set_fail_handler(bind(&telemetry_client::on_fail,this,_1));\n    }\n\n    // This method will block until the connection is complete\n    void run(const std::string & uri) {\n        // Create a new connection to the given URI\n        websocketpp::lib::error_code ec;\n        client::connection_ptr con = m_client.get_connection(uri, ec);\n        if (ec) {\n            m_client.get_alog().write(websocketpp::log::alevel::app,\n                    \"Get Connection Error: \"+ec.message());\n            return;\n        }\n\n        // Grab a handle for this connection so we can talk to it in a thread\n        // safe manor after the event loop starts.\n        m_hdl = con->get_handle();\n\n        // Queue the connection. No DNS queries or network connections will be\n        // made until the io_service event loop is run.\n        m_client.connect(con);\n\n        // Create a thread to run the ASIO io_service event loop\n        websocketpp::lib::thread asio_thread(&client::run, &m_client);\n\n        // Create a thread to run the telemetry loop\n        websocketpp::lib::thread telemetry_thread(&telemetry_client::telemetry_loop,this);\n\n        asio_thread.join();\n        telemetry_thread.join();\n    }\n\n    // The open handler will signal that we are ready to start sending telemetry\n    void on_open(websocketpp::connection_hdl) {\n        m_client.get_alog().write(websocketpp::log::alevel::app,\n            \"Connection opened, starting telemetry!\");\n\n        scoped_lock guard(m_lock);\n        m_open = true;\n    }\n\n    // The close handler will signal that we should stop sending telemetry\n    void on_close(websocketpp::connection_hdl) {\n        m_client.get_alog().write(websocketpp::log::alevel::app,\n            \"Connection closed, stopping telemetry!\");\n\n        scoped_lock guard(m_lock);\n        m_done = true;\n    }\n\n    // The fail handler will signal that we should stop sending telemetry\n    void on_fail(websocketpp::connection_hdl) {\n        m_client.get_alog().write(websocketpp::log::alevel::app,\n            \"Connection failed, stopping telemetry!\");\n\n        scoped_lock guard(m_lock);\n        m_done = true;\n    }\n\n    void telemetry_loop() {\n        uint64_t count = 0;\n        std::stringstream val;\n        websocketpp::lib::error_code ec;\n\n        while(1) {\n            bool wait = false;\n\n            {\n                scoped_lock guard(m_lock);\n                // If the connection has been closed, stop generating telemetry\n                if (m_done) {break;}\n\n                // If the connection hasn't been opened yet wait a bit and retry\n                if (!m_open) {\n                    wait = true;\n                }\n            }\n\n            if (wait) {\n                wait_a_bit();\n                continue;\n            }\n\n            val.str(\"\");\n            val << \"count is \" << count++;\n\n            m_client.get_alog().write(websocketpp::log::alevel::app, val.str());\n            m_client.send(m_hdl,val.str(),websocketpp::frame::opcode::text,ec);\n\n            // The most likely error that we will get is that the connection is\n            // not in the right state. Usually this means we tried to send a\n            // message to a connection that was closed or in the process of\n            // closing. While many errors here can be easily recovered from,\n            // in this simple example, we'll stop the telemetry loop.\n            if (ec) {\n                m_client.get_alog().write(websocketpp::log::alevel::app,\n                    \"Send Error: \"+ec.message());\n                break;\n            }\n\n            wait_a_bit();\n        }\n    }\nprivate:\n    client m_client;\n    websocketpp::connection_hdl m_hdl;\n    websocketpp::lib::mutex m_lock;\n    bool m_open;\n    bool m_done;\n};\n\nint main(int argc, char* argv[]) {\n    telemetry_client c;\n\n    std::string uri = \"ws://localhost:9002\";\n\n    if (argc == 2) {\n        uri = argv[1];\n    }\n\n    c.run(uri);\n}\n"
  },
  {
    "path": "examples/telemetry_server/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (telemetry_server)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n"
  },
  {
    "path": "examples/telemetry_server/SConscript",
    "content": "## Main development example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('telemetry_server', [\"telemetry_server.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('telemetry_server', [\"telemetry_server.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/telemetry_server/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n<title>WebSocket++ Telemetry Client</title>\n</head>\n<body>\n\n<script type=\"text/javascript\">\nvar ws;\nvar url;\n\nfunction connect() {\n\turl = document.getElementById(\"server_url\").value;\n\t\n\tif (\"WebSocket\" in window) {\n\t\tws = new WebSocket(url);\n\t} else if (\"MozWebSocket\" in window) {\n\t\tws = new MozWebSocket(url);\n\t} else {\n\t\tdocument.getElementById(\"messages\").innerHTML += \"This Browser does not support WebSockets<br />\";\n\t\treturn;\n\t}\n\tws.onopen = function(e) {\n\t\tdocument.getElementById(\"messages\").innerHTML += \"Client: A connection to \"+ws.url+\" has been opened.<br />\";\n\t\t\n\t\tdocument.getElementById(\"server_url\").disabled = true;\n\t\tdocument.getElementById(\"toggle_connect\").innerHTML = \"Disconnect\";\n\t};\n\t\n\tws.onerror = function(e) {\n\t\tdocument.getElementById(\"messages\").innerHTML += \"Client: An error occured, see console log for more details.<br />\";\n\t\tconsole.log(e);\n\t};\n\t\n\tws.onclose = function(e) {\n\t\tdocument.getElementById(\"messages\").innerHTML += \"Client: The connection to \"+url+\" was closed. [\"+e.code+(e.reason != \"\" ? \",\"+e.reason : \"\")+\"]<br />\";\n\t    cleanup_disconnect();\n\t};\n\t\n\tws.onmessage = function(e) {\n\t\tdocument.getElementById(\"messages\").innerHTML += \"Server: \"+e.data+\"<br />\";\n\t};\n}\n\nfunction disconnect() {\n\tws.close();\n\tcleanup_disconnect();\n}\n\nfunction cleanup_disconnect() {\n    document.getElementById(\"server_url\").disabled = false;\n\tdocument.getElementById(\"toggle_connect\").innerHTML = \"Connect\";\n}\n\nfunction toggle_connect() {\n\tif (document.getElementById(\"server_url\").disabled === false) {\n\t\tconnect();\n\t} else {\n\t\tdisconnect();\n\t}\n}\n</script>\n\n<style>\nbody,html {\n\tmargin: 0px;\n\tpadding: 0px;\n}\n#controls {\n\tfloat:right;\n\tbackground-color: #999;\n}\n\n</style>\n\n<div id=\"controls\">\n\t<div id=\"server\">\n\t<input type=\"text\" name=\"server_url\" id=\"server_url\" value=\"ws://localhost:9002\" /><br />\n\t<button id=\"toggle_connect\" onclick=\"toggle_connect();\">Connect</button>\n\t</div>\n</div>\n<div id=\"messages\"></div>\n\n</body>\n</html>\n"
  },
  {
    "path": "examples/telemetry_server/telemetry_server.cpp",
    "content": "#include <websocketpp/config/asio_no_tls.hpp>\n\n#include <websocketpp/server.hpp>\n\n#include <fstream>\n#include <iostream>\n#include <set>\n#include <streambuf>\n#include <string>\n\n/**\n * The telemetry server accepts connections and sends a message every second to\n * each client containing an integer count. This example can be used as the\n * basis for programs that expose a stream of telemetry data for logging,\n * dashboards, etc.\n *\n * This example uses the timer based concurrency method and is self contained\n * and singled threaded. Refer to telemetry client for an example of a similar\n * telemetry setup using threads rather than timers.\n *\n * This example also includes an example simple HTTP server that serves a web\n * dashboard displaying the count. This simple design is suitable for use \n * delivering a small number of files to a small number of clients. It is ideal\n * for cases like embedded dashboards that don't want the complexity of an extra\n * HTTP server to serve static files.\n *\n * This design *will* fall over under high traffic or DoS conditions. In such\n * cases you are much better off proxying to a real HTTP server for the http\n * requests.\n */\nclass telemetry_server {\npublic:\n    typedef websocketpp::connection_hdl connection_hdl;\n    typedef websocketpp::server<websocketpp::config::asio> server;\n\n    telemetry_server() : m_count(0) {\n        // set up access channels to only log interesting things\n        m_endpoint.clear_access_channels(websocketpp::log::alevel::all);\n        m_endpoint.set_access_channels(websocketpp::log::alevel::access_core);\n        m_endpoint.set_access_channels(websocketpp::log::alevel::app);\n\n        // Initialize the Asio transport policy\n        m_endpoint.init_asio();\n\n        // Bind the handlers we are using\n        using websocketpp::lib::placeholders::_1;\n        using websocketpp::lib::bind;\n        m_endpoint.set_open_handler(bind(&telemetry_server::on_open,this,_1));\n        m_endpoint.set_close_handler(bind(&telemetry_server::on_close,this,_1));\n        m_endpoint.set_http_handler(bind(&telemetry_server::on_http,this,_1));\n    }\n\n    void run(std::string docroot, uint16_t port) {\n        std::stringstream ss;\n        ss << \"Running telemetry server on port \"<< port <<\" using docroot=\" << docroot;\n        m_endpoint.get_alog().write(websocketpp::log::alevel::app,ss.str());\n        \n        m_docroot = docroot;\n        \n        // listen on specified port\n        m_endpoint.listen(port);\n\n        // Start the server accept loop\n        m_endpoint.start_accept();\n\n        // Set the initial timer to start telemetry\n        set_timer();\n\n        // Start the ASIO io_service run loop\n        try {\n            m_endpoint.run();\n        } catch (websocketpp::exception const & e) {\n            std::cout << e.what() << std::endl;\n        }\n    }\n\n    void set_timer() {\n        m_timer = m_endpoint.set_timer(\n            1000,\n            websocketpp::lib::bind(\n                &telemetry_server::on_timer,\n                this,\n                websocketpp::lib::placeholders::_1\n            )\n        );\n    }\n\n    void on_timer(websocketpp::lib::error_code const & ec) {\n        if (ec) {\n            // there was an error, stop telemetry\n            m_endpoint.get_alog().write(websocketpp::log::alevel::app,\n                    \"Timer Error: \"+ec.message());\n            return;\n        }\n        \n        std::stringstream val;\n        val << \"count is \" << m_count++;\n        \n        // Broadcast count to all connections\n        con_list::iterator it;\n        for (it = m_connections.begin(); it != m_connections.end(); ++it) {\n            m_endpoint.send(*it,val.str(),websocketpp::frame::opcode::text);\n        }\n        \n        // set timer for next telemetry check\n        set_timer();\n    }\n\n    void on_http(connection_hdl hdl) {\n        // Upgrade our connection handle to a full connection_ptr\n        server::connection_ptr con = m_endpoint.get_con_from_hdl(hdl);\n    \n        std::ifstream file;\n        std::string filename = con->get_resource();\n        std::string response;\n    \n        m_endpoint.get_alog().write(websocketpp::log::alevel::app,\n            \"http request1: \"+filename);\n    \n        if (filename == \"/\") {\n            filename = m_docroot+\"index.html\";\n        } else {\n            filename = m_docroot+filename.substr(1);\n        }\n        \n        m_endpoint.get_alog().write(websocketpp::log::alevel::app,\n            \"http request2: \"+filename);\n    \n        file.open(filename.c_str(), std::ios::in);\n        if (!file) {\n            // 404 error\n            std::stringstream ss;\n        \n            ss << \"<!doctype html><html><head>\"\n               << \"<title>Error 404 (Resource not found)</title><body>\"\n               << \"<h1>Error 404</h1>\"\n               << \"<p>The requested URL \" << filename << \" was not found on this server.</p>\"\n               << \"</body></head></html>\";\n        \n            con->set_body(ss.str());\n            con->set_status(websocketpp::http::status_code::not_found);\n            return;\n        }\n    \n        file.seekg(0, std::ios::end);\n        response.reserve(file.tellg());\n        file.seekg(0, std::ios::beg);\n    \n        response.assign((std::istreambuf_iterator<char>(file)),\n                        std::istreambuf_iterator<char>());\n    \n        con->set_body(response);\n        con->set_status(websocketpp::http::status_code::ok);\n    }\n\n    void on_open(connection_hdl hdl) {\n        m_connections.insert(hdl);\n    }\n\n    void on_close(connection_hdl hdl) {\n        m_connections.erase(hdl);\n    }\nprivate:\n    typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;\n    \n    server m_endpoint;\n    con_list m_connections;\n    server::timer_ptr m_timer;\n    \n    std::string m_docroot;\n    \n    // Telemetry data\n    uint64_t m_count;\n};\n\nint main(int argc, char* argv[]) {\n    telemetry_server s;\n\n    std::string docroot;\n    uint16_t port = 9002;\n\n    if (argc == 1) {\n        std::cout << \"Usage: telemetry_server [documentroot] [port]\" << std::endl;\n        return 1;\n    }\n    \n    if (argc >= 2) {\n        docroot = std::string(argv[1]);\n    }\n        \n    if (argc >= 3) {\n        int i = atoi(argv[2]);\n        if (i <= 0 || i > 65535) {\n            std::cout << \"invalid port\" << std::endl;\n            return 1;\n        }\n        \n        port = uint16_t(i);\n    }\n\n    s.run(docroot, port);\n    return 0;\n}\n"
  },
  {
    "path": "examples/testee_client/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\nif (ZLIB_FOUND)\n\ninit_target (testee_client)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nlink_zlib()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n\nendif()"
  },
  {
    "path": "examples/testee_client/SConscript",
    "content": "## Autobahn test client example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']\n   prgs += env_cpp11.Program('testee_client', [\"testee_client.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + ['z']\n   prgs += env.Program('testee_client', [\"testee_client.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/testee_client/testee_client.cpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n#include <websocketpp/extensions/permessage_deflate/enabled.hpp>\n\n#include <iostream>\n\nstruct deflate_config : public websocketpp::config::asio_client {\n    typedef deflate_config type;\n    typedef asio_client base;\n    \n    typedef base::concurrency_type concurrency_type;\n    \n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n    \n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n    \n    typedef base::rng_type rng_type;\n    \n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::basic_socket::endpoint \n            socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config> \n        transport_type;\n        \n    /// permessage_compress extension\n    struct permessage_deflate_config {};\n\n    typedef websocketpp::extensions::permessage_deflate::enabled\n        <permessage_deflate_config> permessage_deflate_type;\n};\n\ntypedef websocketpp::client<deflate_config> client;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n// pull out the type of messages sent by our config\ntypedef websocketpp::config::asio_client::message_type::ptr message_ptr;\n\nint case_count = 0;\n\nvoid on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) {\n    client::connection_ptr con = c->get_con_from_hdl(hdl);\n\n    if (con->get_resource() == \"/getCaseCount\") {\n        std::cout << \"Detected \" << msg->get_payload() << \" test cases.\"\n                  << std::endl;\n        case_count = atoi(msg->get_payload().c_str());\n    } else {\n        c->send(hdl, msg->get_payload(), msg->get_opcode());\n    }\n}\n\nint main(int argc, char* argv[]) {\n    // Create a server endpoint\n    client c;\n\n    std::string uri = \"ws://localhost:9001\";\n\n    if (argc == 2) {\n        uri = argv[1];\n    }\n\n    try {\n        // We expect there to be a lot of errors, so suppress them\n        c.clear_access_channels(websocketpp::log::alevel::all);\n        c.clear_error_channels(websocketpp::log::elevel::all);\n\n        // Initialize ASIO\n        c.init_asio();\n\n        // Register our handlers\n        c.set_message_handler(bind(&on_message,&c,::_1,::_2));\n\n        websocketpp::lib::error_code ec;\n        client::connection_ptr con = c.get_connection(uri+\"/getCaseCount\", ec);\n        c.connect(con);\n\n        // Start the ASIO io_service run loop\n        c.run();\n\n        std::cout << \"case count: \" << case_count << std::endl;\n\n        for (int i = 1; i <= case_count; i++) {\n            c.reset();\n\n            std::stringstream url;\n\n            url << uri << \"/runCase?case=\" << i << \"&agent=\"\n                << websocketpp::user_agent;\n\n            con = c.get_connection(url.str(), ec);\n\n            c.connect(con);\n\n            c.run();\n        }\n\n        std::cout << \"done\" << std::endl;\n\n    } catch (websocketpp::exception const & e) {\n        std::cout << e.what() << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/testee_server/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\nif (ZLIB_FOUND)\n\ninit_target (testee_server)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nlink_zlib()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n\nendif()"
  },
  {
    "path": "examples/testee_server/SConscript",
    "content": "## Autobahn Testee Server\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']\n   prgs += env_cpp11.Program('testee_server', [\"testee_server.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + ['z']\n   prgs += env.Program('testee_server', [\"testee_server.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')\n"
  },
  {
    "path": "examples/testee_server/testee_server.cpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n#include <websocketpp/extensions/permessage_deflate/enabled.hpp>\n#include <iostream>\n\nstruct testee_config : public websocketpp::config::asio {\n    // pull default settings from our core config\n    typedef websocketpp::config::asio core;\n\n    typedef core::concurrency_type concurrency_type;\n    typedef core::request_type request_type;\n    typedef core::response_type response_type;\n    typedef core::message_type message_type;\n    typedef core::con_msg_manager_type con_msg_manager_type;\n    typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef core::alog_type alog_type;\n    typedef core::elog_type elog_type;\n    typedef core::rng_type rng_type;\n    typedef core::endpoint_base endpoint_base;\n\n    static bool const enable_multithreading = true;\n\n    struct transport_config : public core::transport_config {\n        typedef core::concurrency_type concurrency_type;\n        typedef core::elog_type elog_type;\n        typedef core::alog_type alog_type;\n        typedef core::request_type request_type;\n        typedef core::response_type response_type;\n\n        static bool const enable_multithreading = true;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config>\n        transport_type;\n\n    static const websocketpp::log::level elog_level =\n        websocketpp::log::elevel::none;\n    static const websocketpp::log::level alog_level =\n        websocketpp::log::alevel::none;\n        \n    /// permessage_compress extension\n    struct permessage_deflate_config {};\n\n    typedef websocketpp::extensions::permessage_deflate::enabled\n        <permessage_deflate_config> permessage_deflate_type;\n};\n\ntypedef websocketpp::server<testee_config> server;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n// pull out the type of messages sent by our config\ntypedef server::message_ptr message_ptr;\n\n// Define a callback to handle incoming messages\nvoid on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {\n    s->send(hdl, msg->get_payload(), msg->get_opcode());\n}\n\nvoid on_socket_init(websocketpp::connection_hdl, boost::asio::ip::tcp::socket & s) {\n    boost::asio::ip::tcp::no_delay option(true);\n    s.set_option(option);\n}\n\nint main(int argc, char * argv[]) {\n    // Create a server endpoint\n    server testee_server;\n\n    short port = 9002;\n    size_t num_threads = 1;\n\n    if (argc == 3) {\n        port = atoi(argv[1]);\n        num_threads = atoi(argv[2]);\n    }\n\n    try {\n        // Total silence\n        testee_server.clear_access_channels(websocketpp::log::alevel::all);\n        testee_server.clear_error_channels(websocketpp::log::alevel::all);\n\n        // Initialize ASIO\n        testee_server.init_asio();\n        testee_server.set_reuse_addr(true);\n\n        // Register our message handler\n        testee_server.set_message_handler(bind(&on_message,&testee_server,::_1,::_2));\n        testee_server.set_socket_init_handler(bind(&on_socket_init,::_1,::_2));\n\n        // Listen on specified port with extended listen backlog\n        testee_server.set_listen_backlog(8192);\n        testee_server.listen(port);\n\n        // Start the server accept loop\n        testee_server.start_accept();\n\n        // Start the ASIO io_service run loop\n        if (num_threads == 1) {\n            testee_server.run();\n        } else {\n            typedef websocketpp::lib::shared_ptr<websocketpp::lib::thread> thread_ptr;\n            std::vector<thread_ptr> ts;\n            for (size_t i = 0; i < num_threads; i++) {\n                ts.push_back(websocketpp::lib::make_shared<websocketpp::lib::thread>(&server::run, &testee_server));\n            }\n\n            for (size_t i = 0; i < num_threads; i++) {\n                ts[i]->join();\n            }\n        }\n\n    } catch (websocketpp::exception const & e) {\n        std::cout << \"exception: \" << e.what() << std::endl;\n    }\n}\n"
  },
  {
    "path": "examples/utility_client/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (utility_client)\n\nbuild_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"examples\")\n\n"
  },
  {
    "path": "examples/utility_client/SConscript",
    "content": "## Utility client example\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nprgs = []\n\n# if a C++11 environment is available build using that, otherwise use boost\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   prgs += env_cpp11.Program('utility_client', [\"utility_client.cpp\"], LIBS = ALL_LIBS)\nelse:\n   ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]\n   prgs += env.Program('utility_client', [\"utility_client.cpp\"], LIBS = ALL_LIBS)\n\nReturn('prgs')"
  },
  {
    "path": "examples/utility_client/utility_client.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial.\n// Additional related material can be found in the tutorials/utility_client\n// directory of the WebSocket++ repository.\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <websocketpp/common/thread.hpp>\n#include <websocketpp/common/memory.hpp>\n\n#include <cstdlib>\n#include <iostream>\n#include <map>\n#include <string>\n#include <sstream>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nclass connection_metadata {\npublic:\n    typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;\n\n    connection_metadata(int id, websocketpp::connection_hdl hdl, std::string uri)\n      : m_id(id)\n      , m_hdl(hdl)\n      , m_status(\"Connecting\")\n      , m_uri(uri)\n      , m_server(\"N/A\")\n    {}\n\n    void on_open(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Open\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n    }\n\n    void on_fail(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Failed\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n        m_error_reason = con->get_ec().message();\n    }\n    \n    void on_close(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Closed\";\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        std::stringstream s;\n        s << \"close code: \" << con->get_remote_close_code() << \" (\" \n          << websocketpp::close::status::get_string(con->get_remote_close_code()) \n          << \"), close reason: \" << con->get_remote_close_reason();\n        m_error_reason = s.str();\n    }\n\n    void on_message(websocketpp::connection_hdl, client::message_ptr msg) {\n        if (msg->get_opcode() == websocketpp::frame::opcode::text) {\n            m_messages.push_back(\"<< \" + msg->get_payload());\n        } else {\n            m_messages.push_back(\"<< \" + websocketpp::utility::to_hex(msg->get_payload()));\n        }\n    }\n\n    websocketpp::connection_hdl get_hdl() const {\n        return m_hdl;\n    }\n    \n    int get_id() const {\n        return m_id;\n    }\n    \n    std::string get_status() const {\n        return m_status;\n    }\n\n    void record_sent_message(std::string message) {\n        m_messages.push_back(\">> \" + message);\n    }\n\n    friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);\nprivate:\n    int m_id;\n    websocketpp::connection_hdl m_hdl;\n    std::string m_status;\n    std::string m_uri;\n    std::string m_server;\n    std::string m_error_reason;\n    std::vector<std::string> m_messages;\n};\n\nstd::ostream & operator<< (std::ostream & out, connection_metadata const & data) {\n    out << \"> URI: \" << data.m_uri << \"\\n\"\n        << \"> Status: \" << data.m_status << \"\\n\"\n        << \"> Remote Server: \" << (data.m_server.empty() ? \"None Specified\" : data.m_server) << \"\\n\"\n        << \"> Error/close reason: \" << (data.m_error_reason.empty() ? \"N/A\" : data.m_error_reason) << \"\\n\";\n    out << \"> Messages Processed: (\" << data.m_messages.size() << \") \\n\";\n\n    std::vector<std::string>::const_iterator it;\n    for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) {\n        out << *it << \"\\n\";\n    }\n\n    return out;\n}\n\nclass websocket_endpoint {\npublic:\n    websocket_endpoint () : m_next_id(0) {\n        m_endpoint.clear_access_channels(websocketpp::log::alevel::all);\n        m_endpoint.clear_error_channels(websocketpp::log::elevel::all);\n\n        m_endpoint.init_asio();\n        m_endpoint.start_perpetual();\n\n        m_thread = websocketpp::lib::make_shared<websocketpp::lib::thread>(&client::run, &m_endpoint);\n    }\n\n    ~websocket_endpoint() {\n        m_endpoint.stop_perpetual();\n        \n        for (con_list::const_iterator it = m_connection_list.begin(); it != m_connection_list.end(); ++it) {\n            if (it->second->get_status() != \"Open\") {\n                // Only close open connections\n                continue;\n            }\n            \n            std::cout << \"> Closing connection \" << it->second->get_id() << std::endl;\n            \n            websocketpp::lib::error_code ec;\n            m_endpoint.close(it->second->get_hdl(), websocketpp::close::status::going_away, \"\", ec);\n            if (ec) {\n                std::cout << \"> Error closing connection \" << it->second->get_id() << \": \"  \n                          << ec.message() << std::endl;\n            }\n        }\n        \n        m_thread->join();\n    }\n\n    int connect(std::string const & uri) {\n        websocketpp::lib::error_code ec;\n\n        client::connection_ptr con = m_endpoint.get_connection(uri, ec);\n\n        if (ec) {\n            std::cout << \"> Connect initialization error: \" << ec.message() << std::endl;\n            return -1;\n        }\n\n        int new_id = m_next_id++;\n        connection_metadata::ptr metadata_ptr = websocketpp::lib::make_shared<connection_metadata>(new_id, con->get_handle(), uri);\n        m_connection_list[new_id] = metadata_ptr;\n\n        con->set_open_handler(websocketpp::lib::bind(\n            &connection_metadata::on_open,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_fail_handler(websocketpp::lib::bind(\n            &connection_metadata::on_fail,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_close_handler(websocketpp::lib::bind(\n            &connection_metadata::on_close,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_message_handler(websocketpp::lib::bind(\n            &connection_metadata::on_message,\n            metadata_ptr,\n            websocketpp::lib::placeholders::_1,\n            websocketpp::lib::placeholders::_2\n        ));\n\n        m_endpoint.connect(con);\n\n        return new_id;\n    }\n\n    void close(int id, websocketpp::close::status::value code, std::string reason) {\n        websocketpp::lib::error_code ec;\n        \n        con_list::iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            std::cout << \"> No connection found with id \" << id << std::endl;\n            return;\n        }\n        \n        m_endpoint.close(metadata_it->second->get_hdl(), code, reason, ec);\n        if (ec) {\n            std::cout << \"> Error initiating close: \" << ec.message() << std::endl;\n        }\n    }\n\n    void send(int id, std::string message) {\n        websocketpp::lib::error_code ec;\n        \n        con_list::iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            std::cout << \"> No connection found with id \" << id << std::endl;\n            return;\n        }\n        \n        m_endpoint.send(metadata_it->second->get_hdl(), message, websocketpp::frame::opcode::text, ec);\n        if (ec) {\n            std::cout << \"> Error sending message: \" << ec.message() << std::endl;\n            return;\n        }\n        \n        metadata_it->second->record_sent_message(message);\n    }\n\n    connection_metadata::ptr get_metadata(int id) const {\n        con_list::const_iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            return connection_metadata::ptr();\n        } else {\n            return metadata_it->second;\n        }\n    }\nprivate:\n    typedef std::map<int,connection_metadata::ptr> con_list;\n\n    client m_endpoint;\n    websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;\n\n    con_list m_connection_list;\n    int m_next_id;\n};\n\nint main() {\n    bool done = false;\n    std::string input;\n    websocket_endpoint endpoint;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout\n                << \"\\nCommand List:\\n\"\n                << \"connect <ws uri>\\n\"\n                << \"send <connection id> <message>\\n\"\n                << \"close <connection id> [<close code:default=1000>] [<close reason>]\\n\"\n                << \"show <connection id>\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else if (input.substr(0,7) == \"connect\") {\n            int id = endpoint.connect(input.substr(8));\n            if (id != -1) {\n                std::cout << \"> Created connection with id \" << id << std::endl;\n            }\n        } else if (input.substr(0,4) == \"send\") {\n            std::stringstream ss(input);\n            \n            std::string cmd;\n            int id;\n            std::string message;\n            \n            ss >> cmd >> id;\n            std::getline(ss,message);\n            \n            endpoint.send(id, message);\n        } else if (input.substr(0,5) == \"close\") {\n            std::stringstream ss(input);\n            \n            std::string cmd;\n            int id;\n            int close_code = websocketpp::close::status::normal;\n            std::string reason;\n            \n            ss >> cmd >> id >> close_code;\n            std::getline(ss,reason);\n            \n            endpoint.close(id, close_code, reason);\n        } else if (input.substr(0,4) == \"show\") {\n            int id = atoi(input.substr(5).c_str());\n\n            connection_metadata::ptr metadata = endpoint.get_metadata(id);\n            if (metadata) {\n                std::cout << *metadata << std::endl;\n            } else {\n                std::cout << \"> Unknown connection id \" << id << std::endl;\n            }\n        } else {\n            std::cout << \"> Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}"
  },
  {
    "path": "readme.md",
    "content": "WebSocket++ (0.8.2)\n==========================\n\nWebSocket++ is a header only C++ library that implements RFC6455 The WebSocket\nProtocol. It allows integrating WebSocket client and server functionality into\nC++ programs. It uses interchangeable network transport modules including one\nbased on raw char buffers, one based on C++ iostreams, and one based on Asio \n(either via Boost or standalone). End users can write additional transport\npolicies to support other networking or event libraries as needed.\n\nMajor Features\n==============\n* Full support for RFC6455\n* Partial support for Hixie 76 / Hybi 00, 07-17 draft specs (server only)\n* Message/event based interface\n* Supports secure WebSockets (TLS), IPv6, and explicit proxies.\n* Flexible dependency management (C++11 Standard Library or Boost)\n* Interchangeable network transport modules (raw, iostream, Asio, or custom)\n* Portable/cross platform (Posix/Windows, 32/64bit, Intel/ARM/PPC)\n* Thread-safe\n\nGet Involved\n============\n\n[![Build Status](https://travis-ci.org/zaphoyd/websocketpp.png)](https://travis-ci.org/zaphoyd/websocketpp)\n\n**Project Website**\nhttp://www.zaphoyd.com/websocketpp/\n\n**User Manual**\nhttp://docs.websocketpp.org/\n\n**GitHub Repository**\nhttps://github.com/zaphoyd/websocketpp/\n\nGitHub pull requests should be submitted to the `develop` branch.\n\n**Announcements Mailing List**\nhttp://groups.google.com/group/websocketpp-announcements/\n\n**IRC Channel**\n #websocketpp (freenode)\n\n**Discussion / Development / Support Mailing List / Forum**\nhttp://groups.google.com/group/websocketpp/\n\nAuthor\n======\nPeter Thorson - websocketpp@zaphoyd.com\n"
  },
  {
    "path": "roadmap.md",
    "content": "Complete & Tested:\n- Server and client roles pass all Autobahn v0.5.9 test suite tests strictly\n- Streaming UTF8 validation\n- random number generation\n- iostream based transport\n- C++11 support\n- LLVM/Clang support\n- GCC support\n- 64 bit support\n- 32 bit support\n- Logging\n- Client role\n- message_handler\n- ping_handler\n- pong_handler\n- open_handler\n- close_handler\n- echo_server & echo_server_tls\n- External io_service support\n- TLS support\n- exception/error handling\n- Timeouts\n- Subprotocol negotiation\n- validate_handler\n- Hybi 00/Hixie 76 legacy protocol support\n- Outgoing Proxy Support\n- socket_init_handler\n- tls_init_handler\n- tcp_init_handler\n\nOngoing work\n- Performance tuning\n- PowerPC support\n- Visual Studio / Windows support\n- CMake build/install support\n- http_handler\n\nFuture feature roadmap\n- Extension support\n- permessage_compress extension\n- Message buffer pool\n- flow control\n- tutorials & documentation\n"
  },
  {
    "path": "test/connection/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (test_connection)\n\nbuild_test (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n"
  },
  {
    "path": "test/connection/SConscript",
    "content": "## connection unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs]\n\nobjs = env.Object('connection_boost.o', [\"connection.cpp\"], LIBS = BOOST_LIBS)\nobjs = env.Object('connection_tu2_boost.o', [\"connection_tu2.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_connection_boost', [\"connection_boost.o\",\"connection_tu2_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   objs += env_cpp11.Object('connection_stl.o', [\"connection.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('connection_tu2_stl.o', [\"connection_tu2.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_connection_stl', [\"connection_stl.o\",\"connection_tu2_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/connection/connection.cpp",
    "content": "/*\n * Copyright (c) 2011, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE connection\n#include <boost/test/unit_test.hpp>\n\n#include \"connection_tu2.hpp\"\n\n// Include special debugging transport\n//#include <websocketpp/config/minimal_client.hpp>\n#include <websocketpp/transport/debug/endpoint.hpp>\n\n// NOTE: these tests currently test against hardcoded output values. I am not\n// sure how problematic this will be. If issues arise like order of headers the\n// output should be parsed by http::response and have values checked directly\n\nBOOST_AUTO_TEST_CASE( basic_http_request ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\n\\r\\n\";\n    std::string output = \"HTTP/1.1 426 Upgrade Required\\r\\nServer: \" +\n                         std::string(websocketpp::user_agent)+\"\\r\\n\\r\\n\";\n\n    std::string o2 = run_server_test(input);\n\n    BOOST_CHECK(o2 == output);\n}\n\nstruct connection_extension {\n    connection_extension() : extension_value(5) {}\n\n    int extension_method() {\n        return extension_value;\n    }\n\n    bool is_server() const {\n        return false;\n    }\n\n    int extension_value;\n};\n\nstruct stub_config : public websocketpp::config::core {\n    typedef core::concurrency_type concurrency_type;\n\n    typedef core::request_type request_type;\n    typedef core::response_type response_type;\n\n    typedef core::message_type message_type;\n    typedef core::con_msg_manager_type con_msg_manager_type;\n    typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef core::alog_type alog_type;\n    typedef core::elog_type elog_type;\n\n    typedef core::rng_type rng_type;\n\n    typedef core::transport_type transport_type;\n\n    typedef core::endpoint_base endpoint_base;\n    typedef connection_extension connection_base;\n};\n\nstruct debug_config_client : public websocketpp::config::core {\n    typedef debug_config_client type;\n    \n    typedef core::concurrency_type concurrency_type;\n\n    typedef core::request_type request_type;\n    typedef core::response_type response_type;\n\n    typedef core::message_type message_type;\n    typedef core::con_msg_manager_type con_msg_manager_type;\n    typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef core::alog_type alog_type;\n    typedef core::elog_type elog_type;\n\n    typedef websocketpp::random::none::int_generator<uint32_t> rng_type;\n\n    struct transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::elog_type elog_type;\n        typedef type::alog_type alog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n\n        /// Controls compile time enabling/disabling of thread syncronization\n        /// code Disabling can provide a minor performance improvement to single\n        /// threaded applications\n        static bool const enable_multithreading = true;\n\n        /// Default timer values (in ms)\n        static const long timeout_socket_pre_init = 5000;\n        static const long timeout_proxy = 5000;\n        static const long timeout_socket_post_init = 5000;\n        static const long timeout_connect = 5000;\n        static const long timeout_socket_shutdown = 5000;\n    };\n\n    /// Transport Endpoint Component\n    typedef websocketpp::transport::debug::endpoint<transport_config>\n        transport_type;\n\n    typedef core::endpoint_base endpoint_base;\n    typedef connection_extension connection_base;\n    \n    static const websocketpp::log::level elog_level = websocketpp::log::elevel::none;\n    static const websocketpp::log::level alog_level = websocketpp::log::alevel::none;\n};\n\nstruct connection_setup {\n    connection_setup(bool p_is_server)\n            : alog(websocketpp::lib::make_shared<stub_config::alog_type>())\n            , elog(websocketpp::lib::make_shared<stub_config::elog_type>())\n            , c(p_is_server, \"\", alog, elog, rng) {}\n\n    websocketpp::lib::error_code ec;\n    websocketpp::lib::shared_ptr<stub_config::alog_type> alog;\n    websocketpp::lib::shared_ptr<stub_config::elog_type> elog;\n    stub_config::rng_type rng;\n    websocketpp::connection<stub_config> c;\n};\n\ntypedef websocketpp::client<debug_config_client> debug_client;\ntypedef websocketpp::server<debug_config_client> debug_server;\n\n/*void echo_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {\n    s->send(hdl, msg->get_payload(), msg->get_opcode());\n}*/\n\nvoid validate_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {\n    s->send(hdl, msg->get_payload(), msg->get_opcode());\n}\n\nbool validate_set_ua(server* s, websocketpp::connection_hdl hdl) {\n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n    con->replace_header(\"Server\",\"foo\");\n    return true;\n}\n\nvoid http_func(server* s, websocketpp::connection_hdl hdl) {\n    using namespace websocketpp::http;\n\n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n\n    std::string res = con->get_resource();\n\n    con->set_body(res);\n    con->set_status(status_code::ok);\n\n    BOOST_CHECK_EQUAL(con->get_response_code(), status_code::ok);\n    BOOST_CHECK_EQUAL(con->get_response_msg(), status_code::get_string(status_code::ok));\n}\n\nvoid defer_http_func(server* s, bool * deferred, websocketpp::connection_hdl hdl) {\n    *deferred = true;\n    \n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n    \n    websocketpp::lib::error_code ec = con->defer_http_response();\n    BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code());\n}\n\nvoid check_on_fail(server* s, websocketpp::lib::error_code ec, bool & called, \n    websocketpp::connection_hdl hdl)\n{\n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n\n    BOOST_CHECK_EQUAL(ec, con->get_ec());\n    called = true;\n}\n\nvoid on_open_print(server* s, websocketpp::connection_hdl hdl)\n{\n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n\n    std::cout << con->get_uri() << std::endl;\n}\n\nvoid fail_on_open(websocketpp::connection_hdl) {\n    BOOST_CHECK(false);\n}\nvoid fail_on_http(websocketpp::connection_hdl) {\n    BOOST_CHECK(false);\n}\n\nBOOST_AUTO_TEST_CASE( connection_extensions ) {\n    connection_setup env(true);\n\n    BOOST_CHECK( env.c.extension_value == 5 );\n    BOOST_CHECK( env.c.extension_method() == 5 );\n\n    BOOST_CHECK( env.c.is_server() == true );\n}\n\nBOOST_AUTO_TEST_CASE( basic_websocket_request ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nServer: \";\n    output+=websocketpp::user_agent;\n    output+=\"\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    server s;\n    s.set_message_handler(bind(&echo_func,&s,::_1,::_2));\n\n    BOOST_CHECK(run_server_test(s,input) == output);\n}\n\nBOOST_AUTO_TEST_CASE( http_request ) {\n    std::string input = \"GET /foo/bar HTTP/1.1\\r\\nHost: www.example.com\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n    std::string output = \"HTTP/1.1 200 OK\\r\\nContent-Length: 8\\r\\nServer: \";\n    output+=websocketpp::user_agent;\n    output+=\"\\r\\n\\r\\n/foo/bar\";\n\n    server s;\n    s.set_http_handler(bind(&http_func,&s,::_1));\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n}\n\nBOOST_AUTO_TEST_CASE( deferred_http_request ) {\n    std::string input = \"GET /foo/bar HTTP/1.1\\r\\nHost: www.example.com\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n    std::string output = \"HTTP/1.1 200 OK\\r\\nContent-Length: 8\\r\\nServer: \";\n    output+=websocketpp::user_agent;\n    output+=\"\\r\\n\\r\\n/foo/bar\";\n\n    server s;\n    server::connection_ptr con;\n    bool deferred = false;\n    s.set_http_handler(bind(&defer_http_func,&s, &deferred,::_1));\n\n    s.clear_access_channels(websocketpp::log::alevel::all);\n    s.clear_error_channels(websocketpp::log::elevel::all);\n    \n    std::stringstream ostream;\n    s.register_ostream(&ostream);\n\n    con = s.get_connection();\n    con->start();\n    \n    BOOST_CHECK(!deferred);\n    BOOST_CHECK_EQUAL(ostream.str(), \"\");\n    con->read_some(input.data(),input.size());\n    BOOST_CHECK(deferred);\n    BOOST_CHECK_EQUAL(ostream.str(), \"\");\n\n    con->set_body(con->get_resource());\n    con->set_status(websocketpp::http::status_code::ok);\n    \n    websocketpp::lib::error_code ec;\n    s.send_http_response(con->get_handle(),ec);\n    BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code());\n    BOOST_CHECK_EQUAL(ostream.str(), output);\n    con->send_http_response(ec);\n    BOOST_CHECK_EQUAL(ec, make_error_code(websocketpp::error::invalid_state));\n    \n}\n\nBOOST_AUTO_TEST_CASE( request_no_server_header ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    server s;\n    s.set_user_agent(\"\");\n    s.set_message_handler(bind(&echo_func,&s,::_1,::_2));\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n}\n\nBOOST_AUTO_TEST_CASE( request_no_server_header_override ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nServer: foo\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    server s;\n    s.set_user_agent(\"\");\n    s.set_message_handler(bind(&echo_func,&s,::_1,::_2));\n    s.set_validate_handler(bind(&validate_set_ua,&s,::_1));\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n}\n\nBOOST_AUTO_TEST_CASE( basic_client_websocket ) {\n    std::string uri = \"ws://localhost\";\n\n    //std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nServer: foo\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    std::string ref = \"GET / HTTP/1.1\\r\\nConnection: Upgrade\\r\\nFoo: Bar\\r\\nHost: localhost\\r\\nSec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==\\r\\nSec-WebSocket-Version: 13\\r\\nUpgrade: websocket\\r\\nUser-Agent: foo\\r\\n\\r\\n\";\n\n    std::stringstream output;\n\n    client e;\n    e.set_access_channels(websocketpp::log::alevel::none);\n    e.set_error_channels(websocketpp::log::elevel::none);\n    e.set_user_agent(\"foo\");\n    e.register_ostream(&output);\n\n    client::connection_ptr con;\n    websocketpp::lib::error_code ec;\n    con = e.get_connection(uri, ec);\n    con->append_header(\"Foo\",\"Bar\");\n    e.connect(con);\n\n    BOOST_CHECK_EQUAL(ref, output.str());\n}\n\nBOOST_AUTO_TEST_CASE( set_max_message_size ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\n\\r\\n\";\n    \n    // After the handshake, add a single frame with a message that is too long.\n    char frame0[10] = {char(0x82), char(0x83), 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01};\n    input.append(frame0, 10);\n    \n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nServer: foo\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    // After the handshake, add a single frame with a close message with message too big\n    // error code.\n    char frame1[4] = {char(0x88), 0x19, 0x03, char(0xf1)};\n    output.append(frame1, 4);\n    output.append(\"A message was too large\");\n\n    server s;\n    s.set_user_agent(\"\");\n    s.set_validate_handler(bind(&validate_set_ua,&s,::_1));\n    s.set_max_message_size(2);\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n}\n\nBOOST_AUTO_TEST_CASE( websocket_fail_parse_error ) {\n    std::string input = \"asdf\\r\\n\\r\\n\";\n\n    server s;\n    websocketpp::lib::error_code ec = make_error_code(websocketpp::error::http_parse_error);\n    bool called = false;\n    s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));\n\n    run_server_test(s,input,false);\n    BOOST_CHECK(called);\n}\n\nBOOST_AUTO_TEST_CASE( websocket_fail_invalid_version ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: foo\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n\n    server s;\n    websocketpp::lib::error_code ec = make_error_code(websocketpp::error::invalid_version);\n    bool called = false;\n    s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));\n\n    run_server_test(s,input,false);\n    BOOST_CHECK(called);\n}\n\nBOOST_AUTO_TEST_CASE( websocket_fail_unsupported_version ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 12\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n\n    server s;\n    websocketpp::lib::error_code ec = make_error_code(websocketpp::error::unsupported_version);\n    bool called = false;\n    s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));\n\n    run_server_test(s,input,false);\n    BOOST_CHECK(called);\n}\n\n// BOOST_AUTO_TEST_CASE( websocket_fail_invalid_uri ) {\n//     std::string input = \"GET http://345.123.123.123/foo HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n\n//     server s;\n//     websocketpp::lib::error_code ec = make_error_code(websocketpp::error::unsupported_version);\n//     bool called = false;\n//     s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));\n//     s.set_open_handler(bind(&on_open_print,&s,::_1));\n\n//     std::cout << run_server_test(s,input,true) << std::endl;\n//     BOOST_CHECK(called);\n// }\n\n// BOOST_AUTO_TEST_CASE( websocket_fail_invalid_uri_http ) {\n//     std::string input = \"GET http://345.123.123.123/foo HTTP/1.1\\r\\nHost: www.example.com\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n\n//     server s;\n//     websocketpp::lib::error_code ec = make_error_code(websocketpp::error::unsupported_version);\n//     bool called = false;\n//     s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));\n//     s.set_open_handler(bind(&on_open_print,&s,::_1));\n\n//     std::cout << run_server_test(s,input,true) << std::endl;\n//     BOOST_CHECK(called);\n// }\n\nBOOST_AUTO_TEST_CASE( websocket_fail_upgrade_required ) {\n    std::string input = \"GET /foo/bar HTTP/1.1\\r\\nHost: www.example.com\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n\n    server s;\n    websocketpp::lib::error_code ec = make_error_code(websocketpp::error::upgrade_required);\n    bool called = false;\n    s.set_fail_handler(bind(&check_on_fail,&s,ec,websocketpp::lib::ref(called),::_1));\n\n    run_server_test(s,input,false);\n    BOOST_CHECK(called);\n}\n\n// TODO: set max message size in client endpoint test case\n// TODO: set max message size mid connection test case\n// TODO: [maybe] set max message size in open handler\n\n\n\n// BOOST_AUTO_TEST_CASE( user_reject_origin ) {\n//     std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example2.com\\r\\n\\r\\n\";\n//     std::string output = \"HTTP/1.1 403 Forbidden\\r\\nServer: \"+websocketpp::USER_AGENT+\"\\r\\n\\r\\n\";\n\n//     BOOST_CHECK(run_server_test(input) == output);\n// }\n\n// BOOST_AUTO_TEST_CASE( basic_text_message ) {\n//     std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n\n//     unsigned char frames[8] = {0x82,0x82,0xFF,0xFF,0xFF,0xFF,0xD5,0xD5};\n//     input.append(reinterpret_cast<char*>(frames),8);\n\n//     std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nServer: \"+websocketpp::USER_AGENT+\"\\r\\nUpgrade: websocket\\r\\n\\r\\n**\";\n\n//     BOOST_CHECK( run_server_test(input) == output);\n// }\n\n\n\n\n\n\nBOOST_AUTO_TEST_CASE( client_handshake_timeout_race1 ) {\n    debug_client c;\n\n    websocketpp::lib::error_code ec;\n    debug_client::connection_ptr con = c.get_connection(\"ws://localhost:9002\", ec);\n\n    BOOST_CHECK(!ec);\n\n    // This test the case where a handshake times out immediately before the \n    // handler that would have completed it gets invoked. This situation happens\n    // when clients are connecting to overloaded servers and on servers that are\n    // overloaded. \n    c.connect(con);\n    \n    con->expire_timer(websocketpp::lib::error_code());\n    // Fullfil the write to simulate the write completing immediately after\n    // timer expires\n    con->fullfil_write();\n    \n    BOOST_CHECK_EQUAL(con->get_ec(), make_error_code(websocketpp::error::open_handshake_timeout));\n}\n\nBOOST_AUTO_TEST_CASE( client_handshake_timeout_race2 ) {\n    debug_client c;\n\n    websocketpp::lib::error_code ec;\n    debug_client::connection_ptr con = c.get_connection(\"ws://localhost:9002\", ec);\n\n    BOOST_CHECK(!ec);\n\n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: ICX+Yqv66kxgM0FcWaLWlFLwTAI=\\r\\nServer: foo\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    // This test the case where a handshake times out immediately before the \n    // handler that would have completed it gets invoked. This situation happens\n    // when clients are connecting to overloaded servers and on servers that are\n    // overloaded. \n    c.connect(con);\n    con->fullfil_write();\n    \n    con->expire_timer(websocketpp::lib::error_code());\n    // Read valid handshake to simulate receiving the handshake response\n    // immediately after the timer expires\n    con->read_all(output.data(),output.size());\n    \n    BOOST_CHECK_EQUAL(con->get_ec(), make_error_code(websocketpp::error::open_handshake_timeout));\n}\n\nBOOST_AUTO_TEST_CASE( server_handshake_timeout_race1 ) {\n    debug_server s;\n\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==\\r\\n\\r\\n\";\n\n    debug_server::connection_ptr con = s.get_connection();\n    con->start();\n    \n    con->expire_timer(websocketpp::lib::error_code());\n    // Read handshake immediately after timer expire\n    con->read_all(input.data(), input.size());\n    \n    BOOST_CHECK_EQUAL(con->get_ec(), make_error_code(websocketpp::error::open_handshake_timeout));\n}\n\nBOOST_AUTO_TEST_CASE( server_handshake_timeout_race2 ) {\n    debug_server s;\n\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==\\r\\n\\r\\n\";\n\n    debug_server::connection_ptr con = s.get_connection();\n    con->start();\n    \n    con->read_all(input.data(), input.size());\n    \n    con->expire_timer(websocketpp::lib::error_code());\n    // Complete write immediately after timer expire\n    con->fullfil_write();\n    \n    BOOST_CHECK_EQUAL(con->get_ec(), make_error_code(websocketpp::error::open_handshake_timeout));\n}\n\n\n"
  },
  {
    "path": "test/connection/connection_tu2.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#include \"connection_tu2.hpp\"\n\nvoid echo_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {\n    s->send(hdl, msg->get_payload(), msg->get_opcode());\n}\n\nstd::string run_server_test(std::string input, bool log) {\n    server test_server;\n    return run_server_test(test_server,input,log);\n}\n\nstd::string run_server_test(server & s, std::string input, bool log) {\n    server::connection_ptr con;\n    std::stringstream output;\n\n    if (log) {\n        s.set_access_channels(websocketpp::log::alevel::all);\n        s.set_error_channels(websocketpp::log::elevel::all);\n    } else {\n        s.clear_access_channels(websocketpp::log::alevel::all);\n        s.clear_error_channels(websocketpp::log::elevel::all);\n    }\n\n    s.register_ostream(&output);\n\n    con = s.get_connection();\n    con->start();\n\n    std::stringstream channel;\n\n    channel << input;\n    channel >> *con;\n\n    return output.str();\n}\n"
  },
  {
    "path": "test/connection/connection_tu2.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#include <iostream>\n#include <sstream>\n\n// Test Environment:\n// server, no TLS, no locks, iostream based transport\n#include <websocketpp/config/debug.hpp>\n#include <websocketpp/config/core.hpp>\n#include <websocketpp/server.hpp>\n#include <websocketpp/client.hpp>\n\ntypedef websocketpp::server<websocketpp::config::core> server;\n/// NOTE: the \"server\" config is being used for the client here because we don't\n/// want to pull in the real RNG. A better way to do this might be a custom\n/// client config with the RNG explicitly stubbed out.\ntypedef websocketpp::client<websocketpp::config::core> client;\ntypedef websocketpp::config::core::message_type::ptr message_ptr;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\nvoid echo_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg);\nstd::string run_server_test(std::string input, bool log = false);\nstd::string run_server_test(server & s, std::string input, bool log = false);\n"
  },
  {
    "path": "test/endpoint/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\nif (OPENSSL_FOUND)\n\ninit_target (test_endpoint)\n\nbuild_test (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nlink_openssl ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\nendif()"
  },
  {
    "path": "test/endpoint/SConscript",
    "content": "## endpoint unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\nImport('tls_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs] + [tls_libs]\n\nobjs = env.Object('endpoint_boost.o', [\"endpoint.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_endpoint_boost', [\"endpoint_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   objs += env_cpp11.Object('endpoint_stl.o', [\"endpoint.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_endpoint_stl', [\"endpoint_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/endpoint/endpoint.cpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE endpoint\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <sstream>\n\n#include <websocketpp/config/asio.hpp>\n#include <websocketpp/server.hpp>\n\nBOOST_AUTO_TEST_CASE( construct_server_iostream ) {\n    websocketpp::server<websocketpp::config::core> s;\n}\n\nBOOST_AUTO_TEST_CASE( construct_server_asio_plain ) {\n    websocketpp::server<websocketpp::config::asio> s;\n}\n\nBOOST_AUTO_TEST_CASE( construct_server_asio_tls ) {\n    websocketpp::server<websocketpp::config::asio_tls> s;\n}\n\nBOOST_AUTO_TEST_CASE( initialize_server_asio ) {\n    websocketpp::server<websocketpp::config::asio> s;\n    s.init_asio();\n}\n\nBOOST_AUTO_TEST_CASE( initialize_server_asio_external ) {\n    websocketpp::server<websocketpp::config::asio> s;\n    boost::asio::io_service ios;\n    s.init_asio(&ios);\n}\n\n#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_\nBOOST_AUTO_TEST_CASE( move_construct_server_core ) {\n    websocketpp::server<websocketpp::config::core> s1;\n    \n    websocketpp::server<websocketpp::config::core> s2(std::move(s1));\n}\n\n/*\n// temporary disable because library doesn't pass\nBOOST_AUTO_TEST_CASE( emplace ) {\n    std::stringstream out1;\n    std::stringstream out2;\n    \n    std::vector<websocketpp::server<websocketpp::config::asio_tls>> v;\n    \n    v.emplace_back();\n    v.emplace_back();\n    \n    v[0].get_alog().set_ostream(&out1);\n    v[0].get_alog().set_ostream(&out2);\n    \n    v[0].get_alog().write(websocketpp::log::alevel::app,\"devel0\");\n    v[1].get_alog().write(websocketpp::log::alevel::app,\"devel1\");\n    BOOST_CHECK( out1.str().size() > 0 );\n    BOOST_CHECK( out2.str().size() > 0 );\n}*/\n\n#endif // _WEBSOCKETPP_MOVE_SEMANTICS_\n\nstruct endpoint_extension {\n    endpoint_extension() : extension_value(5) {}\n\n    int extension_method() {\n        return extension_value;\n    }\n\n    bool is_server() const {\n        return false;\n    }\n\n    int extension_value;\n};\n\nstruct stub_config : public websocketpp::config::core {\n    typedef core::concurrency_type concurrency_type;\n\n    typedef core::request_type request_type;\n    typedef core::response_type response_type;\n\n    typedef core::message_type message_type;\n    typedef core::con_msg_manager_type con_msg_manager_type;\n    typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef core::alog_type alog_type;\n    typedef core::elog_type elog_type;\n\n    typedef core::rng_type rng_type;\n\n    typedef core::transport_type transport_type;\n\n    typedef endpoint_extension endpoint_base;\n};\n\nBOOST_AUTO_TEST_CASE( endpoint_extensions ) {\n    websocketpp::server<stub_config> s;\n\n    BOOST_CHECK_EQUAL( s.extension_value, 5 );\n    BOOST_CHECK_EQUAL( s.extension_method(), 5 );\n\n    BOOST_CHECK( s.is_server() );\n}\n\nBOOST_AUTO_TEST_CASE( listen_after_listen_failure ) {\n    using websocketpp::transport::asio::error::make_error_code;\n    using websocketpp::transport::asio::error::pass_through;\n\n    websocketpp::server<websocketpp::config::asio> server1;\n    websocketpp::server<websocketpp::config::asio> server2;\n\n    websocketpp::lib::error_code ec;\n\n    server1.init_asio();\n    server2.init_asio();\n\n    boost::asio::ip::tcp::endpoint ep1(boost::asio::ip::address::from_string(\"127.0.0.1\"), 12345);\n    boost::asio::ip::tcp::endpoint ep2(boost::asio::ip::address::from_string(\"127.0.0.1\"), 23456);\n\n    server1.listen(ep1, ec);\n    BOOST_CHECK(!ec);\n\n    // This should return some sort of problem. Usually either \"pass through\" or\n    // a more specific address in use error. It is hard to capture the full range\n    // of 'correctly wrong' values.\n    server2.listen(ep1, ec);\n    BOOST_REQUIRE(ec);\n\n    server2.listen(ep2, ec);\n    BOOST_CHECK(!ec);\n}\n"
  },
  {
    "path": "test/extension/CMakeLists.txt",
    "content": "# Extension Tests\nfile (GLOB SOURCE extension.cpp)\n\ninit_target (test_extension)\nbuild_executable (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\nif ( ZLIB_FOUND )\n\n# Permessage-deflate tests\nfile (GLOB SOURCE permessage_deflate.cpp)\n\ninit_target (test_permessage_deflate)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nlink_zlib()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\nendif ( ZLIB_FOUND )"
  },
  {
    "path": "test/extension/SConscript",
    "content": "## http unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs] + ['z']\n\nobjs = env.Object('extension_boost.o', [\"extension.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('permessage_deflate_boost.o', [\"permessage_deflate.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_extension_boost', [\"extension_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_permessage_deflate_boost', [\"permessage_deflate_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']\n   objs += env_cpp11.Object('extension_stl.o', [\"extension.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('permessage_deflate_stl.o', [\"permessage_deflate.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_extension_stl', [\"extension_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_permessage_deflate_stl', [\"permessage_deflate_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/extension/extension.cpp",
    "content": "/*\n * Copyright (c) 2011, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE extension\n#include <boost/test/unit_test.hpp>\n\n#include <string>\n\n#include <websocketpp/extensions/extension.hpp>\n\nBOOST_AUTO_TEST_CASE( blank ) {\n    BOOST_CHECK( true );\n}\n"
  },
  {
    "path": "test/extension/permessage_deflate.cpp",
    "content": "/*\n * Copyright (c) 2013, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE permessage_deflate\n#include <boost/test/unit_test.hpp>\n\n#include <websocketpp/error.hpp>\n\n#include <websocketpp/extensions/extension.hpp>\n#include <websocketpp/extensions/permessage_deflate/disabled.hpp>\n#include <websocketpp/extensions/permessage_deflate/enabled.hpp>\n\n#include <string>\n\n#include <websocketpp/utilities.hpp>\n#include <iostream>\n\nclass config {};\n\ntypedef websocketpp::extensions::permessage_deflate::enabled<config> enabled_type;\ntypedef websocketpp::extensions::permessage_deflate::disabled<config> disabled_type;\n\nstruct ext_vars {\n    enabled_type exts;\n    enabled_type extc;\n    websocketpp::lib::error_code ec;\n    websocketpp::err_str_pair esp;\n    websocketpp::http::attribute_list attr;\n};\nnamespace pmde = websocketpp::extensions::permessage_deflate::error;\nnamespace pmd_mode = websocketpp::extensions::permessage_deflate::mode;\n\n// Ensure the disabled extension behaves appropriately disabled\n\nBOOST_AUTO_TEST_CASE( disabled_is_disabled ) {\n    disabled_type exts;\n    BOOST_CHECK( !exts.is_implemented() );\n}\n\nBOOST_AUTO_TEST_CASE( disabled_is_off ) {\n    disabled_type exts;\n    BOOST_CHECK( !exts.is_enabled() );\n}\n\n// Ensure the enabled version actually works\n\nBOOST_AUTO_TEST_CASE( enabled_is_enabled ) {\n    ext_vars v;\n    BOOST_CHECK( v.exts.is_implemented() );\n    BOOST_CHECK( v.extc.is_implemented() );\n}\n\n\nBOOST_AUTO_TEST_CASE( enabled_starts_disabled ) {\n    ext_vars v;\n    BOOST_CHECK( !v.exts.is_enabled() );\n    BOOST_CHECK( !v.extc.is_enabled() );\n}\n\nBOOST_AUTO_TEST_CASE( negotiation_empty_attr ) {\n    ext_vars v;\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiation_invalid_attr ) {\n    ext_vars v;\n    v.attr[\"foo\"] = \"bar\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( !v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, pmde::make_error_code(pmde::invalid_attributes) );\n    BOOST_CHECK_EQUAL( v.esp.second, \"\");\n}\n\n// Negotiate server_no_context_takeover\nBOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover_invalid ) {\n    ext_vars v;\n    v.attr[\"server_no_context_takeover\"] = \"foo\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( !v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, pmde::make_error_code(pmde::invalid_attribute_value) );\n    BOOST_CHECK_EQUAL( v.esp.second, \"\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover ) {\n    ext_vars v;\n    v.attr[\"server_no_context_takeover\"].clear();\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_no_context_takeover\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover_server_initiated ) {\n    ext_vars v;\n\n    v.exts.enable_server_no_context_takeover();\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_no_context_takeover\");\n}\n\n// Negotiate client_no_context_takeover\nBOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover_invalid ) {\n    ext_vars v;\n    v.attr[\"client_no_context_takeover\"] = \"foo\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( !v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, pmde::make_error_code(pmde::invalid_attribute_value) );\n    BOOST_CHECK_EQUAL( v.esp.second, \"\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover ) {\n    ext_vars v;\n    v.attr[\"client_no_context_takeover\"].clear();\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_no_context_takeover\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover_server_initiated ) {\n    ext_vars v;\n\n    v.exts.enable_client_no_context_takeover();\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_no_context_takeover\");\n}\n\n\n// Negotiate server_max_window_bits\nBOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_invalid ) {\n    ext_vars v;\n\n    std::vector<std::string> values;\n    values.push_back(\"\");\n    values.push_back(\"foo\");\n    values.push_back(\"7\");\n    values.push_back(\"16\");\n\n    std::vector<std::string>::const_iterator it;\n    for (it = values.begin(); it != values.end(); ++it) {\n        v.attr[\"server_max_window_bits\"] = *it;\n\n        v.esp = v.exts.negotiate(v.attr);\n        BOOST_CHECK( !v.exts.is_enabled() );\n        BOOST_CHECK_EQUAL( v.esp.first, pmde::make_error_code(pmde::invalid_attribute_value) );\n        BOOST_CHECK_EQUAL( v.esp.second, \"\");\n    }\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_valid ) {\n    ext_vars v;\n    \n    // confirm that a request for a value of 8 is interpreted as 9\n    v.attr[\"server_max_window_bits\"] = \"8\";\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_max_window_bits=9\");\n\n    v.attr[\"server_max_window_bits\"] = \"9\";\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_max_window_bits=9\");\n\n\n    v.attr[\"server_max_window_bits\"] = \"15\";\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate\");\n}\n\nBOOST_AUTO_TEST_CASE( invalid_set_server_max_window_bits ) {\n    ext_vars v;\n\n    v.ec = v.exts.set_server_max_window_bits(7,pmd_mode::decline);\n    BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));\n\n    v.ec = v.exts.set_server_max_window_bits(16,pmd_mode::decline);\n    BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_decline ) {\n    ext_vars v;\n    v.attr[\"server_max_window_bits\"] = \"9\";\n\n    v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::decline);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_accept_8 ) {\n    ext_vars v;\n    v.attr[\"server_max_window_bits\"] = \"8\";\n\n    v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::accept);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_max_window_bits=9\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_accept ) {\n    ext_vars v;\n    v.attr[\"server_max_window_bits\"] = \"9\";\n\n    v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::accept);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_max_window_bits=9\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_largest_8 ) {\n    ext_vars v;\n    v.attr[\"server_max_window_bits\"] = \"8\";\n\n    v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::largest);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_max_window_bits=9\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_largest ) {\n    ext_vars v;\n    v.attr[\"server_max_window_bits\"] = \"9\";\n\n    v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::largest);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_max_window_bits=9\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_smallest_8 ) {\n    ext_vars v;\n    v.attr[\"server_max_window_bits\"] = \"8\";\n\n    v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::smallest);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_max_window_bits=9\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_smallest ) {\n    ext_vars v;\n    v.attr[\"server_max_window_bits\"] = \"9\";\n\n    v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::smallest);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_max_window_bits=9\");\n}\n\n// Negotiate server_max_window_bits\nBOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_invalid ) {\n    ext_vars v;\n\n    std::vector<std::string> values;\n    values.push_back(\"foo\");\n    values.push_back(\"7\");\n    values.push_back(\"16\");\n\n    std::vector<std::string>::const_iterator it;\n    for (it = values.begin(); it != values.end(); ++it) {\n        v.attr[\"client_max_window_bits\"] = *it;\n\n        v.esp = v.exts.negotiate(v.attr);\n        BOOST_CHECK( !v.exts.is_enabled() );\n        BOOST_CHECK_EQUAL( v.esp.first, pmde::make_error_code(pmde::invalid_attribute_value) );\n        BOOST_CHECK_EQUAL( v.esp.second, \"\");\n    }\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_valid ) {\n    ext_vars v;\n\n    v.attr[\"client_max_window_bits\"].clear();\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate\");\n\n    v.attr[\"client_max_window_bits\"] = \"8\";\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_max_window_bits=9\");\n\n    v.attr[\"client_max_window_bits\"] = \"9\";\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_max_window_bits=9\");\n\n    v.attr[\"client_max_window_bits\"] = \"15\";\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate\");\n}\n\nBOOST_AUTO_TEST_CASE( invalid_set_client_max_window_bits ) {\n    ext_vars v;\n\n    v.ec = v.exts.set_client_max_window_bits(7,pmd_mode::decline);\n    BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));\n\n    v.ec = v.exts.set_client_max_window_bits(16,pmd_mode::decline);\n    BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits));\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_decline_8 ) {\n    ext_vars v;\n    v.attr[\"client_max_window_bits\"] = \"8\";\n\n    v.ec = v.exts.set_client_max_window_bits(8,pmd_mode::decline);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_decline ) {\n    ext_vars v;\n    v.attr[\"client_max_window_bits\"] = \"9\";\n\n    v.ec = v.exts.set_client_max_window_bits(9,pmd_mode::decline);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_accept_8 ) {\n    ext_vars v;\n    v.attr[\"client_max_window_bits\"] = \"8\";\n\n    v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::accept);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_max_window_bits=9\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_accept ) {\n    ext_vars v;\n    v.attr[\"client_max_window_bits\"] = \"9\";\n\n    v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::accept);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_max_window_bits=9\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_largest_8 ) {\n    ext_vars v;\n    v.attr[\"client_max_window_bits\"] = \"8\";\n\n    v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::largest);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_max_window_bits=9\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_largest ) {\n    ext_vars v;\n    v.attr[\"client_max_window_bits\"] = \"9\";\n\n    v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::largest);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_max_window_bits=9\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_smallest_8 ) {\n    ext_vars v;\n    v.attr[\"client_max_window_bits\"] = \"8\";\n\n    v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::smallest);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_max_window_bits=9\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_smallest ) {\n    ext_vars v;\n    v.attr[\"client_max_window_bits\"] = \"9\";\n\n    v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::smallest);\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_max_window_bits=9\");\n}\n\n\n// Combinations with 2\nBOOST_AUTO_TEST_CASE( negotiate_two_client_initiated1 ) {\n    ext_vars v;\n\n    v.attr[\"server_no_context_takeover\"].clear();\n    v.attr[\"client_no_context_takeover\"].clear();\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_no_context_takeover; client_no_context_takeover\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_two_client_initiated2 ) {\n    ext_vars v;\n\n    v.attr[\"server_no_context_takeover\"].clear();\n    v.attr[\"server_max_window_bits\"] = \"10\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_no_context_takeover; server_max_window_bits=10\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_two_client_initiated3 ) {\n    ext_vars v;\n\n    v.attr[\"server_no_context_takeover\"].clear();\n    v.attr[\"client_max_window_bits\"] = \"10\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_no_context_takeover; client_max_window_bits=10\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_two_client_initiated4 ) {\n    ext_vars v;\n\n    v.attr[\"client_no_context_takeover\"].clear();\n    v.attr[\"server_max_window_bits\"] = \"10\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_no_context_takeover; server_max_window_bits=10\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_two_client_initiated5 ) {\n    ext_vars v;\n\n    v.attr[\"client_no_context_takeover\"].clear();\n    v.attr[\"client_max_window_bits\"] = \"10\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_no_context_takeover; client_max_window_bits=10\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_two_client_initiated6 ) {\n    ext_vars v;\n\n    v.attr[\"server_max_window_bits\"] = \"10\";\n    v.attr[\"client_max_window_bits\"] = \"10\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_max_window_bits=10; client_max_window_bits=10\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_three_client_initiated1 ) {\n    ext_vars v;\n\n    v.attr[\"server_no_context_takeover\"].clear();\n    v.attr[\"client_no_context_takeover\"].clear();\n    v.attr[\"server_max_window_bits\"] = \"10\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_no_context_takeover; client_no_context_takeover; server_max_window_bits=10\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_three_client_initiated2 ) {\n    ext_vars v;\n\n    v.attr[\"server_no_context_takeover\"].clear();\n    v.attr[\"client_no_context_takeover\"].clear();\n    v.attr[\"client_max_window_bits\"] = \"10\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_no_context_takeover; client_no_context_takeover; client_max_window_bits=10\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_three_client_initiated3 ) {\n    ext_vars v;\n\n    v.attr[\"server_no_context_takeover\"].clear();\n    v.attr[\"server_max_window_bits\"] = \"10\";\n    v.attr[\"client_max_window_bits\"] = \"10\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_three_client_initiated4 ) {\n    ext_vars v;\n\n    v.attr[\"client_no_context_takeover\"].clear();\n    v.attr[\"server_max_window_bits\"] = \"10\";\n    v.attr[\"client_max_window_bits\"] = \"10\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; client_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10\");\n}\n\nBOOST_AUTO_TEST_CASE( negotiate_four_client_initiated ) {\n    ext_vars v;\n\n    v.attr[\"server_no_context_takeover\"].clear();\n    v.attr[\"client_no_context_takeover\"].clear();\n    v.attr[\"server_max_window_bits\"] = \"10\";\n    v.attr[\"client_max_window_bits\"] = \"10\";\n\n    v.esp = v.exts.negotiate(v.attr);\n    BOOST_CHECK( v.exts.is_enabled() );\n    BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( v.esp.second, \"permessage-deflate; server_no_context_takeover; client_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10\");\n}\n\n// Compression\nBOOST_AUTO_TEST_CASE( compress_data ) {\n    ext_vars v;\n\n    std::string compress_in = \"Hello\";\n    std::string compress_out;\n    std::string decompress_out;\n\n    v.ec = v.exts.init(true);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.compress(compress_in,compress_out);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( compress_in, decompress_out );\n}\n\nBOOST_AUTO_TEST_CASE( compress_data_multiple ) {\n    ext_vars v;\n\n    v.ec = v.exts.init(true);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    for (int i = 0; i < 2; i++) {\n        std::string compress_in = \"Hello\";\n        std::string compress_out;\n        std::string decompress_out;\n\n        v.ec = v.exts.compress(compress_in,compress_out);\n        BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n        v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);\n        BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n        BOOST_CHECK_EQUAL( compress_in, decompress_out );\n    }\n}\n\nBOOST_AUTO_TEST_CASE( compress_data_large ) {\n    ext_vars v;\n\n    std::string compress_in(600,'*');\n    std::string compress_out;\n    std::string decompress_out;\n\n    websocketpp::http::attribute_list alist;\n\n    alist[\"server_max_window_bits\"] = \"9\";\n    v.exts.set_server_max_window_bits(9,websocketpp::extensions::permessage_deflate::mode::smallest);\n\n    v.exts.negotiate(alist);\n    v.ec = v.exts.init(true);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.compress(compress_in,compress_out);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( compress_in, decompress_out );\n}\n\nBOOST_AUTO_TEST_CASE( compress_data_no_context_takeover ) {\n    ext_vars v;\n\n    std::string compress_in = \"Hello\";\n    std::string compress_out1;\n    std::string compress_out2;\n    std::string decompress_out;\n\n    websocketpp::http::attribute_list alist;\n\n    alist[\"server_no_context_takeover\"].clear();\n    v.exts.enable_server_no_context_takeover();\n\n    v.exts.negotiate(alist);\n    v.ec = v.exts.init(true);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.compress(compress_in,compress_out1);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.decompress(\n        reinterpret_cast<const uint8_t *>(compress_out1.data()),\n        compress_out1.size(),\n        decompress_out\n    );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( compress_in, decompress_out );\n\n    decompress_out.clear();\n\n    v.ec = v.exts.compress(compress_in,compress_out2);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.decompress(\n        reinterpret_cast<const uint8_t *>(compress_out2.data()),\n        compress_out2.size(),\n        decompress_out\n    );\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( compress_in, decompress_out );\n\n    BOOST_CHECK_EQUAL( compress_out1, compress_out2 );\n}\n\nBOOST_AUTO_TEST_CASE( compress_empty ) {\n    ext_vars v;\n\n    std::string compress_in;\n    std::string compress_out;\n    std::string decompress_out;\n\n    v.ec = v.exts.init(true);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.compress(compress_in,compress_out);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);\n\n    compress_out.clear();\n    decompress_out.clear();\n\n    v.ec = v.exts.compress(compress_in,compress_out);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.decompress(reinterpret_cast<const uint8_t *>(compress_out.data()),compress_out.size(),decompress_out);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( compress_in, decompress_out );\n}\n\n/// @todo: more compression tests\n/**\n * - compress at different compression levels\n */\n\n// Decompression\nBOOST_AUTO_TEST_CASE( decompress_data ) {\n    ext_vars v;\n\n    uint8_t in[11] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x00, 0x00, 0xff, 0xff};\n    std::string out;\n    std::string reference = \"Hello\";\n\n    v.ec = v.exts.init(true);\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n\n    v.ec = v.exts.decompress(in,11,out);\n\n    BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() );\n    BOOST_CHECK_EQUAL( out, reference );\n}\n"
  },
  {
    "path": "test/http/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES parser.cpp)\n\ninit_target (test_http)\n\nbuild_test (${TARGET_NAME} ${SOURCE_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n"
  },
  {
    "path": "test/http/SConscript",
    "content": "## http unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework'],env) + [platform_libs]\n\nobjs = env.Object('parser_boost.o', [\"parser.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_http_boost', [\"parser_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   objs += env_cpp11.Object('parser_stl.o', [\"parser.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_http_stl', [\"parser_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/http/parser.cpp",
    "content": "/*\n * Copyright (c) 2011, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE http_parser\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n\nBOOST_AUTO_TEST_CASE( is_token_char ) {\n    // Valid characters\n\n    // misc\n    BOOST_CHECK( websocketpp::http::is_token_char('!') );\n    BOOST_CHECK( websocketpp::http::is_token_char('#') );\n    BOOST_CHECK( websocketpp::http::is_token_char('$') );\n    BOOST_CHECK( websocketpp::http::is_token_char('%') );\n    BOOST_CHECK( websocketpp::http::is_token_char('&') );\n    BOOST_CHECK( websocketpp::http::is_token_char('\\'') );\n    BOOST_CHECK( websocketpp::http::is_token_char('*') );\n    BOOST_CHECK( websocketpp::http::is_token_char('+') );\n    BOOST_CHECK( websocketpp::http::is_token_char('-') );\n    BOOST_CHECK( websocketpp::http::is_token_char('.') );\n    BOOST_CHECK( websocketpp::http::is_token_char('^') );\n    BOOST_CHECK( websocketpp::http::is_token_char('_') );\n    BOOST_CHECK( websocketpp::http::is_token_char('`') );\n    BOOST_CHECK( websocketpp::http::is_token_char('~') );\n\n    // numbers\n    for (int i = 0x30; i < 0x3a; i++) {\n        BOOST_CHECK( websocketpp::http::is_token_char((unsigned char)(i)) );\n    }\n\n    // upper\n    for (int i = 0x41; i < 0x5b; i++) {\n        BOOST_CHECK( websocketpp::http::is_token_char((unsigned char)(i)) );\n    }\n\n    // lower\n    for (int i = 0x61; i < 0x7b; i++) {\n        BOOST_CHECK( websocketpp::http::is_token_char((unsigned char)(i)) );\n    }\n\n    // invalid characters\n\n    // lower unprintable\n    for (int i = 0; i < 33; i++) {\n        BOOST_CHECK( !websocketpp::http::is_token_char((unsigned char)(i)) );\n    }\n\n    // misc\n    BOOST_CHECK( !websocketpp::http::is_token_char('(') );\n    BOOST_CHECK( !websocketpp::http::is_token_char(')') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('<') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('>') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('@') );\n    BOOST_CHECK( !websocketpp::http::is_token_char(',') );\n    BOOST_CHECK( !websocketpp::http::is_token_char(';') );\n    BOOST_CHECK( !websocketpp::http::is_token_char(':') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('\\\\') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('\"') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('/') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('[') );\n    BOOST_CHECK( !websocketpp::http::is_token_char(']') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('?') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('=') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('{') );\n    BOOST_CHECK( !websocketpp::http::is_token_char('}') );\n\n    // upper unprintable and out of ascii range\n    for (int i = 127; i < 256; i++) {\n        BOOST_CHECK( !websocketpp::http::is_token_char((unsigned char)(i)) );\n    }\n\n    // is not\n    BOOST_CHECK( !websocketpp::http::is_not_token_char('!') );\n    BOOST_CHECK( websocketpp::http::is_not_token_char('(') );\n}\n\nBOOST_AUTO_TEST_CASE( extract_token ) {\n    std::string d1 = \"foo\";\n    std::string d2 = \" foo \";\n\n    std::pair<std::string,std::string::const_iterator> ret;\n\n    ret = websocketpp::http::parser::extract_token(d1.begin(),d1.end());\n    BOOST_CHECK( ret.first == \"foo\" );\n    BOOST_CHECK( ret.second == d1.begin()+3 );\n\n    ret = websocketpp::http::parser::extract_token(d2.begin(),d2.end());\n    BOOST_CHECK( ret.first.empty() );\n    BOOST_CHECK( ret.second == d2.begin()+0 );\n\n    ret = websocketpp::http::parser::extract_token(d2.begin()+1,d2.end());\n    BOOST_CHECK( ret.first == \"foo\" );\n    BOOST_CHECK( ret.second == d2.begin()+4 );\n}\n\nBOOST_AUTO_TEST_CASE( extract_quoted_string ) {\n    std::string d1 = \"\\\"foo\\\"\";\n    std::string d2 = \"\\\"foo\\\\\\\"bar\\\\\\\"baz\\\"\";\n    std::string d3 = \"\\\"foo\\\"     \";\n    std::string d4;\n    std::string d5 = \"foo\";\n\n    std::pair<std::string,std::string::const_iterator> ret;\n\n    using websocketpp::http::parser::extract_quoted_string;\n\n    ret = extract_quoted_string(d1.begin(),d1.end());\n    BOOST_CHECK( ret.first == \"foo\" );\n    BOOST_CHECK( ret.second == d1.end() );\n\n    ret = extract_quoted_string(d2.begin(),d2.end());\n    BOOST_CHECK( ret.first == \"foo\\\"bar\\\"baz\" );\n    BOOST_CHECK( ret.second == d2.end() );\n\n    ret = extract_quoted_string(d3.begin(),d3.end());\n    BOOST_CHECK( ret.first == \"foo\" );\n    BOOST_CHECK( ret.second == d3.begin()+5 );\n\n    ret = extract_quoted_string(d4.begin(),d4.end());\n    BOOST_CHECK( ret.first.empty() );\n    BOOST_CHECK( ret.second == d4.begin() );\n\n    ret = extract_quoted_string(d5.begin(),d5.end());\n    BOOST_CHECK( ret.first.empty() );\n    BOOST_CHECK( ret.second == d5.begin() );\n}\n\nBOOST_AUTO_TEST_CASE( extract_all_lws ) {\n    std::string d1 = \" foo     bar\";\n    d1.append(1,char(9));\n    d1.append(\"baz\\r\\n d\\r\\n  \\r\\n  e\\r\\nf\");\n\n    std::string::const_iterator ret;\n\n    ret = websocketpp::http::parser::extract_all_lws(d1.begin(),d1.end());\n    BOOST_CHECK( ret == d1.begin()+1 );\n\n    ret = websocketpp::http::parser::extract_all_lws(d1.begin()+1,d1.end());\n    BOOST_CHECK( ret == d1.begin()+1 );\n\n    ret = websocketpp::http::parser::extract_all_lws(d1.begin()+4,d1.end());\n    BOOST_CHECK( ret == d1.begin()+9 );\n\n    ret = websocketpp::http::parser::extract_all_lws(d1.begin()+12,d1.end());\n    BOOST_CHECK( ret == d1.begin()+13 );\n\n    ret = websocketpp::http::parser::extract_all_lws(d1.begin()+16,d1.end());\n    BOOST_CHECK( ret == d1.begin()+19 );\n\n    ret = websocketpp::http::parser::extract_all_lws(d1.begin()+20,d1.end());\n    BOOST_CHECK( ret == d1.begin()+28 );\n\n    ret = websocketpp::http::parser::extract_all_lws(d1.begin()+29,d1.end());\n    BOOST_CHECK( ret == d1.begin()+29 );\n}\n\nBOOST_AUTO_TEST_CASE( extract_attributes_blank ) {\n    std::string s;\n\n    websocketpp::http::attribute_list a;\n    std::string::const_iterator it;\n\n    it = websocketpp::http::parser::extract_attributes(s.begin(),s.end(),a);\n    BOOST_CHECK( it == s.begin() );\n    BOOST_CHECK_EQUAL( a.size(), 0 );\n}\n\nBOOST_AUTO_TEST_CASE( extract_attributes_simple ) {\n    std::string s = \"foo\";\n\n    websocketpp::http::attribute_list a;\n    std::string::const_iterator it;\n\n    it = websocketpp::http::parser::extract_attributes(s.begin(),s.end(),a);\n    BOOST_CHECK( it == s.end() );\n    BOOST_CHECK_EQUAL( a.size(), 1 );\n    BOOST_CHECK( a.find(\"foo\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"foo\")->second, \"\" );\n}\n\nBOOST_AUTO_TEST_CASE( extract_parameters ) {\n    std::string s1;\n    std::string s2 = \"foo\";\n    std::string s3 = \" foo \\r\\nAbc\";\n    std::string s4 = \"  \\r\\n   foo  \";\n    std::string s5 = \"foo,bar\";\n    std::string s6 = \"foo;bar\";\n    std::string s7 = \"foo;baz,bar\";\n    std::string s8 = \"foo;bar;baz\";\n    std::string s9 = \"foo;bar=baz\";\n    std::string s10 = \"foo;bar=baz;boo\";\n    std::string s11 = \"foo;bar=baz;boo,bob\";\n    std::string s12 = \"foo;bar=\\\"a b c\\\"\";\n    std::string s13 = \"foo;bar=\\\"a \\\\\\\"b\\\\\\\" c\\\"\";\n\n\n    std::string sx = \"foo;bar=\\\"a \\\\\\\"b\\\\\\\" c\\\"\";\n    websocketpp::http::parameter_list p;\n    websocketpp::http::attribute_list a;\n    std::string::const_iterator it;\n\n    using websocketpp::http::parser::extract_parameters;\n\n    it = extract_parameters(s1.begin(),s1.end(),p);\n    BOOST_CHECK( it == s1.begin() );\n\n    p.clear();\n    it = extract_parameters(s2.begin(),s2.end(),p);\n    BOOST_CHECK( it == s2.end() );\n    BOOST_CHECK_EQUAL( p.size(), 1 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    BOOST_CHECK_EQUAL( p[0].second.size(), 0 );\n\n    p.clear();\n    it = extract_parameters(s3.begin(),s3.end(),p);\n    BOOST_CHECK( it == s3.begin()+5 );\n    BOOST_CHECK_EQUAL( p.size(), 1 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    BOOST_CHECK_EQUAL( p[0].second.size(), 0 );\n\n    p.clear();\n    it = extract_parameters(s4.begin(),s4.end(),p);\n    BOOST_CHECK( it == s4.end() );\n    BOOST_CHECK_EQUAL( p.size(), 1 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    BOOST_CHECK_EQUAL( p[0].second.size(), 0 );\n\n    p.clear();\n    it = extract_parameters(s5.begin(),s5.end(),p);\n    BOOST_CHECK( it == s5.end() );\n    BOOST_CHECK_EQUAL( p.size(), 2 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    BOOST_CHECK_EQUAL( p[0].second.size(), 0 );\n    BOOST_CHECK( p[1].first == \"bar\" );\n    BOOST_CHECK_EQUAL( p[1].second.size(), 0 );\n\n    p.clear();\n    it = extract_parameters(s6.begin(),s6.end(),p);\n    BOOST_CHECK( it == s6.end() );\n    BOOST_CHECK_EQUAL( p.size(), 1 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    a = p[0].second;\n    BOOST_CHECK_EQUAL( a.size(), 1 );\n    BOOST_CHECK( a.find(\"bar\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"bar\")->second, \"\" );\n\n    p.clear();\n    it = extract_parameters(s7.begin(),s7.end(),p);\n    BOOST_CHECK( it == s7.end() );\n    BOOST_CHECK_EQUAL( p.size(), 2 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    a = p[0].second;\n    BOOST_CHECK_EQUAL( a.size(), 1 );\n    BOOST_CHECK( a.find(\"baz\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"baz\")->second, \"\" );\n    BOOST_CHECK( p[1].first == \"bar\" );\n    a = p[1].second;\n    BOOST_CHECK_EQUAL( a.size(), 0 );\n\n    p.clear();\n    it = extract_parameters(s8.begin(),s8.end(),p);\n    BOOST_CHECK( it == s8.end() );\n    BOOST_CHECK_EQUAL( p.size(), 1 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    a = p[0].second;\n    BOOST_CHECK_EQUAL( a.size(), 2 );\n    BOOST_CHECK( a.find(\"bar\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"bar\")->second, \"\" );\n    BOOST_CHECK( a.find(\"baz\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"baz\")->second, \"\" );\n\n    p.clear();\n    it = extract_parameters(s9.begin(),s9.end(),p);\n    BOOST_CHECK( it == s9.end() );\n    BOOST_CHECK_EQUAL( p.size(), 1 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    a = p[0].second;\n    BOOST_CHECK_EQUAL( a.size(), 1 );\n    BOOST_CHECK( a.find(\"bar\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"bar\")->second, \"baz\" );\n\n    p.clear();\n    it = extract_parameters(s10.begin(),s10.end(),p);\n    BOOST_CHECK( it == s10.end() );\n    BOOST_CHECK_EQUAL( p.size(), 1 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    a = p[0].second;\n    BOOST_CHECK_EQUAL( a.size(), 2 );\n    BOOST_CHECK( a.find(\"bar\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"bar\")->second, \"baz\" );\n    BOOST_CHECK( a.find(\"boo\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"boo\")->second, \"\" );\n\n    p.clear();\n    it = extract_parameters(s11.begin(),s11.end(),p);\n    BOOST_CHECK( it == s11.end() );\n    BOOST_CHECK_EQUAL( p.size(), 2 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    a = p[0].second;\n    BOOST_CHECK_EQUAL( a.size(), 2 );\n    BOOST_CHECK( a.find(\"bar\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"bar\")->second, \"baz\" );\n    BOOST_CHECK( a.find(\"boo\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"boo\")->second, \"\" );\n    a = p[1].second;\n    BOOST_CHECK_EQUAL( a.size(), 0 );\n\n    p.clear();\n    it = extract_parameters(s12.begin(),s12.end(),p);\n    BOOST_CHECK( it == s12.end() );\n    BOOST_CHECK_EQUAL( p.size(), 1 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    a = p[0].second;\n    BOOST_CHECK_EQUAL( a.size(), 1 );\n    BOOST_CHECK( a.find(\"bar\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"bar\")->second, \"a b c\" );\n\n    p.clear();\n    it = extract_parameters(s13.begin(),s13.end(),p);\n    BOOST_CHECK( it == s13.end() );\n    BOOST_CHECK_EQUAL( p.size(), 1 );\n    BOOST_CHECK( p[0].first == \"foo\" );\n    a = p[0].second;\n    BOOST_CHECK_EQUAL( a.size(), 1 );\n    BOOST_CHECK( a.find(\"bar\") != a.end() );\n    BOOST_CHECK_EQUAL( a.find(\"bar\")->second, \"a \\\"b\\\" c\" );\n}\n\nBOOST_AUTO_TEST_CASE( strip_lws ) {\n    std::string test1 = \"foo\";\n    std::string test2 = \" foo \";\n    std::string test3 = \"foo \";\n    std::string test4 = \" foo\";\n    std::string test5 = \"    foo     \";\n    std::string test6 = \"  \\r\\n  foo     \";\n    std::string test7 = \"  \\t  foo     \";\n    std::string test8 = \"  \\t       \";\n    std::string test9 = \" \\n\\r\";\n\n    BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test1), \"foo\" );\n    BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test2), \"foo\" );\n    BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test3), \"foo\" );\n    BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test4), \"foo\" );\n    BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test5), \"foo\" );\n    BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test6), \"foo\" );\n    BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test7), \"foo\" );\n    BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test8), \"\" );\n    BOOST_CHECK_EQUAL( websocketpp::http::parser::strip_lws(test9), \"\" );\n}\n\nBOOST_AUTO_TEST_CASE( case_insensitive_headers ) {\n    websocketpp::http::parser::parser r;\n\n    r.replace_header(\"foo\",\"bar\");\n\n    BOOST_CHECK_EQUAL( r.get_header(\"foo\"), \"bar\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"FOO\"), \"bar\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Foo\"), \"bar\" );\n}\n\nBOOST_AUTO_TEST_CASE( case_insensitive_headers_overwrite ) {\n    websocketpp::http::parser::parser r;\n\n    r.replace_header(\"foo\",\"bar\");\n\n    BOOST_CHECK_EQUAL( r.get_header(\"foo\"), \"bar\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Foo\"), \"bar\" );\n\n    r.replace_header(\"Foo\",\"baz\");\n\n    BOOST_CHECK_EQUAL( r.get_header(\"foo\"), \"baz\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Foo\"), \"baz\" );\n\n    r.remove_header(\"FoO\");\n\n    BOOST_CHECK_EQUAL( r.get_header(\"foo\"), \"\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Foo\"), \"\" );\n}\n\nBOOST_AUTO_TEST_CASE( blank_consume ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw;\n\n    bool exception = false;\n\n    try {\n        r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK( r.ready() == false );\n}\n\nBOOST_AUTO_TEST_CASE( blank_request ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"\\r\\n\\r\\n\";\n\n    bool exception = false;\n\n    try {\n        r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == true );\n    BOOST_CHECK( r.ready() == false );\n}\n\nBOOST_AUTO_TEST_CASE( bad_request_no_host ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\n\\r\\n\";\n\n    bool exception = false;\n\n    try {\n        r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == true );\n    BOOST_CHECK( r.ready() == false );\n}\n\nBOOST_AUTO_TEST_CASE( basic_request ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK( pos == 41 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK( r.get_version() == \"HTTP/1.1\" );\n    BOOST_CHECK( r.get_method() == \"GET\" );\n    BOOST_CHECK( r.get_uri() == \"/\" );\n    BOOST_CHECK( r.get_header(\"Host\") == \"www.example.com\" );\n}\n\nBOOST_AUTO_TEST_CASE( basic_request_with_body ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nContent-Length: 5\\r\\n\\r\\nabcdef\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 65 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\" );\n    BOOST_CHECK_EQUAL( r.get_method(), \"GET\" );\n    BOOST_CHECK_EQUAL( r.get_uri(), \"/\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Host\"), \"www.example.com\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Content-Length\"), \"5\" );\n    BOOST_CHECK_EQUAL( r.get_body(), \"abcde\" );\n    \n    BOOST_CHECK_EQUAL( r.get_headers().size(), 2);\n    \n    websocketpp::http::parser::header_list::const_iterator it = r.get_headers().begin();\n    \n    BOOST_CHECK_EQUAL( it->first, \"Content-Length\");\n    BOOST_CHECK_EQUAL( it->second, \"5\");\n    \n    it++;\n    \n    BOOST_CHECK_EQUAL( it->first, \"Host\");\n    BOOST_CHECK_EQUAL( it->second, \"www.example.com\");\n}\n\nBOOST_AUTO_TEST_CASE( basic_request_with_body_split ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nContent-Length: 6\\r\\n\\r\\nabc\";\n    std::string raw2 = \"def\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n        pos += r.consume(raw2.c_str(),raw2.size());\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 66 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\" );\n    BOOST_CHECK_EQUAL( r.get_method(), \"GET\" );\n    BOOST_CHECK_EQUAL( r.get_uri(), \"/\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Host\"), \"www.example.com\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Content-Length\"), \"6\" );\n    BOOST_CHECK_EQUAL( r.get_body(), \"abcdef\" );\n}\n\n\n\nBOOST_AUTO_TEST_CASE( trailing_body_characters ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\n\\r\\na\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK( pos == 41 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK( r.get_version() == \"HTTP/1.1\" );\n    BOOST_CHECK( r.get_method() == \"GET\" );\n    BOOST_CHECK( r.get_uri() == \"/\" );\n    BOOST_CHECK( r.get_header(\"Host\") == \"www.example.com\" );\n}\n\nBOOST_AUTO_TEST_CASE( trailing_body_characters_beyond_max_lenth ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\n\\r\\n\";\n    raw.append(websocketpp::http::max_header_size,'*');\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK( pos == 41 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK( r.get_version() == \"HTTP/1.1\" );\n    BOOST_CHECK( r.get_method() == \"GET\" );\n    BOOST_CHECK( r.get_uri() == \"/\" );\n    BOOST_CHECK( r.get_header(\"Host\") == \"www.example.com\" );\n}\n\nBOOST_AUTO_TEST_CASE( basic_split1 ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\n\";\n    std::string raw2 = \"Host: www.example.com\\r\\n\\r\\na\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n        pos += r.consume(raw2.c_str(),raw2.size());\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK( pos == 41 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK( r.get_version() == \"HTTP/1.1\" );\n    BOOST_CHECK( r.get_method() == \"GET\" );\n    BOOST_CHECK( r.get_uri() == \"/\" );\n    BOOST_CHECK( r.get_header(\"Host\") == \"www.example.com\" );\n}\n\nBOOST_AUTO_TEST_CASE( basic_split2 ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\";\n    std::string raw2 = \"\\n\\r\\na\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n        pos += r.consume(raw2.c_str(),raw2.size());\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK( pos == 41 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK( r.get_version() == \"HTTP/1.1\" );\n    BOOST_CHECK( r.get_method() == \"GET\" );\n    BOOST_CHECK( r.get_uri() == \"/\" );\n    BOOST_CHECK( r.get_header(\"Host\") == \"www.example.com\" );\n}\n\nBOOST_AUTO_TEST_CASE( max_header_len ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw(websocketpp::http::max_header_size-1,'*');\n    raw += \"\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n    } catch (const websocketpp::http::exception& e) {\n        if (e.m_error_code == websocketpp::http::status_code::request_header_fields_too_large) {\n            exception = true;\n        }\n    }\n\n    BOOST_CHECK( exception == true );\n}\n\nBOOST_AUTO_TEST_CASE( max_header_len_split ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw(websocketpp::http::max_header_size-1,'*');\n    std::string raw2(2,'*');\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n        pos += r.consume(raw2.c_str(),raw2.size());\n    } catch (const websocketpp::http::exception& e) {\n        if (e.m_error_code == websocketpp::http::status_code::request_header_fields_too_large) {\n            exception = true;\n        }\n    }\n\n    BOOST_CHECK( exception == true );\n}\n\nBOOST_AUTO_TEST_CASE( max_body_len ) {\n    websocketpp::http::parser::request r;\n    \n    r.set_max_body_size(5);\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nContent-Length: 6\\r\\n\\r\\nabcdef\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n    } catch (websocketpp::http::exception const & e) {\n        exception = true;\n        BOOST_CHECK_EQUAL(e.m_error_code,websocketpp::http::status_code::request_entity_too_large);\n    }\n\n    BOOST_CHECK_EQUAL(r.get_max_body_size(),5);\n    BOOST_CHECK( exception == true );\n}\n\nBOOST_AUTO_TEST_CASE( firefox_full_request ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: localhost:5000\\r\\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0) Gecko/20100101 Firefox/10.0\\r\\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\\r\\nAccept-Language: en-us,en;q=0.5\\r\\nAccept-Encoding: gzip, deflate\\r\\nConnection: keep-alive, Upgrade\\r\\nSec-WebSocket-Version: 8\\r\\nSec-WebSocket-Origin: http://zaphoyd.com\\r\\nSec-WebSocket-Key: pFik//FxwFk0riN4ZiPFjQ==\\r\\nPragma: no-cache\\r\\nCache-Control: no-cache\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK( pos == 482 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK( r.get_version() == \"HTTP/1.1\" );\n    BOOST_CHECK( r.get_method() == \"GET\" );\n    BOOST_CHECK( r.get_uri() == \"/\" );\n    BOOST_CHECK( r.get_header(\"Host\") == \"localhost:5000\" );\n    BOOST_CHECK( r.get_header(\"User-Agent\") == \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0) Gecko/20100101 Firefox/10.0\" );\n    BOOST_CHECK( r.get_header(\"Accept\") == \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\" );\n    BOOST_CHECK( r.get_header(\"Accept-Language\") == \"en-us,en;q=0.5\" );\n    BOOST_CHECK( r.get_header(\"Accept-Encoding\") == \"gzip, deflate\" );\n    BOOST_CHECK( r.get_header(\"Connection\") == \"keep-alive, Upgrade\" );\n    BOOST_CHECK( r.get_header(\"Sec-WebSocket-Version\") == \"8\" );\n    BOOST_CHECK( r.get_header(\"Sec-WebSocket-Origin\") == \"http://zaphoyd.com\" );\n    BOOST_CHECK( r.get_header(\"Sec-WebSocket-Key\") == \"pFik//FxwFk0riN4ZiPFjQ==\" );\n    BOOST_CHECK( r.get_header(\"Pragma\") == \"no-cache\" );\n    BOOST_CHECK( r.get_header(\"Cache-Control\") == \"no-cache\" );\n    BOOST_CHECK( r.get_header(\"Upgrade\") == \"websocket\" );\n}\n\nBOOST_AUTO_TEST_CASE( bad_method ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GE]T / HTTP/1.1\\r\\nHost: www.example.com\\r\\n\\r\\n\";\n\n    bool exception = false;\n\n    try {\n        r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == true );\n}\n\nBOOST_AUTO_TEST_CASE( bad_header_name ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHo]st: www.example.com\\r\\n\\r\\n\";\n\n    bool exception = false;\n\n    try {\n        r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == true );\n}\n\nBOOST_AUTO_TEST_CASE( old_http_version ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.0\\r\\nHost: www.example.com\\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 41 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.0\" );\n    BOOST_CHECK_EQUAL( r.get_method(), \"GET\" );\n    BOOST_CHECK_EQUAL( r.get_uri(), \"/\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Host\"), \"www.example.com\" );\n}\n\nBOOST_AUTO_TEST_CASE( new_http_version1 ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.12\\r\\nHost: www.example.com\\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 42 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.12\" );\n    BOOST_CHECK_EQUAL( r.get_method(), \"GET\" );\n    BOOST_CHECK_EQUAL( r.get_uri(), \"/\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Host\"), \"www.example.com\" );\n}\n\nBOOST_AUTO_TEST_CASE( new_http_version2 ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/12.12\\r\\nHost: www.example.com\\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 43 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/12.12\" );\n    BOOST_CHECK_EQUAL( r.get_method(), \"GET\" );\n    BOOST_CHECK_EQUAL( r.get_uri(), \"/\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Host\"), \"www.example.com\" );\n}\n\n/* commented out due to not being implemented yet\n\nBOOST_AUTO_TEST_CASE( new_http_version3 ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTPS/12.12\\r\\nHost: www.example.com\\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == true );\n}*/\n\nBOOST_AUTO_TEST_CASE( header_whitespace1 ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost:  www.example.com \\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 43 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\" );\n    BOOST_CHECK_EQUAL( r.get_method(), \"GET\" );\n    BOOST_CHECK_EQUAL( r.get_uri(), \"/\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Host\"), \"www.example.com\" );\n}\n\nBOOST_AUTO_TEST_CASE( header_whitespace2 ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost:www.example.com\\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 40 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\" );\n    BOOST_CHECK_EQUAL( r.get_method(), \"GET\" );\n    BOOST_CHECK_EQUAL( r.get_uri(), \"/\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Host\"), \"www.example.com\" );\n}\n\nBOOST_AUTO_TEST_CASE( header_aggregation ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nFoo: bar\\r\\nFoo: bat\\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos = r.consume(raw.c_str(),raw.size());\n    } catch (...) {\n        exception = true;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 61 );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\" );\n    BOOST_CHECK_EQUAL( r.get_method(), \"GET\" );\n    BOOST_CHECK_EQUAL( r.get_uri(), \"/\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Foo\"), \"bar, bat\" );\n}\n\nBOOST_AUTO_TEST_CASE( wikipedia_example_response ) {\n    websocketpp::http::parser::response r;\n\n    std::string raw = \"HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: websocket\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=\\r\\nSec-WebSocket-Protocol: chat\\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 159 );\n    BOOST_CHECK( r.headers_ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\" );\n    BOOST_CHECK_EQUAL( r.get_status_code(), websocketpp::http::status_code::switching_protocols );\n    BOOST_CHECK_EQUAL( r.get_status_msg(), \"Switching Protocols\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Upgrade\"), \"websocket\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Connection\"), \"Upgrade\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Sec-WebSocket-Accept\"), \"HSmrc0sMlYUkAGmm5OPpG2HaGWk=\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Sec-WebSocket-Protocol\"), \"chat\" );\n}\n\nBOOST_AUTO_TEST_CASE( wikipedia_example_response_trailing ) {\n    websocketpp::http::parser::response r;\n\n    std::string raw = \"HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: websocket\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=\\r\\nSec-WebSocket-Protocol: chat\\r\\n\\r\\n\";\n    raw += \"a\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 159 );\n    BOOST_CHECK( r.headers_ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\" );\n    BOOST_CHECK_EQUAL( r.get_status_code(), websocketpp::http::status_code::switching_protocols );\n    BOOST_CHECK_EQUAL( r.get_status_msg(), \"Switching Protocols\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Upgrade\"), \"websocket\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Connection\"), \"Upgrade\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Sec-WebSocket-Accept\"), \"HSmrc0sMlYUkAGmm5OPpG2HaGWk=\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Sec-WebSocket-Protocol\"), \"chat\" );\n}\n\nBOOST_AUTO_TEST_CASE( wikipedia_example_response_trailing_large ) {\n    websocketpp::http::parser::response r;\n\n    std::string raw = \"HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: websocket\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=\\r\\nSec-WebSocket-Protocol: chat\\r\\n\\r\\n\";\n    raw.append(websocketpp::http::max_header_size,'*');\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 159 );\n    BOOST_CHECK( r.headers_ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\" );\n    BOOST_CHECK_EQUAL( r.get_status_code(), websocketpp::http::status_code::switching_protocols );\n    BOOST_CHECK_EQUAL( r.get_status_msg(), \"Switching Protocols\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Upgrade\"), \"websocket\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Connection\"), \"Upgrade\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Sec-WebSocket-Accept\"), \"HSmrc0sMlYUkAGmm5OPpG2HaGWk=\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Sec-WebSocket-Protocol\"), \"chat\" );\n}\n\nBOOST_AUTO_TEST_CASE( response_with_non_standard_lws ) {\n    websocketpp::http::parser::response r;\n\n    std::string raw = \"HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: websocket\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept:HSmrc0sMlYUkAGmm5OPpG2HaGWk=\\r\\nSec-WebSocket-Protocol: chat\\r\\n\\r\\n\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 158 );\n    BOOST_CHECK( r.headers_ready() );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\" );\n    BOOST_CHECK_EQUAL( r.get_status_code(), websocketpp::http::status_code::switching_protocols );\n    BOOST_CHECK_EQUAL( r.get_status_msg(), \"Switching Protocols\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Upgrade\"), \"websocket\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Connection\"), \"Upgrade\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Sec-WebSocket-Accept\"), \"HSmrc0sMlYUkAGmm5OPpG2HaGWk=\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Sec-WebSocket-Protocol\"), \"chat\" );\n}\n\nBOOST_AUTO_TEST_CASE( plain_http_response ) {\n    websocketpp::http::parser::response r;\n\n    std::string raw = \"HTTP/1.1 200 OK\\r\\nDate: Thu, 10 May 2012 11:59:25 GMT\\r\\nServer: Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8r DAV/2 PHP/5.3.8 with Suhosin-Patch\\r\\nLast-Modified: Tue, 30 Mar 2010 17:41:28 GMT\\r\\nETag: \\\"16799d-55-4830823a78200\\\"\\r\\nAccept-Ranges: bytes\\r\\nContent-Length: 85\\r\\nVary: Accept-Encoding\\r\\nContent-Type: text/html\\r\\n\\r\\n<!doctype html>\\n<html>\\n<head>\\n<title>Thor</title>\\n</head>\\n<body> \\n<p>Thor</p>\\n</body>\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(raw.c_str(),raw.size());\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK( exception == false );\n    BOOST_CHECK_EQUAL( pos, 405 );\n    BOOST_CHECK( r.headers_ready() == true );\n    BOOST_CHECK( r.ready() == true );\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\" );\n    BOOST_CHECK_EQUAL( r.get_status_code(), websocketpp::http::status_code::ok );\n    BOOST_CHECK_EQUAL( r.get_status_msg(), \"OK\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Date\"), \"Thu, 10 May 2012 11:59:25 GMT\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Server\"), \"Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8r DAV/2 PHP/5.3.8 with Suhosin-Patch\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Last-Modified\"), \"Tue, 30 Mar 2010 17:41:28 GMT\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"ETag\"), \"\\\"16799d-55-4830823a78200\\\"\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Accept-Ranges\"), \"bytes\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Content-Length\"), \"85\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Vary\"), \"Accept-Encoding\" );\n    BOOST_CHECK_EQUAL( r.get_header(\"Content-Type\"), \"text/html\" );\n    BOOST_CHECK_EQUAL( r.get_body(), \"<!doctype html>\\n<html>\\n<head>\\n<title>Thor</title>\\n</head>\\n<body> \\n<p>Thor</p>\\n</body>\" );\n}\n\nBOOST_AUTO_TEST_CASE( parse_istream ) {\n    websocketpp::http::parser::response r;\n\n    std::stringstream s;\n\n    s << \"HTTP/1.1 200 OK\\r\\nDate: Thu, 10 May 2012 11:59:25 GMT\\r\\nServer: Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8r DAV/2 PHP/5.3.8 with Suhosin-Patch\\r\\nLast-Modified: Tue, 30 Mar 2010 17:41:28 GMT\\r\\nETag: \\\"16799d-55-4830823a78200\\\"\\r\\nAccept-Ranges: bytes\\r\\nContent-Length: 85\\r\\nVary: Accept-Encoding\\r\\nContent-Type: text/html\\r\\n\\r\\n<!doctype html>\\n<html>\\n<head>\\n<title>Thor</title>\\n</head>\\n<body> \\n<p>Thor</p>\\n</body>\";\n\n    bool exception = false;\n    size_t pos = 0;\n\n    try {\n        pos += r.consume(s);\n    } catch (std::exception &e) {\n        exception = true;\n        std::cout << e.what() << std::endl;\n    }\n\n    BOOST_CHECK_EQUAL( exception, false );\n    BOOST_CHECK_EQUAL( pos, 405 );\n    BOOST_CHECK_EQUAL( r.headers_ready(), true );\n    BOOST_CHECK_EQUAL( r.ready(), true );\n}\n\nBOOST_AUTO_TEST_CASE( write_request_basic ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\n\\r\\n\";\n\n    r.set_version(\"HTTP/1.1\");\n    r.set_method(\"GET\");\n    r.set_uri(\"/\");\n\n    BOOST_CHECK_EQUAL( r.raw(), raw );\n}\n\nBOOST_AUTO_TEST_CASE( write_request_with_header ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: http://example.com\\r\\n\\r\\n\";\n\n    r.set_version(\"HTTP/1.1\");\n    r.set_method(\"GET\");\n    r.set_uri(\"/\");\n    r.replace_header(\"Host\",\"http://example.com\");\n\n    BOOST_CHECK_EQUAL( r.raw(), raw );\n}\n\nBOOST_AUTO_TEST_CASE( write_request_with_body ) {\n    websocketpp::http::parser::request r;\n\n    std::string raw = \"POST / HTTP/1.1\\r\\nContent-Length: 48\\r\\nContent-Type: application/x-www-form-urlencoded\\r\\nHost: http://example.com\\r\\n\\r\\nlicenseID=string&content=string&paramsXML=string\";\n\n    r.set_version(\"HTTP/1.1\");\n    r.set_method(\"POST\");\n    r.set_uri(\"/\");\n    r.replace_header(\"Host\",\"http://example.com\");\n    r.replace_header(\"Content-Type\",\"application/x-www-form-urlencoded\");\n    r.set_body(\"licenseID=string&content=string&paramsXML=string\");\n\n    BOOST_CHECK_EQUAL( r.raw(), raw );\n}\n"
  },
  {
    "path": "test/http/parser_perf.cpp",
    "content": "/*\n * Copyright (c) 2011, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#include <websocketpp/http/parser.hpp>\n\n#include <chrono>\n\nclass scoped_timer {\npublic:\n    scoped_timer(std::string i) : m_id(i),m_start(std::chrono::steady_clock::now()) {\n        std::cout << \"Clock \" << i << \": \";\n    }\n    ~scoped_timer() {\n        std::chrono::nanoseconds time_taken = std::chrono::steady_clock::now()-m_start;\n\n        //nanoseconds_per_test\n\n        //tests_per_second\n\n        //1000000000.0/(double(time_taken.count())/1000.0)\n\n        std::cout << 1000000000.0/(double(time_taken.count())/1000.0) << std::endl;\n\n        //std::cout << (1.0/double(time_taken.count())) * double(1000000000*1000) << std::endl;\n    }\n\nprivate:\n    std::string m_id;\n    std::chrono::steady_clock::time_point m_start;\n};\n\nint main() {\n    std::string raw = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\n\\r\\n\";\n\n    std::string firefox = \"GET / HTTP/1.1\\r\\nHost: localhost:5000\\r\\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0) Gecko/20100101 Firefox/10.0\\r\\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\\r\\nAccept-Language: en-us,en;q=0.5\\r\\nAccept-Encoding: gzip, deflate\\r\\nConnection: keep-alive, Upgrade\\r\\nSec-WebSocket-Version: 8\\r\\nSec-WebSocket-Origin: http://zaphoyd.com\\r\\nSec-WebSocket-Key: pFik//FxwFk0riN4ZiPFjQ==\\r\\nPragma: no-cache\\r\\nCache-Control: no-cache\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    std::string firefox1 = \"GET / HTTP/1.1\\r\\nHost: localhost:5000\\r\\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0) Gecko/20100101 Firefox/10.0\\r\\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\\r\\nAccept-Language: en-us,en;q=0.5\\r\\n\";\n\n    std::string firefox2 = \"Accept-Encoding: gzip, deflate\\r\\nConnection: keep-alive, Upgrade\\r\\nSec-WebSocket-Version: 8\\r\\nSec-WebSocket-Origin: http://zaphoyd.com\\r\\nSec-WebSocket-Key: pFik//FxwFk0riN4ZiPFjQ==\\r\\nPragma: no-cache\\r\\nCache-Control: no-cache\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    {\n        scoped_timer timer(\"Simplest 1 chop\");\n        for (int i = 0; i < 1000; i++) {\n            websocketpp::http::parser::request r;\n\n            try {\n                r.consume(raw.c_str(),raw.size());\n            } catch (...) {\n                std::cout << \"exception\" << std::endl;\n            }\n\n            if (!r.ready()) {\n                std::cout << \"error\" << std::endl;\n                break;\n            }\n        }\n    }\n\n    {\n        scoped_timer timer(\"FireFox, 1 chop, consume old\");\n        for (int i = 0; i < 1000; i++) {\n            websocketpp::http::parser::request r;\n\n            try {\n                r.consume2(firefox.c_str(),firefox.size());\n            } catch (...) {\n                std::cout << \"exception\" << std::endl;\n            }\n\n            if (!r.ready()) {\n                std::cout << \"error\" << std::endl;\n                break;\n            }\n        }\n    }\n\n    {\n        scoped_timer timer(\"FireFox, 1 chop\");\n        for (int i = 0; i < 1000; i++) {\n            websocketpp::http::parser::request r;\n\n            try {\n                r.consume(firefox.c_str(),firefox.size());\n            } catch (...) {\n                std::cout << \"exception\" << std::endl;\n            }\n\n            if (!r.ready()) {\n                std::cout << \"error\" << std::endl;\n                break;\n            }\n        }\n    }\n\n\n\n    {\n        scoped_timer timer(\"FireFox, 2 chop\");\n        for (int i = 0; i < 1000; i++) {\n            websocketpp::http::parser::request r;\n\n            try {\n                r.consume(firefox1.c_str(),firefox1.size());\n                r.consume(firefox2.c_str(),firefox2.size());\n            } catch (...) {\n                std::cout << \"exception\" << std::endl;\n            }\n\n            if (!r.ready()) {\n                std::cout << \"error\" << std::endl;\n                break;\n            }\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "test/logger/CMakeLists.txt",
    "content": "\nfile (GLOB SOURCE_FILES *.cpp)\nfile (GLOB HEADER_FILES *.hpp)\n\ninit_target (test_logger)\n\nbuild_test (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})\n\nlink_boost ()\nfinal_target ()\n\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n"
  },
  {
    "path": "test/logger/SConscript",
    "content": "## logger unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs]\n\nobjs = env.Object('logger_basic_boost.o', [\"basic.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('logger_basic_boost', [\"logger_basic_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   objs += env_cpp11.Object('logger_basic_stl.o', [\"basic.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('logger_basic_stl', [\"logger_basic_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/logger/basic.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE basic_log\n#include <boost/test/unit_test.hpp>\n\n#include <string>\n\n#include <websocketpp/logger/basic.hpp>\n#include <websocketpp/concurrency/none.hpp>\n#include <websocketpp/concurrency/basic.hpp>\n\ntypedef websocketpp::log::basic<websocketpp::concurrency::basic,websocketpp::log::alevel> basic_access_log_type;\n\nBOOST_AUTO_TEST_CASE( is_token_char ) {\n    typedef websocketpp::log::basic<websocketpp::concurrency::none,websocketpp::log::elevel> error_log;\n\n    error_log elog;\n\n    BOOST_CHECK( elog.static_test(websocketpp::log::elevel::info ) == true );\n    BOOST_CHECK( elog.static_test(websocketpp::log::elevel::warn ) == true );\n    BOOST_CHECK( elog.static_test(websocketpp::log::elevel::rerror ) == true );\n    BOOST_CHECK( elog.static_test(websocketpp::log::elevel::fatal ) == true );\n\n    elog.set_channels(websocketpp::log::elevel::info);\n\n    elog.write(websocketpp::log::elevel::info,\"Information\");\n    elog.write(websocketpp::log::elevel::warn,\"A warning\");\n    elog.write(websocketpp::log::elevel::rerror,\"A error\");\n    elog.write(websocketpp::log::elevel::fatal,\"A critical error\");\n}\n\nBOOST_AUTO_TEST_CASE( access_clear ) {\n    typedef websocketpp::log::basic<websocketpp::concurrency::none,websocketpp::log::alevel> access_log;\n\n    std::stringstream out;\n    access_log logger(0xffffffff,&out);\n\n    // clear all channels\n    logger.clear_channels(0xffffffff);\n\n    // writes shouldn't happen\n    logger.write(websocketpp::log::alevel::devel,\"devel\");\n    //std::cout << \"|\" << out.str() << \"|\" << std::endl;\n    BOOST_CHECK( out.str().size() == 0 );\n}\n\nBOOST_AUTO_TEST_CASE( basic_concurrency ) {\n    typedef websocketpp::log::basic<websocketpp::concurrency::basic,websocketpp::log::alevel> access_log;\n\n    std::stringstream out;\n    access_log logger(0xffffffff,&out);\n\n    logger.set_channels(0xffffffff);\n\n    logger.write(websocketpp::log::alevel::devel,\"devel\");\n    //std::cout << \"|\" << out.str() << \"|\" << std::endl;\n    BOOST_CHECK( out.str().size() > 0 );\n}\n\n\nBOOST_AUTO_TEST_CASE( copy_constructor ) {\n    std::stringstream out;\n\n    basic_access_log_type logger1(0xffffffff,&out);\n    basic_access_log_type logger2(logger1);\n\n    logger2.set_channels(0xffffffff);\n    logger2.write(websocketpp::log::alevel::devel,\"devel\");\n    BOOST_CHECK( out.str().size() > 0 );\n}\n\n#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_\nBOOST_AUTO_TEST_CASE( move_constructor ) {\n    std::stringstream out;\n\n    basic_access_log_type logger1(0xffffffff,&out);\n    basic_access_log_type logger2(std::move(logger1));\n\n    logger2.set_channels(0xffffffff);\n    logger2.write(websocketpp::log::alevel::devel,\"devel\");\n    BOOST_CHECK( out.str().size() > 0 );\n}\n\n// Emplace requires move assignment, which logger doesn't support right now\n// due to const members. This is pretty irritating and will probably result in\n// the const members being removed. For now though this test will fail to\n// compile\n/*BOOST_AUTO_TEST_CASE( emplace ) {\n    std::stringstream out1;\n    std::stringstream out2;\n\n    std::vector<basic_access_log_type> v;\n\n    v.emplace_back(websocketpp::log::level(0xffffffff),&out1);\n    v.emplace_back(websocketpp::log::level(0xffffffff),&out2);\n\n    v[0].set_channels(0xffffffff);\n    v[1].set_channels(0xffffffff);\n    v[0].write(websocketpp::log::alevel::devel,\"devel\");\n    v[1].write(websocketpp::log::alevel::devel,\"devel\");\n    BOOST_CHECK( out1.str().size() > 0 );\n    BOOST_CHECK( out2.str().size() > 0 );\n}*/\n#endif // #ifdef _WEBSOCKETPP_MOVE_SEMANTICS_\n\n// As long as there are const member variables these can't exist\n// These remain commented as they are useful for testing the deleted operators\n/*BOOST_AUTO_TEST_CASE( copy_assign ) {\n    basic_access_log_type logger1;\n    basic_access_log_type logger2;\n\n    logger2 = logger1;\n}\n\nBOOST_AUTO_TEST_CASE( move_assign ) {\n    basic_access_log_type logger1;\n    basic_access_log_type logger2;\n\n    logger2 = std::move(logger1);\n}*/\n"
  },
  {
    "path": "test/message_buffer/CMakeLists.txt",
    "content": "# Test alloc message buffer strategy\nfile (GLOB SOURCE alloc.cpp)\n\ninit_target (test_message_alloc)\nbuild_executable (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test message buffers\nfile (GLOB SOURCE message.cpp)\n\ninit_target (test_message_buffer)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n"
  },
  {
    "path": "test/message_buffer/SConscript",
    "content": "## message_buffer unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs]\n\nobjs = env.Object('message_boost.o', [\"message.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('alloc_boost.o', [\"alloc.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_message_boost', [\"message_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_alloc_boost', [\"alloc_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   objs += env_cpp11.Object('message_stl.o', [\"message.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('alloc_stl.o', [\"alloc.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_message_stl', [\"message_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_alloc_stl', [\"alloc_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/message_buffer/alloc.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE message_buffer_alloc\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/message_buffer/alloc.hpp>\n\ntemplate <template <class> class con_msg_manager>\nstruct stub {\n    typedef websocketpp::lib::shared_ptr<stub> ptr;\n\n    typedef con_msg_manager<stub> con_msg_man_type;\n    typedef typename con_msg_man_type::ptr con_msg_man_ptr;\n    typedef typename con_msg_man_type::weak_ptr con_msg_man_weak_ptr;\n\n    stub(con_msg_man_ptr manager, websocketpp::frame::opcode::value op, size_t size = 128)\n      : m_opcode(op)\n      , m_manager(manager)\n      , m_size(size) {}\n\n    bool recycle() {\n        con_msg_man_ptr shared = m_manager.lock();\n\n        if (shared) {\n            return shared->recycle(this);\n        } else {\n            return false;\n        }\n    }\n\n    websocketpp::frame::opcode::value   m_opcode;\n    con_msg_man_weak_ptr                m_manager;\n    size_t                              m_size;\n};\n\nBOOST_AUTO_TEST_CASE( basic_get_message ) {\n    typedef stub<websocketpp::message_buffer::alloc::con_msg_manager>\n        message_type;\n    typedef websocketpp::message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_man_type;\n\n    con_msg_man_type::ptr manager(new con_msg_man_type());\n    message_type::ptr msg = manager->get_message(websocketpp::frame::opcode::TEXT,512);\n\n    BOOST_CHECK(msg);\n    BOOST_CHECK(msg->m_opcode == websocketpp::frame::opcode::TEXT);\n    BOOST_CHECK(msg->m_manager.lock() == manager);\n    BOOST_CHECK(msg->m_size == 512);\n}\n\nBOOST_AUTO_TEST_CASE( basic_get_manager ) {\n    typedef stub<websocketpp::message_buffer::alloc::con_msg_manager>\n        message_type;\n    typedef websocketpp::message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_man_type;\n    typedef websocketpp::message_buffer::alloc::endpoint_msg_manager\n        <con_msg_man_type> endpoint_manager_type;\n\n    endpoint_manager_type em;\n    con_msg_man_type::ptr manager = em.get_manager();\n    message_type::ptr msg = manager->get_message(websocketpp::frame::opcode::TEXT,512);\n\n    BOOST_CHECK(msg);\n    BOOST_CHECK(msg->m_opcode == websocketpp::frame::opcode::TEXT);\n    BOOST_CHECK(msg->m_manager.lock() == manager);\n    BOOST_CHECK(msg->m_size == 512);\n}\n\n"
  },
  {
    "path": "test/message_buffer/message.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE message\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/message_buffer/message.hpp>\n\ntemplate <typename message>\nstruct stub {\n    typedef websocketpp::lib::weak_ptr<stub> weak_ptr;\n    typedef websocketpp::lib::shared_ptr<stub> ptr;\n\n    stub() : recycled(false) {}\n\n    bool recycle(message *) {\n        this->recycled = true;\n        return false;\n    }\n\n    bool recycled;\n};\n\nBOOST_AUTO_TEST_CASE( basic_size_check ) {\n    typedef websocketpp::message_buffer::message<stub> message_type;\n    typedef stub<message_type> stub_type;\n\n    stub_type::ptr s(new stub_type());\n    message_type::ptr msg(new message_type(s,websocketpp::frame::opcode::TEXT,500));\n\n    BOOST_CHECK(msg->get_payload().capacity() >= 500);\n}\n\nBOOST_AUTO_TEST_CASE( recycle ) {\n    typedef websocketpp::message_buffer::message<stub> message_type;\n    typedef stub<message_type> stub_type;\n\n    stub_type::ptr s(new stub_type());\n    message_type::ptr msg(new message_type(s,websocketpp::frame::opcode::TEXT,500));\n\n    BOOST_CHECK(s->recycled == false);\n    BOOST_CHECK(msg->recycle() == false);\n    BOOST_CHECK(s->recycled == true);\n}\n\n"
  },
  {
    "path": "test/message_buffer/pool.cpp",
    "content": "/*\n * Copyright (c) 2011, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE hybi_00_processor\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/processors/hybi00.hpp>\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n\n\nBOOST_AUTO_TEST_CASE( exact_match ) {\n    websocketpp::http::parser::request r;\n    websocketpp::http::parser::response response;\n    websocketpp::processor::hybi00<websocketpp::http::parser::request,websocketpp::http::parser::response> p(false);\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nOrigin: http://example.com\\r\\nSec-WebSocket-Key1: 3e6b263  4 17 80\\r\\nSec-WebSocket-Key2: 17  9 G`ZD9   2 2b 7X 3 /r90\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n    r.replace_header(\"Sec-WebSocket-Key3\",\"WjN}|M(6\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    BOOST_CHECK(p.validate_handshake(r));\n\n    websocketpp::uri_ptr u;\n    bool exception;\n\n    try {\n        u = p.get_uri(r);\n    } catch (const websocketpp::uri_exception& e) {\n        exception = true;\n    }\n\n    BOOST_CHECK(exception == false);\n    BOOST_CHECK(u->get_secure() == false);\n    BOOST_CHECK(u->get_host() == \"www.example.com\");\n    BOOST_CHECK(u->get_resource() == \"/\");\n    BOOST_CHECK(u->get_port() == websocketpp::URI_DEFAULT_PORT);\n\n    p.process_handshake(r,response);\n\n    BOOST_CHECK(response.get_header(\"Connection\") == \"Upgrade\");\n    BOOST_CHECK(response.get_header(\"Upgrade\") == \"websocket\");\n    BOOST_CHECK(response.get_header(\"Sec-WebSocket-Origin\") == \"http://example.com\");\n\n    BOOST_CHECK(response.get_header(\"Sec-WebSocket-Location\") == \"ws://www.example.com/\");\n    BOOST_CHECK(response.get_header(\"Sec-WebSocket-Key3\") == \"n`9eBk9z$R8pOtVb\");\n}\n\nBOOST_AUTO_TEST_CASE( non_get_method ) {\n    websocketpp::http::parser::request r;\n    websocketpp::processor::hybi00<websocketpp::http::parser::request,websocketpp::http::parser::response> p(false);\n\n    std::string handshake = \"POST / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Key1: 3e6b263  4 17 80\\r\\nSec-WebSocket-Key2: 17  9 G`ZD9   2 2b 7X 3 /r90\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n    r.replace_header(\"Sec-WebSocket-Key3\",\"janelle!\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    BOOST_CHECK(!p.validate_handshake(r));\n}\n\nBOOST_AUTO_TEST_CASE( old_http_version ) {\n    websocketpp::http::parser::request r;\n    websocketpp::processor::hybi00<websocketpp::http::parser::request,websocketpp::http::parser::response> p(false);\n\n    std::string handshake = \"GET / HTTP/1.0\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Key1: 3e6b263  4 17 80\\r\\nSec-WebSocket-Key2: 17  9 G`ZD9   2 2b 7X 3 /r90\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n    r.replace_header(\"Sec-WebSocket-Key3\",\"janelle!\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    BOOST_CHECK(!p.validate_handshake(r));\n}\n\nBOOST_AUTO_TEST_CASE( missing_handshake_key1 ) {\n    websocketpp::http::parser::request r;\n    websocketpp::processor::hybi00<websocketpp::http::parser::request,websocketpp::http::parser::response> p(false);\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Key1: 3e6b263  4 17 80\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n    r.replace_header(\"Sec-WebSocket-Key3\",\"janelle!\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    BOOST_CHECK(!p.validate_handshake(r));\n}\n\nBOOST_AUTO_TEST_CASE( missing_handshake_key2 ) {\n    websocketpp::http::parser::request r;\n    websocketpp::processor::hybi00<websocketpp::http::parser::request,websocketpp::http::parser::response> p(false);\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Key2: 17  9 G`ZD9   2 2b 7X 3 /r90\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n    r.replace_header(\"Sec-WebSocket-Key3\",\"janelle!\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    BOOST_CHECK(!p.validate_handshake(r));\n}\n\nBOOST_AUTO_TEST_CASE( bad_host ) {\n    websocketpp::http::parser::request r;\n    websocketpp::processor::hybi00<websocketpp::http::parser::request,websocketpp::http::parser::response> p(false);\n    websocketpp::uri_ptr u;\n    bool exception = false;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com:70000\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Key2: 17  9 G`ZD9   2 2b 7X 3 /r90\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n    r.replace_header(\"Sec-WebSocket-Key3\",\"janelle!\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    BOOST_CHECK(!p.validate_handshake(r));\n\n    try {\n        u = p.get_uri(r);\n    } catch (const websocketpp::uri_exception& e) {\n        exception = true;\n    }\n\n    BOOST_CHECK(exception == true);\n}\n"
  },
  {
    "path": "test/processors/CMakeLists.txt",
    "content": "# Generic processor tests\nfile (GLOB SOURCE processor.cpp)\n\ninit_target (test_processor)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Hybi00 processor tests\nfile (GLOB SOURCE hybi00.cpp)\n\ninit_target (test_processor_hybi00)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Hybi07 processor tests\nfile (GLOB SOURCE hybi07.cpp)\n\ninit_target (test_processor_hybi07)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Hybi08 processor tests\nfile (GLOB SOURCE hybi08.cpp)\n\ninit_target (test_processor_hybi08)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\nif (ZLIB_FOUND)\n\n# Hybi13 processor tests\nfile (GLOB SOURCE hybi13.cpp)\n\ninit_target (test_processor_hybi13)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nlink_zlib()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Permessage compression extension processor tests\nfile (GLOB SOURCE extension_permessage_compress.cpp)\n\ninit_target (test_processor_extension_permessage_compress)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nlink_zlib()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\nendif ( ZLIB_FOUND )"
  },
  {
    "path": "test/processors/SConscript",
    "content": "## processor unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs] + ['z']\n\nobjs = env.Object('test_processor_boost.o', [\"processor.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('test_hybi13_boost.o', [\"hybi13.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('test_hybi08_boost.o', [\"hybi08.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('test_hybi07_boost.o', [\"hybi07.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('test_hybi00_boost.o', [\"hybi00.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('test_extension_permessage_compress_boost.o', [\"extension_permessage_compress.cpp\"], LIBS = BOOST_LIBS)\n\nprgs = env.Program('test_processor_boost', [\"test_processor_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_hybi13_boost', [\"test_hybi13_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_hybi08_boost', [\"test_hybi08_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_hybi07_boost', [\"test_hybi07_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_hybi00_boost', [\"test_hybi00_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_extension_permessage_compress_boost', [\"test_extension_permessage_compress_boost.o\"], LIBS = BOOST_LIBS + ['z'])\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z']\n   # no C++11 features are used in processor so there are no C++11 versions of\n   # these tests.\n   objs += env_cpp11.Object('test_processor_stl.o', [\"processor.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('test_hybi13_stl.o', [\"hybi13.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('test_hybi08_stl.o', [\"hybi08.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('test_hybi07_stl.o', [\"hybi07.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('test_hybi00_stl.o', [\"hybi00.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('test_extension_permessage_compress_stl.o', [\"extension_permessage_compress.cpp\"], LIBS = BOOST_LIBS_CPP11 + ['z'])\n\n   prgs += env_cpp11.Program('test_processor_stl', [\"test_processor_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_hybi13_stl', [\"test_hybi13_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_hybi08_stl', [\"test_hybi08_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_hybi07_stl', [\"test_hybi07_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_hybi00_stl', [\"test_hybi00_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_extension_permessage_compress_stl', [\"test_extension_permessage_compress_stl.o\"], LIBS = BOOST_LIBS_CPP11 + ['z'])\n\nReturn('prgs')\n"
  },
  {
    "path": "test/processors/extension_permessage_compress.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE extension_permessage_deflate\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n#include <websocketpp/common/memory.hpp>\n\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/extensions/permessage_deflate/enabled.hpp>\n\nstruct config {\n    typedef websocketpp::http::parser::request request_type;\n};\ntypedef websocketpp::extensions::permessage_deflate::enabled<config>\n    compressor_type;\n\nusing namespace websocketpp;\n\nBOOST_AUTO_TEST_CASE( deflate_init ) {\n    /*compressor_type compressor;\n    websocketpp::http::parser::attribute_list attributes;\n    std::pair<lib::error_code,std::string> neg_ret;\n\n    neg_ret = compressor.negotiate(attributes);\n\n    BOOST_CHECK_EQUAL( neg_ret.first,\n        extensions::permessage_deflate::error::invalid_parameters );*/\n\n    /**\n     * Window size is primarily controlled by the writer. A stream can only be\n     * read by a window size equal to or greater than the one use to compress\n     * it initially. The default windows size is also the maximum window size.\n     * Thus:\n     *\n     * Outbound window size can be limited unilaterally under the assumption\n     * that the opposite end will be using the default (maximum size which can\n     * read anything)\n     *\n     * Inbound window size must be limited by asking the remote endpoint to\n     * do so and it agreeing.\n     *\n     * Context takeover is also primarily controlled by the writer. If the\n     * compressor does not clear its context between messages then the reader\n     * can't either.\n     *\n     * Outbound messages may clear context between messages unilaterally.\n     * Inbound messages must retain state unless the remote endpoint signals\n     * otherwise.\n     *\n     * Negotiation options:\n     * Client must choose from the following options:\n     * - whether or not to request an inbound window limit\n     * - whether or not to signal that it will honor an outbound window limit\n     * - whether or not to request that the server disallow context takeover\n     *\n     * Server must answer in the following ways\n     * - If client requested a window size limit, is the window size limit\n     *   acceptable?\n     * - If client allows window limit requests, should we send one?\n     * - If client requested no context takeover, should we accept?\n     *\n     *\n     *\n     * All Defaults\n     * Req: permessage-compress; method=deflate\n     * Ans: permessage-compress; method=deflate\n     *\n     * # Client wants to limit the size of inbound windows from server\n     * permessage-compress; method=\"deflate; s2c_max_window_bits=8, deflate\"\n     * Ans: permessage-compress; method=\"deflate; s2c_max_window_bits=8\"\n     * OR\n     * Ans: permessage-compress; method=deflate\n     *\n     * # Server wants to limit the size of inbound windows from client\n     * Client:\n     * permessage-compress; method=\"deflate; c2s_max_window_bits, deflate\"\n     *\n     * Server:\n     * permessage-compress; method=\"deflate; c2s_max_window_bits=8\"\n     *\n     * # Client wants to\n     *\n     *\n     *\n     *\n     *\n     *\n     */\n\n\n\n\n   /* processor::extensions::deflate_method d(true);\n    http::parser::attribute_list attributes;\n    lib::error_code ec;\n\n    attributes.push_back(http::parser::attribute(\"foo\",\"bar\"));\n    ec = d.init(attributes);\n    BOOST_CHECK(ec == processor::extensions::error::unknown_method_parameter);\n\n    attributes.clear();\n    attributes.push_back(http::parser::attribute(\"s2c_max_window_bits\",\"bar\"));\n    ec = d.init(attributes);\n    BOOST_CHECK(ec == processor::extensions::error::invalid_algorithm_settings);\n\n    attributes.clear();\n    attributes.push_back(http::parser::attribute(\"s2c_max_window_bits\",\"7\"));\n    ec = d.init(attributes);\n    BOOST_CHECK(ec == processor::extensions::error::invalid_algorithm_settings);\n\n    attributes.clear();\n    attributes.push_back(http::parser::attribute(\"s2c_max_window_bits\",\"16\"));\n    ec = d.init(attributes);\n    BOOST_CHECK(ec == processor::extensions::error::invalid_algorithm_settings);\n\n    attributes.clear();\n    attributes.push_back(http::parser::attribute(\"s2c_max_window_bits\",\"9\"));\n    ec = d.init(attributes);\n    BOOST_CHECK( !ec);\n\n    attributes.clear();\n    ec = d.init(attributes);\n    BOOST_CHECK( !ec);\n\n    processor::extensions::deflate_engine de;\n\n    unsigned char test_in[] = \"HelloHelloHelloHello\";\n    unsigned char test_out[30];\n\n    uLongf test_out_size = 30;\n\n    int ret;\n\n    ret = compress(test_out, &test_out_size, test_in, 20);\n\n    std::cout << ret << std::endl\n              << websocketpp::utility::to_hex(test_in,20) << std::endl\n              << websocketpp::utility::to_hex(test_out,test_out_size) << std::endl;\n\n    std::string input = \"Hello\";\n    std::string output;\n    ec = de.compress(input,output);\n\n    BOOST_CHECK( ec == processor::extensions::error::uninitialized );\n\n    //std::cout << ec.message() << websocketpp::utility::to_hex(output) << std::endl;\n\n    ec = de.init(15,15,Z_DEFAULT_COMPRESSION,8,Z_FIXED);\n    //ec = de.init();\n    BOOST_CHECK( !ec );\n\n    ec = de.compress(input,output);\n    std::cout << ec.message() << std::endl\n              << websocketpp::utility::to_hex(input) << std::endl\n              << websocketpp::utility::to_hex(output) << std::endl;\n\n    output.clear();\n\n    ec = de.compress(input,output);\n    std::cout << ec.message() << std::endl\n              << websocketpp::utility::to_hex(input) << std::endl\n              << websocketpp::utility::to_hex(output) << std::endl;\n\n    input = output;\n    output.clear();\n    ec = de.decompress(input,output);\n    std::cout << ec.message() << std::endl\n              << websocketpp::utility::to_hex(input) << std::endl\n              << websocketpp::utility::to_hex(output) << std::endl;\n    */\n}\n"
  },
  {
    "path": "test/processors/hybi00.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE hybi_00_processor\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/processors/hybi00.hpp>\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n#include <websocketpp/message_buffer/message.hpp>\n#include <websocketpp/message_buffer/alloc.hpp>\n\nstruct stub_config {\n    typedef websocketpp::http::parser::request request_type;\n    typedef websocketpp::http::parser::response response_type;\n\n    typedef websocketpp::message_buffer::message\n        <websocketpp::message_buffer::alloc::con_msg_manager> message_type;\n    typedef websocketpp::message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_manager_type;\n        \n    static const size_t max_message_size = 16000000;\n};\n\nstruct processor_setup {\n    processor_setup(bool server)\n      : msg_manager(new stub_config::con_msg_manager_type())\n      , p(false,server,msg_manager) {}\n\n    websocketpp::lib::error_code ec;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::request_type req;\n    stub_config::response_type res;\n    websocketpp::processor::hybi00<stub_config> p;\n};\n\ntypedef stub_config::message_type::ptr message_ptr;\n\nBOOST_AUTO_TEST_CASE( exact_match ) {\n    processor_setup env(true);\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nOrigin: http://example.com\\r\\nSec-WebSocket-Key1: 3e6b263  4 17 80\\r\\nSec-WebSocket-Key2: 17  9 G`ZD9   2 2b 7X 3 /r90\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n    env.req.replace_header(\"Sec-WebSocket-Key3\",\"WjN}|M(6\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(env.req));\n    BOOST_CHECK_EQUAL(websocketpp::processor::get_websocket_version(env.req), env.p.get_version());\n    env.ec = env.p.validate_handshake(env.req);\n    BOOST_CHECK(!env.ec);\n\n    websocketpp::uri_ptr u;\n\n    BOOST_CHECK_NO_THROW( u = env.p.get_uri(env.req) );\n\n    BOOST_CHECK_EQUAL(u->get_secure(), false);\n    BOOST_CHECK_EQUAL(u->get_host(), \"www.example.com\");\n    BOOST_CHECK_EQUAL(u->get_resource(), \"/\");\n    BOOST_CHECK_EQUAL(u->get_port(), websocketpp::uri_default_port);\n\n    env.p.process_handshake(env.req,\"\",env.res);\n\n    BOOST_CHECK_EQUAL(env.res.get_header(\"Connection\"), \"Upgrade\");\n    BOOST_CHECK_EQUAL(env.res.get_header(\"Upgrade\"), \"WebSocket\");\n    BOOST_CHECK_EQUAL(env.res.get_header(\"Sec-WebSocket-Origin\"), \"http://example.com\");\n\n    BOOST_CHECK_EQUAL(env.res.get_header(\"Sec-WebSocket-Location\"), \"ws://www.example.com/\");\n    BOOST_CHECK_EQUAL(env.res.get_header(\"Sec-WebSocket-Key3\"), \"n`9eBk9z$R8pOtVb\");\n}\n\nBOOST_AUTO_TEST_CASE( non_get_method ) {\n    processor_setup env(true);\n\n    std::string handshake = \"POST / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Key1: 3e6b263  4 17 80\\r\\nSec-WebSocket-Key2: 17  9 G`ZD9   2 2b 7X 3 /r90\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n    env.req.replace_header(\"Sec-WebSocket-Key3\",\"janelle!\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(env.req));\n    BOOST_CHECK_EQUAL(websocketpp::processor::get_websocket_version(env.req), env.p.get_version());\n    BOOST_CHECK_EQUAL( env.p.validate_handshake(env.req), websocketpp::processor::error::invalid_http_method );\n}\n\nBOOST_AUTO_TEST_CASE( old_http_version ) {\n    processor_setup env(true);\n\n    std::string handshake = \"GET / HTTP/1.0\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Key1: 3e6b263  4 17 80\\r\\nSec-WebSocket-Key2: 17  9 G`ZD9   2 2b 7X 3 /r90\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n    env.req.replace_header(\"Sec-WebSocket-Key3\",\"janelle!\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(env.req));\n    BOOST_CHECK_EQUAL(websocketpp::processor::get_websocket_version(env.req), env.p.get_version());\n    BOOST_CHECK_EQUAL( env.p.validate_handshake(env.req), websocketpp::processor::error::invalid_http_version );\n}\n\nBOOST_AUTO_TEST_CASE( missing_handshake_key1 ) {\n    processor_setup env(true);\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Key1: 3e6b263  4 17 80\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n    env.req.replace_header(\"Sec-WebSocket-Key3\",\"janelle!\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(env.req));\n    BOOST_CHECK_EQUAL(websocketpp::processor::get_websocket_version(env.req), env.p.get_version());\n    BOOST_CHECK_EQUAL( env.p.validate_handshake(env.req), websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( missing_handshake_key2 ) {\n    processor_setup env(true);\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Key2: 17  9 G`ZD9   2 2b 7X 3 /r90\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n    env.req.replace_header(\"Sec-WebSocket-Key3\",\"janelle!\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(env.req));\n    BOOST_CHECK_EQUAL(websocketpp::processor::get_websocket_version(env.req), env.p.get_version());\n    BOOST_CHECK_EQUAL( env.p.validate_handshake(env.req), websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( bad_host ) {\n    processor_setup env(true);\n    websocketpp::uri_ptr u;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com:70000\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nOrigin: http://example.com\\r\\nSec-WebSocket-Key1: 3e6b263  4 17 80\\r\\nSec-WebSocket-Key2: 17  9 G`ZD9   2 2b 7X 3 /r90\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n    env.req.replace_header(\"Sec-WebSocket-Key3\",\"janelle!\");\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(env.req));\n    BOOST_CHECK_EQUAL(websocketpp::processor::get_websocket_version(env.req), env.p.get_version());\n    BOOST_CHECK( !env.p.validate_handshake(env.req) );\n\n    BOOST_CHECK( !env.p.get_uri(env.req)->get_valid() );\n}\n\nBOOST_AUTO_TEST_CASE( extract_subprotocols ) {\n    processor_setup env(true);\n\n    std::vector<std::string> subps;\n\n    BOOST_CHECK( !env.p.extract_subprotocols(env.req,subps) );\n    BOOST_CHECK_EQUAL( subps.size(), 0 );\n}\n\nBOOST_AUTO_TEST_CASE( prepare_data_frame_null ) {\n    processor_setup env(true);\n\n    message_ptr in = env.msg_manager->get_message();\n    message_ptr out = env.msg_manager->get_message();\n    message_ptr invalid;\n\n\n    // empty pointers arguements should return sane error\n    BOOST_CHECK_EQUAL( env.p.prepare_data_frame(invalid,invalid), websocketpp::processor::error::invalid_arguments );\n\n    BOOST_CHECK_EQUAL( env.p.prepare_data_frame(in,invalid), websocketpp::processor::error::invalid_arguments );\n\n    BOOST_CHECK_EQUAL( env.p.prepare_data_frame(invalid,out), websocketpp::processor::error::invalid_arguments );\n\n    // test valid opcodes\n    // text (1) should be the only valid opcode\n    for (int i = 0; i < 0xF; i++) {\n        in->set_opcode(websocketpp::frame::opcode::value(i));\n\n        env.ec = env.p.prepare_data_frame(in,out);\n\n        if (i != 1) {\n            BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::invalid_opcode );\n        } else {\n            BOOST_CHECK_NE( env.ec, websocketpp::processor::error::invalid_opcode );\n        }\n    }\n\n    /*\n     * TODO: tests for invalid UTF8\n    char buf[2] = {0x00, 0x00};\n\n    in->set_opcode(websocketpp::frame::opcode::text);\n    in->set_payload(\"foo\");\n\n    env.ec = env.p.prepare_data_frame(in,out);\n    BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::invalid_payload );\n    */\n}\n\nBOOST_AUTO_TEST_CASE( prepare_data_frame ) {\n    processor_setup env(true);\n\n    message_ptr in = env.msg_manager->get_message();\n    message_ptr out = env.msg_manager->get_message();\n\n    in->set_opcode(websocketpp::frame::opcode::text);\n    in->set_payload(\"foo\");\n\n    env.ec = env.p.prepare_data_frame(in,out);\n\n    unsigned char raw_header[1] = {0x00};\n    unsigned char raw_payload[4] = {0x66,0x6f,0x6f,0xff};\n\n    BOOST_CHECK( !env.ec );\n    BOOST_CHECK_EQUAL( out->get_header(), std::string(reinterpret_cast<char*>(raw_header),1) );\n    BOOST_CHECK_EQUAL( out->get_payload(), std::string(reinterpret_cast<char*>(raw_payload),4) );\n}\n\n\nBOOST_AUTO_TEST_CASE( empty_consume ) {\n    uint8_t frame[2] = {0x00,0x00};\n\n    processor_setup env(true);\n\n    size_t ret = env.p.consume(frame,0,env.ec);\n\n    BOOST_CHECK_EQUAL( ret, 0);\n    BOOST_CHECK( !env.ec );\n    BOOST_CHECK_EQUAL( env.p.ready(), false );\n}\n\nBOOST_AUTO_TEST_CASE( empty_frame ) {\n    uint8_t frame[2] = {0x00, 0xff};\n\n    processor_setup env(true);\n\n    size_t ret = env.p.consume(frame,2,env.ec);\n\n    BOOST_CHECK_EQUAL( ret, 2);\n    BOOST_CHECK( !env.ec );\n    BOOST_CHECK_EQUAL( env.p.ready(), true );\n    BOOST_CHECK_EQUAL( env.p.get_message()->get_payload(), \"\" );\n    BOOST_CHECK_EQUAL( env.p.ready(), false );\n}\n\nBOOST_AUTO_TEST_CASE( short_frame ) {\n    uint8_t frame[5] = {0x00, 0x66, 0x6f, 0x6f, 0xff};\n\n    processor_setup env(true);\n\n    size_t ret = env.p.consume(frame,5,env.ec);\n\n    BOOST_CHECK_EQUAL( ret, 5);\n    BOOST_CHECK( !env.ec );\n    BOOST_CHECK_EQUAL( env.p.ready(), true );\n    BOOST_CHECK_EQUAL( env.p.get_message()->get_payload(), \"foo\" );\n    BOOST_CHECK_EQUAL( env.p.ready(), false );\n}\n"
  },
  {
    "path": "test/processors/hybi07.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE hybi_07_processor\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/processors/hybi07.hpp>\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n#include <websocketpp/message_buffer/message.hpp>\n#include <websocketpp/message_buffer/alloc.hpp>\n#include <websocketpp/extensions/permessage_deflate/disabled.hpp>\n#include <websocketpp/random/none.hpp>\n\nstruct stub_config {\n    typedef websocketpp::http::parser::request request_type;\n    typedef websocketpp::http::parser::response response_type;\n\n    typedef websocketpp::message_buffer::message\n        <websocketpp::message_buffer::alloc::con_msg_manager> message_type;\n    typedef websocketpp::message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_manager_type;\n\n    typedef websocketpp::random::none::int_generator<uint32_t> rng_type;\n\n    static const size_t max_message_size = 16000000;\n\n    /// Extension related config\n    static const bool enable_extensions = false;\n\n    /// Extension specific config\n\n    /// permessage_compress_config\n    struct permessage_deflate_config {\n        typedef stub_config::request_type request_type;\n    };\n\n    typedef websocketpp::extensions::permessage_deflate::disabled\n        <permessage_deflate_config> permessage_deflate_type;\n};\n\nBOOST_AUTO_TEST_CASE( exact_match ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi07<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 7\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK(!ec);\n\n    websocketpp::uri_ptr u;\n\n    u = p.get_uri(r);\n\n    BOOST_CHECK(u->get_valid());\n    BOOST_CHECK(!u->get_secure());\n    BOOST_CHECK_EQUAL(u->get_host(), \"www.example.com\");\n    BOOST_CHECK_EQUAL(u->get_resource(), \"/\");\n    BOOST_CHECK_EQUAL(u->get_port(), websocketpp::uri_default_port);\n\n    p.process_handshake(r,\"\",response);\n\n    BOOST_CHECK_EQUAL(response.get_header(\"Connection\"), \"Upgrade\");\n    BOOST_CHECK_EQUAL(response.get_header(\"Upgrade\"), \"websocket\");\n    BOOST_CHECK_EQUAL(response.get_header(\"Sec-WebSocket-Accept\"), \"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\");\n}\n\nBOOST_AUTO_TEST_CASE( non_get_method ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi07<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"POST / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 7\\r\\nSec-WebSocket-Key: foo\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK( ec == websocketpp::processor::error::invalid_http_method );\n}\n\nBOOST_AUTO_TEST_CASE( old_http_version ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi07<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"GET / HTTP/1.0\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 7\\r\\nSec-WebSocket-Key: foo\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK( ec == websocketpp::processor::error::invalid_http_version );\n}\n\nBOOST_AUTO_TEST_CASE( missing_handshake_key1 ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi07<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 7\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK( ec == websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( missing_handshake_key2 ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi07<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 7\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK( ec == websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( bad_host ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi07<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com:70000\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 7\\r\\nSec-WebSocket-Key: foo\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK( !ec );\n\n    BOOST_CHECK( !p.get_uri(r)->get_valid() );\n}\n"
  },
  {
    "path": "test/processors/hybi08.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE hybi_08_processor\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/processors/hybi08.hpp>\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n#include <websocketpp/message_buffer/message.hpp>\n#include <websocketpp/message_buffer/alloc.hpp>\n#include <websocketpp/extensions/permessage_deflate/disabled.hpp>\n#include <websocketpp/random/none.hpp>\n\nstruct stub_config {\n    typedef websocketpp::http::parser::request request_type;\n    typedef websocketpp::http::parser::response response_type;\n\n    typedef websocketpp::message_buffer::message\n        <websocketpp::message_buffer::alloc::con_msg_manager> message_type;\n    typedef websocketpp::message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_manager_type;\n\n    typedef websocketpp::random::none::int_generator<uint32_t> rng_type;\n\n    static const size_t max_message_size = 16000000;\n\n    /// Extension related config\n    static const bool enable_extensions = false;\n\n    /// Extension specific config\n\n    /// permessage_deflate_config\n    struct permessage_deflate_config {\n        typedef stub_config::request_type request_type;\n    };\n\n    typedef websocketpp::extensions::permessage_deflate::disabled\n        <permessage_deflate_config> permessage_deflate_type;\n};\n\nBOOST_AUTO_TEST_CASE( exact_match ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi08<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 8\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK(!ec);\n\n    websocketpp::uri_ptr u;\n\n    u = p.get_uri(r);\n\n    BOOST_CHECK(u->get_valid() == true);\n    BOOST_CHECK(u->get_secure() == false);\n    BOOST_CHECK(u->get_host() == \"www.example.com\");\n    BOOST_CHECK(u->get_resource() == \"/\");\n    BOOST_CHECK(u->get_port() == websocketpp::uri_default_port);\n\n    p.process_handshake(r,\"\",response);\n\n    BOOST_CHECK(response.get_header(\"Connection\") == \"Upgrade\");\n    BOOST_CHECK(response.get_header(\"Upgrade\") == \"websocket\");\n    BOOST_CHECK(response.get_header(\"Sec-WebSocket-Accept\") == \"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\");\n}\n\nBOOST_AUTO_TEST_CASE( non_get_method ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::rng_type rng;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    websocketpp::processor::hybi08<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"POST / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 8\\r\\nSec-WebSocket-Key: foo\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK( ec == websocketpp::processor::error::invalid_http_method );\n}\n\nBOOST_AUTO_TEST_CASE( old_http_version ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi08<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"GET / HTTP/1.0\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 8\\r\\nSec-WebSocket-Key: foo\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK( ec == websocketpp::processor::error::invalid_http_version );\n}\n\nBOOST_AUTO_TEST_CASE( missing_handshake_key1 ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi08<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 8\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK( ec == websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( missing_handshake_key2 ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi08<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 8\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK( ec == websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( bad_host ) {\n    stub_config::request_type r;\n    stub_config::response_type response;\n    stub_config::con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    websocketpp::processor::hybi08<stub_config> p(false,true,msg_manager,rng);\n    websocketpp::uri_ptr u;\n    websocketpp::lib::error_code ec;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com:70000\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 8\\r\\nSec-WebSocket-Key: foo\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == p.get_version());\n    ec = p.validate_handshake(r);\n    BOOST_CHECK( !ec );\n\n    u = p.get_uri(r);\n\n    BOOST_CHECK( !u->get_valid() );\n}\n\n"
  },
  {
    "path": "test/processors/hybi13.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE hybi_13_processor\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/processors/hybi13.hpp>\n\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n#include <websocketpp/message_buffer/message.hpp>\n#include <websocketpp/message_buffer/alloc.hpp>\n#include <websocketpp/random/none.hpp>\n\n#include <websocketpp/extensions/permessage_deflate/disabled.hpp>\n#include <websocketpp/extensions/permessage_deflate/enabled.hpp>\n\nstruct stub_config {\n    typedef websocketpp::http::parser::request request_type;\n    typedef websocketpp::http::parser::response response_type;\n\n    typedef websocketpp::message_buffer::message\n        <websocketpp::message_buffer::alloc::con_msg_manager> message_type;\n    typedef websocketpp::message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_manager_type;\n\n    typedef websocketpp::random::none::int_generator<uint32_t> rng_type;\n\n    struct permessage_deflate_config {\n        typedef stub_config::request_type request_type;\n    };\n\n    typedef websocketpp::extensions::permessage_deflate::disabled\n        <permessage_deflate_config> permessage_deflate_type;\n\n    static const size_t max_message_size = 16000000;\n    static const bool enable_extensions = false;\n};\n\nstruct stub_config_ext {\n    typedef websocketpp::http::parser::request request_type;\n    typedef websocketpp::http::parser::response response_type;\n\n    typedef websocketpp::message_buffer::message\n        <websocketpp::message_buffer::alloc::con_msg_manager> message_type;\n    typedef websocketpp::message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_manager_type;\n\n    typedef websocketpp::random::none::int_generator<uint32_t> rng_type;\n\n    struct permessage_deflate_config {\n        typedef stub_config_ext::request_type request_type;\n    };\n\n    typedef websocketpp::extensions::permessage_deflate::enabled\n        <permessage_deflate_config> permessage_deflate_type;\n\n    static const size_t max_message_size = 16000000;\n    static const bool enable_extensions = true;\n};\n\ntypedef stub_config::con_msg_manager_type con_msg_manager_type;\ntypedef stub_config::message_type::ptr message_ptr;\n\n// Set up a structure that constructs new copies of all of the support structure\n// for using connection processors\nstruct processor_setup {\n    processor_setup(bool server)\n      : msg_manager(new con_msg_manager_type())\n      , p(false,server,msg_manager,rng) {}\n\n    websocketpp::lib::error_code ec;\n    con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    stub_config::request_type req;\n    stub_config::response_type res;\n    websocketpp::processor::hybi13<stub_config> p;\n};\n\nstruct processor_setup_ext {\n    processor_setup_ext(bool server)\n      : msg_manager(new con_msg_manager_type())\n      , p(false,server,msg_manager,rng) {}\n\n    websocketpp::lib::error_code ec;\n    con_msg_manager_type::ptr msg_manager;\n    stub_config::rng_type rng;\n    stub_config::request_type req;\n    stub_config::response_type res;\n    websocketpp::processor::hybi13<stub_config_ext> p;\n};\n\nBOOST_AUTO_TEST_CASE( exact_match ) {\n    processor_setup env(true);\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(env.req));\n    BOOST_CHECK_EQUAL(websocketpp::processor::get_websocket_version(env.req), env.p.get_version());\n    BOOST_CHECK(!env.p.validate_handshake(env.req));\n\n    websocketpp::uri_ptr u;\n\n    BOOST_CHECK_NO_THROW( u = env.p.get_uri(env.req) );\n\n    BOOST_CHECK_EQUAL(u->get_secure(), false);\n    BOOST_CHECK_EQUAL(u->get_host(), \"www.example.com\");\n    BOOST_CHECK_EQUAL(u->get_resource(), \"/\");\n    BOOST_CHECK_EQUAL(u->get_port(), websocketpp::uri_default_port);\n\n    env.p.process_handshake(env.req,\"\",env.res);\n\n    BOOST_CHECK_EQUAL(env.res.get_header(\"Connection\"), \"Upgrade\");\n    BOOST_CHECK_EQUAL(env.res.get_header(\"Upgrade\"), \"websocket\");\n    BOOST_CHECK_EQUAL(env.res.get_header(\"Sec-WebSocket-Accept\"), \"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\");\n}\n\nBOOST_AUTO_TEST_CASE( non_get_method ) {\n    processor_setup env(true);\n\n    std::string handshake = \"POST / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: foo\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(env.req));\n    BOOST_CHECK_EQUAL(websocketpp::processor::get_websocket_version(env.req), env.p.get_version());\n    BOOST_CHECK( env.p.validate_handshake(env.req) == websocketpp::processor::error::invalid_http_method );\n}\n\nBOOST_AUTO_TEST_CASE( old_http_version ) {\n    processor_setup env(true);\n\n    std::string handshake = \"GET / HTTP/1.0\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: foo\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(env.req));\n    BOOST_CHECK_EQUAL(websocketpp::processor::get_websocket_version(env.req), env.p.get_version());\n    BOOST_CHECK_EQUAL( env.p.validate_handshake(env.req), websocketpp::processor::error::invalid_http_version );\n}\n\nBOOST_AUTO_TEST_CASE( missing_handshake_key1 ) {\n    processor_setup env(true);\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK( websocketpp::processor::is_websocket_handshake(env.req) );\n    BOOST_CHECK_EQUAL( websocketpp::processor::get_websocket_version(env.req), env.p.get_version() );\n    BOOST_CHECK_EQUAL( env.p.validate_handshake(env.req), websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( missing_handshake_key2 ) {\n    processor_setup env(true);\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK( websocketpp::processor::is_websocket_handshake(env.req) );\n    BOOST_CHECK_EQUAL( websocketpp::processor::get_websocket_version(env.req), env.p.get_version() );\n    BOOST_CHECK_EQUAL( env.p.validate_handshake(env.req), websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( bad_host ) {\n    processor_setup env(true);\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com:70000\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: foo\\r\\n\\r\\n\";\n\n    env.req.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK( websocketpp::processor::is_websocket_handshake(env.req) );\n    BOOST_CHECK_EQUAL( websocketpp::processor::get_websocket_version(env.req), env.p.get_version() );\n    BOOST_CHECK( !env.p.validate_handshake(env.req) );\n    BOOST_CHECK( !env.p.get_uri(env.req)->get_valid() );\n}\n\n// FRAME TESTS TO DO\n//\n// unmasked, 0 length, binary\n// 0x82 0x00\n//\n// masked, 0 length, binary\n// 0x82 0x80\n//\n// unmasked, 0 length, text\n// 0x81 0x00\n//\n// masked, 0 length, text\n// 0x81 0x80\n\nBOOST_AUTO_TEST_CASE( frame_empty_binary_unmasked ) {\n    uint8_t frame[2] = {0x82, 0x00};\n\n    // all in one chunk\n    processor_setup env1(false);\n\n    size_t ret1 = env1.p.consume(frame,2,env1.ec);\n\n    BOOST_CHECK_EQUAL( ret1, 2 );\n    BOOST_CHECK( !env1.ec );\n    BOOST_CHECK_EQUAL( env1.p.ready(), true );\n\n    // two separate chunks\n    processor_setup env2(false);\n\n    BOOST_CHECK_EQUAL( env2.p.consume(frame,1,env2.ec), 1 );\n    BOOST_CHECK( !env2.ec );\n    BOOST_CHECK_EQUAL( env2.p.ready(), false );\n\n    BOOST_CHECK_EQUAL( env2.p.consume(frame+1,1,env2.ec), 1 );\n    BOOST_CHECK( !env2.ec );\n    BOOST_CHECK_EQUAL( env2.p.ready(), true );\n}\n\nBOOST_AUTO_TEST_CASE( frame_small_binary_unmasked ) {\n    processor_setup env(false);\n\n    uint8_t frame[4] = {0x82, 0x02, 0x2A, 0x2A};\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( env.p.consume(frame,4,env.ec), 4 );\n    BOOST_CHECK( !env.ec );\n    BOOST_CHECK_EQUAL( env.p.ready(), true );\n\n    message_ptr foo = env.p.get_message();\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( foo->get_payload(), \"**\" );\n\n}\n\nBOOST_AUTO_TEST_CASE( frame_extended_binary_unmasked ) {\n    processor_setup env(false);\n\n    uint8_t frame[130] = {0x82, 0x7E, 0x00, 0x7E};\n    frame[0] = 0x82;\n    frame[1] = 0x7E;\n    frame[2] = 0x00;\n    frame[3] = 0x7E;\n    std::fill_n(frame+4,126,0x2A);\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( env.p.consume(frame,130,env.ec), 130 );\n    BOOST_CHECK( !env.ec );\n    BOOST_CHECK_EQUAL( env.p.ready(), true );\n\n    message_ptr foo = env.p.get_message();\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( foo->get_payload().size(), 126 );\n}\n\nBOOST_AUTO_TEST_CASE( frame_jumbo_binary_unmasked ) {\n    processor_setup env(false);\n\n    uint8_t frame[130] = {0x82, 0x7E, 0x00, 0x7E};\n    std::fill_n(frame+4,126,0x2A);\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( env.p.consume(frame,130,env.ec), 130 );\n    BOOST_CHECK( !env.ec );\n    BOOST_CHECK_EQUAL( env.p.ready(), true );\n\n    message_ptr foo = env.p.get_message();\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( foo->get_payload().size(), 126 );\n}\n\nBOOST_AUTO_TEST_CASE( control_frame_too_large ) {\n    processor_setup env(false);\n\n    uint8_t frame[130] = {0x88, 0x7E, 0x00, 0x7E};\n    std::fill_n(frame+4,126,0x2A);\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_GT( env.p.consume(frame,130,env.ec), 0 );\n    BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::control_too_big  );\n    BOOST_CHECK_EQUAL( env.p.ready(), false );\n}\n\nBOOST_AUTO_TEST_CASE( rsv_bits_used ) {\n    uint8_t frame[3][2] = {{0x90, 0x00},\n                           {0xA0, 0x00},\n                           {0xC0, 0x00}};\n\n    for (int i = 0; i < 3; i++) {\n        processor_setup env(false);\n\n        BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n        BOOST_CHECK_GT( env.p.consume(frame[i],2,env.ec), 0 );\n        BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::invalid_rsv_bit  );\n        BOOST_CHECK_EQUAL( env.p.ready(), false );\n    }\n}\n\n\nBOOST_AUTO_TEST_CASE( reserved_opcode_used ) {\n    uint8_t frame[10][2] = {{0x83, 0x00},\n                            {0x84, 0x00},\n                            {0x85, 0x00},\n                            {0x86, 0x00},\n                            {0x87, 0x00},\n                            {0x8B, 0x00},\n                            {0x8C, 0x00},\n                            {0x8D, 0x00},\n                            {0x8E, 0x00},\n                            {0x8F, 0x00}};\n\n    for (int i = 0; i < 10; i++) {\n        processor_setup env(false);\n\n        BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n        BOOST_CHECK_GT( env.p.consume(frame[i],2,env.ec), 0 );\n        BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::invalid_opcode  );\n        BOOST_CHECK_EQUAL( env.p.ready(), false );\n    }\n}\n\nBOOST_AUTO_TEST_CASE( fragmented_control_message ) {\n    processor_setup env(false);\n\n    uint8_t frame[2] = {0x08, 0x00};\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_GT( env.p.consume(frame,2,env.ec), 0 );\n    BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::fragmented_control );\n    BOOST_CHECK_EQUAL( env.p.ready(), false );\n}\n\nBOOST_AUTO_TEST_CASE( fragmented_binary_message ) {\n    processor_setup env0(false);\n    processor_setup env1(false);\n\n    uint8_t frame0[6] = {0x02, 0x01, 0x2A, 0x80, 0x01, 0x2A};\n    uint8_t frame1[8] = {0x02, 0x01, 0x2A, 0x89, 0x00, 0x80, 0x01, 0x2A};\n\n    // read fragmented message in one chunk\n    BOOST_CHECK_EQUAL( env0.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( env0.p.consume(frame0,6,env0.ec), 6 );\n    BOOST_CHECK( !env0.ec );\n    BOOST_CHECK_EQUAL( env0.p.ready(), true );\n    BOOST_CHECK_EQUAL( env0.p.get_message()->get_payload(), \"**\" );\n\n    // read fragmented message in two chunks\n    BOOST_CHECK_EQUAL( env0.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( env0.p.consume(frame0,3,env0.ec), 3 );\n    BOOST_CHECK( !env0.ec );\n    BOOST_CHECK_EQUAL( env0.p.ready(), false );\n    BOOST_CHECK_EQUAL( env0.p.consume(frame0+3,3,env0.ec), 3 );\n    BOOST_CHECK( !env0.ec );\n    BOOST_CHECK_EQUAL( env0.p.ready(), true );\n    BOOST_CHECK_EQUAL( env0.p.get_message()->get_payload(), \"**\" );\n\n    // read fragmented message with control message in between\n    BOOST_CHECK_EQUAL( env0.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( env0.p.consume(frame1,8,env0.ec), 5 );\n    BOOST_CHECK( !env0.ec );\n    BOOST_CHECK_EQUAL( env0.p.ready(), true );\n    BOOST_CHECK_EQUAL( env0.p.get_message()->get_opcode(), websocketpp::frame::opcode::PING);\n    BOOST_CHECK_EQUAL( env0.p.consume(frame1+5,3,env0.ec), 3 );\n    BOOST_CHECK( !env0.ec );\n    BOOST_CHECK_EQUAL( env0.p.ready(), true );\n    BOOST_CHECK_EQUAL( env0.p.get_message()->get_payload(), \"**\" );\n\n    // read lone continuation frame\n    BOOST_CHECK_EQUAL( env0.p.get_message(), message_ptr() );\n    BOOST_CHECK_GT( env0.p.consume(frame0+3,3,env0.ec), 0);\n    BOOST_CHECK_EQUAL( env0.ec, websocketpp::processor::error::invalid_continuation );\n\n    // read two start frames in a row\n    BOOST_CHECK_EQUAL( env1.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( env1.p.consume(frame0,3,env1.ec), 3);\n    BOOST_CHECK( !env1.ec );\n    BOOST_CHECK_GT( env1.p.consume(frame0,3,env1.ec), 0);\n    BOOST_CHECK_EQUAL( env1.ec, websocketpp::processor::error::invalid_continuation );\n}\n\nBOOST_AUTO_TEST_CASE( unmasked_client_frame ) {\n    processor_setup env(true);\n\n    uint8_t frame[2] = {0x82, 0x00};\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_GT( env.p.consume(frame,2,env.ec), 0 );\n    BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::masking_required );\n    BOOST_CHECK_EQUAL( env.p.ready(), false );\n}\n\nBOOST_AUTO_TEST_CASE( masked_server_frame ) {\n    processor_setup env(false);\n\n    uint8_t frame[8] = {0x82, 0x82, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xD5};\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_GT( env.p.consume(frame,8,env.ec), 0 );\n    BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::masking_forbidden );\n    BOOST_CHECK_EQUAL( env.p.ready(), false );\n}\n\nBOOST_AUTO_TEST_CASE( frame_small_binary_masked ) {\n    processor_setup env(true);\n\n    uint8_t frame[8] = {0x82, 0x82, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xD5};\n\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( env.p.consume(frame,8,env.ec), 8 );\n    BOOST_CHECK( !env.ec );\n    BOOST_CHECK_EQUAL( env.p.ready(), true );\n    BOOST_CHECK_EQUAL( env.p.get_message()->get_payload(), \"**\" );\n}\n\nBOOST_AUTO_TEST_CASE( masked_fragmented_binary_message ) {\n    processor_setup env(true);\n\n    uint8_t frame0[14] = {0x02, 0x81, 0xAB, 0x23, 0x98, 0x45, 0x81,\n                         0x80, 0x81, 0xB8, 0x34, 0x12, 0xFF, 0x92};\n\n    // read fragmented message in one chunk\n    BOOST_CHECK_EQUAL( env.p.get_message(), message_ptr() );\n    BOOST_CHECK_EQUAL( env.p.consume(frame0,14,env.ec), 14 );\n    BOOST_CHECK( !env.ec );\n    BOOST_CHECK_EQUAL( env.p.ready(), true );\n    BOOST_CHECK_EQUAL( env.p.get_message()->get_payload(), \"**\" );\n}\n\nBOOST_AUTO_TEST_CASE( prepare_data_frame ) {\n    processor_setup env(true);\n\n    message_ptr in = env.msg_manager->get_message();\n    message_ptr out = env.msg_manager->get_message();\n    message_ptr invalid;\n\n    // empty pointers arguements should return sane error\n    BOOST_CHECK_EQUAL( env.p.prepare_data_frame(invalid,invalid), websocketpp::processor::error::invalid_arguments );\n\n    BOOST_CHECK_EQUAL( env.p.prepare_data_frame(in,invalid), websocketpp::processor::error::invalid_arguments );\n\n    BOOST_CHECK_EQUAL( env.p.prepare_data_frame(invalid,out), websocketpp::processor::error::invalid_arguments );\n\n    // test valid opcodes\n    // control opcodes should return an error, data ones shouldn't\n    for (int i = 0; i < 0xF; i++) {\n        in->set_opcode(websocketpp::frame::opcode::value(i));\n\n        env.ec = env.p.prepare_data_frame(in,out);\n\n        if (websocketpp::frame::opcode::is_control(in->get_opcode())) {\n            BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::invalid_opcode );\n        } else {\n            BOOST_CHECK_NE( env.ec, websocketpp::processor::error::invalid_opcode );\n        }\n    }\n\n\n    //in.set_payload(\"foo\");\n\n    //e = prepare_data_frame(in,out);\n\n\n}\n\nBOOST_AUTO_TEST_CASE( single_frame_message_too_large ) {\n    processor_setup env(true);\n    \n    env.p.set_max_message_size(3);\n    \n    uint8_t frame0[10] = {0x82, 0x84, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01};\n\n    // read message that is one byte too large\n    BOOST_CHECK_EQUAL( env.p.consume(frame0,10,env.ec), 6 );\n    BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::message_too_big );\n}\n\nBOOST_AUTO_TEST_CASE( multiple_frame_message_too_large ) {\n    processor_setup env(true);\n    \n    env.p.set_max_message_size(4);\n    \n    uint8_t frame0[8] = {0x02, 0x82, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01};\n    uint8_t frame1[9] = {0x80, 0x83, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01};\n\n    // read first message frame with size under the limit\n    BOOST_CHECK_EQUAL( env.p.consume(frame0,8,env.ec), 8 );\n    BOOST_CHECK( !env.ec );\n    \n    // read second message frame that puts the size over the limit\n    BOOST_CHECK_EQUAL( env.p.consume(frame1,9,env.ec), 6 );\n    BOOST_CHECK_EQUAL( env.ec, websocketpp::processor::error::message_too_big );\n}\n\n\n\nBOOST_AUTO_TEST_CASE( client_handshake_request ) {\n    processor_setup env(false);\n\n    websocketpp::uri_ptr u(new websocketpp::uri(\"ws://localhost/\"));\n\n    env.p.client_handshake_request(env.req,u, std::vector<std::string>());\n\n    BOOST_CHECK_EQUAL( env.req.get_method(), \"GET\" );\n    BOOST_CHECK_EQUAL( env.req.get_version(), \"HTTP/1.1\");\n    BOOST_CHECK_EQUAL( env.req.get_uri(), \"/\");\n\n    BOOST_CHECK_EQUAL( env.req.get_header(\"Host\"), \"localhost\");\n    BOOST_CHECK_EQUAL( env.req.get_header(\"Sec-WebSocket-Version\"), \"13\");\n    BOOST_CHECK_EQUAL( env.req.get_header(\"Connection\"), \"Upgrade\");\n    BOOST_CHECK_EQUAL( env.req.get_header(\"Upgrade\"), \"websocket\");\n}\n\n// TODO:\n// test cases\n// - adding headers\n// - adding Upgrade header\n// - adding Connection header\n// - adding Sec-WebSocket-Version, Sec-WebSocket-Key, or Host header\n// - other Sec* headers?\n// - User Agent header?\n\n// Origin support\n// Subprotocol requests\n\n//websocketpp::uri_ptr u(new websocketpp::uri(\"ws://localhost/\"));\n    //env.p.client_handshake_request(env.req,u);\n\nBOOST_AUTO_TEST_CASE( client_handshake_response_404 ) {\n    processor_setup env(false);\n\n    std::string res = \"HTTP/1.1 404 Not Found\\r\\n\\r\\n\";\n    env.res.consume(res.data(),res.size());\n\n    BOOST_CHECK_EQUAL( env.p.validate_server_handshake_response(env.req,env.res), websocketpp::processor::error::invalid_http_status );\n}\n\nBOOST_AUTO_TEST_CASE( client_handshake_response_no_upgrade ) {\n    processor_setup env(false);\n\n    std::string res = \"HTTP/1.1 101 Switching Protocols\\r\\n\\r\\n\";\n    env.res.consume(res.data(),res.size());\n\n    BOOST_CHECK_EQUAL( env.p.validate_server_handshake_response(env.req,env.res), websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( client_handshake_response_no_connection ) {\n    processor_setup env(false);\n\n    std::string res = \"HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: foo, wEbsOckEt\\r\\n\\r\\n\";\n    env.res.consume(res.data(),res.size());\n\n    BOOST_CHECK_EQUAL( env.p.validate_server_handshake_response(env.req,env.res), websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( client_handshake_response_no_accept ) {\n    processor_setup env(false);\n\n    std::string res = \"HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: foo, wEbsOckEt\\r\\nConnection: bar, UpGrAdE\\r\\n\\r\\n\";\n    env.res.consume(res.data(),res.size());\n\n    BOOST_CHECK_EQUAL( env.p.validate_server_handshake_response(env.req,env.res), websocketpp::processor::error::missing_required_header );\n}\n\nBOOST_AUTO_TEST_CASE( client_handshake_response ) {\n    processor_setup env(false);\n\n    env.req.append_header(\"Sec-WebSocket-Key\", \"dGhlIHNhbXBsZSBub25jZQ==\");\n\n    std::string res = \"HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: foo, wEbsOckEt\\r\\nConnection: bar, UpGrAdE\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\n\\r\\n\";\n    env.res.consume(res.data(),res.size());\n\n    BOOST_CHECK( !env.p.validate_server_handshake_response(env.req,env.res) );\n}\n\nBOOST_AUTO_TEST_CASE( extensions_disabled ) {\n    processor_setup env(true);\n\n    env.req.replace_header(\"Sec-WebSocket-Extensions\",\"\");\n\n    std::pair<websocketpp::lib::error_code,std::string> neg_results;\n    neg_results = env.p.negotiate_extensions(env.req);\n\n    BOOST_CHECK_EQUAL( neg_results.first, websocketpp::processor::error::extensions_disabled );\n    BOOST_CHECK_EQUAL( neg_results.second, \"\" );\n}\n\nBOOST_AUTO_TEST_CASE( extension_negotiation_blank ) {\n    processor_setup_ext env(true);\n\n    env.req.replace_header(\"Sec-WebSocket-Extensions\",\"\");\n\n    std::pair<websocketpp::lib::error_code,std::string> neg_results;\n    neg_results = env.p.negotiate_extensions(env.req);\n\n    BOOST_CHECK( !neg_results.first );\n    BOOST_CHECK_EQUAL( neg_results.second, \"\" );\n}\n\nBOOST_AUTO_TEST_CASE( extension_negotiation_unknown ) {\n    processor_setup_ext env(true);\n\n    env.req.replace_header(\"Sec-WebSocket-Extensions\",\"foo\");\n\n    std::pair<websocketpp::lib::error_code,std::string> neg_results;\n    neg_results = env.p.negotiate_extensions(env.req);\n\n    BOOST_CHECK( !neg_results.first );\n    BOOST_CHECK_EQUAL( neg_results.second, \"\" );\n}\n\nBOOST_AUTO_TEST_CASE( extract_subprotocols_empty ) {\n    processor_setup env(true);\n    std::vector<std::string> subps;\n\n    BOOST_CHECK( !env.p.extract_subprotocols(env.req,subps) );\n    BOOST_CHECK_EQUAL( subps.size(), 0 );\n}\n\nBOOST_AUTO_TEST_CASE( extract_subprotocols_one ) {\n    processor_setup env(true);\n    std::vector<std::string> subps;\n\n    env.req.replace_header(\"Sec-WebSocket-Protocol\",\"foo\");\n\n    BOOST_CHECK( !env.p.extract_subprotocols(env.req,subps) );\n    BOOST_REQUIRE_EQUAL( subps.size(), 1 );\n    BOOST_CHECK_EQUAL( subps[0], \"foo\" );\n}\n\nBOOST_AUTO_TEST_CASE( extract_subprotocols_multiple ) {\n    processor_setup env(true);\n    std::vector<std::string> subps;\n\n    env.req.replace_header(\"Sec-WebSocket-Protocol\",\"foo,bar\");\n\n    BOOST_CHECK( !env.p.extract_subprotocols(env.req,subps) );\n    BOOST_REQUIRE_EQUAL( subps.size(), 2 );\n    BOOST_CHECK_EQUAL( subps[0], \"foo\" );\n    BOOST_CHECK_EQUAL( subps[1], \"bar\" );\n}\n\nBOOST_AUTO_TEST_CASE( extract_subprotocols_invalid) {\n    processor_setup env(true);\n    std::vector<std::string> subps;\n\n    env.req.replace_header(\"Sec-WebSocket-Protocol\",\"foo,bar,,,,\");\n\n    BOOST_CHECK_EQUAL( env.p.extract_subprotocols(env.req,subps), websocketpp::processor::error::make_error_code(websocketpp::processor::error::subprotocol_parse_error) );\n    BOOST_CHECK_EQUAL( subps.size(), 0 );\n}\n\nBOOST_AUTO_TEST_CASE( extension_negotiation_permessage_deflate ) {\n    processor_setup_ext env(true);\n\n    env.req.replace_header(\"Sec-WebSocket-Extensions\",\n        \"permessage-deflate; client_max_window_bits\");\n\n    std::pair<websocketpp::lib::error_code,std::string> neg_results;\n    neg_results = env.p.negotiate_extensions(env.req);\n\n    BOOST_CHECK( !neg_results.first );\n    BOOST_CHECK_EQUAL( neg_results.second, \"permessage-deflate\" );\n}\n\n"
  },
  {
    "path": "test/processors/processor.cpp",
    "content": "/*\n * Copyright (c) 2011, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE processors\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/processors/processor.hpp>\n#include <websocketpp/http/request.hpp>\n\nBOOST_AUTO_TEST_CASE( exact_match ) {\n    websocketpp::http::parser::request r;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n}\n\nBOOST_AUTO_TEST_CASE( non_match ) {\n    websocketpp::http::parser::request r;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\n\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(!websocketpp::processor::is_websocket_handshake(r));\n}\n\nBOOST_AUTO_TEST_CASE( ci_exact_match ) {\n    websocketpp::http::parser::request r;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: UpGrAde\\r\\nUpgrade: WebSocket\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n}\n\nBOOST_AUTO_TEST_CASE( non_exact_match1 ) {\n    websocketpp::http::parser::request r;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade,foo\\r\\nUpgrade: websocket,foo\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n}\n\nBOOST_AUTO_TEST_CASE( non_exact_match2 ) {\n    websocketpp::http::parser::request r;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: keep-alive,Upgrade,foo\\r\\nUpgrade: foo,websocket,bar\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::is_websocket_handshake(r));\n}\n\nBOOST_AUTO_TEST_CASE( version_blank ) {\n    websocketpp::http::parser::request r;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == 0);\n}\n\nBOOST_AUTO_TEST_CASE( version_7 ) {\n    websocketpp::http::parser::request r;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 7\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == 7);\n}\n\nBOOST_AUTO_TEST_CASE( version_8 ) {\n    websocketpp::http::parser::request r;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 8\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == 8);\n}\n\nBOOST_AUTO_TEST_CASE( version_13 ) {\n    websocketpp::http::parser::request r;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == 13);\n}\n\nBOOST_AUTO_TEST_CASE( version_non_numeric ) {\n    websocketpp::http::parser::request r;\n\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: abc\\r\\n\\r\\n\";\n\n    r.consume(handshake.c_str(),handshake.size());\n\n    BOOST_CHECK(websocketpp::processor::get_websocket_version(r) == -1);\n}"
  },
  {
    "path": "test/random/CMakeLists.txt",
    "content": "# Test RNG policy none\nfile (GLOB SOURCE none.cpp)\n\ninit_target (test_random_none)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test RNG policy random_device\nfile (GLOB SOURCE random_device.cpp)\n\ninit_target (test_random_random_device)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n"
  },
  {
    "path": "test/random/SConscript",
    "content": "## random number generation unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','random','system'],env) + [platform_libs]\n\nobjs = env.Object('random_none_boost.o', [\"none.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('random_device_boost.o', [\"random_device.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_random_none_boost', [\"random_none_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_random_device_boost', [\"random_device_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   objs += env_cpp11.Object('random_none_stl.o', [\"none.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('random_device_stl.o', [\"random_device.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_random_none_stl', [\"random_none_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_random_device_stl', [\"random_device_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/random/none.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE random_none\n#include <boost/test/unit_test.hpp>\n\n#include <websocketpp/common/stdint.hpp>\n#include <websocketpp/random/none.hpp>\n\nBOOST_AUTO_TEST_CASE( does_it_compile ) {\n    websocketpp::random::none::int_generator<int32_t> rng;\n\n    int32_t foo = rng();\n\n    BOOST_CHECK( foo == 0 );\n}\n"
  },
  {
    "path": "test/random/random_device.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE random_device\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n\n#include <websocketpp/common/stdint.hpp>\n#include <websocketpp/random/random_device.hpp>\n#include <websocketpp/concurrency/none.hpp>\n\nBOOST_AUTO_TEST_CASE( compiles ) {\n    websocketpp::random::random_device::int_generator<int32_t,websocketpp::concurrency::none> rng;\n\n    bool e = false;\n\n    try {\n        int32_t foo = rng();\n        std::cout << foo << std::endl;\n    } catch (...) {\n        e = true;\n    }\n\n    BOOST_CHECK( e == false );\n}\n"
  },
  {
    "path": "test/roles/CMakeLists.txt",
    "content": "# Test client role\nfile (GLOB SOURCE client.cpp)\n\ninit_target (test_roles_client)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test server role\nfile (GLOB SOURCE server.cpp)\n\ninit_target (test_roles_server)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n"
  },
  {
    "path": "test/roles/SConscript",
    "content": "## role unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system','random'],env) + [platform_libs]\n\nobjs = env.Object('client_boost.o', [\"client.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('server_boost.o', [\"server.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_client_boost', [\"client_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_server_boost', [\"server_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   objs += env_cpp11.Object('client_stl.o', [\"client.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('server_stl.o', [\"server.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_client_stl', [\"client_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_server_stl', [\"server_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/roles/client.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE client\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n\n#include <websocketpp/random/random_device.hpp>\n\n#include <websocketpp/config/core.hpp>\n#include <websocketpp/client.hpp>\n\n#include <websocketpp/http/request.hpp>\n\nstruct stub_config : public websocketpp::config::core {\n    typedef core::concurrency_type concurrency_type;\n\n    typedef core::request_type request_type;\n    typedef core::response_type response_type;\n\n    typedef core::message_type message_type;\n    typedef core::con_msg_manager_type con_msg_manager_type;\n    typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef core::alog_type alog_type;\n    typedef core::elog_type elog_type;\n\n    //typedef core::rng_type rng_type;\n    typedef websocketpp::random::random_device::int_generator<uint32_t,concurrency_type> rng_type;\n\n    typedef core::transport_type transport_type;\n\n    typedef core::endpoint_base endpoint_base;\n\n    static const websocketpp::log::level elog_level = websocketpp::log::elevel::none;\n    static const websocketpp::log::level alog_level = websocketpp::log::alevel::none;\n};\n\ntypedef websocketpp::client<stub_config> client;\ntypedef client::connection_ptr connection_ptr;\n\nBOOST_AUTO_TEST_CASE( invalid_uri ) {\n    client c;\n    websocketpp::lib::error_code ec;\n\n    connection_ptr con = c.get_connection(\"foo\", ec);\n\n    BOOST_CHECK_EQUAL( ec , websocketpp::error::make_error_code(websocketpp::error::invalid_uri) );\n}\n\nBOOST_AUTO_TEST_CASE( unsecure_endpoint ) {\n    client c;\n    websocketpp::lib::error_code ec;\n\n    connection_ptr con = c.get_connection(\"wss://localhost/\", ec);\n\n    BOOST_CHECK_EQUAL( ec , websocketpp::error::make_error_code(websocketpp::error::endpoint_not_secure) );\n}\n\nBOOST_AUTO_TEST_CASE( get_connection ) {\n    client c;\n    websocketpp::lib::error_code ec;\n\n    connection_ptr con = c.get_connection(\"ws://localhost/\", ec);\n\n    BOOST_CHECK( con );\n    BOOST_CHECK_EQUAL( con->get_host() , \"localhost\" );\n    BOOST_CHECK_EQUAL( con->get_port() , 80 );\n    BOOST_CHECK_EQUAL( con->get_secure() , false );\n    BOOST_CHECK_EQUAL( con->get_resource() , \"/\" );\n}\n\nBOOST_AUTO_TEST_CASE( connect_con ) {\n    client c;\n    websocketpp::lib::error_code ec;\n    std::stringstream out;\n    std::string o;\n\n    c.register_ostream(&out);\n\n    connection_ptr con = c.get_connection(\"ws://localhost/\", ec);\n    c.connect(con);\n\n    o = out.str();\n    websocketpp::http::parser::request r;\n    r.consume(o.data(),o.size());\n\n    BOOST_CHECK( r.ready() );\n    BOOST_CHECK_EQUAL( r.get_method(), \"GET\");\n    BOOST_CHECK_EQUAL( r.get_version(), \"HTTP/1.1\");\n    BOOST_CHECK_EQUAL( r.get_uri(), \"/\");\n\n    BOOST_CHECK_EQUAL( r.get_header(\"Host\"), \"localhost\");\n    BOOST_CHECK_EQUAL( r.get_header(\"Sec-WebSocket-Version\"), \"13\");\n    BOOST_CHECK_EQUAL( r.get_header(\"Connection\"), \"Upgrade\");\n    BOOST_CHECK_EQUAL( r.get_header(\"Upgrade\"), \"websocket\");\n\n    // Key is randomly generated & User-Agent will change so just check that\n    // they are not empty.\n    BOOST_CHECK_NE( r.get_header(\"Sec-WebSocket-Key\"), \"\");\n    BOOST_CHECK_NE( r.get_header(\"User-Agent\"), \"\" );\n\n    // connection should have written out an opening handshake request and be in\n    // the read response internal state\n\n    // TODO: more tests related to reading the HTTP response\n    std::stringstream channel2;\n    channel2 << \"e\\r\\n\\r\\n\";\n    channel2 >> *con;\n}\n\nBOOST_AUTO_TEST_CASE( select_subprotocol ) {\n    client c;\n    websocketpp::lib::error_code ec;\n    using websocketpp::error::make_error_code;\n\n    connection_ptr con = c.get_connection(\"ws://localhost/\", ec);\n\n    BOOST_CHECK( con );\n\n    con->select_subprotocol(\"foo\",ec);\n    BOOST_CHECK_EQUAL( ec , make_error_code(websocketpp::error::server_only) );\n    BOOST_CHECK_THROW( con->select_subprotocol(\"foo\") , websocketpp::exception );\n}\n\nBOOST_AUTO_TEST_CASE( add_subprotocols_invalid ) {\n    client c;\n    websocketpp::lib::error_code ec;\n    using websocketpp::error::make_error_code;\n\n    connection_ptr con = c.get_connection(\"ws://localhost/\", ec);\n    BOOST_CHECK( con );\n\n    con->add_subprotocol(\"\",ec);\n    BOOST_CHECK_EQUAL( ec , make_error_code(websocketpp::error::invalid_subprotocol) );\n    BOOST_CHECK_THROW( con->add_subprotocol(\"\") , websocketpp::exception );\n\n    con->add_subprotocol(\"foo,bar\",ec);\n    BOOST_CHECK_EQUAL( ec , make_error_code(websocketpp::error::invalid_subprotocol) );\n    BOOST_CHECK_THROW( con->add_subprotocol(\"foo,bar\") , websocketpp::exception );\n}\n\nBOOST_AUTO_TEST_CASE( add_subprotocols ) {\n    client c;\n    websocketpp::lib::error_code ec;\n    std::stringstream out;\n    std::string o;\n\n    c.register_ostream(&out);\n\n    connection_ptr con = c.get_connection(\"ws://localhost/\", ec);\n    BOOST_CHECK( con );\n\n    con->add_subprotocol(\"foo\",ec);\n    BOOST_CHECK( !ec );\n\n    BOOST_CHECK_NO_THROW( con->add_subprotocol(\"bar\") );\n\n    c.connect(con);\n\n    o = out.str();\n    websocketpp::http::parser::request r;\n    r.consume(o.data(),o.size());\n\n    BOOST_CHECK( r.ready() );\n    BOOST_CHECK_EQUAL( r.get_header(\"Sec-WebSocket-Protocol\"), \"foo, bar\");\n}\n\n\n"
  },
  {
    "path": "test/roles/server.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE server\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n\n// Test Environment:\n// server, no TLS, no locks, iostream based transport\n#include <websocketpp/config/core.hpp>\n#include <websocketpp/server.hpp>\n\ntypedef websocketpp::server<websocketpp::config::core> server;\ntypedef websocketpp::config::core::message_type::ptr message_ptr;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\n/*struct stub_config : public websocketpp::config::core {\n    typedef core::concurrency_type concurrency_type;\n\n    typedef core::request_type request_type;\n    typedef core::response_type response_type;\n\n    typedef core::message_type message_type;\n    typedef core::con_msg_manager_type con_msg_manager_type;\n    typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef core::alog_type alog_type;\n    typedef core::elog_type elog_type;\n\n    typedef core::rng_type rng_type;\n\n    typedef core::transport_type transport_type;\n\n    typedef core::endpoint_base endpoint_base;\n};*/\n\n/* Run server and return output test rig */\nstd::string run_server_test(server& s, std::string input) {\n    server::connection_ptr con;\n    std::stringstream output;\n\n    s.register_ostream(&output);\n    s.clear_access_channels(websocketpp::log::alevel::all);\n    s.clear_error_channels(websocketpp::log::elevel::all);\n\n    con = s.get_connection();\n    con->start();\n\n    std::stringstream channel;\n\n    channel << input;\n    channel >> *con;\n\n    return output.str();\n}\n\n/* handler library*/\nvoid echo_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {\n    s->send(hdl, msg->get_payload(), msg->get_opcode());\n}\n\nbool validate_func_subprotocol(server* s, std::string* out, std::string accept,\n    websocketpp::connection_hdl hdl)\n{\n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n\n    std::stringstream o;\n\n    const std::vector<std::string> & protocols = con->get_requested_subprotocols();\n    std::vector<std::string>::const_iterator it;\n\n    for (it = protocols.begin(); it != protocols.end(); ++it) {\n        o << *it << \",\";\n    }\n\n    *out = o.str();\n\n    if (!accept.empty()) {\n        con->select_subprotocol(accept);\n    }\n\n    return true;\n}\n\nvoid open_func_subprotocol(server* s, std::string* out, websocketpp::connection_hdl hdl) {\n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n\n    *out = con->get_subprotocol();\n}\n\n/* Tests */\nBOOST_AUTO_TEST_CASE( basic_websocket_request ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nServer: test\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    server s;\n    s.set_user_agent(\"test\");\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n}\n\nBOOST_AUTO_TEST_CASE( invalid_websocket_version ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: a\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n    std::string output = \"HTTP/1.1 400 Bad Request\\r\\nServer: test\\r\\n\\r\\n\";\n\n    server s;\n    s.set_user_agent(\"test\");\n    //s.set_message_handler(bind(&echo_func,&s,::_1,::_2));\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n}\n\nBOOST_AUTO_TEST_CASE( unimplemented_websocket_version ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 14\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\n\\r\\n\";\n\n    std::string output = \"HTTP/1.1 400 Bad Request\\r\\nSec-WebSocket-Version: 0,7,8,13\\r\\nServer: test\\r\\n\\r\\n\";\n\n    server s;\n    s.set_user_agent(\"test\");\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n}\n\nBOOST_AUTO_TEST_CASE( list_subprotocol_empty ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\nSec-WebSocket-Protocol: foo\\r\\n\\r\\n\";\n\n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nServer: test\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    std::string subprotocol;\n\n    server s;\n    s.set_user_agent(\"test\");\n    s.set_open_handler(bind(&open_func_subprotocol,&s,&subprotocol,::_1));\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n    BOOST_CHECK_EQUAL(subprotocol, \"\");\n}\n\nBOOST_AUTO_TEST_CASE( list_subprotocol_one ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\nSec-WebSocket-Protocol: foo\\r\\n\\r\\n\";\n\n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nServer: test\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    std::string validate;\n    std::string open;\n\n    server s;\n    s.set_user_agent(\"test\");\n    s.set_validate_handler(bind(&validate_func_subprotocol,&s,&validate,\"\",::_1));\n    s.set_open_handler(bind(&open_func_subprotocol,&s,&open,::_1));\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n    BOOST_CHECK_EQUAL(validate, \"foo,\");\n    BOOST_CHECK_EQUAL(open, \"\");\n}\n\nBOOST_AUTO_TEST_CASE( accept_subprotocol_one ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\nSec-WebSocket-Protocol: foo\\r\\n\\r\\n\";\n\n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nSec-WebSocket-Protocol: foo\\r\\nServer: test\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    std::string validate;\n    std::string open;\n\n    server s;\n    s.set_user_agent(\"test\");\n    s.set_validate_handler(bind(&validate_func_subprotocol,&s,&validate,\"foo\",::_1));\n    s.set_open_handler(bind(&open_func_subprotocol,&s,&open,::_1));\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n    BOOST_CHECK_EQUAL(validate, \"foo,\");\n    BOOST_CHECK_EQUAL(open, \"foo\");\n}\n\nBOOST_AUTO_TEST_CASE( accept_subprotocol_invalid ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\nSec-WebSocket-Protocol: foo\\r\\n\\r\\n\";\n\n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nSec-WebSocket-Protocol: foo\\r\\nServer: test\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    std::string validate;\n    std::string open;\n\n    server s;\n    s.set_user_agent(\"test\");\n    s.set_validate_handler(bind(&validate_func_subprotocol,&s,&validate,\"foo2\",::_1));\n    s.set_open_handler(bind(&open_func_subprotocol,&s,&open,::_1));\n\n    std::string o;\n\n    BOOST_CHECK_THROW(o = run_server_test(s,input), websocketpp::exception);\n}\n\nBOOST_AUTO_TEST_CASE( accept_subprotocol_two ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example.com\\r\\nSec-WebSocket-Protocol: foo, bar\\r\\n\\r\\n\";\n\n    std::string output = \"HTTP/1.1 101 Switching Protocols\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\\r\\nSec-WebSocket-Protocol: bar\\r\\nServer: test\\r\\nUpgrade: websocket\\r\\n\\r\\n\";\n\n    std::string validate;\n    std::string open;\n\n    server s;\n    s.set_user_agent(\"test\");\n    s.set_validate_handler(bind(&validate_func_subprotocol,&s,&validate,\"bar\",::_1));\n    s.set_open_handler(bind(&open_func_subprotocol,&s,&open,::_1));\n\n    BOOST_CHECK_EQUAL(run_server_test(s,input), output);\n    BOOST_CHECK_EQUAL(validate, \"foo,bar,\");\n    BOOST_CHECK_EQUAL(open, \"bar\");\n}\n\n/*BOOST_AUTO_TEST_CASE( user_reject_origin ) {\n    std::string input = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\nOrigin: http://www.example2.com\\r\\n\\r\\n\";\n    std::string output = \"HTTP/1.1 403 Forbidden\\r\\nServer: test\\r\\n\\r\\n\";\n\n    server s;\n    s.set_user_agent(\"test\");\n\n    BOOST_CHECK(run_server_test(s,input) == output);\n}*/\n"
  },
  {
    "path": "test/transport/CMakeLists.txt",
    "content": "if (OPENSSL_FOUND)\n\n# Test transport integration\nfile (GLOB SOURCE integration.cpp)\n\ninit_target (test_transport)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nlink_openssl()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test transport asio timers\nfile (GLOB SOURCE asio/timers.cpp)\n\ninit_target (test_transport_asio_timers)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nlink_openssl()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test transport asio security\nfile (GLOB SOURCE asio/security.cpp)\n\ninit_target (test_transport_asio_security)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nlink_openssl()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\nendif()\n\n# Test transport iostream base\nfile (GLOB SOURCE iostream/base.cpp)\n\ninit_target (test_transport_iostream_base)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test transport iostream endpoint\nfile (GLOB SOURCE iostream/endpoint.cpp)\n\ninit_target (test_transport_iostream_endpoint)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test transport iostream connection\nfile (GLOB SOURCE iostream/connection.cpp)\n\ninit_target (test_transport_iostream_connection)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test transport asio base\nfile (GLOB SOURCE asio/base.cpp)\n\ninit_target (test_transport_asio_base)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n\n"
  },
  {
    "path": "test/transport/SConscript",
    "content": "## transport integration tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\nImport('tls_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system','thread','random','chrono'],env) + [platform_libs] + [tls_libs]\n\nobjs = env.Object('boost_integration.o', [\"integration.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_boost_integration', [\"boost_integration.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   objs += env_cpp11.Object('stl_integration.o', [\"integration.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_stl_integration', [\"stl_integration.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/transport/asio/SConscript",
    "content": "## asio transport unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\nImport('tls_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system','thread','chrono'],env) + [platform_libs] + [tls_libs]\n\nobjs = env.Object('base_boost.o', [\"base.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('timers_boost.o', [\"timers.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('security_boost.o', [\"security.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_base_boost', [\"base_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_timers_boost', [\"timers_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_security_boost', [\"security_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]\n   objs += env_cpp11.Object('base_stl.o', [\"base.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('timers_stl.o', [\"timers.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('security_stl.o', [\"security.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_base_stl', [\"base_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_timers_stl', [\"timers_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_security_stl', [\"security_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/transport/asio/base.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE transport_asio_base\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n\n#include <websocketpp/transport/asio/base.hpp>\n\nBOOST_AUTO_TEST_CASE( blank_error ) {\n    websocketpp::lib::error_code ec;\n\n    BOOST_CHECK( !ec );\n}\n\nBOOST_AUTO_TEST_CASE( asio_error ) {\n    using websocketpp::transport::asio::error::make_error_code;\n    using websocketpp::transport::asio::error::general;\n\n    websocketpp::lib::error_code ec = make_error_code(general);\n\n    BOOST_CHECK( ec == general );\n    BOOST_CHECK( ec.value() == 1 );\n}\n"
  },
  {
    "path": "test/transport/asio/security.cpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE transport_asio_base\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n\n#include <websocketpp/common/type_traits.hpp>\n\n#include <websocketpp/transport/asio/security/none.hpp>\n#include <websocketpp/transport/asio/security/tls.hpp>\n\ntemplate <typename base>\nstruct dummy_con : public base {\n\twebsocketpp::lib::error_code test() {\n\t\treturn this->translate_ec(websocketpp::lib::asio::error_code());\n\t}\n};\n\nBOOST_AUTO_TEST_CASE( translated_ec_none ) {\n    dummy_con<websocketpp::transport::asio::basic_socket::connection> tscon;\n\n\t// If the current configuration settings result in the library error type and the asio\n\t// error type being the same, then the code should pass through natively. Otherwise\n\t// we should get a generic pass through error.\n\tif(websocketpp::lib::is_same<websocketpp::lib::error_code,websocketpp::lib::asio::error_code>::value) {\n    \tBOOST_CHECK_EQUAL( tscon.test(), websocketpp::lib::error_code() );\n    } else {\n    \tBOOST_CHECK_EQUAL( tscon.test(), websocketpp::transport::error::make_error_code(websocketpp::transport::error::pass_through) );\n    }\n}\n\nBOOST_AUTO_TEST_CASE( translated_ec_tls ) {\n    dummy_con<websocketpp::transport::asio::tls_socket::connection> tscon;\n\n\t// If the current configuration settings result in the library error type and the asio\n\t// error type being the same, then the code should pass through natively. Otherwise\n\t// we should get a generic pass through error.\n\tif(websocketpp::lib::is_same<websocketpp::lib::error_code,websocketpp::lib::asio::error_code>::value) {\n    \tBOOST_CHECK_EQUAL( tscon.test(), websocketpp::lib::error_code() );\n    } else {\n    \tBOOST_CHECK_EQUAL( tscon.test(), websocketpp::transport::error::make_error_code(websocketpp::transport::error::pass_through) );\n    }\n}\n"
  },
  {
    "path": "test/transport/asio/timers.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE transport_asio_timers\n#include <boost/test/unit_test.hpp>\n\n#include <exception>\n#include <iostream>\n\n#include <websocketpp/common/thread.hpp>\n\n#include <websocketpp/transport/asio/endpoint.hpp>\n#include <websocketpp/transport/asio/security/tls.hpp>\n\n// Concurrency\n#include <websocketpp/concurrency/none.hpp>\n\n// HTTP\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n\n// Loggers\n#include <websocketpp/logger/stub.hpp>\n//#include <websocketpp/logger/basic.hpp>\n\n#include <boost/asio.hpp>\n\n// Accept a connection, read data, and discard until EOF\nvoid run_dummy_server(int port) {\n    using boost::asio::ip::tcp;\n\n    try {\n        boost::asio::io_service io_service;\n        tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v6(), port));\n        tcp::socket socket(io_service);\n\n        acceptor.accept(socket);\n        for (;;) {\n            char data[512];\n            boost::system::error_code ec;\n            socket.read_some(boost::asio::buffer(data), ec);\n            if (ec == boost::asio::error::eof) {\n                break;\n            } else if (ec) {\n                // other error\n                throw ec;\n            }\n        }\n    } catch (std::exception & e) {\n        std::cout << e.what() << std::endl;\n    } catch (boost::system::error_code & ec) {\n        std::cout << ec.message() << std::endl;\n    }\n}\n\n// Wait for the specified time period then fail the test\nvoid run_test_timer(long value) {\n    boost::asio::io_service ios;\n    boost::asio::deadline_timer t(ios,boost::posix_time::milliseconds(value));\n    boost::system::error_code ec;\n    t.wait(ec);\n    BOOST_FAIL( \"Test timed out\" );\n}\n\nstruct config {\n    typedef websocketpp::concurrency::none concurrency_type;\n    //typedef websocketpp::log::basic<concurrency_type,websocketpp::log::alevel> alog_type;\n    typedef websocketpp::log::stub alog_type;\n    typedef websocketpp::log::stub elog_type;\n    typedef websocketpp::http::parser::request request_type;\n    typedef websocketpp::http::parser::response response_type;\n    typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;\n\n    static const bool enable_multithreading = true;\n\n    static const long timeout_socket_pre_init = 1000;\n    static const long timeout_proxy = 1000;\n    static const long timeout_socket_post_init = 1000;\n    static const long timeout_dns_resolve = 1000;\n    static const long timeout_connect = 1000;\n    static const long timeout_socket_shutdown = 1000;\n};\n\n// Mock context that does no validation\ntypedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;\ncontext_ptr on_tls_init(websocketpp::connection_hdl) {\n    return context_ptr(new boost::asio::ssl::context(boost::asio::ssl::context::sslv23));\n}\n\n// Mock connection\nstruct mock_con: public websocketpp::transport::asio::connection<config> {\n    typedef websocketpp::transport::asio::connection<config> base;\n\n    mock_con(bool a, const websocketpp::lib::shared_ptr<config::alog_type>& b,\n             const websocketpp::lib::shared_ptr<config::elog_type>& c)\n            : base(a,b,c) {}\n\n    void start() {\n        base::init(websocketpp::lib::bind(&mock_con::handle_start,this,\n            websocketpp::lib::placeholders::_1));\n    }\n\n    void handle_start(const websocketpp::lib::error_code& ec) {\n        using websocketpp::transport::asio::socket::make_error_code;\n        using websocketpp::transport::asio::socket::error::tls_handshake_timeout;\n\n        BOOST_CHECK_EQUAL( ec, make_error_code(tls_handshake_timeout) );\n\n        base::cancel_socket();\n    }\n};\n\ntypedef websocketpp::transport::asio::connection<config> con_type;\ntypedef websocketpp::lib::shared_ptr<mock_con> connection_ptr;\n\nstruct mock_endpoint : public websocketpp::transport::asio::endpoint<config> {\n    typedef websocketpp::transport::asio::endpoint<config> base;\n\n    mock_endpoint()\n        : alog(websocketpp::lib::make_shared<config::alog_type>())\n        , elog(websocketpp::lib::make_shared<config::elog_type>())\n    {\n        alog->set_channels(websocketpp::log::alevel::all);\n        base::init_logging(alog,elog);\n        init_asio();\n    }\n\n    void connect(std::string u) {\n        m_con.reset(new mock_con(false,alog,elog));\n        websocketpp::uri_ptr uri(new websocketpp::uri(u));\n\n        BOOST_CHECK( uri->get_valid() );\n        BOOST_CHECK_EQUAL( base::init(m_con), websocketpp::lib::error_code() );\n\n        base::async_connect(\n            m_con,\n            uri,\n            websocketpp::lib::bind(\n                &mock_endpoint::handle_connect,\n                this,\n                m_con,\n                websocketpp::lib::placeholders::_1\n            )\n        );\n    }\n\n    void handle_connect(connection_ptr con, websocketpp::lib::error_code const & ec)\n    {\n        BOOST_CHECK( !ec );\n        con->start();\n    }\n\n    connection_ptr m_con;\n    websocketpp::lib::shared_ptr<config::alog_type> alog;\n    websocketpp::lib::shared_ptr<config::elog_type> elog;\n};\n\nBOOST_AUTO_TEST_CASE( tls_handshake_timeout ) {\n    websocketpp::lib::thread dummy_server(websocketpp::lib::bind(&run_dummy_server,9005));\n    websocketpp::lib::thread timer(websocketpp::lib::bind(&run_test_timer,5000));\n    dummy_server.detach();\n    timer.detach();\n\n    sleep(1); // give the server thread some time to start\n\n    mock_endpoint endpoint;\n    endpoint.set_tls_init_handler(&on_tls_init);\n    endpoint.connect(\"wss://localhost:9005\");\n    endpoint.run();\n}\n"
  },
  {
    "path": "test/transport/hybi_util.cpp",
    "content": "/*\n * Copyright (c) 2011, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE hybi_util\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n\n#include \"../../src/processors/hybi_util.hpp\"\n#include \"../../src/network_utilities.hpp\"\n\nBOOST_AUTO_TEST_CASE( circshift_0 ) {\n    if (sizeof(size_t) == 8) {\n        size_t test = 0x0123456789abcdef;\n\n        test = websocketpp::processor::hybi_util::circshift_prepared_key(test,0);\n\n        BOOST_CHECK( test == 0x0123456789abcdef);\n    } else {\n        size_t test = 0x01234567;\n\n        test = websocketpp::processor::hybi_util::circshift_prepared_key(test,0);\n\n        BOOST_CHECK( test == 0x01234567);\n    }\n}\n\nBOOST_AUTO_TEST_CASE( circshift_1 ) {\n    if (sizeof(size_t) == 8) {\n        size_t test = 0x0123456789abcdef;\n\n        test = websocketpp::processor::hybi_util::circshift_prepared_key(test,1);\n\n        BOOST_CHECK( test == 0xef0123456789abcd);\n    } else {\n        size_t test = 0x01234567;\n\n        test = websocketpp::processor::hybi_util::circshift_prepared_key(test,1);\n\n        BOOST_CHECK( test == 0x67012345);\n    }\n}\n\nBOOST_AUTO_TEST_CASE( circshift_2 ) {\n    if (sizeof(size_t) == 8) {\n        size_t test = 0x0123456789abcdef;\n\n        test = websocketpp::processor::hybi_util::circshift_prepared_key(test,2);\n\n        BOOST_CHECK( test == 0xcdef0123456789ab);\n    } else {\n        size_t test = 0x01234567;\n\n        test = websocketpp::processor::hybi_util::circshift_prepared_key(test,2);\n\n        BOOST_CHECK( test == 0x45670123);\n    }\n}\n\nBOOST_AUTO_TEST_CASE( circshift_3 ) {\n    if (sizeof(size_t) == 8) {\n        size_t test = 0x0123456789abcdef;\n\n        test = websocketpp::processor::hybi_util::circshift_prepared_key(test,3);\n\n        BOOST_CHECK( test == 0xabcdef0123456789);\n    } else {\n        size_t test = 0x01234567;\n\n        test = websocketpp::processor::hybi_util::circshift_prepared_key(test,3);\n\n        BOOST_CHECK( test == 0x23456701);\n    }\n}\n"
  },
  {
    "path": "test/transport/integration.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE transport_integration\n#include <boost/test/unit_test.hpp>\n\n#include <websocketpp/common/thread.hpp>\n\n#include <websocketpp/config/core.hpp>\n#include <websocketpp/config/core_client.hpp>\n#include <websocketpp/config/asio.hpp>\n#include <websocketpp/config/asio_client.hpp>\n#include <websocketpp/config/debug_asio.hpp>\n#include <websocketpp/server.hpp>\n#include <websocketpp/client.hpp>\n\nstruct config : public websocketpp::config::asio_client {\n    typedef config type;\n    typedef websocketpp::config::asio base;\n\n    typedef base::concurrency_type concurrency_type;\n\n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n\n    typedef base::rng_type rng_type;\n\n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::basic_socket::endpoint\n            socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config>\n        transport_type;\n\n    //static const websocketpp::log::level elog_level = websocketpp::log::elevel::all;\n    //static const websocketpp::log::level alog_level = websocketpp::log::alevel::all;\n\n    /// Length of time before an opening handshake is aborted\n    static const long timeout_open_handshake = 500;\n    /// Length of time before a closing handshake is aborted\n    static const long timeout_close_handshake = 500;\n    /// Length of time to wait for a pong after a ping\n    static const long timeout_pong = 500;\n};\n\nstruct config_tls : public websocketpp::config::asio_tls_client {\n    typedef config type;\n    typedef websocketpp::config::asio base;\n\n    typedef base::concurrency_type concurrency_type;\n\n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n\n    typedef base::rng_type rng_type;\n\n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::basic_socket::endpoint\n            socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config>\n        transport_type;\n\n    //static const websocketpp::log::level elog_level = websocketpp::log::elevel::all;\n    //static const websocketpp::log::level alog_level = websocketpp::log::alevel::all;\n\n    /// Length of time before an opening handshake is aborted\n    static const long timeout_open_handshake = 500;\n    /// Length of time before a closing handshake is aborted\n    static const long timeout_close_handshake = 500;\n    /// Length of time to wait for a pong after a ping\n    static const long timeout_pong = 500;\n};\n\ntypedef websocketpp::server<config> server;\ntypedef websocketpp::client<config> client;\n\ntypedef websocketpp::server<config_tls> server_tls;\ntypedef websocketpp::client<config_tls> client_tls;\n\ntypedef websocketpp::server<websocketpp::config::core> iostream_server;\ntypedef websocketpp::client<websocketpp::config::core_client> iostream_client;\n\nusing websocketpp::lib::placeholders::_1;\nusing websocketpp::lib::placeholders::_2;\nusing websocketpp::lib::bind;\n\ntemplate <typename T>\nvoid close_after_timeout(T & e, websocketpp::connection_hdl hdl, long timeout) {\n    sleep(timeout);\n\n    websocketpp::lib::error_code ec;\n    e.close(hdl,websocketpp::close::status::normal,\"\",ec);\n    BOOST_CHECK(!ec);\n}\n\nvoid run_server(server * s, int port, bool log = false) {\n    if (log) {\n        s->set_access_channels(websocketpp::log::alevel::all);\n        s->set_error_channels(websocketpp::log::elevel::all);\n    } else {\n        s->clear_access_channels(websocketpp::log::alevel::all);\n        s->clear_error_channels(websocketpp::log::elevel::all);\n    }\n\n    s->init_asio();\n    s->set_reuse_addr(true);\n\n    s->listen(port);\n    s->start_accept();\n    s->run();\n}\n\nvoid run_client(client & c, std::string uri, bool log = false) {\n    if (log) {\n        c.set_access_channels(websocketpp::log::alevel::all);\n        c.set_error_channels(websocketpp::log::elevel::all);\n    } else {\n        c.clear_access_channels(websocketpp::log::alevel::all);\n        c.clear_error_channels(websocketpp::log::elevel::all);\n    }\n    websocketpp::lib::error_code ec;\n    c.init_asio(ec);\n    c.set_reuse_addr(true);\n    BOOST_CHECK(!ec);\n\n    client::connection_ptr con = c.get_connection(uri,ec);\n    BOOST_CHECK( !ec );\n    c.connect(con);\n\n    c.run();\n}\n\nvoid run_client_and_mark(client * c, bool * flag, websocketpp::lib::mutex * mutex) {\n    c->run();\n    BOOST_CHECK( true );\n    websocketpp::lib::lock_guard<websocketpp::lib::mutex> lock(*mutex);\n    *flag = true;\n    BOOST_CHECK( true );\n}\n\nvoid run_time_limited_client(client & c, std::string uri, long timeout,\n    bool log)\n{\n    if (log) {\n        c.set_access_channels(websocketpp::log::alevel::all);\n        c.set_error_channels(websocketpp::log::elevel::all);\n    } else {\n        c.clear_access_channels(websocketpp::log::alevel::all);\n        c.clear_error_channels(websocketpp::log::elevel::all);\n    }\n    c.init_asio();\n\n    websocketpp::lib::error_code ec;\n    client::connection_ptr con = c.get_connection(uri,ec);\n    BOOST_CHECK( !ec );\n    c.connect(con);\n\n    websocketpp::lib::thread tthread(websocketpp::lib::bind(\n        &close_after_timeout<client>,\n        websocketpp::lib::ref(c),\n        con->get_handle(),\n        timeout\n    ));\n    tthread.detach();\n\n    c.run();\n}\n\nvoid run_dummy_server(int port) {\n    using boost::asio::ip::tcp;\n\n    try {\n        boost::asio::io_service io_service;\n        tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v6(), port));\n        tcp::socket socket(io_service);\n\n        acceptor.accept(socket);\n        for (;;) {\n            char data[512];\n            boost::system::error_code ec;\n            socket.read_some(boost::asio::buffer(data), ec);\n            if (ec == boost::asio::error::eof) {\n                break;\n            } else if (ec) {\n                // other error\n                throw ec;\n            }\n        }\n    } catch (std::exception & e) {\n        std::cout << e.what() << std::endl;\n    } catch (boost::system::error_code & ec) {\n        std::cout << ec.message() << std::endl;\n    }\n}\n\nvoid run_dummy_client(std::string port) {\n    using boost::asio::ip::tcp;\n\n    try {\n        boost::asio::io_service io_service;\n        tcp::resolver resolver(io_service);\n        tcp::resolver::query query(\"localhost\", port);\n        tcp::resolver::iterator iterator = resolver.resolve(query);\n        tcp::socket socket(io_service);\n\n        boost::asio::connect(socket, iterator);\n        for (;;) {\n            char data[512];\n            boost::system::error_code ec;\n            socket.read_some(boost::asio::buffer(data), ec);\n            if (ec == boost::asio::error::eof) {\n                break;\n            } else if (ec) {\n                // other error\n                throw ec;\n            }\n        }\n    } catch (std::exception & e) {\n        std::cout << e.what() << std::endl;\n    } catch (boost::system::error_code & ec) {\n        std::cout << ec.message() << std::endl;\n    }\n}\n\nbool on_ping(server * s, websocketpp::connection_hdl, std::string) {\n    s->get_alog().write(websocketpp::log::alevel::app,\"got ping\");\n    return false;\n}\n\nvoid cancel_on_open(server * s, websocketpp::connection_hdl) {\n    s->stop_listening();\n}\n\nvoid stop_on_close(server * s, websocketpp::connection_hdl hdl) {\n    server::connection_ptr con = s->get_con_from_hdl(hdl);\n    //BOOST_CHECK_EQUAL( con->get_local_close_code(), websocketpp::close::status::normal );\n    //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal );\n    s->stop();\n}\n\ntemplate <typename T>\nvoid ping_on_open(T * c, std::string payload, websocketpp::connection_hdl hdl) {\n    typename T::connection_ptr con = c->get_con_from_hdl(hdl);\n    websocketpp::lib::error_code ec;\n    con->ping(payload,ec);\n    BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code());\n}\n\nvoid fail_on_pong(websocketpp::connection_hdl, std::string) {\n    BOOST_FAIL( \"expected no pong handler\" );\n}\n\nvoid fail_on_pong_timeout(websocketpp::connection_hdl, std::string) {\n    BOOST_FAIL( \"expected no pong timeout\" );\n}\n\nvoid req_pong(std::string expected_payload, websocketpp::connection_hdl,\n    std::string payload)\n{\n    BOOST_CHECK_EQUAL( expected_payload, payload );\n}\n\nvoid fail_on_open(websocketpp::connection_hdl) {\n    BOOST_FAIL( \"expected no open handler\" );\n}\n\nvoid delay(websocketpp::connection_hdl, long duration) {\n    sleep(duration);\n}\n\ntemplate <typename T>\nvoid check_ec(T * c, websocketpp::lib::error_code ec,\n    websocketpp::connection_hdl hdl)\n{\n    typename T::connection_ptr con = c->get_con_from_hdl(hdl);\n    BOOST_CHECK_EQUAL( con->get_ec(), ec );\n    //BOOST_CHECK_EQUAL( con->get_local_close_code(), websocketpp::close::status::normal );\n    //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal );\n}\n\ntemplate <typename T>\nvoid check_ec_and_stop(T * e, websocketpp::lib::error_code ec,\n    websocketpp::connection_hdl hdl)\n{\n    typename T::connection_ptr con = e->get_con_from_hdl(hdl);\n    BOOST_CHECK_EQUAL( con->get_ec(), ec );\n    //BOOST_CHECK_EQUAL( con->get_local_close_code(), websocketpp::close::status::normal );\n    //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal );\n    e->stop();\n}\n\ntemplate <typename T>\nvoid req_pong_timeout(T * c, std::string expected_payload,\n    websocketpp::connection_hdl hdl, std::string payload)\n{\n    typename T::connection_ptr con = c->get_con_from_hdl(hdl);\n    BOOST_CHECK_EQUAL( payload, expected_payload );\n    con->close(websocketpp::close::status::normal,\"\");\n}\n\ntemplate <typename T>\nvoid close(T * e, websocketpp::connection_hdl hdl) {\n    e->get_con_from_hdl(hdl)->close(websocketpp::close::status::normal,\"\");\n}\n\nclass test_deadline_timer\n{\npublic:\n    test_deadline_timer(int seconds)\n    : m_timer(m_io_service, boost::posix_time::seconds(seconds))\n    {\n        m_timer.async_wait(bind(&test_deadline_timer::expired, this, ::_1));\n        std::size_t (boost::asio::io_service::*run)() = &boost::asio::io_service::run;\n        m_timer_thread = websocketpp::lib::thread(websocketpp::lib::bind(run, &m_io_service));\n    }\n    ~test_deadline_timer()\n    {\n        m_timer.cancel();\n        m_timer_thread.join();\n    }\n\n  private:\n    void expired(const boost::system::error_code & ec)\n    {\n        if (ec == boost::asio::error::operation_aborted)\n            return;\n        BOOST_CHECK(!ec);\n        BOOST_FAIL(\"Test timed out\");\n    }\n\n    boost::asio::io_service m_io_service;\n    boost::asio::deadline_timer m_timer;\n    websocketpp::lib::thread m_timer_thread;\n};\n\nBOOST_AUTO_TEST_CASE( pong_no_timeout ) {\n    server s;\n    client c;\n\n    s.set_close_handler(bind(&stop_on_close,&s,::_1));\n\n    // send a ping when the connection is open\n    c.set_open_handler(bind(&ping_on_open<client>,&c,\"foo\",::_1));\n    // require that a pong with matching payload is received\n    c.set_pong_handler(bind(&req_pong,\"foo\",::_1,::_2));\n    // require that a pong timeout is NOT received\n    c.set_pong_timeout_handler(bind(&fail_on_pong_timeout,::_1,::_2));\n\n    websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));\n\n    sleep(1); // give the server thread some time to start\n\n    // Run a client that closes the connection after 1 seconds\n    run_time_limited_client(c, \"http://localhost:9005\", 1, false);\n\n    sthread.join();\n}\n\nBOOST_AUTO_TEST_CASE( pong_timeout ) {\n    server s;\n    client c;\n\n    s.set_ping_handler(bind(&on_ping, &s,::_1,::_2));\n    s.set_close_handler(bind(&stop_on_close,&s,::_1));\n\n    c.set_fail_handler(bind(&check_ec<client>,&c,\n        websocketpp::lib::error_code(),::_1));\n\n    c.set_pong_handler(bind(&fail_on_pong,::_1,::_2));\n    c.set_open_handler(bind(&ping_on_open<client>,&c,\"foo\",::_1));\n    c.set_pong_timeout_handler(bind(&req_pong_timeout<client>,&c,\"foo\",::_1,::_2));\n    c.set_close_handler(bind(&check_ec<client>,&c,\n        websocketpp::lib::error_code(),::_1));\n\n    websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));\n    sleep(1); // give the server thread some time to start\n\n    test_deadline_timer deadline(10);\n\n    run_client(c, \"http://localhost:9005\",false);\n\n    sthread.join();\n}\n\nBOOST_AUTO_TEST_CASE( client_open_handshake_timeout ) {\n    client c;\n\n    // set open handler to fail test\n    c.set_open_handler(bind(&fail_on_open,::_1));\n    // set fail hander to test for the right fail error code\n    c.set_fail_handler(bind(&check_ec<client>,&c,\n        websocketpp::error::open_handshake_timeout,::_1));\n\n    websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_dummy_server,9005));\n    sthread.detach();\n\n    sleep(1); // give the server thread some time to start\n\n    test_deadline_timer deadline(10);\n\n    run_client(c, \"http://localhost:9005\");\n}\n\nBOOST_AUTO_TEST_CASE( server_open_handshake_timeout ) {\n    server s;\n\n    // set open handler to fail test\n    s.set_open_handler(bind(&fail_on_open,::_1));\n    // set fail hander to test for the right fail error code\n    s.set_fail_handler(bind(&check_ec_and_stop<server>,&s,\n        websocketpp::error::open_handshake_timeout,::_1));\n\n    websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));\n\n    test_deadline_timer deadline(10);\n\n    sleep(1); // give the server thread some time to start\n\n    run_dummy_client(\"9005\");\n\n    sthread.join();\n}\n\nBOOST_AUTO_TEST_CASE( client_self_initiated_close_handshake_timeout ) {\n    server s;\n    client c;\n\n    // on open server sleeps for longer than the timeout\n    // on open client sends close handshake\n    // client handshake timer should be triggered\n    s.set_open_handler(bind(&delay,::_1,1));\n    s.set_close_handler(bind(&stop_on_close,&s,::_1));\n\n    c.set_open_handler(bind(&close<client>,&c,::_1));\n    c.set_close_handler(bind(&check_ec<client>,&c,\n        websocketpp::error::close_handshake_timeout,::_1));\n\n    websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));\n\n    test_deadline_timer deadline(10);\n\n    sleep(1); // give the server thread some time to start\n\n    run_client(c, \"http://localhost:9005\", false);\n\n    sthread.join();\n}\n\nBOOST_AUTO_TEST_CASE( client_peer_initiated_close_handshake_timeout ) {\n    // on open server sends close\n    // client should ack normally and then wait\n    // server leaves TCP connection open\n    // client handshake timer should be triggered\n\n    // TODO: how to make a mock server that leaves the TCP connection open?\n}\n\nBOOST_AUTO_TEST_CASE( server_self_initiated_close_handshake_timeout ) {\n    server s;\n    client c;\n\n    // on open server sends close\n    // on open client sleeps for longer than the timeout\n    // server handshake timer should be triggered\n\n    s.set_open_handler(bind(&close<server>,&s,::_1));\n    s.set_close_handler(bind(&check_ec_and_stop<server>,&s,\n        websocketpp::error::close_handshake_timeout,::_1));\n\n    c.set_open_handler(bind(&delay,::_1,1));\n\n    websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));\n    test_deadline_timer deadline(10);\n\n    sleep(1); // give the server thread some time to start\n\n    run_client(c, \"http://localhost:9005\", false);\n\n    sthread.join();\n}\n\nBOOST_AUTO_TEST_CASE( client_runs_out_of_work ) {\n    client c;\n\n    test_deadline_timer deadline(3);\n\n    websocketpp::lib::error_code ec;\n    c.init_asio(ec);\n    BOOST_CHECK(!ec);\n\n    c.run();\n\n    // This test checks that an io_service with no work ends immediately.\n    BOOST_CHECK(true);\n}\n\n\n\n\nBOOST_AUTO_TEST_CASE( client_is_perpetual ) {\n    client c;\n    bool flag = false;\n    websocketpp::lib::mutex mutex;\n\n    websocketpp::lib::error_code ec;\n    c.init_asio(ec);\n    BOOST_CHECK(!ec);\n\n    c.start_perpetual();\n\n    websocketpp::lib::thread cthread(websocketpp::lib::bind(&run_client_and_mark,&c,&flag,&mutex));\n\n    sleep(1);\n\n    {\n        // Checks that the thread hasn't exited yet\n        websocketpp::lib::lock_guard<websocketpp::lib::mutex> lock(mutex);\n        BOOST_CHECK( !flag );\n    }\n\n    c.stop_perpetual();\n\n    sleep(1);\n\n    {\n        // Checks that the thread has exited\n        websocketpp::lib::lock_guard<websocketpp::lib::mutex> lock(mutex);\n        BOOST_CHECK( flag );\n    }\n\n    cthread.join();\n}\n\nBOOST_AUTO_TEST_CASE( client_failed_connection ) {\n    client c;\n\n    run_time_limited_client(c,\"http://localhost:9005\", 5, false);\n}\n\nBOOST_AUTO_TEST_CASE( stop_listening ) {\n    server s;\n    client c;\n\n    // the first connection stops the server from listening\n    s.set_open_handler(bind(&cancel_on_open,&s,::_1));\n\n    // client immediately closes after opening a connection\n    c.set_open_handler(bind(&close<client>,&c,::_1));\n\n    websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));\n    test_deadline_timer deadline(5);\n\n    sleep(1); // give the server thread some time to start\n\n    run_client(c, \"http://localhost:9005\", false);\n\n    sthread.join();\n}\n\nBOOST_AUTO_TEST_CASE( pause_reading ) {\n    iostream_server s;\n    std::string handshake = \"GET / HTTP/1.1\\r\\nHost: www.example.com\\r\\nConnection: Upgrade\\r\\nUpgrade: websocket\\r\\nSec-WebSocket-Version: 13\\r\\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\\r\\n\\r\\n\";\n    char buffer[2] = { char(0x81), char(0x80) };\n\n    // suppress output (it needs a place to go to avoid error but we don't care what it is)\n    std::stringstream null_output;\n    s.register_ostream(&null_output);\n\n    iostream_server::connection_ptr con = s.get_connection();\n    con->start();\n\n    // read handshake, should work\n    BOOST_CHECK_EQUAL( con->read_some(handshake.data(), handshake.length()), handshake.length());\n\n    // pause reading and try again. The first read should work, the second should return 0\n    // the first read was queued already after the handshake so it will go through because\n    // reading wasn't paused when it was queued. The byte it reads wont be enough to\n    // complete the frame so another read will be requested. This one wont actually happen\n    // because the connection is paused now.\n    con->pause_reading();\n    BOOST_CHECK_EQUAL( con->read_some(buffer, 1), 1);\n    BOOST_CHECK_EQUAL( con->read_some(buffer+1, 1), 0);\n    // resume reading and try again. Should work this time because the resume should have\n    // re-queued a read.\n    con->resume_reading();\n    BOOST_CHECK_EQUAL( con->read_some(buffer+1, 1), 1);\n}\n\n\nBOOST_AUTO_TEST_CASE( server_connection_cleanup ) {\n    server_tls s;\n}\n\n#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_\nBOOST_AUTO_TEST_CASE( move_construct_transport ) {\n    server s1;\n    \n    server s2(std::move(s1));\n}\n#endif // _WEBSOCKETPP_MOVE_SEMANTICS_\n"
  },
  {
    "path": "test/transport/iostream/SConscript",
    "content": "## iostream transport unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs]\n\nobjs = env.Object('iostream_base_boost.o', [\"base.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('iostream_connection_boost.o', [\"connection.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('iostream_endpoint_boost.o', [\"endpoint.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_iostream_base_boost', [\"iostream_base_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_iostream_connection_boost', [\"iostream_connection_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_iostream_endpoint_boost', [\"iostream_endpoint_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   objs += env_cpp11.Object('iostream_base_stl.o', [\"base.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('iostream_connection_stl.o', [\"connection.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('iostream_endpoint_stl.o', [\"endpoint.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_iostream_base_stl', [\"iostream_base_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_iostream_connection_stl', [\"iostream_connection_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_iostream_endpoint_stl', [\"iostream_endpoint_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/transport/iostream/base.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE transport_iostream_base\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n\nBOOST_AUTO_TEST_CASE( placeholder ) {}\n"
  },
  {
    "path": "test/transport/iostream/connection.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE transport_iostream_connection\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <cstring>\n#include <string>\n\n#include <websocketpp/common/memory.hpp>\n\n#include <websocketpp/error.hpp>\n#include <websocketpp/transport/iostream/connection.hpp>\n\n// Policies\n#include <websocketpp/concurrency/basic.hpp>\n#include <websocketpp/logger/basic.hpp>\n\nstruct config {\n    typedef websocketpp::concurrency::basic concurrency_type;\n    typedef websocketpp::log::basic<concurrency_type,\n        websocketpp::log::elevel> elog_type;\n    typedef websocketpp::log::basic<concurrency_type,\n        websocketpp::log::alevel> alog_type;\n};\n\ntypedef websocketpp::transport::iostream::connection<config> iostream_con;\n\nusing websocketpp::transport::iostream::error::make_error_code;\n\nstruct stub_con : public iostream_con {\n    typedef stub_con type;\n    typedef websocketpp::lib::shared_ptr<type> ptr;\n    typedef iostream_con::timer_ptr timer_ptr;\n\n    stub_con(bool is_server, const websocketpp::lib::shared_ptr<config::alog_type>& a, const websocketpp::lib::shared_ptr<config::elog_type>& e)\n        : iostream_con(is_server,a,e)\n        // Set the error to a known code that is unused by the library\n        // This way we can easily confirm that the handler was run at all.\n        , ec(websocketpp::error::make_error_code(websocketpp::error::test))\n        , indef_read_total(0)\n    {}\n\n    /// Get a shared pointer to this component\n    ptr get_shared() {\n        return websocketpp::lib::static_pointer_cast<type>(iostream_con::get_shared());\n    }\n\n    void write(std::string msg) {\n        iostream_con::async_write(\n            msg.data(),\n            msg.size(),\n            websocketpp::lib::bind(\n                &stub_con::handle_op,\n                type::get_shared(),\n                websocketpp::lib::placeholders::_1\n            )\n        );\n    }\n\n    void write(std::vector<websocketpp::transport::buffer> & bufs) {\n        iostream_con::async_write(\n            bufs,\n            websocketpp::lib::bind(\n                &stub_con::handle_op,\n                type::get_shared(),\n                websocketpp::lib::placeholders::_1\n            )\n        );\n    }\n\n    void async_read_at_least(size_t num_bytes, char *buf, size_t len)\n    {\n        iostream_con::async_read_at_least(\n            num_bytes,\n            buf,\n            len,\n            websocketpp::lib::bind(\n                &stub_con::handle_op,\n                type::get_shared(),\n                websocketpp::lib::placeholders::_1\n            )\n        );\n    }\n\n    void handle_op(websocketpp::lib::error_code const & e) {\n        ec = e;\n    }\n\n    void async_read_indef(size_t num_bytes, char *buf, size_t len)\n    {\n        indef_read_size = num_bytes;\n        indef_read_buf = buf;\n        indef_read_len = len;\n\n        indef_read();\n    }\n\n    void indef_read() {\n        iostream_con::async_read_at_least(\n            indef_read_size,\n            indef_read_buf,\n            indef_read_len,\n            websocketpp::lib::bind(\n                &stub_con::handle_indef,\n                type::get_shared(),\n                websocketpp::lib::placeholders::_1,\n                websocketpp::lib::placeholders::_2\n            )\n        );\n    }\n\n    void handle_indef(websocketpp::lib::error_code const & e, size_t amt_read) {\n        ec = e;\n        indef_read_total += amt_read;\n\n        indef_read();\n    }\n\n    void shutdown() {\n        iostream_con::async_shutdown(\n            websocketpp::lib::bind(\n                &stub_con::handle_async_shutdown,\n                type::get_shared(),\n                websocketpp::lib::placeholders::_1\n            )\n        );\n    }\n\n    void handle_async_shutdown(websocketpp::lib::error_code const & e) {\n        ec = e;\n    }\n\n    websocketpp::lib::error_code ec;\n    size_t indef_read_size;\n    char * indef_read_buf;\n    size_t indef_read_len;\n    size_t indef_read_total;\n};\n\n// Stubs\nwebsocketpp::lib::shared_ptr<config::alog_type> alogger = websocketpp::lib::make_shared<config::alog_type>();\nwebsocketpp::lib::shared_ptr<config::elog_type> elogger = websocketpp::lib::make_shared<config::elog_type>();\n\nBOOST_AUTO_TEST_CASE( const_methods ) {\n    iostream_con::ptr con(new iostream_con(true,alogger,elogger));\n\n    BOOST_CHECK( !con->is_secure() );\n    BOOST_CHECK_EQUAL( con->get_remote_endpoint(), \"iostream transport\" );\n}\n\nBOOST_AUTO_TEST_CASE( write_before_output_method_set ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    con->write(\"foo\");\n    BOOST_CHECK( con->ec == make_error_code(websocketpp::transport::iostream::error::output_stream_required) );\n\n    std::vector<websocketpp::transport::buffer> bufs;\n    con->write(bufs);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::iostream::error::output_stream_required) );\n}\n\nBOOST_AUTO_TEST_CASE( async_write_ostream ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    std::stringstream output;\n\n    con->register_ostream(&output);\n\n    con->write(\"foo\");\n\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( output.str(), \"foo\" );\n}\n\nwebsocketpp::lib::error_code write_handler(std::string & o, websocketpp::connection_hdl, char const * buf, size_t len) {\n    o += std::string(buf,len);\n    return websocketpp::lib::error_code();\n}\n\nwebsocketpp::lib::error_code vector_write_handler(std::string & o, websocketpp::connection_hdl, std::vector<websocketpp::transport::buffer> const & bufs) {\n    std::vector<websocketpp::transport::buffer>::const_iterator it;\n    for (it = bufs.begin(); it != bufs.end(); it++) {\n        o += std::string((*it).buf, (*it).len);\n    }\n\n    return websocketpp::lib::error_code();\n}\n\nwebsocketpp::lib::error_code write_handler_error(websocketpp::connection_hdl, char const *, size_t) {\n    return make_error_code(websocketpp::transport::error::general);\n}\n\nBOOST_AUTO_TEST_CASE( async_write_handler ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n    std::string output;\n\n    con->set_write_handler(websocketpp::lib::bind(\n        &write_handler,\n        websocketpp::lib::ref(output),\n        websocketpp::lib::placeholders::_1,\n        websocketpp::lib::placeholders::_2,\n        websocketpp::lib::placeholders::_3\n    ));\n    con->write(\"foo\");\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL(output, \"foo\");\n}\n\nBOOST_AUTO_TEST_CASE( async_write_handler_error ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    con->set_write_handler(&write_handler_error);\n    con->write(\"foo\");\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::general) );\n}\n\nBOOST_AUTO_TEST_CASE( async_write_vector_0_ostream ) {\n    std::stringstream output;\n\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n    con->register_ostream(&output);\n\n    std::vector<websocketpp::transport::buffer> bufs;\n\n    con->write(bufs);\n\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( output.str(), \"\" );\n}\n\nBOOST_AUTO_TEST_CASE( async_write_vector_0_write_handler ) {\n    std::string output;\n\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    con->set_write_handler(websocketpp::lib::bind(\n        &write_handler,\n        websocketpp::lib::ref(output),\n        websocketpp::lib::placeholders::_1,\n        websocketpp::lib::placeholders::_2,\n        websocketpp::lib::placeholders::_3\n    ));\n\n    std::vector<websocketpp::transport::buffer> bufs;\n\n    con->write(bufs);\n\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( output, \"\" );\n}\n\nBOOST_AUTO_TEST_CASE( async_write_vector_1_ostream ) {\n    std::stringstream output;\n\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n    con->register_ostream(&output);\n\n    std::vector<websocketpp::transport::buffer> bufs;\n\n    std::string foo = \"foo\";\n\n    bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));\n\n    con->write(bufs);\n\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( output.str(), \"foo\" );\n}\n\nBOOST_AUTO_TEST_CASE( async_write_vector_1_write_handler ) {\n    std::string output;\n\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n    con->set_write_handler(websocketpp::lib::bind(\n        &write_handler,\n        websocketpp::lib::ref(output),\n        websocketpp::lib::placeholders::_1,\n        websocketpp::lib::placeholders::_2,\n        websocketpp::lib::placeholders::_3\n    ));\n\n    std::vector<websocketpp::transport::buffer> bufs;\n\n    std::string foo = \"foo\";\n\n    bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));\n\n    con->write(bufs);\n\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( output, \"foo\" );\n}\n\nBOOST_AUTO_TEST_CASE( async_write_vector_2_ostream ) {\n    std::stringstream output;\n\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n    con->register_ostream(&output);\n\n    std::vector<websocketpp::transport::buffer> bufs;\n\n    std::string foo = \"foo\";\n    std::string bar = \"bar\";\n\n    bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));\n    bufs.push_back(websocketpp::transport::buffer(bar.data(),bar.size()));\n\n    con->write(bufs);\n\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( output.str(), \"foobar\" );\n}\n\nBOOST_AUTO_TEST_CASE( async_write_vector_2_write_handler ) {\n    std::string output;\n\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n    con->set_write_handler(websocketpp::lib::bind(\n        &write_handler,\n        websocketpp::lib::ref(output),\n        websocketpp::lib::placeholders::_1,\n        websocketpp::lib::placeholders::_2,\n        websocketpp::lib::placeholders::_3\n    ));\n\n    std::vector<websocketpp::transport::buffer> bufs;\n\n    std::string foo = \"foo\";\n    std::string bar = \"bar\";\n\n    bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));\n    bufs.push_back(websocketpp::transport::buffer(bar.data(),bar.size()));\n\n    con->write(bufs);\n\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( output, \"foobar\" );\n}\n\nBOOST_AUTO_TEST_CASE( async_write_vector_2_vector_write_handler ) {\n    std::string output;\n\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n    con->set_vector_write_handler(websocketpp::lib::bind(\n        &vector_write_handler,\n        websocketpp::lib::ref(output),\n        websocketpp::lib::placeholders::_1,\n        websocketpp::lib::placeholders::_2\n    ));\n\n    std::vector<websocketpp::transport::buffer> bufs;\n\n    std::string foo = \"foo\";\n    std::string bar = \"bar\";\n\n    bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));\n    bufs.push_back(websocketpp::transport::buffer(bar.data(),bar.size()));\n\n    con->write(bufs);\n\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( output, \"foobar\" );\n}\n\nBOOST_AUTO_TEST_CASE( async_read_at_least_too_much ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    char buf[10];\n\n    con->async_read_at_least(11,buf,10);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::iostream::error::invalid_num_bytes) );\n}\n\nBOOST_AUTO_TEST_CASE( async_read_at_least_double_read ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    char buf[10];\n\n    con->async_read_at_least(5,buf,10);\n    con->async_read_at_least(5,buf,10);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::iostream::error::double_read) );\n}\n\nBOOST_AUTO_TEST_CASE( async_read_at_least ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    char buf[10];\n\n    memset(buf,'x',10);\n\n    con->async_read_at_least(5,buf,10);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n\n    std::stringstream channel;\n    channel << \"abcd\";\n    channel >> *con;\n    BOOST_CHECK_EQUAL( channel.tellg(), -1 );\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n\n    std::stringstream channel2;\n    channel2 << \"e\";\n    channel2 >> *con;\n    BOOST_CHECK_EQUAL( channel2.tellg(), -1 );\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"abcdexxxxx\" );\n\n    std::stringstream channel3;\n    channel3 << \"f\";\n    channel3 >> *con;\n    BOOST_CHECK_EQUAL( channel3.tellg(), 0 );\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"abcdexxxxx\" );\n    con->async_read_at_least(1,buf+5,5);\n    channel3 >> *con;\n    BOOST_CHECK_EQUAL( channel3.tellg(), -1 );\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"abcdefxxxx\" );\n}\n\nBOOST_AUTO_TEST_CASE( async_read_at_least2 ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    char buf[10];\n\n    memset(buf,'x',10);\n\n    con->async_read_at_least(5,buf,5);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n\n    std::stringstream channel;\n    channel << \"abcdefg\";\n    channel >> *con;\n    BOOST_CHECK_EQUAL( channel.tellg(), 5 );\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"abcdexxxxx\" );\n\n    con->async_read_at_least(1,buf+5,5);\n    channel >> *con;\n    BOOST_CHECK_EQUAL( channel.tellg(), -1 );\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"abcdefgxxx\" );\n}\n\nvoid timer_callback_stub(websocketpp::lib::error_code const &) {}\n\nBOOST_AUTO_TEST_CASE( set_timer ) {\n   stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    stub_con::timer_ptr tp = con->set_timer(1000,timer_callback_stub);\n\n    BOOST_CHECK( !tp );\n}\n\nBOOST_AUTO_TEST_CASE( async_read_at_least_read_some ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    char buf[10];\n    memset(buf,'x',10);\n\n    con->async_read_at_least(5,buf,5);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n\n    char input[10] = \"abcdefg\";\n    BOOST_CHECK_EQUAL(con->read_some(input,5), 5);\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"abcdexxxxx\" );\n\n    BOOST_CHECK_EQUAL(con->read_some(input+5,2), 0);\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"abcdexxxxx\" );\n\n    con->async_read_at_least(1,buf+5,5);\n    BOOST_CHECK_EQUAL(con->read_some(input+5,2), 2);\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"abcdefgxxx\" );\n}\n\nBOOST_AUTO_TEST_CASE( async_read_at_least_read_some_indef ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    char buf[20];\n    memset(buf,'x',20);\n\n    con->async_read_indef(5,buf,5);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n\n    // here we expect to return early from read some because the outstanding\n    // read was for 5 bytes and we were called with 10.\n    char input[11] = \"aaaaabbbbb\";\n    BOOST_CHECK_EQUAL(con->read_some(input,10), 5);\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"aaaaaxxxxx\" );\n    BOOST_CHECK_EQUAL( con->indef_read_total, 5 );\n\n    // A subsequent read should read 5 more because the indef read refreshes\n    // itself. The new read will start again at the beginning of the buffer.\n    BOOST_CHECK_EQUAL(con->read_some(input+5,5), 5);\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"bbbbbxxxxx\" );\n    BOOST_CHECK_EQUAL( con->indef_read_total, 10 );\n}\n\nBOOST_AUTO_TEST_CASE( async_read_at_least_read_all ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    char buf[20];\n    memset(buf,'x',20);\n\n    con->async_read_indef(5,buf,5);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n\n    char input[11] = \"aaaaabbbbb\";\n    BOOST_CHECK_EQUAL(con->read_all(input,10), 10);\n    BOOST_CHECK( !con->ec );\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"bbbbbxxxxx\" );\n    BOOST_CHECK_EQUAL( con->indef_read_total, 10 );\n}\n\nBOOST_AUTO_TEST_CASE( eof_flag ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n    char buf[10];\n    con->async_read_at_least(5,buf,5);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n    con->eof();\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::eof) );\n}\n\nBOOST_AUTO_TEST_CASE( fatal_error_flag ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n    char buf[10];\n    con->async_read_at_least(5,buf,5);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n    con->fatal_error();\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::pass_through) );\n}\n\nBOOST_AUTO_TEST_CASE( shutdown ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n    con->shutdown();\n    BOOST_CHECK_EQUAL( con->ec, websocketpp::lib::error_code() );\n}\n\nwebsocketpp::lib::error_code sd_handler(websocketpp::connection_hdl) {\n    return make_error_code(websocketpp::transport::error::general);\n}\n\nBOOST_AUTO_TEST_CASE( shutdown_handler ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    con->set_shutdown_handler(&sd_handler);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n    con->shutdown();\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::general) );\n}\n\nBOOST_AUTO_TEST_CASE( clear_handler ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    con->set_shutdown_handler(&sd_handler);\n    con->set_shutdown_handler(NULL);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n    con->shutdown();\n    BOOST_CHECK_EQUAL( con->ec, websocketpp::lib::error_code() );\n}\n\nBOOST_AUTO_TEST_CASE( shared_pointer_memory_cleanup ) {\n    stub_con::ptr con(new stub_con(true,alogger,elogger));\n\n    BOOST_CHECK_EQUAL(con.use_count(), 1);\n\n    char buf[10];\n    memset(buf,'x',10);\n    con->async_read_at_least(5,buf,5);\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );\n    BOOST_CHECK_EQUAL(con.use_count(), 2);\n\n    char input[10] = \"foo\";\n    con->read_some(input,3);\n    BOOST_CHECK_EQUAL(con.use_count(), 2);\n\n    con->read_some(input,2);\n    BOOST_CHECK_EQUAL( std::string(buf,10), \"foofoxxxxx\" );\n    BOOST_CHECK_EQUAL(con.use_count(), 1);\n\n    con->async_read_at_least(5,buf,5);\n    BOOST_CHECK_EQUAL(con.use_count(), 2);\n\n    con->eof();\n    BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::eof) );\n    BOOST_CHECK_EQUAL(con.use_count(), 1);\n}\n\n"
  },
  {
    "path": "test/transport/iostream/endpoint.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE transport_iostream_endpoint\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n\n#include <websocketpp/transport/iostream/endpoint.hpp>\n\nBOOST_AUTO_TEST_CASE( placeholder ) {}\n\n/*BOOST_AUTO_TEST_CASE( blank_error ) {\n    websocketpp::lib::error_code ec;\n\n    BOOST_CHECK( !ec );\n}*/\n"
  },
  {
    "path": "test/utility/CMakeLists.txt",
    "content": "# Test close utilities\nfile (GLOB SOURCE close.cpp)\n\ninit_target (test_close)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test error utilities\nfile (GLOB SOURCE error.cpp)\n\ninit_target (test_error)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test frame utilities\nfile (GLOB SOURCE frame.cpp)\n\ninit_target (test_frame)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test sha1 utilities\nfile (GLOB SOURCE sha1.cpp)\n\ninit_target (test_sha1)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test uri utilities\nfile (GLOB SOURCE uri.cpp)\n\ninit_target (test_uri)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n\n# Test misc utilities\nfile (GLOB SOURCE utilities.cpp)\n\ninit_target (test_utilities)\nbuild_test (${TARGET_NAME} ${SOURCE})\nlink_boost ()\nfinal_target ()\nset_target_properties(${TARGET_NAME} PROPERTIES FOLDER \"test\")\n"
  },
  {
    "path": "test/utility/SConscript",
    "content": "## utility unit tests\n##\n\nImport('env')\nImport('env_cpp11')\nImport('boostlibs')\nImport('platform_libs')\nImport('polyfill_libs')\n\nenv = env.Clone ()\nenv_cpp11 = env_cpp11.Clone ()\n\nBOOST_LIBS = boostlibs(['unit_test_framework','system'],env) + [platform_libs]\n\nobjs = env.Object('uri_boost.o', [\"uri.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('utilities_boost.o', [\"utilities.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('close_boost.o', [\"close.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('sha1_boost.o', [\"sha1.cpp\"], LIBS = BOOST_LIBS)\nobjs += env.Object('error_boost.o', [\"error.cpp\"], LIBS = BOOST_LIBS)\nprgs = env.Program('test_uri_boost', [\"uri_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_utility_boost', [\"utilities_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_frame', [\"frame.cpp\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_close_boost', [\"close_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_sha1_boost', [\"sha1_boost.o\"], LIBS = BOOST_LIBS)\nprgs += env.Program('test_error_boost', [\"error_boost.o\"], LIBS = BOOST_LIBS)\n\nif env_cpp11.has_key('WSPP_CPP11_ENABLED'):\n   BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]\n   objs += env_cpp11.Object('utilities_stl.o', [\"utilities.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('uri_stl.o', [\"uri.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('close_stl.o', [\"close.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('sha1_stl.o', [\"sha1.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   objs += env_cpp11.Object('error_stl.o', [\"error.cpp\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_utility_stl', [\"utilities_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_uri_stl', [\"uri_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_close_stl', [\"close_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_sha1_stl', [\"sha1_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n   prgs += env_cpp11.Program('test_error_stl', [\"error_stl.o\"], LIBS = BOOST_LIBS_CPP11)\n\nReturn('prgs')\n"
  },
  {
    "path": "test/utility/close.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE close\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/close.hpp>\n#include <websocketpp/utilities.hpp>\n\nusing namespace websocketpp;\n\nBOOST_AUTO_TEST_CASE( reserved_values ) {\n    BOOST_CHECK( !close::status::reserved(999) );\n    BOOST_CHECK( close::status::reserved(1004) );\n    BOOST_CHECK( close::status::reserved(1016) );\n    BOOST_CHECK( close::status::reserved(2999) );\n    BOOST_CHECK( !close::status::reserved(1000) );\n}\n\nBOOST_AUTO_TEST_CASE( invalid_values ) {\n    BOOST_CHECK( close::status::invalid(0) );\n    BOOST_CHECK( close::status::invalid(999) );\n    BOOST_CHECK( !close::status::invalid(1000) );\n    BOOST_CHECK( close::status::invalid(1005) );\n    BOOST_CHECK( close::status::invalid(1006) );\n    BOOST_CHECK( close::status::invalid(1015) );\n    BOOST_CHECK( !close::status::invalid(2999) );\n    BOOST_CHECK( !close::status::invalid(3000) );\n    BOOST_CHECK( close::status::invalid(5000) );\n}\n\nBOOST_AUTO_TEST_CASE( value_extraction ) {\n    lib::error_code ec;\n    std::string payload = \"oo\";\n\n    // Value = 1000\n    payload[0] = 0x03;\n    payload[1] = char(0xe8);\n    BOOST_CHECK( close::extract_code(payload,ec) == close::status::normal );\n    BOOST_CHECK( !ec );\n\n    // Value = 1004\n    payload[0] = 0x03;\n    payload[1] = char(0xec);\n    BOOST_CHECK( close::extract_code(payload,ec) == 1004 );\n    BOOST_CHECK( ec == error::reserved_close_code );\n\n    // Value = 1005\n    payload[0] = 0x03;\n    payload[1] = char(0xed);\n    BOOST_CHECK( close::extract_code(payload,ec) == close::status::no_status );\n    BOOST_CHECK( ec == error::invalid_close_code );\n\n    // Value = 3000\n    payload[0] = 0x0b;\n    payload[1] = char(0xb8);\n    BOOST_CHECK( close::extract_code(payload,ec) == 3000 );\n    BOOST_CHECK( !ec );\n}\n\nBOOST_AUTO_TEST_CASE( extract_empty ) {\n    lib::error_code ec;\n    std::string payload;\n\n    BOOST_CHECK( close::extract_code(payload,ec) == close::status::no_status );\n    BOOST_CHECK( !ec );\n}\n\nBOOST_AUTO_TEST_CASE( extract_short ) {\n    lib::error_code ec;\n    std::string payload = \"0\";\n\n    BOOST_CHECK( close::extract_code(payload,ec) == close::status::protocol_error );\n    BOOST_CHECK( ec == error::bad_close_code );\n}\n\nBOOST_AUTO_TEST_CASE( extract_reason ) {\n    lib::error_code ec;\n    std::string payload = \"00Foo\";\n\n    BOOST_CHECK( close::extract_reason(payload,ec) == \"Foo\" );\n    BOOST_CHECK( !ec );\n\n    payload.clear();\n    BOOST_CHECK( close::extract_reason(payload,ec).empty() );\n    BOOST_CHECK( !ec );\n\n    payload = \"00\";\n    BOOST_CHECK( close::extract_reason(payload,ec).empty() );\n    BOOST_CHECK( !ec );\n\n    payload = \"000\";\n    payload[2] = char(0xFF);\n\n    close::extract_reason(payload,ec);\n    BOOST_CHECK( ec == error::invalid_utf8 );\n}\n"
  },
  {
    "path": "test/utility/error.cpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE error\n#include <boost/test/unit_test.hpp>\n\n#include <websocketpp/error.hpp>\n\nBOOST_AUTO_TEST_CASE( constructing_exceptions ) {\n    websocketpp::lib::error_code test_ec = websocketpp::error::make_error_code(websocketpp::error::test);\n    websocketpp::lib::error_code general_ec = websocketpp::error::make_error_code(websocketpp::error::general);\n\n    websocketpp::exception b(\"foo\");\n    websocketpp::exception c(\"foo\",test_ec);\n    websocketpp::exception d(\"\");\n    websocketpp::exception e(\"\",test_ec);\n\n    BOOST_CHECK_EQUAL(b.what(),\"foo\");\n    BOOST_CHECK_EQUAL(b.code(),general_ec);\n\n    BOOST_CHECK_EQUAL(c.what(),\"foo\");\n    BOOST_CHECK_EQUAL(c.code(),test_ec);\n\n    BOOST_CHECK_EQUAL(d.what(),\"Generic error\");\n    BOOST_CHECK_EQUAL(d.code(),general_ec);\n\n    BOOST_CHECK_EQUAL(e.what(),\"Test Error\");\n    BOOST_CHECK_EQUAL(e.code(),test_ec);\n}\n\n"
  },
  {
    "path": "test/utility/frame.cpp",
    "content": "/*\n * Copyright (c) 2011, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE frame\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/frame.hpp>\n#include <websocketpp/utilities.hpp>\n\nusing namespace websocketpp;\n\nBOOST_AUTO_TEST_CASE( basic_bits ) {\n    frame::basic_header h1(0x00,0x00); // all false\n    frame::basic_header h2(0xF0,0x80); // all true\n\n    // Read Values\n    BOOST_CHECK( frame::get_fin(h1) == false );\n    BOOST_CHECK( frame::get_rsv1(h1) == false );\n    BOOST_CHECK( frame::get_rsv2(h1) == false );\n    BOOST_CHECK( frame::get_rsv3(h1) == false );\n    BOOST_CHECK( frame::get_masked(h1) == false );\n\n    BOOST_CHECK( frame::get_fin(h2) == true );\n    BOOST_CHECK( frame::get_rsv1(h2) == true );\n    BOOST_CHECK( frame::get_rsv2(h2) == true );\n    BOOST_CHECK( frame::get_rsv3(h2) == true );\n    BOOST_CHECK( frame::get_masked(h2) == true );\n\n    // Set Values\n    frame::set_fin(h1,true);\n    BOOST_CHECK( h1.b0 == 0x80 );\n\n    frame::set_rsv1(h1,true);\n    BOOST_CHECK( h1.b0 == 0xC0 );\n\n    frame::set_rsv2(h1,true);\n    BOOST_CHECK( h1.b0 == 0xE0 );\n\n    frame::set_rsv3(h1,true);\n    BOOST_CHECK( h1.b0 == 0xF0 );\n\n    frame::set_masked(h1,true);\n    BOOST_CHECK( h1.b1 == 0x80 );\n}\n\nBOOST_AUTO_TEST_CASE( basic_constructors ) {\n    // Read Values\n    frame::basic_header h1(frame::opcode::TEXT,12,true,false);\n    BOOST_CHECK( frame::get_opcode(h1) == frame::opcode::TEXT );\n    BOOST_CHECK( frame::get_basic_size(h1) == 12 );\n    BOOST_CHECK( frame::get_fin(h1) == true );\n    BOOST_CHECK( frame::get_rsv1(h1) == false );\n    BOOST_CHECK( frame::get_rsv2(h1) == false );\n    BOOST_CHECK( frame::get_rsv3(h1) == false );\n    BOOST_CHECK( frame::get_masked(h1) == false );\n\n    frame::basic_header h2(frame::opcode::BINARY,0,false,false,false,true);\n    BOOST_CHECK( frame::get_opcode(h2) == frame::opcode::BINARY );\n    BOOST_CHECK( frame::get_basic_size(h2) == 0 );\n    BOOST_CHECK( frame::get_fin(h2) == false );\n    BOOST_CHECK( frame::get_rsv1(h2) == false );\n    BOOST_CHECK( frame::get_rsv2(h2) == true );\n    BOOST_CHECK( frame::get_rsv3(h2) == false );\n    BOOST_CHECK( frame::get_masked(h2) == false );\n}\n\nBOOST_AUTO_TEST_CASE( basic_size ) {\n    frame::basic_header h1(0x00,0x00); // length 0\n    frame::basic_header h2(0x00,0x01); // length 1\n    frame::basic_header h3(0x00,0x7D); // length 125\n    frame::basic_header h4(0x00,0x7E); // length 126\n    frame::basic_header h5(0x00,0x7F); // length 127\n    frame::basic_header h6(0x00,0x80); // length 0, mask bit set\n\n    BOOST_CHECK( frame::get_basic_size(h1) == 0 );\n    BOOST_CHECK( frame::get_basic_size(h2) == 1 );\n    BOOST_CHECK( frame::get_basic_size(h3) == 125 );\n    BOOST_CHECK( frame::get_basic_size(h4) == 126 );\n    BOOST_CHECK( frame::get_basic_size(h5) == 127 );\n    BOOST_CHECK( frame::get_basic_size(h6) == 0 );\n\n    /*frame::set_basic_size(h1,1);\n    BOOST_CHECK( h1.b1 == 0x01 );\n\n    frame::set_basic_size(h1,125);\n    BOOST_CHECK( h1.b1 == 0x7D );\n\n    frame::set_basic_size(h1,126);\n    BOOST_CHECK( h1.b1 == 0x7E );\n\n    frame::set_basic_size(h1,127);\n    BOOST_CHECK( h1.b1 == 0x7F );\n\n    frame::set_basic_size(h1,0);\n    BOOST_CHECK( h1.b1 == 0x00 );*/\n}\n\nBOOST_AUTO_TEST_CASE( basic_header_length ) {\n    frame::basic_header h1(0x82,0x00); // short binary frame, unmasked\n    frame::basic_header h2(0x82,0x80); // short binary frame, masked\n    frame::basic_header h3(0x82,0x7E); // medium binary frame, unmasked\n    frame::basic_header h4(0x82,0xFE); // medium binary frame, masked\n    frame::basic_header h5(0x82,0x7F); // jumbo binary frame, unmasked\n    frame::basic_header h6(0x82,0xFF); // jumbo binary frame, masked\n\n    BOOST_CHECK( frame::get_header_len(h1) == 2);\n    BOOST_CHECK( frame::get_header_len(h2) == 6);\n    BOOST_CHECK( frame::get_header_len(h3) == 4);\n    BOOST_CHECK( frame::get_header_len(h4) == 8);\n    BOOST_CHECK( frame::get_header_len(h5) == 10);\n    BOOST_CHECK( frame::get_header_len(h6) == 14);\n}\n\nBOOST_AUTO_TEST_CASE( basic_opcode ) {\n    frame::basic_header h1(0x00,0x00);\n\n    BOOST_CHECK( is_control(frame::opcode::CONTINUATION) == false);\n    BOOST_CHECK( is_control(frame::opcode::TEXT) == false);\n    BOOST_CHECK( is_control(frame::opcode::BINARY) == false);\n    BOOST_CHECK( is_control(frame::opcode::CLOSE) == true);\n    BOOST_CHECK( is_control(frame::opcode::PING) == true);\n    BOOST_CHECK( is_control(frame::opcode::PONG) == true);\n\n    BOOST_CHECK( frame::get_opcode(h1) == frame::opcode::CONTINUATION );\n}\n\nBOOST_AUTO_TEST_CASE( extended_header_basics ) {\n    frame::extended_header h1;\n    uint8_t h1_solution[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\n    frame::extended_header h2(uint16_t(255));\n    uint8_t h2_solution[12] = {0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,\n                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\n    frame::extended_header h3(uint16_t(256),htonl(0x8040201));\n    uint8_t h3_solution[12] = {0x01, 0x00, 0x08, 0x04, 0x02, 0x01,\n                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\n    frame::extended_header h4(uint64_t(0x0807060504030201LL));\n    uint8_t h4_solution[12] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03,\n                               0x02, 0x01, 0x00, 0x00, 0x00, 0x00};\n\n    frame::extended_header h5(uint64_t(0x0807060504030201LL),htonl(0x8040201));\n    uint8_t h5_solution[12] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03,\n                               0x02, 0x01, 0x08, 0x04, 0x02, 0x01};\n\n    BOOST_CHECK( std::equal(h1_solution,h1_solution+12,h1.bytes) );\n    BOOST_CHECK( std::equal(h2_solution,h2_solution+12,h2.bytes) );\n    BOOST_CHECK( std::equal(h3_solution,h3_solution+12,h3.bytes) );\n    BOOST_CHECK( std::equal(h4_solution,h4_solution+12,h4.bytes) );\n    BOOST_CHECK( std::equal(h5_solution,h5_solution+12,h5.bytes) );\n}\n\nBOOST_AUTO_TEST_CASE( extended_header_extractors ) {\n    frame::basic_header h1(0x00,0x7E);\n    frame::extended_header e1(uint16_t(255));\n    BOOST_CHECK( get_extended_size(e1) == 255 );\n    BOOST_CHECK( get_payload_size(h1,e1) == 255 );\n    BOOST_CHECK( get_masking_key_offset(h1) == 2 );\n    BOOST_CHECK( get_masking_key(h1,e1).i == 0 );\n\n    frame::basic_header h2(0x00,0x7F);\n    frame::extended_header e2(uint64_t(0x0807060504030201LL));\n    BOOST_CHECK( get_jumbo_size(e2) == 0x0807060504030201LL );\n    BOOST_CHECK( get_payload_size(h2,e2) == 0x0807060504030201LL );\n    BOOST_CHECK( get_masking_key_offset(h2) == 8 );\n    BOOST_CHECK( get_masking_key(h2,e2).i == 0 );\n\n    frame::basic_header h3(0x00,0xFE);\n    frame::extended_header e3(uint16_t(255),0x08040201);\n    BOOST_CHECK( get_extended_size(e3) == 255 );\n    BOOST_CHECK( get_payload_size(h3,e3) == 255 );\n    BOOST_CHECK( get_masking_key_offset(h3) == 2 );\n    BOOST_CHECK( get_masking_key(h3,e3).i == 0x08040201 );\n\n    frame::basic_header h4(0x00,0xFF);\n    frame::extended_header e4(uint64_t(0x0807060504030201LL),0x08040201);\n    BOOST_CHECK( get_jumbo_size(e4) == 0x0807060504030201LL );\n    BOOST_CHECK( get_payload_size(h4,e4) == 0x0807060504030201LL );\n    BOOST_CHECK( get_masking_key_offset(h4) == 8 );\n    BOOST_CHECK( get_masking_key(h4,e4).i == 0x08040201 );\n\n    frame::basic_header h5(0x00,0x7D);\n    frame::extended_header e5;\n    BOOST_CHECK( get_payload_size(h5,e5) == 125 );\n}\n\nBOOST_AUTO_TEST_CASE( header_preparation ) {\n    frame::basic_header h1(0x81,0xFF); //\n    frame::extended_header e1(uint64_t(0xFFFFFLL),htonl(0xD5FB70EE));\n    std::string p1 = prepare_header(h1, e1);\n    uint8_t s1[14] = {0x81, 0xFF,\n                     0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF,\n                     0xD5, 0xFB, 0x70, 0xEE};\n\n    BOOST_CHECK( p1.size() == 14);\n    BOOST_CHECK( std::equal(p1.begin(),p1.end(),reinterpret_cast<char*>(s1)) );\n\n    frame::basic_header h2(0x81,0x7E); //\n    frame::extended_header e2(uint16_t(255));\n    std::string p2 = prepare_header(h2, e2);\n    uint8_t s2[4] = {0x81, 0x7E, 0x00, 0xFF};\n\n    BOOST_CHECK( p2.size() == 4);\n    BOOST_CHECK( std::equal(p2.begin(),p2.end(),reinterpret_cast<char*>(s2)) );\n}\n\nBOOST_AUTO_TEST_CASE( prepare_masking_key ) {\n    frame::masking_key_type key;\n\n    key.i = htonl(0x12345678);\n\n    if (sizeof(size_t) == 8) {\n        BOOST_CHECK(\n            frame::prepare_masking_key(key) == lib::net::_htonll(0x1234567812345678LL)\n        );\n    } else {\n        BOOST_CHECK( frame::prepare_masking_key(key) == htonl(0x12345678) );\n    }\n}\n\nBOOST_AUTO_TEST_CASE( prepare_masking_key2 ) {\n    frame::masking_key_type key;\n\n    key.i = htonl(0xD5FB70EE);\n\n    // One call\n    if (sizeof(size_t) == 8) {\n        BOOST_CHECK(\n            frame::prepare_masking_key(key) == lib::net::_htonll(0xD5FB70EED5FB70EELL)\n        );\n    } else {\n        BOOST_CHECK( frame::prepare_masking_key(key) == htonl(0xD5FB70EE) );\n    }\n}\n\n// TODO: figure out a way to run/test both 4 and 8 byte versions.\nBOOST_AUTO_TEST_CASE( circshift ) {\n    /*if (sizeof(size_t) == 8) {\n        size_t test = 0x0123456789abcdef;\n\n        BOOST_CHECK( frame::circshift_prepared_key(test,0) == 0x0123456789abcdef);\n        BOOST_CHECK( frame::circshift_prepared_key(test,1) == 0xef0123456789abcd);\n        BOOST_CHECK( frame::circshift_prepared_key(test,2) == 0xcdef0123456789ab);\n        BOOST_CHECK( frame::circshift_prepared_key(test,3) == 0xabcdef0123456789);\n    } else {\n        size_t test = 0x01234567;\n\n        BOOST_CHECK( frame::circshift_prepared_key(test,0) == 0x01234567);\n        BOOST_CHECK( frame::circshift_prepared_key(test,1) == 0x67012345);\n        BOOST_CHECK( frame::circshift_prepared_key(test,2) == 0x45670123);\n        BOOST_CHECK( frame::circshift_prepared_key(test,3) == 0x23456701);\n    }*/\n}\n\nBOOST_AUTO_TEST_CASE( block_byte_mask ) {\n    uint8_t input[15] = {0x00, 0x00, 0x00, 0x00,\n                         0x00, 0x00, 0x00, 0x00,\n                         0x00, 0x00, 0x00, 0x00,\n                         0x00, 0x00, 0x00};\n\n    uint8_t output[15];\n\n    uint8_t masked[15] = {0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02};\n\n    frame::masking_key_type key;\n    key.c[0] = 0x00;\n    key.c[1] = 0x01;\n    key.c[2] = 0x02;\n    key.c[3] = 0x03;\n\n    byte_mask(input,input+15,output,key);\n\n    BOOST_CHECK( std::equal(output,output+15,masked) );\n}\n\nBOOST_AUTO_TEST_CASE( block_byte_mask_inplace ) {\n    uint8_t buffer[15] = {0x00, 0x00, 0x00, 0x00,\n                          0x00, 0x00, 0x00, 0x00,\n                          0x00, 0x00, 0x00, 0x00,\n                          0x00, 0x00, 0x00};\n\n    uint8_t masked[15] = {0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02};\n\n    frame::masking_key_type key;\n    key.c[0] = 0x00;\n    key.c[1] = 0x01;\n    key.c[2] = 0x02;\n    key.c[3] = 0x03;\n\n    byte_mask(buffer,buffer+15,key);\n\n    BOOST_CHECK( std::equal(buffer,buffer+15,masked) );\n}\n\nBOOST_AUTO_TEST_CASE( block_word_mask ) {\n    uint8_t input[15] =  {0x00, 0x00, 0x00, 0x00,\n                          0x00, 0x00, 0x00, 0x00,\n                          0x00, 0x00, 0x00, 0x00,\n                          0x00, 0x00, 0x00};\n\n    uint8_t output[15];\n\n    uint8_t masked[15] = {0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02};\n\n    frame::masking_key_type key;\n    key.c[0] = 0x00;\n    key.c[1] = 0x01;\n    key.c[2] = 0x02;\n    key.c[3] = 0x03;\n\n    word_mask_exact(input,output,15,key);\n\n    BOOST_CHECK( std::equal(output,output+15,masked) );\n}\n\nBOOST_AUTO_TEST_CASE( block_word_mask_inplace ) {\n    uint8_t buffer[15] = {0x00, 0x00, 0x00, 0x00,\n                          0x00, 0x00, 0x00, 0x00,\n                          0x00, 0x00, 0x00, 0x00,\n                          0x00, 0x00, 0x00};\n\n    uint8_t masked[15] = {0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02};\n\n    frame::masking_key_type key;\n    key.c[0] = 0x00;\n    key.c[1] = 0x01;\n    key.c[2] = 0x02;\n    key.c[3] = 0x03;\n\n    word_mask_exact(buffer,15,key);\n\n    BOOST_CHECK( std::equal(buffer,buffer+15,masked) );\n}\n\nBOOST_AUTO_TEST_CASE( continuous_word_mask ) {\n    uint8_t input[16];\n    uint8_t output[16];\n\n    uint8_t masked[16] = {0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x00};\n\n    frame::masking_key_type key;\n    key.c[0] = 0x00;\n    key.c[1] = 0x01;\n    key.c[2] = 0x02;\n    key.c[3] = 0x03;\n\n    // One call\n    size_t pkey,pkey_temp;\n    pkey = frame::prepare_masking_key(key);\n    std::fill_n(input,16,0x00);\n    std::fill_n(output,16,0x00);\n    frame::word_mask_circ(input,output,15,pkey);\n    BOOST_CHECK( std::equal(output,output+16,masked) );\n\n    // calls not split on word boundaries\n    pkey = frame::prepare_masking_key(key);\n    std::fill_n(input,16,0x00);\n    std::fill_n(output,16,0x00);\n\n    pkey_temp = frame::word_mask_circ(input,output,7,pkey);\n    BOOST_CHECK( std::equal(output,output+7,masked) );\n    BOOST_CHECK( pkey_temp == frame::circshift_prepared_key(pkey,3) );\n\n    pkey_temp = frame::word_mask_circ(input+7,output+7,8,pkey_temp);\n    BOOST_CHECK( std::equal(output,output+16,masked) );\n    BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );\n}\n\nBOOST_AUTO_TEST_CASE( continuous_byte_mask ) {\n    uint8_t input[16];\n    uint8_t output[16];\n\n    uint8_t masked[16] = {0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x00};\n\n    frame::masking_key_type key;\n    key.c[0] = 0x00;\n    key.c[1] = 0x01;\n    key.c[2] = 0x02;\n    key.c[3] = 0x03;\n\n    // One call\n    size_t pkey,pkey_temp;\n    pkey = frame::prepare_masking_key(key);\n    std::fill_n(input,16,0x00);\n    std::fill_n(output,16,0x00);\n    frame::byte_mask_circ(input,output,15,pkey);\n    BOOST_CHECK( std::equal(output,output+16,masked) );\n\n    // calls not split on word boundaries\n    pkey = frame::prepare_masking_key(key);\n    std::fill_n(input,16,0x00);\n    std::fill_n(output,16,0x00);\n\n    pkey_temp = frame::byte_mask_circ(input,output,7,pkey);\n    BOOST_CHECK( std::equal(output,output+7,masked) );\n    BOOST_CHECK( pkey_temp == frame::circshift_prepared_key(pkey,3) );\n\n    pkey_temp = frame::byte_mask_circ(input+7,output+7,8,pkey_temp);\n    BOOST_CHECK( std::equal(output,output+16,masked) );\n    BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );\n}\n\nBOOST_AUTO_TEST_CASE( continuous_word_mask_inplace ) {\n    uint8_t buffer[16];\n\n    uint8_t masked[16] = {0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x00};\n\n    frame::masking_key_type key;\n    key.c[0] = 0x00;\n    key.c[1] = 0x01;\n    key.c[2] = 0x02;\n    key.c[3] = 0x03;\n\n    // One call\n    size_t pkey,pkey_temp;\n    pkey = frame::prepare_masking_key(key);\n    std::fill_n(buffer,16,0x00);\n    frame::word_mask_circ(buffer,15,pkey);\n    BOOST_CHECK( std::equal(buffer,buffer+16,masked) );\n\n    // calls not split on word boundaries\n    pkey = frame::prepare_masking_key(key);\n    std::fill_n(buffer,16,0x00);\n\n    pkey_temp = frame::word_mask_circ(buffer,7,pkey);\n    BOOST_CHECK( std::equal(buffer,buffer+7,masked) );\n    BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );\n\n    pkey_temp = frame::word_mask_circ(buffer+7,8,pkey_temp);\n    BOOST_CHECK( std::equal(buffer,buffer+16,masked) );\n    BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );\n}\n\nBOOST_AUTO_TEST_CASE( continuous_byte_mask_inplace ) {\n    uint8_t buffer[16];\n\n    uint8_t masked[16] = {0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x03,\n                          0x00, 0x01, 0x02, 0x00};\n\n    frame::masking_key_type key;\n    key.c[0] = 0x00;\n    key.c[1] = 0x01;\n    key.c[2] = 0x02;\n    key.c[3] = 0x03;\n\n    // One call\n    size_t pkey,pkey_temp;\n    pkey = frame::prepare_masking_key(key);\n    std::fill_n(buffer,16,0x00);\n    frame::byte_mask_circ(buffer,15,pkey);\n    BOOST_CHECK( std::equal(buffer,buffer+16,masked) );\n\n    // calls not split on word boundaries\n    pkey = frame::prepare_masking_key(key);\n    std::fill_n(buffer,16,0x00);\n\n    pkey_temp = frame::byte_mask_circ(buffer,7,pkey);\n    BOOST_CHECK( std::equal(buffer,buffer+7,masked) );\n    BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );\n\n    pkey_temp = frame::byte_mask_circ(buffer+7,8,pkey_temp);\n    BOOST_CHECK( std::equal(buffer,buffer+16,masked) );\n    BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );\n}\n\nBOOST_AUTO_TEST_CASE( continuous_word_mask2 ) {\n    uint8_t buffer[12] = {0xA6, 0x15, 0x97, 0xB9,\n                          0x81, 0x50, 0xAC, 0xBA,\n                          0x9C, 0x1C, 0x9F, 0xF4};\n\n    uint8_t unmasked[12] = {0x48, 0x65, 0x6C, 0x6C,\n                            0x6F, 0x20, 0x57, 0x6F,\n                            0x72, 0x6C, 0x64, 0x21};\n\n    frame::masking_key_type key;\n    key.c[0] = 0xEE;\n    key.c[1] = 0x70;\n    key.c[2] = 0xFB;\n    key.c[3] = 0xD5;\n\n    // One call\n    size_t pkey;\n    pkey = frame::prepare_masking_key(key);\n    frame::word_mask_circ(buffer,12,pkey);\n    BOOST_CHECK( std::equal(buffer,buffer+12,unmasked) );\n}\n"
  },
  {
    "path": "test/utility/sha1.cpp",
    "content": "/*\n * Copyright (c) 2011, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE sha1\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/sha1/sha1.hpp>\n#include <websocketpp/utilities.hpp>\n\nBOOST_AUTO_TEST_SUITE ( sha1 )\n\nBOOST_AUTO_TEST_CASE( sha1_test_a ) {\n    unsigned char hash[20];\n    unsigned char reference[20] = {0xa9, 0x99, 0x3e, 0x36, 0x47,\n                                   0x06, 0x81, 0x6a, 0xba, 0x3e,\n                                   0x25, 0x71, 0x78, 0x50, 0xc2,\n                                   0x6c, 0x9c, 0xd0, 0xd8, 0x9d};\n\n    websocketpp::sha1::calc(\"abc\",3,hash);\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(hash, hash+20, reference, reference+20);\n}\n\nBOOST_AUTO_TEST_CASE( sha1_test_b ) {\n    unsigned char hash[20];\n    unsigned char reference[20] = {0x84, 0x98, 0x3e, 0x44, 0x1c,\n                                   0x3b, 0xd2, 0x6e, 0xba, 0xae,\n                                   0x4a, 0xa1, 0xf9, 0x51, 0x29,\n                                   0xe5, 0xe5, 0x46, 0x70, 0xf1};\n\n    websocketpp::sha1::calc(\n        \"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\",56,hash);\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(hash, hash+20, reference, reference+20);\n}\n\nBOOST_AUTO_TEST_CASE( sha1_test_c ) {\n    std::string input;\n    unsigned char hash[20];\n    unsigned char reference[20] = {0x34, 0xaa, 0x97, 0x3c, 0xd4,\n                                   0xc4, 0xda, 0xa4, 0xf6, 0x1e,\n                                   0xeb, 0x2b, 0xdb, 0xad, 0x27,\n                                   0x31, 0x65, 0x34, 0x01, 0x6f};\n\n    for (int i = 0; i < 1000000; i++) {\n        input += 'a';\n    }\n\n    websocketpp::sha1::calc(input.c_str(),input.size(),hash);\n\n    BOOST_CHECK_EQUAL_COLLECTIONS(hash, hash+20, reference, reference+20);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/utility/uri.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE uri\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/uri.hpp>\n\n// Test a regular valid ws URI\nBOOST_AUTO_TEST_CASE( uri_valid ) {\n    websocketpp::uri uri(\"ws://localhost:9000/chat\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( !uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"ws\");\n    BOOST_CHECK_EQUAL( uri.get_host(), \"localhost\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 9000 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/chat\" );\n    BOOST_CHECK_EQUAL( uri.get_query(), \"\" );\n}\n\n// Test a regular valid ws URI\nBOOST_AUTO_TEST_CASE( uri_valid_no_port_unsecure ) {\n    websocketpp::uri uri(\"ws://localhost/chat\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( !uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"ws\");\n    BOOST_CHECK_EQUAL( uri.get_host(), \"localhost\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 80 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/chat\" );\n}\n\n// Valid URI with no port (secure)\nBOOST_AUTO_TEST_CASE( uri_valid_no_port_secure ) {\n    websocketpp::uri uri(\"wss://localhost/chat\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"wss\");\n    BOOST_CHECK_EQUAL( uri.get_host(), \"localhost\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 443 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/chat\" );\n}\n\n// Valid URI with no resource\nBOOST_AUTO_TEST_CASE( uri_valid_no_resource ) {\n    websocketpp::uri uri(\"wss://localhost:9000\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"wss\");\n    BOOST_CHECK_EQUAL( uri.get_host(), \"localhost\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 9000 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/\" );\n}\n\n// Valid URI IPv6 Literal\nBOOST_AUTO_TEST_CASE( uri_valid_ipv6_literal ) {\n    websocketpp::uri uri(\"wss://[::1]:9000/chat\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"wss\");\n    BOOST_CHECK_EQUAL( uri.get_host(), \"::1\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 9000 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/chat\" );\n}\n\n// Valid URI with more complicated host\nBOOST_AUTO_TEST_CASE( uri_valid_2 ) {\n    websocketpp::uri uri(\"wss://thor-websocket.zaphoyd.net:88/\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"wss\");\n    BOOST_CHECK_EQUAL( uri.get_host(), \"thor-websocket.zaphoyd.net\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 88 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/\" );\n}\n\n\n// Invalid URI (port too long)\nBOOST_AUTO_TEST_CASE( uri_invalid_long_port ) {\n    websocketpp::uri uri(\"wss://localhost:900000/chat\");\n\n    BOOST_CHECK( !uri.get_valid() );\n}\n\n// Invalid URI (bogus scheme method)\nBOOST_AUTO_TEST_CASE( uri_invalid_scheme ) {\n    websocketpp::uri uri(\"foo://localhost:9000/chat\");\n\n    BOOST_CHECK( !uri.get_valid() );\n}\n\n// Valid URI (http method)\nBOOST_AUTO_TEST_CASE( uri_http_scheme ) {\n    websocketpp::uri uri(\"http://localhost:9000/chat\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( !uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"http\");\n    BOOST_CHECK_EQUAL( uri.get_host(), \"localhost\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 9000 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/chat\" );\n}\n\n// Valid URI IPv4 literal\nBOOST_AUTO_TEST_CASE( uri_valid_ipv4_literal ) {\n    websocketpp::uri uri(\"wss://127.0.0.1:9000/chat\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"wss\");\n    BOOST_CHECK_EQUAL( uri.get_host(), \"127.0.0.1\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 9000 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/chat\" );\n}\n\n// Valid URI complicated resource path\nBOOST_AUTO_TEST_CASE( uri_valid_3 ) {\n    websocketpp::uri uri(\"wss://localhost:9000/chat/foo/bar\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"wss\");\n    BOOST_CHECK_EQUAL( uri.get_host(), \"localhost\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 9000 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/chat/foo/bar\" );\n}\n\n// Invalid URI broken method separator\nBOOST_AUTO_TEST_CASE( uri_invalid_method_separator ) {\n    websocketpp::uri uri(\"wss:/localhost:9000/chat\");\n\n    BOOST_CHECK( !uri.get_valid() );\n}\n\n// Invalid URI port > 65535\nBOOST_AUTO_TEST_CASE( uri_invalid_gt_16_bit_port ) {\n    websocketpp::uri uri(\"wss:/localhost:70000/chat\");\n\n    BOOST_CHECK( !uri.get_valid() );\n}\n\n// Invalid URI includes uri fragment\nBOOST_AUTO_TEST_CASE( uri_invalid_fragment ) {\n    websocketpp::uri uri(\"wss:/localhost:70000/chat#foo\");\n\n    BOOST_CHECK( !uri.get_valid() );\n}\n\n// Invalid URI with no brackets around IPv6 literal\nBOOST_AUTO_TEST_CASE( uri_invalid_bad_v6_literal_1 ) {\n    websocketpp::uri uri(\"wss://::1/chat\");\n\n    BOOST_CHECK( !uri.get_valid() );\n}\n\n// Invalid URI with port and no brackets around IPv6 literal\nBOOST_AUTO_TEST_CASE( uri_invalid_bad_v6_literal_2 ) {\n    websocketpp::uri uri(\"wss://::1:2009/chat\");\n\n    BOOST_CHECK( !uri.get_valid() );\n}\n\n// Valid URI complicated resource path with query\nBOOST_AUTO_TEST_CASE( uri_valid_4 ) {\n    websocketpp::uri uri(\"wss://localhost:9000/chat/foo/bar?foo=bar\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"wss\" );\n    BOOST_CHECK_EQUAL( uri.get_host(), \"localhost\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 9000 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/chat/foo/bar?foo=bar\" );\n    BOOST_CHECK_EQUAL( uri.get_query(), \"foo=bar\" );\n}\n\n// Valid URI with a mapped v4 ipv6 literal\nBOOST_AUTO_TEST_CASE( uri_valid_v4_mapped ) {\n    websocketpp::uri uri(\"wss://[0000:0000:0000:0000:0000:0000:192.168.1.1]:9000/\");\n\n    BOOST_CHECK( uri.get_valid() );\n    BOOST_CHECK( uri.get_secure() );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"wss\" );\n    BOOST_CHECK_EQUAL( uri.get_host(), \"0000:0000:0000:0000:0000:0000:192.168.1.1\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 9000 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/\" );\n}\n\n// Valid URI with a v6 address with mixed case\nBOOST_AUTO_TEST_CASE( uri_valid_v6_mixed_case ) {\n    websocketpp::uri uri(\"wss://[::10aB]:9000/\");\n\n    BOOST_CHECK( uri.get_valid() == true );\n    BOOST_CHECK( uri.get_secure() == true );\n    BOOST_CHECK_EQUAL( uri.get_scheme(), \"wss\" );\n    BOOST_CHECK_EQUAL( uri.get_host(), \"::10aB\");\n    BOOST_CHECK_EQUAL( uri.get_port(), 9000 );\n    BOOST_CHECK_EQUAL( uri.get_resource(), \"/\" );\n}\n\n// Valid URI with a v6 address with mixed case\nBOOST_AUTO_TEST_CASE( uri_invalid_no_scheme ) {\n    websocketpp::uri uri(\"myserver.com\");\n\n    BOOST_CHECK( !uri.get_valid() );\n}\n\n// Invalid IPv6 literal\n/*BOOST_AUTO_TEST_CASE( uri_invalid_v6_nonhex ) {\n    websocketpp::uri uri(\"wss://[g::1]:9000/\");\n\n    BOOST_CHECK( uri.get_valid() == false );\n}*/\n\n// TODO: tests for the other two constructors\n"
  },
  {
    "path": "test/utility/utilities.cpp",
    "content": "/*\n * Copyright (c) 2011, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n//#define BOOST_TEST_DYN_LINK\n#define BOOST_TEST_MODULE utility\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/utilities.hpp>\n\nBOOST_AUTO_TEST_SUITE ( utility )\n\nBOOST_AUTO_TEST_CASE( substr_found ) {\n    std::string haystack = \"abc123\";\n    std::string needle = \"abc\";\n\n    BOOST_CHECK(websocketpp::utility::ci_find_substr(haystack,needle) ==haystack.begin());\n}\n\nBOOST_AUTO_TEST_CASE( substr_found_ci ) {\n    std::string haystack = \"abc123\";\n    std::string needle = \"aBc\";\n\n    BOOST_CHECK(websocketpp::utility::ci_find_substr(haystack,needle) ==haystack.begin());\n}\n\nBOOST_AUTO_TEST_CASE( substr_not_found ) {\n    std::string haystack = \"abd123\";\n    std::string needle = \"abcd\";\n\n    BOOST_CHECK(websocketpp::utility::ci_find_substr(haystack,needle) == haystack.end());\n}\n\nBOOST_AUTO_TEST_CASE( to_lower ) {\n    std::string in = \"AbCd\";\n\n    BOOST_CHECK_EQUAL(websocketpp::utility::to_lower(in), \"abcd\");\n}\n\nBOOST_AUTO_TEST_CASE( string_replace_all ) {\n    std::string source = \"foo \\\"bar\\\" baz\";\n    std::string dest = \"foo \\\\\\\"bar\\\\\\\" baz\";\n\n    using websocketpp::utility::string_replace_all;\n    BOOST_CHECK_EQUAL(string_replace_all(source,\"\\\"\",\"\\\\\\\"\"),dest);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "tutorials/broadcast_tutorial/broadcast_tutorial.md",
    "content": "Broadcast Tutorial\n==================\n\nThis tutorial will dig into some more nitty gritty details on how to build high\nscalability, high performance websocket servers for broadcast like workflows.\n\nWill go into features like:\n- minimizing work done in handlers\n- using asio thread pool mode\n- teaming multiple endpoints\n- setting accept queue depth\n- tuning compile time buffer sizes\n- prepared messages\n- flow control\n- basic operating system level tuning, particularly increasing file descriptor limits.\n- measuring performance with wsperf / autobahn\n- tuning permessage-deflate compression settings"
  },
  {
    "path": "tutorials/chat_tutorial/chat_tutorial.md",
    "content": "Chat Tutorial\n=============\n\nGoals of this tutorial:\n- Implement a realtime websocket chat server\n\n\nServer\n- Nicknames\n- Channels\n- Subprotocol\n- Origin restrictions\n- HTTP statistics page\n"
  },
  {
    "path": "tutorials/utility_client/step1.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial.\n// Additional related material can be found in the tutorials/utility_client\n// directory of the WebSocket++ repository.\n\n#include <iostream>\n#include <string>\n\nint main() {\n    bool done = false;\n    std::string input;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout \n                << \"\\nCommand List:\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else {\n            std::cout << \"Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tutorials/utility_client/step2.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial.\n// Additional related material can be found in the tutorials/utility_client\n// directory of the WebSocket++ repository.\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <iostream>\n#include <string>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nint main() {\n    bool done = false;\n    std::string input;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout\n                << \"\\nCommand List:\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else {\n            std::cout << \"Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tutorials/utility_client/step3.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial.\n// Additional related material can be found in the tutorials/utility_client\n// directory of the WebSocket++ repository.\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <websocketpp/common/thread.hpp>\n#include <websocketpp/common/memory.hpp>\n\n#include <iostream>\n#include <string>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nclass websocket_endpoint {\npublic:\n    websocket_endpoint () {\n        m_endpoint.clear_access_channels(websocketpp::log::alevel::all);\n        m_endpoint.clear_error_channels(websocketpp::log::elevel::all);\n\n        m_endpoint.init_asio();\n        m_endpoint.start_perpetual();\n\n        m_thread = websocketpp::lib::make_shared<websocketpp::lib::thread>(&client::run, &m_endpoint);\n    }\nprivate:\n    client m_endpoint;\n    websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;\n};\n\nint main() {\n    bool done = false;\n    std::string input;\n    websocket_endpoint endpoint;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout \n                << \"\\nCommand List:\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else {\n            std::cout << \"Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tutorials/utility_client/step4.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial.\n// Additional related material can be found in the tutorials/utility_client\n// directory of the WebSocket++ repository.\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <websocketpp/common/thread.hpp>\n#include <websocketpp/common/memory.hpp>\n\n#include <cstdlib>\n#include <iostream>\n#include <map>\n#include <string>\n#include <sstream>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nclass connection_metadata {\npublic:\n    typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;\n\n    connection_metadata(int id, websocketpp::connection_hdl hdl, std::string uri)\n      : m_id(id)\n      , m_hdl(hdl)\n      , m_status(\"Connecting\")\n      , m_uri(uri)\n      , m_server(\"N/A\")\n    {}\n\n    void on_open(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Open\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n    }\n\n    void on_fail(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Failed\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n        m_error_reason = con->get_ec().message();\n    }\n\n    friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);\nprivate:\n    int m_id;\n    websocketpp::connection_hdl m_hdl;\n    std::string m_status;\n    std::string m_uri;\n    std::string m_server;\n    std::string m_error_reason;\n};\n\nstd::ostream & operator<< (std::ostream & out, connection_metadata const & data) {\n    out << \"> URI: \" << data.m_uri << \"\\n\"\n        << \"> Status: \" << data.m_status << \"\\n\"\n        << \"> Remote Server: \" << (data.m_server.empty() ? \"None Specified\" : data.m_server) << \"\\n\"\n        << \"> Error/close reason: \" << (data.m_error_reason.empty() ? \"N/A\" : data.m_error_reason);\n\n    return out;\n}\n\nclass websocket_endpoint {\npublic:\n    websocket_endpoint () : m_next_id(0) {\n        m_endpoint.clear_access_channels(websocketpp::log::alevel::all);\n        m_endpoint.clear_error_channels(websocketpp::log::elevel::all);\n\n        m_endpoint.init_asio();\n        m_endpoint.start_perpetual();\n\n        m_thread = websocketpp::lib::make_shared<websocketpp::lib::thread>(&client::run, &m_endpoint);\n    }\n\n    int connect(std::string const & uri) {\n        websocketpp::lib::error_code ec;\n\n        client::connection_ptr con = m_endpoint.get_connection(uri, ec);\n\n        if (ec) {\n            std::cout << \"> Connect initialization error: \" << ec.message() << std::endl;\n            return -1;\n        }\n\n        int new_id = m_next_id++;\n        connection_metadata::ptr metadata_ptr = websocketpp::lib::make_shared<connection_metadata>(new_id, con->get_handle(), uri);\n        m_connection_list[new_id] = metadata_ptr;\n\n        con->set_open_handler(websocketpp::lib::bind(\n            &connection_metadata::on_open,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_fail_handler(websocketpp::lib::bind(\n            &connection_metadata::on_fail,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n\n        m_endpoint.connect(con);\n\n        return new_id;\n    }\n\n    connection_metadata::ptr get_metadata(int id) const {\n        con_list::const_iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            return connection_metadata::ptr();\n        } else {\n            return metadata_it->second;\n        }\n    }\nprivate:\n    typedef std::map<int,connection_metadata::ptr> con_list;\n\n    client m_endpoint;\n    websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;\n\n    con_list m_connection_list;\n    int m_next_id;\n};\n\nint main() {\n    bool done = false;\n    std::string input;\n    websocket_endpoint endpoint;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout\n                << \"\\nCommand List:\\n\"\n                << \"connect <ws uri>\\n\"\n                << \"show <connection id>\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else if (input.substr(0,7) == \"connect\") {\n            int id = endpoint.connect(input.substr(8));\n            if (id != -1) {\n                std::cout << \"> Created connection with id \" << id << std::endl;\n            }\n        } else if (input.substr(0,4) == \"show\") {\n            int id = atoi(input.substr(5).c_str());\n\n            connection_metadata::ptr metadata = endpoint.get_metadata(id);\n            if (metadata) {\n                std::cout << *metadata << std::endl;\n            } else {\n                std::cout << \"> Unknown connection id \" << id << std::endl;\n            }\n        } else {\n            std::cout << \"> Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n\n/*\n\nclang++ -std=c++11 -stdlib=libc++ -I/Users/zaphoyd/software/websocketpp/ -I/Users/zaphoyd/software/boost_1_55_0/ -D_WEBSOCKETPP_CPP11_STL_ step4.cpp /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_system.a\n\nclang++ -I/Users/zaphoyd/software/websocketpp/ -I/Users/zaphoyd/software/boost_1_55_0/ step4.cpp /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_system.a /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_thread.a /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_random.a\n\nclang++ -std=c++11 -stdlib=libc++ -I/Users/zaphoyd/Documents/websocketpp/ -I/Users/zaphoyd/Documents/boost_1_53_0_libcpp/ -D_WEBSOCKETPP_CPP11_STL_ step4.cpp /Users/zaphoyd/Documents/boost_1_53_0_libcpp/stage/lib/libboost_system.a\n\n*/\n"
  },
  {
    "path": "tutorials/utility_client/step5.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial.\n// Additional related material can be found in the tutorials/utility_client\n// directory of the WebSocket++ repository.\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <websocketpp/common/thread.hpp>\n#include <websocketpp/common/memory.hpp>\n\n#include <cstdlib>\n#include <iostream>\n#include <map>\n#include <string>\n#include <sstream>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nclass connection_metadata {\npublic:\n    typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;\n\n    connection_metadata(int id, websocketpp::connection_hdl hdl, std::string uri)\n      : m_id(id)\n      , m_hdl(hdl)\n      , m_status(\"Connecting\")\n      , m_uri(uri)\n      , m_server(\"N/A\")\n    {}\n\n    void on_open(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Open\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n    }\n\n    void on_fail(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Failed\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n        m_error_reason = con->get_ec().message();\n    }\n    \n    void on_close(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Closed\";\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        std::stringstream s;\n        s << \"close code: \" << con->get_remote_close_code() << \" (\" \n          << websocketpp::close::status::get_string(con->get_remote_close_code()) \n          << \"), close reason: \" << con->get_remote_close_reason();\n        m_error_reason = s.str();\n    }\n\n    websocketpp::connection_hdl get_hdl() const {\n        return m_hdl;\n    }\n    \n    int get_id() const {\n        return m_id;\n    }\n    \n    std::string get_status() const {\n        return m_status;\n    }\n\n    friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);\nprivate:\n    int m_id;\n    websocketpp::connection_hdl m_hdl;\n    std::string m_status;\n    std::string m_uri;\n    std::string m_server;\n    std::string m_error_reason;\n};\n\nstd::ostream & operator<< (std::ostream & out, connection_metadata const & data) {\n    out << \"> URI: \" << data.m_uri << \"\\n\"\n        << \"> Status: \" << data.m_status << \"\\n\"\n        << \"> Remote Server: \" << (data.m_server.empty() ? \"None Specified\" : data.m_server) << \"\\n\"\n        << \"> Error/close reason: \" << (data.m_error_reason.empty() ? \"N/A\" : data.m_error_reason);\n\n    return out;\n}\n\nclass websocket_endpoint {\npublic:\n    websocket_endpoint () : m_next_id(0) {\n        m_endpoint.clear_access_channels(websocketpp::log::alevel::all);\n        m_endpoint.clear_error_channels(websocketpp::log::elevel::all);\n\n        m_endpoint.init_asio();\n        m_endpoint.start_perpetual();\n\n        m_thread = websocketpp::lib::make_shared<websocketpp::lib::thread>(&client::run, &m_endpoint);\n    }\n\n    ~websocket_endpoint() {\n        m_endpoint.stop_perpetual();\n        \n        for (con_list::const_iterator it = m_connection_list.begin(); it != m_connection_list.end(); ++it) {\n            if (it->second->get_status() != \"Open\") {\n                // Only close open connections\n                continue;\n            }\n            \n            std::cout << \"> Closing connection \" << it->second->get_id() << std::endl;\n            \n            websocketpp::lib::error_code ec;\n            m_endpoint.close(it->second->get_hdl(), websocketpp::close::status::going_away, \"\", ec);\n            if (ec) {\n                std::cout << \"> Error closing connection \" << it->second->get_id() << \": \"  \n                          << ec.message() << std::endl;\n            }\n        }\n        \n        m_thread->join();\n    }\n\n    int connect(std::string const & uri) {\n        websocketpp::lib::error_code ec;\n\n        client::connection_ptr con = m_endpoint.get_connection(uri, ec);\n\n        if (ec) {\n            std::cout << \"> Connect initialization error: \" << ec.message() << std::endl;\n            return -1;\n        }\n\n        int new_id = m_next_id++;\n        connection_metadata::ptr metadata_ptr = websocketpp::lib::make_shared<connection_metadata>(new_id, con->get_handle(), uri);\n        m_connection_list[new_id] = metadata_ptr;\n\n        con->set_open_handler(websocketpp::lib::bind(\n            &connection_metadata::on_open,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_fail_handler(websocketpp::lib::bind(\n            &connection_metadata::on_fail,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_close_handler(websocketpp::lib::bind(\n            &connection_metadata::on_close,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n\n        m_endpoint.connect(con);\n\n        return new_id;\n    }\n\n    void close(int id, websocketpp::close::status::value code, std::string reason) {\n        websocketpp::lib::error_code ec;\n        \n        con_list::iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            std::cout << \"> No connection found with id \" << id << std::endl;\n            return;\n        }\n        \n        m_endpoint.close(metadata_it->second->get_hdl(), code, reason, ec);\n        if (ec) {\n            std::cout << \"> Error initiating close: \" << ec.message() << std::endl;\n        }\n    }\n\n    connection_metadata::ptr get_metadata(int id) const {\n        con_list::const_iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            return connection_metadata::ptr();\n        } else {\n            return metadata_it->second;\n        }\n    }\nprivate:\n    typedef std::map<int,connection_metadata::ptr> con_list;\n\n    client m_endpoint;\n    websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;\n\n    con_list m_connection_list;\n    int m_next_id;\n};\n\nint main() {\n    bool done = false;\n    std::string input;\n    websocket_endpoint endpoint;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout\n                << \"\\nCommand List:\\n\"\n                << \"connect <ws uri>\\n\"\n                << \"close <connection id> [<close code:default=1000>] [<close reason>]\\n\"\n                << \"show <connection id>\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else if (input.substr(0,7) == \"connect\") {\n            int id = endpoint.connect(input.substr(8));\n            if (id != -1) {\n                std::cout << \"> Created connection with id \" << id << std::endl;\n            }\n        } else if (input.substr(0,5) == \"close\") {\n            std::stringstream ss(input);\n            \n            std::string cmd;\n            int id;\n            int close_code = websocketpp::close::status::normal;\n            std::string reason;\n            \n            ss >> cmd >> id >> close_code;\n            std::getline(ss,reason);\n            \n            endpoint.close(id, close_code, reason);\n        }  else if (input.substr(0,4) == \"show\") {\n            int id = atoi(input.substr(5).c_str());\n\n            connection_metadata::ptr metadata = endpoint.get_metadata(id);\n            if (metadata) {\n                std::cout << *metadata << std::endl;\n            } else {\n                std::cout << \"> Unknown connection id \" << id << std::endl;\n            }\n        } else {\n            std::cout << \"> Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n\n/*\n\nclang++ -std=c++11 -stdlib=libc++ -I/Users/zaphoyd/software/websocketpp/ -I/Users/zaphoyd/software/boost_1_55_0/ -D_WEBSOCKETPP_CPP11_STL_ step4.cpp /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_system.a\n\nclang++ -I/Users/zaphoyd/software/websocketpp/ -I/Users/zaphoyd/software/boost_1_55_0/ step4.cpp /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_system.a /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_thread.a /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_random.a\n\nclang++ -std=c++11 -stdlib=libc++ -I/Users/zaphoyd/Documents/websocketpp/ -I/Users/zaphoyd/Documents/boost_1_53_0_libcpp/ -D_WEBSOCKETPP_CPP11_STL_ step4.cpp /Users/zaphoyd/Documents/boost_1_53_0_libcpp/stage/lib/libboost_system.a\n\n*/\n"
  },
  {
    "path": "tutorials/utility_client/step6.cpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial.\n// Additional related material can be found in the tutorials/utility_client\n// directory of the WebSocket++ repository.\n\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <websocketpp/common/thread.hpp>\n#include <websocketpp/common/memory.hpp>\n\n#include <cstdlib>\n#include <iostream>\n#include <map>\n#include <string>\n#include <sstream>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nclass connection_metadata {\npublic:\n    typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;\n\n    connection_metadata(int id, websocketpp::connection_hdl hdl, std::string uri)\n      : m_id(id)\n      , m_hdl(hdl)\n      , m_status(\"Connecting\")\n      , m_uri(uri)\n      , m_server(\"N/A\")\n    {}\n\n    void on_open(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Open\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n    }\n\n    void on_fail(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Failed\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n        m_error_reason = con->get_ec().message();\n    }\n    \n    void on_close(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Closed\";\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        std::stringstream s;\n        s << \"close code: \" << con->get_remote_close_code() << \" (\" \n          << websocketpp::close::status::get_string(con->get_remote_close_code()) \n          << \"), close reason: \" << con->get_remote_close_reason();\n        m_error_reason = s.str();\n    }\n\n    void on_message(websocketpp::connection_hdl, client::message_ptr msg) {\n        if (msg->get_opcode() == websocketpp::frame::opcode::text) {\n            m_messages.push_back(\"<< \" + msg->get_payload());\n        } else {\n            m_messages.push_back(\"<< \" + websocketpp::utility::to_hex(msg->get_payload()));\n        }\n    }\n\n    websocketpp::connection_hdl get_hdl() const {\n        return m_hdl;\n    }\n    \n    int get_id() const {\n        return m_id;\n    }\n    \n    std::string get_status() const {\n        return m_status;\n    }\n\n    void record_sent_message(std::string message) {\n        m_messages.push_back(\">> \" + message);\n    }\n\n    friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);\nprivate:\n    int m_id;\n    websocketpp::connection_hdl m_hdl;\n    std::string m_status;\n    std::string m_uri;\n    std::string m_server;\n    std::string m_error_reason;\n    std::vector<std::string> m_messages;\n};\n\nstd::ostream & operator<< (std::ostream & out, connection_metadata const & data) {\n    out << \"> URI: \" << data.m_uri << \"\\n\"\n        << \"> Status: \" << data.m_status << \"\\n\"\n        << \"> Remote Server: \" << (data.m_server.empty() ? \"None Specified\" : data.m_server) << \"\\n\"\n        << \"> Error/close reason: \" << (data.m_error_reason.empty() ? \"N/A\" : data.m_error_reason) << \"\\n\";\n    out << \"> Messages Processed: (\" << data.m_messages.size() << \") \\n\";\n\n    std::vector<std::string>::const_iterator it;\n    for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) {\n        out << *it << \"\\n\";\n    }\n\n    return out;\n}\n\nclass websocket_endpoint {\npublic:\n    websocket_endpoint () : m_next_id(0) {\n        m_endpoint.clear_access_channels(websocketpp::log::alevel::all);\n        m_endpoint.clear_error_channels(websocketpp::log::elevel::all);\n\n        m_endpoint.init_asio();\n        m_endpoint.start_perpetual();\n\n        m_thread = websocketpp::lib::make_shared<websocketpp::lib::thread>(&client::run, &m_endpoint);\n    }\n\n    ~websocket_endpoint() {\n        m_endpoint.stop_perpetual();\n        \n        for (con_list::const_iterator it = m_connection_list.begin(); it != m_connection_list.end(); ++it) {\n            if (it->second->get_status() != \"Open\") {\n                // Only close open connections\n                continue;\n            }\n            \n            std::cout << \"> Closing connection \" << it->second->get_id() << std::endl;\n            \n            websocketpp::lib::error_code ec;\n            m_endpoint.close(it->second->get_hdl(), websocketpp::close::status::going_away, \"\", ec);\n            if (ec) {\n                std::cout << \"> Error closing connection \" << it->second->get_id() << \": \"  \n                          << ec.message() << std::endl;\n            }\n        }\n        \n        m_thread->join();\n    }\n\n    int connect(std::string const & uri) {\n        websocketpp::lib::error_code ec;\n\n        client::connection_ptr con = m_endpoint.get_connection(uri, ec);\n\n        if (ec) {\n            std::cout << \"> Connect initialization error: \" << ec.message() << std::endl;\n            return -1;\n        }\n\n        int new_id = m_next_id++;\n        connection_metadata::ptr metadata_ptr = websocketpp::lib::make_shared<connection_metadata>(new_id, con->get_handle(), uri);\n        m_connection_list[new_id] = metadata_ptr;\n\n        con->set_open_handler(websocketpp::lib::bind(\n            &connection_metadata::on_open,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_fail_handler(websocketpp::lib::bind(\n            &connection_metadata::on_fail,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_close_handler(websocketpp::lib::bind(\n            &connection_metadata::on_close,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_message_handler(websocketpp::lib::bind(\n            &connection_metadata::on_message,\n            metadata_ptr,\n            websocketpp::lib::placeholders::_1,\n            websocketpp::lib::placeholders::_2\n        ));\n\n        m_endpoint.connect(con);\n\n        return new_id;\n    }\n\n    void close(int id, websocketpp::close::status::value code, std::string reason) {\n        websocketpp::lib::error_code ec;\n        \n        con_list::iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            std::cout << \"> No connection found with id \" << id << std::endl;\n            return;\n        }\n        \n        m_endpoint.close(metadata_it->second->get_hdl(), code, reason, ec);\n        if (ec) {\n            std::cout << \"> Error initiating close: \" << ec.message() << std::endl;\n        }\n    }\n\n    void send(int id, std::string message) {\n        websocketpp::lib::error_code ec;\n        \n        con_list::iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            std::cout << \"> No connection found with id \" << id << std::endl;\n            return;\n        }\n        \n        m_endpoint.send(metadata_it->second->get_hdl(), message, websocketpp::frame::opcode::text, ec);\n        if (ec) {\n            std::cout << \"> Error sending message: \" << ec.message() << std::endl;\n            return;\n        }\n        \n        metadata_it->second->record_sent_message(message);\n    }\n\n    connection_metadata::ptr get_metadata(int id) const {\n        con_list::const_iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            return connection_metadata::ptr();\n        } else {\n            return metadata_it->second;\n        }\n    }\nprivate:\n    typedef std::map<int,connection_metadata::ptr> con_list;\n\n    client m_endpoint;\n    websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;\n\n    con_list m_connection_list;\n    int m_next_id;\n};\n\nint main() {\n    bool done = false;\n    std::string input;\n    websocket_endpoint endpoint;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout\n                << \"\\nCommand List:\\n\"\n                << \"connect <ws uri>\\n\"\n                << \"send <connection id> <message>\\n\"\n                << \"close <connection id> [<close code:default=1000>] [<close reason>]\\n\"\n                << \"show <connection id>\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else if (input.substr(0,7) == \"connect\") {\n            int id = endpoint.connect(input.substr(8));\n            if (id != -1) {\n                std::cout << \"> Created connection with id \" << id << std::endl;\n            }\n        } else if (input.substr(0,4) == \"send\") {\n            std::stringstream ss(input);\n            \n            std::string cmd;\n            int id;\n            std::string message;\n            \n            ss >> cmd >> id;\n            std::getline(ss,message);\n            \n            endpoint.send(id, message);\n        } else if (input.substr(0,5) == \"close\") {\n            std::stringstream ss(input);\n            \n            std::string cmd;\n            int id;\n            int close_code = websocketpp::close::status::normal;\n            std::string reason;\n            \n            ss >> cmd >> id >> close_code;\n            std::getline(ss,reason);\n            \n            endpoint.close(id, close_code, reason);\n        } else if (input.substr(0,4) == \"show\") {\n            int id = atoi(input.substr(5).c_str());\n\n            connection_metadata::ptr metadata = endpoint.get_metadata(id);\n            if (metadata) {\n                std::cout << *metadata << std::endl;\n            } else {\n                std::cout << \"> Unknown connection id \" << id << std::endl;\n            }\n        } else {\n            std::cout << \"> Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n\n/*\n\nclang++ -std=c++11 -stdlib=libc++ -I/Users/zaphoyd/software/websocketpp/ -I/Users/zaphoyd/software/boost_1_55_0/ -D_WEBSOCKETPP_CPP11_STL_ step4.cpp /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_system.a\n\nclang++ -I/Users/zaphoyd/software/websocketpp/ -I/Users/zaphoyd/software/boost_1_55_0/ step4.cpp /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_system.a /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_thread.a /Users/zaphoyd/software/boost_1_55_0/stage/lib/libboost_random.a\n\nclang++ -std=c++11 -stdlib=libc++ -I/Users/zaphoyd/Documents/websocketpp/ -I/Users/zaphoyd/Documents/boost_1_53_0_libcpp/ -D_WEBSOCKETPP_CPP11_STL_ step4.cpp /Users/zaphoyd/Documents/boost_1_53_0_libcpp/stage/lib/libboost_system.a\n\n*/\n"
  },
  {
    "path": "tutorials/utility_client/utility_client.md",
    "content": "Utility Client Example Application Tutorial\n===========================================\n\nChapter 1: Initial Setup & Basics\n---------------------------------\n\nSetting up the basic types, opening and closing connections, sending and receiving messages.\n\n### Step 1\n\nA basic program loop that prompts the user for a command and then processes it. In this tutorial we will modify this program to perform tasks and retrieve data from a remote server over a WebSocket connection.\n\n#### Build\n`clang++ step1.cpp`\n\n#### Code so far\n\n*note* A code snapshot for each step is present next to this tutorial file in the git repository.\n\n~~~{.cpp}\n#include <iostream>\n#include <string>\n\nint main() {\n    bool done = false;\n    std::string input;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout\n                << \"\\nCommand List:\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else {\n            std::cout << \"Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n~~~\n\n### Step 2\n\n_Add WebSocket++ includes and set up an endpoint type._\n\nWebSocket++ includes two major object types. The endpoint and the connection. The\nendpoint creates and launches new connections and maintains default settings for\nthose connections. Endpoints also manage any shared network resources.\n\nThe connection stores information specific to each WebSocket session.\n\n> **Note:** Once a connection is launched, there is no link between the endpoint and the connection. All default settings are copied into the new connection by the endpoint. Changing default settings on an endpoint will only affect future connections.\nConnections do not maintain a link back to their associated endpoint. Endpoints do not maintain a list of outstanding connections. If your application needs to iterate over all connections it will need to maintain a list of them itself.\n\nWebSocket++ endpoints are built by combining an endpoint role with an endpoint config. There are two different types of endpoint roles, one each for the client and server roles in a WebSocket session. This is a client tutorial so we will use the client role `websocketpp::client` which is provided by the `<websocketpp/client.hpp>` header.\n\n> ##### Terminology: Endpoint Config\n> WebSocket++ endpoints have a group of settings that may be configured at compile time via the `config` template parameter. A config is a struct that contains types and static constants that are used to produce an endpoint with specific properties. Depending on which config is being used the endpoint will have different methods available and may have additional third party dependencies.\n\nThe endpoint role takes a template parameter called `config` that is used to configure the behavior of endpoint at compile time. For this example we are going to use a default config provided by the library called `asio_client`, provided by `<websocketpp/config/asio_no_tls_client.hpp>`. This is a client config that uses boost::asio to provide network transport and does not support TLS based security. Later on we will discuss how to introduce TLS based security into a WebSocket++ application, more about the other stock configs, and how to build your own custom configs.\n\nCombine a config with an endpoint role to produce a fully configured endpoint. This type will be used frequently so I would recommend a typedef here.\n\n`typedef websocketpp::client<websocketpp::config::asio_client> client`\n\n#### Build\nAdding WebSocket++ has added a few dependencies to our program that must be addressed in the build system. Firstly, the WebSocket++ and Boost library headers must be in the include search path of your build system. How exactly this is done depends on where you have the WebSocket++ headers installed and what build system you are using.\n\nIn addition to the new headers, boost::asio depends on the `boost_system` shared library. This will need to be added (either as a static or dynamic) to the linker. Refer to your build environment documentation for instructions on linking to shared libraries.\n\n`clang++ step2.cpp -lboost_system`\n\n#### Code so far\n~~~{.cpp}\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <iostream>\n#include <string>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nint main() {\n    bool done = false;\n    std::string input;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout\n                << \"\\nCommand List:\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else {\n            std::cout << \"Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n~~~\n\n### Step 3\n\n_Create endpoint wrapper object that handles initialization and setting up the background thread._\n\nIn order to process user input while network processing occurs in the background we are going to use a separate thread for the WebSocket++ processing loop. This leaves the main thread free to process foreground user input. In order to enable simple RAII style resource management for our thread and endpoint we will use a wrapper object that configures them both in its constructor.\n\n> ##### Terminology: websocketpp::lib namespace\n> WebSocket++ is designed to be used with a C++11 standard library. As this is not universally available in popular build systems the Boost libraries may be used as polyfills for the C++11 standard library in C++98 build environments. The `websocketpp::lib` namespace is used by the library and its associated examples to abstract away the distinctions between the two. `websocketpp::lib::shared_ptr` will evaluate to `std::shared_ptr` in a C++11 environment and `boost::shared_ptr` otherwise.\n>\n> This tutorial uses the `websocketpp::lib` wrappers because it doesn't know what the build environment of the reader is. For your applications, unless you are interested in similar portability, are free to use the boost or std versions of these types directly.\n>\n>[TODO: link to more information about websocketpp::lib namespace and C++11 setup]\n\nWithin the `websocket_endpoint` constructor several things happen:\n\nFirst, we set the endpoint logging behavior to silent by clearing all of the access and error logging channels. [TODO: link to more information about logging]\n~~~{.cpp}\nm_endpoint.clear_access_channels(websocketpp::log::alevel::all);\nm_endpoint.clear_error_channels(websocketpp::log::elevel::all);\n~~~\n\nNext, we initialize the transport system underlying the endpoint and set it to perpetual mode. In perpetual mode the endpoint's processing loop will not exit automatically when it has no connections. This is important because we want this endpoint to remain active while our application is running and process requests for new WebSocket connections on demand as we need them. Both of these methods are specific to the asio transport. They will not be  necessary or present in endpoints that use a non-asio config.\n~~~{.cpp}\nm_endpoint.init_asio();\nm_endpoint.start_perpetual();\n~~~\n\nFinally, we launch a thread to run the `run` method of our client endpoint. While the endpoint is running it will process connection tasks (read and deliver incoming messages, frame and send outgoing messages, etc). Because it is running in perpetual mode, when there are no connections active it will wait for a new connection.\n~~~{.cpp}\nm_thread.reset(new websocketpp::lib::thread(&client::run, &m_endpoint));\n~~~\n\n#### Build\n\nNow that our client endpoint template is actually instantiated a few more linker dependencies will show up. In particular, WebSocket clients require a cryptographically secure random number generator. WebSocket++ is able to use either `boost_random` or the C++11 standard library <random> for this purpose. Because this example also uses threads, if we do not have C++11 std::thread available we will need to include `boost_thread`.\n\n##### Clang (C++98 & boost)\n`clang++ step3.cpp -lboost_system -lboost_random -lboost_thread`\n\n##### Clang (C++11)\n`clang++ -std=c++0x -stdlib=libc++ step3.cpp -lboost_system -D_WEBSOCKETPP_CPP11_STL_`\n\n##### G++ (C++98 & Boost)\n`g++ step3.cpp -lboost_system -lboost_random -lboost_thread`\n\n##### G++ v4.6+ (C++11)\n`g++ -std=c++0x step3.cpp -lboost_system -D_WEBSOCKETPP_CPP11_STL_`\n\n#### Code so far\n\n~~~{.cpp}\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <websocketpp/common/thread.hpp>\n#include <websocketpp/common/memory.hpp>\n\n#include <iostream>\n#include <string>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nclass websocket_endpoint {\npublic:\n    websocket_endpoint () {\n        m_endpoint.clear_access_channels(websocketpp::log::alevel::all);\n        m_endpoint.clear_error_channels(websocketpp::log::elevel::all);\n\n        m_endpoint.init_asio();\n        m_endpoint.start_perpetual();\n\n        m_thread.reset(new websocketpp::lib::thread(&client::run, &m_endpoint));\n    }\nprivate:\n    client m_endpoint;\n    websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;\n};\n\nint main() {\n    bool done = false;\n    std::string input;\n    websocket_endpoint endpoint;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout\n                << \"\\nCommand List:\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else {\n            std::cout << \"Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n~~~\n\n### Step 4\n\n_Opening WebSocket connections_\n\nThis step adds two new commands to utility_client. The ability to open a new connection and the ability to view information about a previously opened connection. Every connection that gets opened will be assigned an integer connection id that the user of the program can use to interact with that connection.\n\n#### New Connection Metadata Object\n\nIn order to track information about each connection a `connection_metadata` object is defined. This object stores the numeric connection id and a number of fields that will be filled in as the connection is processed. Initially this includes the state of the connection (opening, open, failed, closed, etc), the original URI connected to, an identifying value from the server, and a description of the reason for connection failure/closure. Future steps will add more information to this metadata object.\n\n#### Update `websocket_endpoint`\n\nThe `websocket_endpoint` object has gained some new data members and methods. It now tracks a mapping between connection IDs and their associated metadata as well as the next sequential ID number to hand out. The `connect()` method initiates a new connection. The `get_metadata` method retrieves metadata given an ID.\n\n#### The connect method\nA new WebSocket connection is initiated via a three step process. First, a connection request is created by `endpoint::get_connection(uri)`. Next, the connection request is configured. Lastly, the connection request is submitted back to the endpoint via `endpoint::connect()` which adds it to the queue of new connections to make.\n\n> ##### Terminology `connection_ptr`\n> WebSocket++ keeps track of connection related resources using a reference counted shared pointer. The type of this pointer is `endpoint::connection_ptr`. A `connection_ptr` allows direct access to information about the connection and allows changing connection settings. Because of this direct access and their internal resource management role within the library it is not safe for end applications to use `connection_ptr` except in the specific circumstances detailed below.\n>\n> **When is it safe to use `connection_ptr`?**\n> - After `endpoint::get_connection(...)` and before `endpoint::connect()`: `get_connection` returns a `connection_ptr`. It is safe to use this pointer to configure your new connection. Once you submit the connection to `connect` you may no longer use the `connection_ptr` and should discard it immediately for optimal memory management.\n> - During a handler: WebSocket++ allows you to register hooks / callbacks / event handlers for specific events that happen during a connection's lifetime. During the invocation of one of these handlers the library guarantees that it is safe to use a `connection_ptr` for the connection associated with the currently running handler.\n\n> ##### Terminology `connection_hdl`\n> Because of the limited thread safety of the `connection_ptr` the library also provides a more flexible connection identifier, the `connection_hdl`. The `connection_hdl` has type `websocketpp::connection_hdl` and it is defined in `<websocketpp/common/connection_hdl.hpp>`. Note that unlike `connection_ptr` this is not dependent on the type or config of the endpoint. Code that simply stores or transmits `connection_hdl` but does not use them can include only the header above and can treat its hdls like values.\n>\n> Connection handles are not used directly. They are used by endpoint methods to identify the target of the desired action. For example, the endpoint method that sends a new message will take as a parameter the hdl of the connection to send the message to.\n>\n> **When is it safe to use `connection_hdl`?**\n> `connection_hdl`s may be used at any time from any thread. They may be copied and stored in containers. Deleting a hdl will not affect the connection in any way. Handles may be upgraded to a `connection_ptr` during a handler call by using `endpoint::get_con_from_hdl()`. The resulting `connection_ptr` is safe to use for the duration of that handler invocation.\n>\n> **`connection_hdl` FAQs**\n> - `connection_hdl`s are guaranteed to be unique within a program. Multiple endpoints in a single program will always create connections with unique handles.\n> - Using a `connection_hdl` with a different endpoint than the one that created its associated connection will result in undefined behavior.\n> - Using a `connection_hdl` whose associated connection has been closed or deleted is safe. The endpoint will return a specific error saying the operation couldn't be completed because the associated connection doesn't exist.\n> [TODO: more here? link to a connection_hdl FAQ elsewhere?]\n\n`websocket_endpoint::connect()` begins by calling `endpoint::get_connection()` using a uri passed as a parameter. Additionally, an error output value is passed to capture any errors that might occur during. If an error does occur an error notice is printed along with a descriptive message and the -1 / 'invalid' value is returned as the new ID.\n\n> ###### Terminology: `error handling: exceptions vs error_code`\n> WebSocket++ uses the error code system defined by the C++11 `<system_error>` library. It can optionally fall back to a similar system provided by the Boost libraries. All user facing endpoint methods that can fail take an `error_code` in an output parameter and store the error that occured there before returning. An empty/default constructed value is returned in the case of success.\n>\n> **Exception throwing varients**\n> All user facing endpoint methods that take and use an `error_code` parameter have a version that throws an exception instead. These methods are identical in function and signature except for the lack of the final ec parameter. The type of the exception thrown is `websocketpp::exception`. This type derives from `std::exception` so it can be caught by catch blocks grabbing generic `std::exception`s. The `websocketpp::exception::code()` method may be used to extract the machine readable `error_code` value from an exception.\n>\n> For clarity about error handling the utility_client example uses exclusively the exception free varients of these methods. Your application may choose to use either.\n\nIf connection creation succeeds, the next sequential connection ID is generated and a `connection_metadata` object is inserted into the connection list under that ID. Initially the metadata object stores the connection ID, the `connection_hdl`, and the URI the connection was opened to.\n\n~~~{.cpp}\nint new_id = m_next_id++;\nmetadata_ptr metadata(new connection_metadata(new_id, con->get_handle(), uri));\nm_connection_list[new_id] = metadata;\n~~~\n\nNext, the connection request is configured. For this step the only configuration we will do is setting up a few default handlers. Later on we will return and demonstrate some more detailed configuration that can happen here (setting user agents, origin, proxies, custom headers, subprotocols, etc).\n\n> ##### Terminology: Registering handlers\n> WebSocket++ provides a number of execution points where you can register to have a handler run. Which of these points are available to your endpoint will depend on its config. TLS handlers will not exist on non-TLS endpoints for example. A complete list of handlers can be found at  http://www.zaphoyd.com/websocketpp/manual/reference/handler-list.\n>\n> Handlers can be registered at the endpoint level and at the connection level. Endpoint handlers are copied into new connections as they are created. Changing an endpoint handler will affect only future connections. Handlers registered at the connection level will be bound to that specific connection only.\n>\n> The signature of handler binding methods is the same for endpoints and connections. The format is: `set_*_handler(...)`. Where * is the name of the handler. For example, `set_open_handler(...)` will set the handler to be called when a new connection is open. `set_fail_handler(...)` will set the handler to be called when a connection fails to connect.\n>\n> All handlers take one argument, a callable type that can be converted to a `std::function` with the correct count and type of arguments. You can pass free functions, functors, and Lambdas with matching argument lists as handlers. In addition, you can use `std::bind` (or `boost::bind`) to register functions with non-matching argument lists. This is useful for passing additional parameters not present in the handler signature or member functions that need to carry a 'this' pointer.\n>\n> The function signature of each handler can be looked up in the list above in the manual. In general, all handlers include the `connection_hdl` identifying which connection this even is associated with as the first parameter. Some handlers (such as the message handler) include additional parameters. Most handlers have a void return value but some (`validate`, `ping`, `tls_init`) do not. The specific meanings of the return values are documented in the handler list linked above.\n\n`utility_client` registers an open and a fail handler. We will use these to track whether each connection was successfully opened or failed. If it successfully opens, we will gather some information from the opening handshake and store it with our connection metadata.\n\nIn this example we are going to set connection specific handlers that are bound directly to the metadata object associated with our connection. This allows us to avoid performing a lookup in each handler to find the metadata object we plan to update which is a bit more efficient.\n\nLets look at the parameters being sent to bind in detail:\n\n~~~{.cpp}\ncon->set_open_handler(websocketpp::lib::bind(\n    &connection_metadata::on_open,\n    metadata,\n    &m_endpoint,\n    websocketpp::lib::placeholders::_1\n));\n~~~\n\n`&connection_metadata::on_open` is the address of the `on_open` member function of the `connection_metadata` class. `metadata_ptr` is a pointer to the `connection_metadata` object associated with this class. It will be used as the object on which the `on_open` member function will be called. `&m_endpoint` is the address of the endpoint in use. This parameter will be passed as-is to the `on_open` method. Lastly, `websocketpp::lib::placeholders::_1` is a placeholder indicating that the bound function should take one additional argument to be filled in at a later time. WebSocket++ will fill in this placeholder with the `connection_hdl` when it invokes the handler.\n\nFinally, we call `endpoint::connect()` on our configured connection request and return the new connection ID.\n\n#### Handler Member Functions\n\nThe open handler we registered, `connection_metadata::on_open`, sets the status metadata field to \"Open\" and retrieves the value of the \"Server\" header from the remote endpoint's HTTP response and stores it in the metadata object. Servers often set an identifying string in this header.\n\nThe fail handler we registered, `connection_metadata::on_fail`, sets the status metadata field to \"Failed\", the server field similarly to `on_open`, and retrieves the error code describing why the connection failed. The human readable message associated with that error code is saved to the metadata object.\n\n#### New Commands\n\nTwo new commands have been set up. \"connect [uri]\" will pass the URI to the `websocket_endpoint` connect method and report an error or the connection ID of the new connection. \"show [connection id]\" will retrieve and print out the metadata associated with that connection. The help text has been updated accordingly.\n\n~~~{.cpp}\n} else if (input.substr(0,7) == \"connect\") {\n    int id = endpoint.connect(input.substr(8));\n    if (id != -1) {\n        std::cout << \"> Created connection with id \" << id << std::endl;\n    }\n} else if (input.substr(0,4) == \"show\") {\n    int id = atoi(input.substr(5).c_str());\n\n    connection_metadata::ptr metadata = endpoint.get_metadata(id);\n    if (metadata) {\n        std::cout << *metadata << std::endl;\n    } else {\n        std::cout << \"> Unknown connection id \" << id << std::endl;\n    }\n}\n~~~\n\n#### Build\n\nThere are no changes to the build instructions from step 3\n\n#### Run\n\n~~~\nEnter Command: connect not a websocket uri\n> Connect initialization error: invalid uri\nEnter Command: show 0\n> Unknown connection id 0\nEnter Command: connect ws://echo.websocket.org\n> Created connection with id 0\nEnter Command: show 0\n> URI: ws://echo.websocket.org\n> Status: Open\n> Remote Server: Kaazing Gateway\n> Error/close reason: N/A\nEnter Command: connect ws://wikipedia.org\n> Created connection with id 1\nEnter Command: show 1\n> URI: ws://wikipedia.org\n> Status: Failed\n> Remote Server: Apache\n> Error/close reason: Invalid HTTP status.\n~~~\n\n#### Code so far\n\n~~~{.cpp}\n#include <websocketpp/config/asio_no_tls_client.hpp>\n#include <websocketpp/client.hpp>\n\n#include <websocketpp/common/thread.hpp>\n#include <websocketpp/common/memory.hpp>\n\n#include <cstdlib>\n#include <iostream>\n#include <map>\n#include <string>\n#include <sstream>\n\ntypedef websocketpp::client<websocketpp::config::asio_client> client;\n\nclass connection_metadata {\npublic:\n    typedef websocketpp::lib::shared_ptr<connection_metadata> ptr;\n\n    connection_metadata(int id, websocketpp::connection_hdl hdl, std::string uri)\n      : m_id(id)\n      , m_hdl(hdl)\n      , m_status(\"Connecting\")\n      , m_uri(uri)\n      , m_server(\"N/A\")\n    {}\n\n    void on_open(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Open\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n    }\n\n    void on_fail(client * c, websocketpp::connection_hdl hdl) {\n        m_status = \"Failed\";\n\n        client::connection_ptr con = c->get_con_from_hdl(hdl);\n        m_server = con->get_response_header(\"Server\");\n        m_error_reason = con->get_ec().message();\n    }\n\n    friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data);\nprivate:\n    int m_id;\n    websocketpp::connection_hdl m_hdl;\n    std::string m_status;\n    std::string m_uri;\n    std::string m_server;\n    std::string m_error_reason;\n};\n\nstd::ostream & operator<< (std::ostream & out, connection_metadata const & data) {\n    out << \"> URI: \" << data.m_uri << \"\\n\"\n        << \"> Status: \" << data.m_status << \"\\n\"\n        << \"> Remote Server: \" << (data.m_server.empty() ? \"None Specified\" : data.m_server) << \"\\n\"\n        << \"> Error/close reason: \" << (data.m_error_reason.empty() ? \"N/A\" : data.m_error_reason);\n\n    return out;\n}\n\nclass websocket_endpoint {\npublic:\n    websocket_endpoint () : m_next_id(0) {\n        m_endpoint.clear_access_channels(websocketpp::log::alevel::all);\n        m_endpoint.clear_error_channels(websocketpp::log::elevel::all);\n\n        m_endpoint.init_asio();\n        m_endpoint.start_perpetual();\n\n        m_thread.reset(new websocketpp::lib::thread(&client::run, &m_endpoint));\n    }\n\n    int connect(std::string const & uri) {\n        websocketpp::lib::error_code ec;\n\n        client::connection_ptr con = m_endpoint.get_connection(uri, ec);\n\n        if (ec) {\n            std::cout << \"> Connect initialization error: \" << ec.message() << std::endl;\n            return -1;\n        }\n\n        int new_id = m_next_id++;\n        connection_metadata::ptr metadata_ptr(new connection_metadata(new_id, con->get_handle(), uri));\n        m_connection_list[new_id] = metadata_ptr;\n\n        con->set_open_handler(websocketpp::lib::bind(\n            &connection_metadata::on_open,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n        con->set_fail_handler(websocketpp::lib::bind(\n            &connection_metadata::on_fail,\n            metadata_ptr,\n            &m_endpoint,\n            websocketpp::lib::placeholders::_1\n        ));\n\n        m_endpoint.connect(con);\n\n        return new_id;\n    }\n\n    connection_metadata::ptr get_metadata(int id) const {\n        con_list::const_iterator metadata_it = m_connection_list.find(id);\n        if (metadata_it == m_connection_list.end()) {\n            return connection_metadata::ptr();\n        } else {\n            return metadata_it->second;\n        }\n    }\nprivate:\n    typedef std::map<int,connection_metadata::ptr> con_list;\n\n    client m_endpoint;\n    websocketpp::lib::shared_ptr<websocketpp::lib::thread> m_thread;\n\n    con_list m_connection_list;\n    int m_next_id;\n};\n\nint main() {\n    bool done = false;\n    std::string input;\n    websocket_endpoint endpoint;\n\n    while (!done) {\n        std::cout << \"Enter Command: \";\n        std::getline(std::cin, input);\n\n        if (input == \"quit\") {\n            done = true;\n        } else if (input == \"help\") {\n            std::cout\n                << \"\\nCommand List:\\n\"\n                << \"connect <ws uri>\\n\"\n                << \"show <connection id>\\n\"\n                << \"help: Display this help text\\n\"\n                << \"quit: Exit the program\\n\"\n                << std::endl;\n        } else if (input.substr(0,7) == \"connect\") {\n            int id = endpoint.connect(input.substr(8));\n            if (id != -1) {\n                std::cout << \"> Created connection with id \" << id << std::endl;\n            }\n        } else if (input.substr(0,4) == \"show\") {\n            int id = atoi(input.substr(5).c_str());\n\n            connection_metadata::ptr metadata = endpoint.get_metadata(id);\n            if (metadata) {\n                std::cout << *metadata << std::endl;\n            } else {\n                std::cout << \"> Unknown connection id \" << id << std::endl;\n            }\n        } else {\n            std::cout << \"> Unrecognized Command\" << std::endl;\n        }\n    }\n\n    return 0;\n}\n~~~\n\n### Step 5\n\n_Closing connections_\n\nThis step adds a command that allows you to close a WebSocket connection and adjusts the quit command so that it cleanly closes all outstanding connections before quitting.\n\n#### Getting connection close information out of WebSocket++\n\n> ##### Terminology: WebSocket close codes & reasons\n> The WebSocket close handshake involves an exchange of optional machine readable close codes and human readable reason strings. Each endpoint sends independent close details. The codes are short integers. The reasons are UTF8 text strings of at most 125 characters. More details about valid close code ranges and the meaning of each code can be found at https://tools.ietf.org/html/rfc6455#section-7.4\n\nThe `websocketpp::close::status` namespace contains named constants for all of the IANA defined close codes. It also includes free functions to determine whether a value is reserved or invalid and to convert a code to a human readable text representation.\n\nDuring the close handler call WebSocket++ connections offer the following methods for accessing close handshake information:\n\n- `connection::get_remote_close_code()`: Get the close code as reported by the remote endpoint\n- `connection::get_remote_close_reason()`: Get the close reason as reported by the remote endpoint\n- `connection::get_local_close_code()`: Get the close code that this endpoint sent.\n- `connection::get_local_close_reason()`: Get the close reason that this endpoint sent.\n- `connection::get_ec()`: Get a more detailed/specific WebSocket++ `error_code` indicating what library error (if any) ultimately resulted in the connection closure.\n\n*Note:* there are some special close codes that will report a code that was not actually sent on the wire. For example 1005/\"no close code\" indicates that the endpoint omitted a close code entirely and 1006/\"abnormal close\" indicates that there was a problem that resulted in the connection closing without having performed a close handshake.\n\n#### Add close handler\n\nThe `connection_metadata::on_close` method is added. This method retrieves the close code and reason from the closing handshake and stores it in the local error reason field.\n\n~~~{.cpp}\nvoid on_close(client * c, websocketpp::connection_hdl hdl) {\n    m_status = \"Closed\";\n    client::connection_ptr con = c->get_con_from_hdl(hdl);\n    std::stringstream s;\n    s << \"close code: \" << con->get_remote_close_code() << \" (\" \n      << websocketpp::close::status::get_string(con->get_remote_close_code()) \n      << \"), close reason: \" << con->get_remote_close_reason();\n    m_error_reason = s.str();\n}\n~~~\n\nSimilarly to `on_open` and `on_fail`, `websocket_endpoint::connect` registers this close handler when a new connection is made.\n\n#### Add close method to `websocket_endpoint`\n\nThis method starts by looking up the given connection ID in the connection list.  Next a close request is sent to the connection's handle with the specified WebSocket close code. This is done by calling `endpoint::close`. This is a thread safe method that is used to asynchronously dispatch a close signal to the connection with the given handle. When the operation is complete the connection's close handler will be triggered.\n\n~~~{.cpp}\nvoid close(int id, websocketpp::close::status::value code) {\n    websocketpp::lib::error_code ec;\n    \n    con_list::iterator metadata_it = m_connection_list.find(id);\n    if (metadata_it == m_connection_list.end()) {\n        std::cout << \"> No connection found with id \" << id << std::endl;\n        return;\n    }\n    \n    m_endpoint.close(metadata_it->second->get_hdl(), code, \"\", ec);\n    if (ec) {\n        std::cout << \"> Error initiating close: \" << ec.message() << std::endl;\n    }\n}\n~~~\n\n#### Add close option to the command loop and help message\n\nA close option is added to the command loop. It takes a connection ID and optionally a close code and a close reason. If no code is specified the default of 1000/Normal is used. If no reason is specified, none is sent. The `endpoint::close` method will do some error checking and abort the close request if you try and send an invalid code or a reason with invalid UTF8 formatting. Reason strings longer than 125 characters will be truncated.\n\nAn entry is also added to the help system to describe how the new command may be used.\n\n~~~{.cpp}\nelse if (input.substr(0,5) == \"close\") {\n    std::stringstream ss(input);\n    \n    std::string cmd;\n    int id;\n    int close_code = websocketpp::close::status::normal;\n    std::string reason;\n    \n    ss >> cmd >> id >> close_code;\n    std::getline(ss,reason);\n    \n    endpoint.close(id, close_code, reason);\n}\n~~~\n\n#### Close all outstanding connections in `websocket_endpoint` destructor\n\nUntil now quitting the program left outstanding connections and the WebSocket++ network thread in a lurch. Now that we have a method of closing connections we can clean this up properly.\n\nThe destructor for `websocket_endpoint` now stops perpetual mode (so the run thread exits after the last connection is closed) and iterates through the list of open connections and requests a clean close for each. Finally, the run thread is joined which causes the program to wait until those connection closes complete.\n\n~~~{.cpp}\n~websocket_endpoint() {\n    m_endpoint.stop_perpetual();\n    \n    for (con_list::const_iterator it = m_connection_list.begin(); it != m_connection_list.end(); ++it) {\n        if (it->second->get_status() != \"Open\") {\n            // Only close open connections\n            continue;\n        }\n        \n        std::cout << \"> Closing connection \" << it->second->get_id() << std::endl;\n        \n        websocketpp::lib::error_code ec;\n        m_endpoint.close(it->second->get_hdl(), websocketpp::close::status::going_away, \"\", ec);\n        if (ec) {\n            std::cout << \"> Error closing connection \" << it->second->get_id() << \": \"  \n                      << ec.message() << std::endl;\n        }\n    }\n    \n    m_thread->join();\n}\n~~~\n\n#### Build\n\nThere are no changes to the build instructions from step 4\n\n#### Run\n\n~~~\nEnter Command: connect ws://localhost:9002\n> Created connection with id 0\nEnter Command: close 0 1001 example message\nEnter Command: show 0\n> URI: ws://localhost:9002\n> Status: Closed\n> Remote Server: WebSocket++/0.4.0\n> Error/close reason: close code: 1001 (Going away), close reason:  example message\nEnter Command: connect ws://localhost:9002\n> Created connection with id 1\nEnter Command: close 1 1006\n> Error initiating close: Invalid close code used\nEnter Command: quit\n> Closing connection 1\n~~~\n\n### Step 6\n\n_Sending and receiving messages_\n\nThis step adds a command to send a message on a given connection and updates the show command to print a transcript of all sent and received messages for that connection.\n\n> ##### Terminology: WebSocket message types (opcodes)\n> WebSocket messages have types indicated by their opcode. The protocol currently specifies two different opcodes for data messages, text and binary. Text messages represent UTF8 text and will be validated as such. Binary messages represent raw binary bytes and are passed through directly with no validation. \n>\n> WebSocket++ provides the values `websocketpp::frame::opcode::text` and `websocketpp::frame::opcode::binary` that can be used to direct how outgoing messages should be sent and to check how incoming messages are formatted.\n\n#### Sending Messages\n\nMessages are sent using `endpoint::send`. This is a thread safe method that may be called from anywhere to queue a message for sending on the specified connection. There are three send overloads for use with different scenarios. \n\nEach method takes a `connection_hdl` to indicate which connection to send the message on as well as a `frame::opcode::value` to indicate which opcode to label the message as. All overloads are also available with an exception free varient that fills in a a status/error code instead of throwing.\n\nThe first overload, `connection_hdl hdl, std::string const & payload, frame::opcode::value op`, takes a `std::string`. The string contents are copied into an internal buffer and can be safely modified after calling send.\n\nThe second overload, `connection_hdl hdl, void const * payload, size_t len, frame::opcode::value op`, takes a void * buffer and length. The buffer contents are copied and can be safely modified after calling send.\n\nThe third overload, `connection_hdl hdl, message_ptr msg`, takes a WebSocket++ `message_ptr`. This overload allows a message to be constructed in place before the call to send. It also may allow a single message buffer to be sent multiple times, including to multiple connections, without copying. Whether or not this actually happens depends on other factors such as whether compression is enabled. The contents of the message buffer may not be safely modified after being sent.\n\n> ###### Terminology: Outgoing WebSocket message queueing & flow control\n> In many configurations, such as when the Asio based transport is in use, WebSocket++ is an asynchronous system. As such the `endpoint::send` method may return before any bytes are actually written to the outgoing socket. In cases where send is called multiple times in quick succession messages may be coalesced and sent in the same operation or even the same TCP packet. When this happens the message boundaries are preserved (each call to send will produce a separate message).\n>\n> In the case of applications that call send from inside a handler this means that no messages will be written to the socket until that handler returns. If you are planning to send many messages in this manor or need a message to be written on the wire before continuing you should look into using multiple threads or the built in timer/interrupt handler functionality.\n>\n> If the outgoing socket link is slow messages may build up in this queue. You can use `connection::get_buffered_amount` to query the current size of the written message queue to decide if you want to change your sending behavior.\n\n#### Add send method to `websocket_endpoint`\n\nLike the close method, send will start by looking up the given connection ID in the connection list.  Next a send request is sent to the connection's handle with the specified WebSocket message and the text opcode. Finally, we record the sent message with our connection metadata object so later our show connection command can print a list of messages sent.\n\n~~~{.cpp}\nvoid send(int id, std::string message) {\n    websocketpp::lib::error_code ec;\n    \n    con_list::iterator metadata_it = m_connection_list.find(id);\n    if (metadata_it == m_connection_list.end()) {\n        std::cout << \"> No connection found with id \" << id << std::endl;\n        return;\n    }\n    \n    m_endpoint.send(metadata_it->second->get_hdl(), message, websocketpp::frame::opcode::text, ec);\n    if (ec) {\n        std::cout << \"> Error sending message: \" << ec.message() << std::endl;\n        return;\n    }\n    \n    metadata_it->second->record_sent_message(message);\n}\n~~~\n\n#### Add send option to the command loop and help message\n\nA send option is added to the command loop. It takes a connection ID and a text message to send. An entry is also added to the help system to describe how the new command may be used.\n\n~~~{.cpp}\nelse if (input.substr(0,4) == \"send\") {\n    std::stringstream ss(input);\n        \n        std::string cmd;\n        int id;\n        std::string message = \"\";\n        \n        ss >> cmd >> id;\n        std::getline(ss,message);\n        \n        endpoint.send(id, message);\n}\n~~~\n\n#### Add glue to `connection_metadata` for storing sent messages\n\nIn order to store messages sent on this connection some code is added to `connection_metadata`. This includes a new data member `std::vector<std::string> m_messages` to keep track of all messages sent and received as well as a method for adding a sent message in that list:\n\n~~~{.cpp}\nvoid record_sent_message(std::string message) {\n    m_messages.push_back(\">> \" + message);\n}\n~~~\n\nFinally the connection metadata output operator is updated to also print a list of processed messages:\n\n~~~{.cpp}\nout << \"> Messages Processed: (\" << data.m_messages.size() << \") \\n\";\n\nstd::vector<std::string>::const_iterator it;\nfor (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) {\n    out << *it << \"\\n\";\n}\n~~~\n\n#### Receiving Messages\n\nMessages are received by registering a message handler. This handler will be called once per message received and its signature is `void on_message(websocketpp::connection_hdl hdl, endpoint::message_ptr msg)`. The `connection_hdl`, like the similar parameter from the other handlers is a handle for the connection that the message was received on. The `message_ptr` is a pointer to an object that can be queried for the message payload, opcode, and other metadata. Note that the message_ptr type, as well as its underlying message type, is dependent on how your endpoint is configured and may be different for different configs.\n\n#### Add a message handler to method to `connection_metadata`\n\nThe message receiving behave that we are implementing will be to collect all messages sent and received and to print them in order when the show connection command is run. The sent messages are already being added to that list. Now we add a message handler that pushes received messages to the list as well. Text messages are pushed as-is. Binary messages are first converted to printable hexadecimal format.\n\n~~~{.cpp}\nvoid on_message(websocketpp::connection_hdl hdl, client::message_ptr msg) {\n    if (msg->get_opcode() == websocketpp::frame::opcode::text) {\n        m_messages.push_back(msg->get_payload());\n    } else {\n        m_messages.push_back(websocketpp::utility::to_hex(msg->get_payload()));\n    }\n}\n~~~\n\nIn order to have this handler called when new messages are received we also register it with our connection. Note that unlike most other handlers, the message handler has two parameters and thus needs two placeholders.\n\n~~~{.cpp}\ncon->set_message_handler(websocketpp::lib::bind(\n    &connection_metadata::on_message,\n    metadata_ptr,\n    websocketpp::lib::placeholders::_1,\n    websocketpp::lib::placeholders::_2\n));\n~~~\n\n#### Build\n\nThere are no changes to the build instructions from step 5\n\n#### Run\n\nIn this example run we are connecting to the WebSocket++ example echo_server. This server will repeat any message we send back to it. You can also try testing this with the echo server at `ws://echo.websocket.org` with similar results.\n\n~~~\nEnter Command: connect ws://localhost:9002\n> Created connection with id 0\nEnter Command: send 0 example message\nEnter Command: show 0\n> URI: ws://localhost:9002\n> Status: Open\n> Remote Server: WebSocket++/0.4.0\n> Error/close reason: N/A\n> Messages Processed: (2)\n>>  example message\n<<  example message\n~~~\n\n### Step 7\n\n_Using TLS / Secure WebSockets_\n\n- Change the includes\n- link to the new library dependencies\n- Switch the config\n- add the `tls_init_handler`\n- configure the SSL context for desired security level\n- mixing secure and non-secure connections in one application.\n\nChapter 2: Intermediate Features\n--------------------------------\n\n### Step 8\n\n_Intermediate level features_\n\n- Subprotocol negotiation\n- Setting and reading custom headers\n- Ping and Pong\n- Proxies?\n- Setting user agent\n- Setting Origin\n- Timers and security\n- Close behavior\n- Send one message to all connections\n\n\n### Misc stuff not sure if it should be included here or elsewhere?\n\ncore websocket++ control flow.\nA handshake, followed by a split into 2 independent control strands\n- Handshake\n-- use information specified before the call to endpoint::connect to construct a WebSocket handshake request.\n-- Pass the WebSocket handshake request to the transport policy. The transport policy determines how to get these bytes to the endpoint playing the server role. Depending on which transport policy your endpoint uses this method will be different.\n-- Receive a handshake response from the underlying transport. This is parsed and checked for conformance to RFC6455. If the validation fails, the fail handler is called. Otherwise the open handler is called.\n- At this point control splits into two separate strands. One that reads new bytes from the transport policy on the incoming channle, the other that accepts new messages from the local application for framing and writing to the outgoing transport channel.\n- Read strand\n-- Read and process new bytes from transport\n-- If the bytes contain at least one complete message dispatch each message by calling the appropriate handler. This is either the message handler for data messages, or ping/pong/close handlers for each respective control message. If no handler is registered for a particular message it is ignored.\n-- Ask the transport layer for more bytes\n- Write strand\n-- Wait for messages from the application\n-- Perform error checking on message input,\n-- Frame message per RFC6455\n-- Queue message for sending\n-- Pass all outstanding messages to the transport policy for output\n-- When there are no messages left to send, return to waiting\n\nImportant observations\nHandlers run in line with library processing which has several implications applications should be aware of:\n"
  },
  {
    "path": "tutorials/utility_server/step1.cpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// **NOTE:** This file is a snapshot of the WebSocket++ utility server tutorial.\n// Additional related material can be found in the tutorials/utility_server\n// directory of the WebSocket++ repository.\n\n// The ASIO_STANDALONE define is necessary to use the standalone version of Asio.\n// Remove if you are using Boost Asio.\n#define ASIO_STANDALONE\n\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\n#include <functional>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nclass utility_server {\npublic:\n    utility_server() {\n         // Set logging settings\n        m_endpoint.set_error_channels(websocketpp::log::elevel::all);\n        m_endpoint.set_access_channels(websocketpp::log::alevel::all ^ websocketpp::log::alevel::frame_payload);\n\n        // Initialize Asio\n        m_endpoint.init_asio();\n    }\n\n    void run() {\n        // Listen on port 9002\n        m_endpoint.listen(9002);\n\n        // Queues a connection accept operation\n        m_endpoint.start_accept();\n\n        // Start the Asio io_service run loop\n        m_endpoint.run();\n    }\nprivate:\n    server m_endpoint;\n};\n\nint main() {\n    utility_server s;\n    s.run();\n    return 0;\n}\n"
  },
  {
    "path": "tutorials/utility_server/step2.cpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n// **NOTE:** This file is a snapshot of the WebSocket++ utility server tutorial.\n// Additional related material can be found in the tutorials/utility_server\n// directory of the WebSocket++ repository.\n\n// The ASIO_STANDALONE define is necessary to use the standalone version of Asio.\n// Remove if you are using Boost Asio.\n#define ASIO_STANDALONE\n\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\n#include <functional>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nclass utility_server {\npublic:\n    utility_server() {\n         // Set logging settings\n        m_endpoint.set_error_channels(websocketpp::log::elevel::all);\n        m_endpoint.set_access_channels(websocketpp::log::alevel::all ^ websocketpp::log::alevel::frame_payload);\n\n        // Initialize Asio\n        m_endpoint.init_asio();\n\n        // Set the default message handler to the echo handler\n        m_endpoint.set_message_handler(std::bind(\n            &utility_server::echo_handler, this,\n            std::placeholders::_1, std::placeholders::_2\n        ));\n    }\n\n    void echo_handler(websocketpp::connection_hdl hdl, server::message_ptr msg) {\n        // write a new message\n        m_endpoint.send(hdl, msg->get_payload(), msg->get_opcode());\n    }\n\n    void run() {\n        // Listen on port 9002\n        m_endpoint.listen(9002);\n\n        // Queues a connection accept operation\n        m_endpoint.start_accept();\n\n        // Start the Asio io_service run loop\n        m_endpoint.run();\n    }\nprivate:\n    server m_endpoint;\n};\n\nint main() {\n    utility_server s;\n    s.run();\n    return 0;\n}\n"
  },
  {
    "path": "tutorials/utility_server/utility_server.md",
    "content": "Utility Server Example Application Tutorial\n===========================================\n\nIntroduction\n------------\n\nThis tutorial provides a step by step discussion of building a basic WebSocket++ server. The final product of this tutorial is the utility_server example application from the example section. This server demonstrates the following features:\n\n- Use Asio Transport for networking\n- Accept multiple WebSocket connections at once\n- Read incoming messages and perform a few basic actions (echo, broadcast, telemetry, server commands) based on the path\n- Use validate handler to reject connections to invalid paths\n- Serve basic HTTP responses with the http handler\n- Gracefully exit the server\n- Encrypt connections with TLS\n\nThis tutorial is current as of the 0.6.x version of the library.\n\nChapter 1: Initial Setup & Basics\n---------------------------------\n\n### Step 1\n\n_Add WebSocket++ includes and set up a a server endpoint type._\n\nWebSocket++ includes two major object types. The endpoint and the connection. The\nendpoint creates and launches new connections and maintains default settings for\nthose connections. Endpoints also manage any shared network resources.\n\nThe connection stores information specific to each WebSocket session.\n\n> **Note:** Once a connection is launched, there is no link between the endpoint and the connection. All default settings are copied into the new connection by the endpoint. Changing default settings on an endpoint will only affect future connections.\nConnections do not maintain a link back to their associated endpoint. Endpoints do not maintain a list of outstanding connections. If your application needs to iterate over all connections it will need to maintain a list of them itself.\n\nWebSocket++ endpoints are built by combining an endpoint role with an endpoint config. There are two different types of endpoint roles, one each for the client and server roles in a WebSocket session. This is a server tutorial so we will use the server role `websocketpp::server` which is provided by the `<websocketpp/server.hpp>` header.\n\n> #### Terminology: Endpoint Config\n> WebSocket++ endpoints have a group of settings that may be configured at compile time via the `config` template parameter. A config is a struct that contains types and static constants that are used to produce an endpoint with specific properties. Depending on which config is being used the endpoint will have different methods available and may have additional third party dependencies.\n\nThe endpoint role takes a template parameter called `config` that is used to configure the behavior of endpoint at compile time. For this example we are going to use a default config provided by the library called `asio`, provided by `<websocketpp/config/asio_no_tls.hpp>`. This is a server config that uses the Asio library to provide network transport and does not support TLS based security. Later on we will discuss how to introduce TLS based security into a WebSocket++ application, more about the other stock configs, and how to build your own custom configs.\n\nCombine a config with an endpoint role to produce a fully configured endpoint. This type will be used frequently so I would recommend a typedef here.\n\n`typedef websocketpp::server<websocketpp::config::asio> server`\n\n#### `utility_server` constructor\n\nThis endpoint type will be the base of the utility_server object that will keep track of the state of the server. Within the `utility_server` constructor several things happen:\n\nFirst, we adjust the endpoint logging behavior to include all error logging channels and all access logging channels except the frame payload, which is particularly noisy and generally useful only for debugging. [TODO: link to more information about logging]\n\n~~~{.cpp}\nm_endpoint.set_error_channels(websocketpp::log::elevel::all);\nm_endpoint.set_access_channels(websocketpp::log::alevel::all ^ websocketpp::log::alevel::frame_payload);\n~~~\n\nNext, we initialize the transport system underlying the endpoint. This method is specific to the Asio transport not WebSocket++ core. It will not be necessary or present in endpoints that use a non-asio config.\n\n> **Note:** This example uses an internal Asio `io_service` that is managed by the endpoint itself. This is a simple arrangement suitable for programs where WebSocket++ is the only code using Asio. If you have an existing program that already manages an `io_service` object or want to build a new program where WebSocket++ handlers share an io_service with other handlers you can pass the `io_service` you want WebSocket++ to register its handlers on to the `init_asio()` method and it will use it instead of generating and managing its own. [TODO: FAQ link instead?]\n\n~~~{.cpp}\nm_endpoint.init_asio();\n~~~\n\n#### `utility_server::run` method\n\nIn addition to the constructor, we also add a run method that sets up the listening socket, begins accepting connections, starts the Asio io_service event loop.\n\n~~~{.cpp}\n// Listen on port 9002\nm_endpoint.listen(9002);\n\n// Queues a connection accept operation\nm_endpoint.start_accept();\n\n// Start the Asio io_service run loop\nm_endpoint.run();\n~~~\n\nThe final line, `m_endpoint.run();`, will block until the endpoint is instructed to stop listening for new connections. While running it will listen for and process new connections as well as accept and process new data and control messages for existing connections. WebSocket++ uses Asio in an asyncronous mode where multiple connections can be similtaneously serviced efficiently within a single thread.\n\n#### Build\nAdding WebSocket++ has added a few dependencies to our program that must be addressed in the build system. Firstly, the WebSocket++ library headers need must be in the include search path of your build system. How exactly this is done depends on where you have the WebSocket++ headers installed what build system you are using.\n\nFor the rest of this tutorial we are going to assume a C++11 build environment. WebSocket++ will work with pre-C++11 systems if your build system has access to a recent version of the Boost library headers.\n\nFinally, to use the Asio transport config we need to bring in the Asio library. There are two options here. If you have access to a C++11 build environment the standalone version from http://think-async.com is a good option. This header only library does not bring in any special dependencies and ensures you have the latest version of Asio. If you do not have a C++11 build environment or already have brought in the Boost libraries you can also use the version of Asio bundled with Boost.\n\nTo use standalone Asio, make sure the Asio headers are in your include path and define ASIO_STANDALONE. To use Boost Asio, make sure the Boost headers are in your include path and that you are linking to the boost_system library.\n\n`c++ -std=c++11 step1.cpp` (Asio Standalone)\nOR\n`c++ -std=c++11 step1.cpp -lboost_system` (Boost Asio)\n\n#### Code so far\n```cpp\n// The ASIO_STANDALONE define is necessary to use the standalone version of Asio.\n// Remove if you are using Boost Asio.\n#define ASIO_STANDALONE\n\n#include <websocketpp/config/asio_no_tls.hpp>\n#include <websocketpp/server.hpp>\n\n#include <functional>\n\ntypedef websocketpp::server<websocketpp::config::asio> server;\n\nclass utility_server {\npublic:\n    utility_server() {\n         // Set logging settings\n        m_endpoint.set_error_channels(websocketpp::log::elevel::all);\n        m_endpoint.set_access_channels(websocketpp::log::alevel::all ^ websocketpp::log::alevel::frame_payload);\n\n        // Initialize Asio\n        m_endpoint.init_asio();\n    }\n\n    void run() {\n        // Listen on port 9002\n        m_endpoint.listen(9002);\n\n        // Queues a connection accept operation\n        m_endpoint.start_accept();\n\n        // Start the Asio io_service run loop\n        m_endpoint.run();\n    }\nprivate:\n    server m_endpoint;\n};\n\nint main() {\n    utility_server s;\n    s.run();\n    return 0;\n}\n```\n\n### Step 2\n\n_Set up a message handler to echo all replies back to the original user_\n\n#### Setting a message handler\n\n> ###### Terminology: Registering handlers\n> WebSocket++ provides a number of execution points where you can register to have a handler run. Which of these points are available to your endpoint will depend on its config. TLS handlers will not exist on non-TLS endpoints for example. A complete list of handlers can be found at  http://www.zaphoyd.com/websocketpp/manual/reference/handler-list.\n>\n> Handlers can be registered at the endpoint level and at the connection level. Endpoint handlers are copied into new connections as they are created. Changing an endpoint handler will affect only future connections. Handlers registered at the connection level will be bound to that specific connection only.\n>\n> The signature of handler binding methods is the same for endpoints and connections. The format is: `set_*_handler(...)`. Where * is the name of the handler. For example, `set_open_handler(...)` will set the handler to be called when a new connection is open. `set_fail_handler(...)` will set the handler to be called when a connection fails to connect.\n>\n> All handlers take one argument, a callable type that can be converted to a `std::function` with the correct count and type of arguments. You can pass free functions, functors, and Lambdas with matching argument lists as handlers. In addition, you can use `std::bind` (or `boost::bind`) to register functions with non-matching argument lists. This is useful for passing additional parameters not present in the handler signature or member functions that need to carry a 'this' pointer.\n>\n> The function signature of each handler can be looked up in the list above in the manual. In general, all handlers include the `connection_hdl` identifying which connection this even is associated with as the first parameter. Some handlers (such as the message handler) include additional parameters. Most handlers have a void return value but some (`validate`, `ping`, `tls_init`) do not. The specific meanings of the return values are documented in the handler list linked above.\n\n\n### Step 3\n\n_error handling_\n\n\n### Step 4\n\n_Set up open and close handlers and a connection data structure_\n\n### Step 5\n\n_Change the message handler for connections based on URI and add a validate handler to reject invalid URIs_\n\n### Step 6\n\n_Add some Admin commands (report total clients, cleanly shut down server)_\n\n### Step 7\n\n_Add some Broadcast commands_\n\n### Step 8\n\n_Add TLS_\n"
  },
  {
    "path": "websocketpp/CMakeLists.txt",
    "content": "init_target(\"websocketpp\")\nfinal_target ()\n"
  },
  {
    "path": "websocketpp/base64/base64.hpp",
    "content": "/*\n    ******\n    base64.hpp is a repackaging of the base64.cpp and base64.h files into a\n    single header suitable for use as a header only library. This conversion was\n    done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to\n    the code are redistributed under the same license as the original, which is\n    listed below.\n    ******\n\n   base64.cpp and base64.h\n\n   Copyright (C) 2004-2008 René Nyffenegger\n\n   This source code is provided 'as-is', without any express or implied\n   warranty. In no event will the author be held liable for any damages\n   arising from the use of this software.\n\n   Permission is granted to anyone to use this software for any purpose,\n   including commercial applications, and to alter it and redistribute it\n   freely, subject to the following restrictions:\n\n   1. The origin of this source code must not be misrepresented; you must not\n      claim that you wrote the original source code. If you use this source code\n      in a product, an acknowledgment in the product documentation would be\n      appreciated but is not required.\n\n   2. Altered source versions must be plainly marked as such, and must not be\n      misrepresented as being the original source code.\n\n   3. This notice may not be removed or altered from any source distribution.\n\n   René Nyffenegger rene.nyffenegger@adp-gmbh.ch\n\n*/\n\n#ifndef _BASE64_HPP_\n#define _BASE64_HPP_\n\n#include <string>\n\nnamespace websocketpp {\n\nstatic std::string const base64_chars =\n             \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n             \"abcdefghijklmnopqrstuvwxyz\"\n             \"0123456789+/\";\n\n/// Test whether a character is a valid base64 character\n/**\n * @param c The character to test\n * @return true if c is a valid base64 character\n */\nstatic inline bool is_base64(unsigned char c) {\n    return (c == 43 || // +\n           (c >= 47 && c <= 57) || // /-9\n           (c >= 65 && c <= 90) || // A-Z\n           (c >= 97 && c <= 122)); // a-z\n}\n\n/// Encode a char buffer into a base64 string\n/**\n * @param input The input data\n * @param len The length of input in bytes\n * @return A base64 encoded string representing input\n */\ninline std::string base64_encode(unsigned char const * input, size_t len) {\n    std::string ret;\n    int i = 0;\n    int j = 0;\n    unsigned char char_array_3[3];\n    unsigned char char_array_4[4];\n\n    while (len--) {\n        char_array_3[i++] = *(input++);\n        if (i == 3) {\n            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;\n            char_array_4[1] = ((char_array_3[0] & 0x03) << 4) +\n                              ((char_array_3[1] & 0xf0) >> 4);\n            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) +\n                              ((char_array_3[2] & 0xc0) >> 6);\n            char_array_4[3] = char_array_3[2] & 0x3f;\n\n            for(i = 0; (i <4) ; i++) {\n                ret += base64_chars[char_array_4[i]];\n            }\n            i = 0;\n        }\n    }\n\n    if (i) {\n        for(j = i; j < 3; j++) {\n            char_array_3[j] = '\\0';\n        }\n\n        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;\n        char_array_4[1] = ((char_array_3[0] & 0x03) << 4) +\n                          ((char_array_3[1] & 0xf0) >> 4);\n        char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) +\n                          ((char_array_3[2] & 0xc0) >> 6);\n        char_array_4[3] = char_array_3[2] & 0x3f;\n\n        for (j = 0; (j < i + 1); j++) {\n            ret += base64_chars[char_array_4[j]];\n        }\n\n        while((i++ < 3)) {\n            ret += '=';\n        }\n    }\n\n    return ret;\n}\n\n/// Encode a string into a base64 string\n/**\n * @param input The input data\n * @return A base64 encoded string representing input\n */\ninline std::string base64_encode(std::string const & input) {\n    return base64_encode(\n        reinterpret_cast<const unsigned char *>(input.data()),\n        input.size()\n    );\n}\n\n/// Decode a base64 encoded string into a string of raw bytes\n/**\n * @param input The base64 encoded input data\n * @return A string representing the decoded raw bytes\n */\ninline std::string base64_decode(std::string const & input) {\n    size_t in_len = input.size();\n    int i = 0;\n    int j = 0;\n    int in_ = 0;\n    unsigned char char_array_4[4], char_array_3[3];\n    std::string ret;\n\n    while (in_len-- && ( input[in_] != '=') && is_base64(input[in_])) {\n        char_array_4[i++] = input[in_]; in_++;\n        if (i ==4) {\n            for (i = 0; i <4; i++) {\n                char_array_4[i] = static_cast<unsigned char>(base64_chars.find(char_array_4[i]));\n            }\n\n            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);\n            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);\n            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];\n\n            for (i = 0; (i < 3); i++) {\n                ret += char_array_3[i];\n            }\n            i = 0;\n        }\n    }\n\n    if (i) {\n        for (j = i; j <4; j++)\n            char_array_4[j] = 0;\n\n        for (j = 0; j <4; j++)\n            char_array_4[j] = static_cast<unsigned char>(base64_chars.find(char_array_4[j]));\n\n        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);\n        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);\n        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];\n\n        for (j = 0; (j < i - 1); j++) {\n            ret += static_cast<std::string::value_type>(char_array_3[j]);\n        }\n    }\n\n    return ret;\n}\n\n} // namespace websocketpp\n\n#endif // _BASE64_HPP_\n"
  },
  {
    "path": "websocketpp/client.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CLIENT_HPP\n#define WEBSOCKETPP_CLIENT_HPP\n\n#include <websocketpp/roles/client_endpoint.hpp>\n\n#endif //WEBSOCKETPP_CLIENT_HPP\n"
  },
  {
    "path": "websocketpp/close.hpp",
    "content": "\n/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CLOSE_HPP\n#define WEBSOCKETPP_CLOSE_HPP\n\n/** \\file\n * A package of types and methods for manipulating WebSocket close codes.\n */\n\n#include <websocketpp/error.hpp>\n#include <websocketpp/common/network.hpp>\n#include <websocketpp/common/stdint.hpp>\n#include <websocketpp/utf8_validator.hpp>\n\n#include <string>\n\nnamespace websocketpp {\n/// A package of types and methods for manipulating WebSocket close codes.\nnamespace close {\n/// A package of types and methods for manipulating WebSocket close status'\nnamespace status {\n    /// The type of a close code value.\n    typedef uint16_t value;\n\n    /// A blank value for internal use.\n    static value const blank = 0;\n\n    /// Close the connection without a WebSocket close handshake.\n    /**\n     * This special value requests that the WebSocket connection be closed\n     * without performing the WebSocket closing handshake. This does not comply\n     * with RFC6455, but should be safe to do if necessary. This could be useful\n     * for clients that need to disconnect quickly and cannot afford the\n     * complete handshake.\n     */\n    static value const omit_handshake = 1;\n\n    /// Close the connection with a forced TCP drop.\n    /**\n     * This special value requests that the WebSocket connection be closed by\n     * forcibly dropping the TCP connection. This will leave the other side of\n     * the connection with a broken connection and some expensive timeouts. this\n     * should not be done except in extreme cases or in cases of malicious\n     * remote endpoints.\n     */\n    static value const force_tcp_drop = 2;\n\n    /// Normal closure, meaning that the purpose for which the connection was\n    /// established has been fulfilled.\n    static value const normal = 1000;\n\n    /// The endpoint was \"going away\", such as a server going down or a browser\n    /// navigating away from a page.\n    static value const going_away = 1001;\n\n    /// A protocol error occurred.\n    static value const protocol_error = 1002;\n\n    /// The connection was terminated because an endpoint received a type of\n    /// data it cannot accept.\n    /**\n     * (e.g., an endpoint that understands only text data MAY send this if it\n     * receives a binary message).\n     */\n    static value const unsupported_data = 1003;\n\n    /// A dummy value to indicate that no status code was received.\n    /**\n     * This value is illegal on the wire.\n     */\n    static value const no_status = 1005;\n\n    /// A dummy value to indicate that the connection was closed abnormally.\n    /**\n     * In such a case there was no close frame to extract a value from. This\n     * value is illegal on the wire.\n     */\n    static value const abnormal_close = 1006;\n\n    /// An endpoint received message data inconsistent with its type.\n    /**\n     * For example: Invalid UTF8 bytes in a text message.\n     */\n    static value const invalid_payload = 1007;\n\n    /// An endpoint received a message that violated its policy.\n    /**\n     * This is a generic status code that can be returned when there is no other\n     * more suitable status code (e.g., 1003 or 1009) or if there is a need to\n     * hide specific details about the policy.\n     */\n    static value const policy_violation = 1008;\n\n    /// An endpoint received a message too large to process.\n    static value const message_too_big = 1009;\n\n    /// A client expected the server to accept a required extension request\n    /**\n     * The list of extensions that are needed SHOULD appear in the /reason/ part\n     * of the Close frame. Note that this status code is not used by the server,\n     * because it can fail the WebSocket handshake instead.\n     */\n    static value const extension_required = 1010;\n\n    /// An endpoint encountered an unexpected condition that prevented it from\n    /// fulfilling the request.\n    static value const internal_endpoint_error = 1011;\n\n    /// Indicates that the service is restarted. A client may reconnect and if\n    /// if it chooses to do so, should reconnect using a randomized delay of\n    /// 5-30s\n    static value const service_restart = 1012;\n\n    /// Indicates that the service is experiencing overload. A client should\n    /// only connect to a different IP (when there are multiple for the target)\n    /// or reconnect to the same IP upon user action.\n    static value const try_again_later = 1013;\n\n    /// Indicates that the server was acting as a gateway or proxy and received\n    /// an invalid response from the upstream server. This is similar to 502\n    /// HTTP Status Code.\n    static value const bad_gateway = 1014;\n\n    /// An endpoint failed to perform a TLS handshake\n    /**\n     * Designated for use in applications expecting a status code to indicate\n     * that the connection was closed due to a failure to perform a TLS\n     * handshake (e.g., the server certificate can't be verified). This value is\n     * illegal on the wire.\n     */\n    static value const tls_handshake = 1015;\n    \n    /// A generic subprotocol error\n    /**\n     * Indicates that a subprotocol error occurred. Typically this involves\n     * receiving a message that is not formatted as a valid message for the\n     * subprotocol in use.\n     */\n    static value const subprotocol_error = 3000;\n    \n    /// A invalid subprotocol data\n    /**\n     * Indicates that data was received that violated the specification of the\n     * subprotocol in use.\n     */\n    static value const invalid_subprotocol_data = 3001;\n\n    /// First value in range reserved for future protocol use\n    static value const rsv_start = 1016;\n    /// Last value in range reserved for future protocol use\n    static value const rsv_end = 2999;\n\n    /// Test whether a close code is in a reserved range\n    /**\n     * @param [in] code The code to test\n     * @return Whether or not code is reserved\n     */\n    inline bool reserved(value code) {\n        return ((code >= rsv_start && code <= rsv_end) ||\n                code == 1004);\n    }\n\n    /// First value in range that is always invalid on the wire\n    static value const invalid_low = 999;\n    /// Last value in range that is always invalid on the wire\n    static value const invalid_high = 5000;\n\n    /// Test whether a close code is invalid on the wire\n    /**\n     * @param [in] code The code to test\n     * @return Whether or not code is invalid on the wire\n     */\n    inline bool invalid(value code) {\n        return (code <= invalid_low || code >= invalid_high ||\n                code == no_status || code == abnormal_close ||\n                code == tls_handshake);\n    }\n\n    /// Determine if the code represents an unrecoverable error\n    /**\n     * There is a class of errors for which once they are discovered normal\n     * WebSocket functionality can no longer occur. This function determines\n     * if a given code is one of these values. This information is used to\n     * determine if the system has the capability of waiting for a close\n     * acknowledgement or if it should drop the TCP connection immediately\n     * after sending its close frame.\n     *\n     * @param [in] code The value to test.\n     * @return True if the code represents an unrecoverable error\n     */\n    inline bool terminal(value code) {\n        return (code == protocol_error || code == invalid_payload ||\n                code == policy_violation || code == message_too_big ||\n                 code == internal_endpoint_error);\n    }\n    \n    /// Return a human readable interpretation of a WebSocket close code\n    /**\n     * See https://tools.ietf.org/html/rfc6455#section-7.4 for more details.\n     *\n     * @since 0.3.0\n     *\n     * @param [in] code The code to look up.\n     * @return A human readable interpretation of the code.\n     */\n    inline std::string get_string(value code) {\n        switch (code) {\n            case normal:\n                return \"Normal close\";\n            case going_away:\n                return \"Going away\";\n            case protocol_error:\n                return \"Protocol error\";\n            case unsupported_data:\n                return \"Unsupported data\";\n            case no_status:\n                return \"No status set\";\n            case abnormal_close:\n                return \"Abnormal close\";\n            case invalid_payload:\n                return \"Invalid payload\";\n            case policy_violation:\n                return \"Policy violoation\";\n            case message_too_big:\n                return \"Message too big\";\n            case extension_required:\n                return \"Extension required\";\n            case internal_endpoint_error:\n                return \"Internal endpoint error\";\n            case service_restart:\n                return \"Service restart\";\n            case try_again_later:\n                return \"Try again later\";\n            case bad_gateway:\n                return \"Bad gateway\";\n            case tls_handshake:\n                return \"TLS handshake failure\";\n            case subprotocol_error:\n                return \"Generic subprotocol error\";\n            case invalid_subprotocol_data:\n                return \"Invalid subprotocol data\";\n            default:\n                return \"Unknown\";\n        }\n    }\n} // namespace status\n\n/// Type used to convert close statuses between integer and wire representations\nunion code_converter {\n    uint16_t i;\n    char c[2];\n};\n\n/// Extract a close code value from a close payload\n/**\n * If there is no close value (ie string is empty) status::no_status is\n * returned. If a code couldn't be extracted (usually do to a short or\n * otherwise mangled payload) status::protocol_error is returned and the ec\n * value is flagged as an error. Note that this case is different than the case\n * where protocol error is received over the wire.\n *\n * If the value is in an invalid or reserved range ec is set accordingly.\n *\n * @param [in] payload Close frame payload value received over the wire.\n * @param [out] ec Set to indicate what error occurred, if any.\n * @return The extracted value\n */\ninline status::value extract_code(std::string const & payload, lib::error_code\n    & ec)\n{\n    ec = lib::error_code();\n\n    if (payload.size() == 0) {\n        return status::no_status;\n    } else if (payload.size() == 1) {\n        ec = make_error_code(error::bad_close_code);\n        return status::protocol_error;\n    }\n\n    code_converter val;\n\n    val.c[0] = payload[0];\n    val.c[1] = payload[1];\n\n    status::value code(ntohs(val.i));\n\n    if (status::invalid(code)) {\n        ec = make_error_code(error::invalid_close_code);\n    }\n\n    if (status::reserved(code)) {\n        ec = make_error_code(error::reserved_close_code);\n    }\n\n    return code;\n}\n\n/// Extract the reason string from a close payload\n/**\n * The string should be a valid UTF8 message. error::invalid_utf8 will be set if\n * the function extracts a reason that is not valid UTF8.\n *\n * @param [in] payload The payload string to extract a reason from.\n * @param [out] ec Set to indicate what error occurred, if any.\n * @return The reason string.\n */\ninline std::string extract_reason(std::string const & payload, lib::error_code\n    & ec)\n{\n    std::string reason;\n    ec = lib::error_code();\n\n    if (payload.size() > 2) {\n        reason.append(payload.begin()+2,payload.end());\n    }\n\n    if (!websocketpp::utf8_validator::validate(reason)) {\n        ec = make_error_code(error::invalid_utf8);\n    }\n\n    return reason;\n}\n\n} // namespace close\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CLOSE_HPP\n"
  },
  {
    "path": "websocketpp/common/asio.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_ASIO_HPP\n#define WEBSOCKETPP_COMMON_ASIO_HPP\n\n// This file goes to some length to preserve compatibility with versions of \n// boost older than 1.49 (where the first modern steady_timer timer based on \n// boost/std chrono was introduced.\n//\n// For the versions older than 1.49, the deadline_timer is used instead. this\n// brings in dependencies on boost date_time and it has a different interface\n// that is normalized by the `lib::asio::is_neg` and `lib::asio::milliseconds`\n// wrappers provided by this file.\n//\n// The primary reason for this continued support is that boost 1.48 is the\n// default and not easily changeable version of boost supplied by the package\n// manager of popular Linux distributions like Ubuntu 12.04 LTS. Once the need\n// for this has passed this should be cleaned up and simplified.\n\n#ifdef ASIO_STANDALONE\n    #include <asio/version.hpp>\n    \n    #if (ASIO_VERSION/100000) == 1 && ((ASIO_VERSION/100)%1000) < 8\n        static_assert(false, \"The minimum version of standalone Asio is 1.8.0\");\n    #endif\n    \n    #include <asio.hpp>\n    #include <asio/steady_timer.hpp>\n    #include <websocketpp/common/chrono.hpp> \n#else\n    #include <boost/version.hpp>\n    \n    // See note above about boost <1.49 compatibility. If we are running on \n    // boost > 1.48 pull in the steady timer and chrono library\n    #if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48\n        #include <boost/asio/steady_timer.hpp>\n        #include <websocketpp/common/chrono.hpp>\n    #endif\n    \n    #include <boost/asio.hpp>\n    #include <boost/system/error_code.hpp>\n#endif\n\nnamespace websocketpp {\nnamespace lib {\n\n#ifdef ASIO_STANDALONE\n    namespace asio {\n        using namespace ::asio;\n        // Here we assume that we will be using std::error_code with standalone\n        // Asio. This is probably a good assumption, but it is possible in rare\n        // cases that local Asio versions would be used.\n        using std::errc;\n        \n        // See note above about boost <1.49 compatibility. Because we require\n        // a standalone Asio version of 1.8+ we are guaranteed to have \n        // steady_timer available. By convention we require the chrono library\n        // (either boost or std) for use with standalone Asio.\n        template <typename T>\n        bool is_neg(T duration) {\n            return duration.count() < 0;\n        }\n        inline lib::chrono::milliseconds milliseconds(long duration) {\n            return lib::chrono::milliseconds(duration);\n        }\n    } // namespace asio\n    \n#else\n    namespace asio {\n        using namespace boost::asio;\n        \n        // See note above about boost <1.49 compatibility\n        #if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48\n            // Using boost::asio >=1.49 so we use chrono and steady_timer\n            template <typename T>\n            bool is_neg(T duration) {\n                return duration.count() < 0;\n            }\n\n            // If boost believes it has std::chrono available it will use it\n            // so we should also use it for things that relate to boost, even\n            // if the library would otherwise use boost::chrono.\n            #if defined(BOOST_ASIO_HAS_STD_CHRONO)\n                inline std::chrono::milliseconds milliseconds(long duration) {\n                    return std::chrono::milliseconds(duration);\n                }\n            #else\n                inline lib::chrono::milliseconds milliseconds(long duration) {\n                    return lib::chrono::milliseconds(duration);\n                }\n            #endif\n        #else\n            // Using boost::asio <1.49 we pretend a deadline timer is a steady\n            // timer and wrap the negative detection and duration conversion\n            // appropriately.\n            typedef boost::asio::deadline_timer steady_timer;\n            \n            template <typename T>\n            bool is_neg(T duration) {\n                return duration.is_negative();\n            }\n            inline boost::posix_time::time_duration milliseconds(long duration) {\n                return boost::posix_time::milliseconds(duration);\n            }\n        #endif\n        \n        using boost::system::error_code;\n        namespace errc = boost::system::errc;\n    } // namespace asio\n#endif\n\n\n} // namespace lib\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_COMMON_ASIO_HPP\n"
  },
  {
    "path": "websocketpp/common/asio_ssl.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_ASIO_SSL_HPP\n#define WEBSOCKETPP_COMMON_ASIO_SSL_HPP\n\n// NOTE: This file must be included before common/asio.hpp\n\n#ifdef ASIO_STANDALONE\n    #include <asio/ssl.hpp>\n#else\n    #include <boost/asio/ssl.hpp>\n#endif\n\n#endif // WEBSOCKETPP_COMMON_ASIO_SSL_HPP\n"
  },
  {
    "path": "websocketpp/common/chrono.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_CHRONO_HPP\n#define WEBSOCKETPP_COMMON_CHRONO_HPP\n\n#include <websocketpp/common/cpp11.hpp>\n\n// If we've determined that we're in full C++11 mode and the user hasn't\n// explicitly disabled the use of C++11 functional header, then prefer it to\n// boost.\n#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_\n    #ifndef _WEBSOCKETPP_CPP11_CHRONO_\n        #define _WEBSOCKETPP_CPP11_CHRONO_\n    #endif\n#endif\n\n// If we're on Visual Studio 2012 or higher and haven't explicitly disabled\n// the use of C++11 chrono header then prefer it to boost.\n#if defined(_MSC_VER) && _MSC_VER >= 1700 && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_\n    #ifndef _WEBSOCKETPP_CPP11_CHRONO_\n        #define _WEBSOCKETPP_CPP11_CHRONO_\n    #endif\n#endif\n\n#ifdef _WEBSOCKETPP_CPP11_CHRONO_\n    #include <chrono>\n#else\n    #include <boost/chrono.hpp>\n#endif\n\nnamespace websocketpp {\nnamespace lib {\n\n#ifdef _WEBSOCKETPP_CPP11_CHRONO_\n    namespace chrono = std::chrono;\n#else\n    namespace chrono = boost::chrono;\n#endif\n\n} // namespace lib\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_COMMON_CHRONO_HPP\n"
  },
  {
    "path": "websocketpp/common/connection_hdl.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_CONNECTION_HDL_HPP\n#define WEBSOCKETPP_COMMON_CONNECTION_HDL_HPP\n\n#include <websocketpp/common/memory.hpp>\n\nnamespace websocketpp {\n\n/// A handle to uniquely identify a connection.\n/**\n * This type uniquely identifies a connection. It is implemented as a weak\n * pointer to the connection in question. This provides uniqueness across\n * multiple endpoints and ensures that IDs never conflict or run out.\n *\n * It is safe to make copies of this handle, store those copies in containers,\n * and use them from other threads.\n *\n * This handle can be upgraded to a full shared_ptr using\n * `endpoint::get_con_from_hdl()` from within a handler fired by the connection\n * that owns the handler.\n */\ntypedef lib::weak_ptr<void> connection_hdl;\n\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_COMMON_CONNECTION_HDL_HPP\n"
  },
  {
    "path": "websocketpp/common/cpp11.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_CPP11_HPP\n#define WEBSOCKETPP_COMMON_CPP11_HPP\n\n/**\n * This header sets up some constants based on the state of C++11 support\n */\n\n// Hide clang feature detection from other compilers\n#ifndef __has_feature         // Optional of course.\n  #define __has_feature(x) 0  // Compatibility with non-clang compilers.\n#endif\n#ifndef __has_extension\n  #define __has_extension __has_feature // Compatibility with pre-3.0 compilers.\n#endif\n\n// The code below attempts to use information provided by the build system or\n// user supplied defines to selectively enable C++11 language and library\n// features. In most cases features that are targeted individually may also be\n// selectively disabled via an associated _WEBSOCKETPP_NOXXX_ define.\n\n#if defined(_WEBSOCKETPP_CPP11_STL_) || __cplusplus >= 201103L || defined(_WEBSOCKETPP_CPP11_STRICT_)\n    // This check tests for blanket c++11 coverage. It can be activated in one\n    // of three ways. Either the compiler itself reports that it is a full \n    // C++11 compiler via the __cplusplus macro or the user/build system\n    // supplies one of the two preprocessor defines below:\n    \n    // This is defined to allow other WebSocket++ common headers to enable\n    // C++11 features when they are detected by this file rather than\n    // duplicating the above logic in every common header.\n    #define _WEBSOCKETPP_CPP11_INTERNAL_\n    \n    // _WEBSOCKETPP_CPP11_STRICT_\n    //\n    // This define reports to WebSocket++ that 100% of the language and library\n    // features of C++11 are available. Using this define on a non-C++11\n    // compiler will result in problems.\n    \n    // _WEBSOCKETPP_CPP11_STL_ \n    //\n    // This define enables *most* C++11 options that were implemented early on\n    // by compilers. It is typically used for compilers that have many, but not\n    // all C++11 features. It should be safe to use on GCC 4.7-4.8 and perhaps\n    // earlier. \n    #ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_\n        #define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept\n    #endif\n    #ifndef _WEBSOCKETPP_CONSTEXPR_TOKEN_\n        #define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr\n    #endif\n    #ifndef _WEBSOCKETPP_INITIALIZER_LISTS_\n        #define _WEBSOCKETPP_INITIALIZER_LISTS_\n    #endif\n    #ifndef _WEBSOCKETPP_NULLPTR_TOKEN_\n        #define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr\n    #endif\n    #ifndef _WEBSOCKETPP_MOVE_SEMANTICS_\n        #define _WEBSOCKETPP_MOVE_SEMANTICS_\n    #endif\n    #ifndef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n        #define _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n    #endif\n    \n    #ifndef __GNUC__\n        // GCC as of version 4.9 (latest) does not support std::put_time yet.\n        // so ignore it\n        #define _WEBSOCKETPP_PUTTIME_\n    #endif\n#else\n    // In the absence of a blanket define, try to use compiler versions or\n    // feature testing macros to selectively enable what we can.\n\n    // Test for noexcept\n    #ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_\n        #ifdef _WEBSOCKETPP_NOEXCEPT_\n            // build system says we have noexcept\n            #define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept\n        #else\n            #if __has_feature(cxx_noexcept)\n                // clang feature detect says we have noexcept\n                #define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept\n            #elif defined(_MSC_VER) && _MSC_VER >= 1900\n            \t// Visual Studio 2015+ has noexcept\n                #define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept\n            #else\n                // assume we don't have noexcept\n                #define _WEBSOCKETPP_NOEXCEPT_TOKEN_\n            #endif\n        #endif\n    #endif\n\n    // Test for constexpr\n    #ifndef _WEBSOCKETPP_CONSTEXPR_TOKEN_\n        #ifdef _WEBSOCKETPP_CONSTEXPR_\n            // build system says we have constexpr\n            #define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr\n        #else\n            #if __has_feature(cxx_constexpr)\n                // clang feature detect says we have constexpr\n                #define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr\n            #elif defined(_MSC_VER) && _MSC_VER >= 1900\n            \t// Visual Studio 2015+ has constexpr\n                #define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr\n            #else\n                // assume we don't have constexpr\n                #define _WEBSOCKETPP_CONSTEXPR_TOKEN_\n            #endif\n        #endif\n    #endif\n\n    // Enable initializer lists on clang when available.\n    #if __has_feature(cxx_generalized_initializers) && !defined(_WEBSOCKETPP_INITIALIZER_LISTS_)\n        #define _WEBSOCKETPP_INITIALIZER_LISTS_\n    #endif\n    \n    // Test for nullptr\n    #ifndef _WEBSOCKETPP_NULLPTR_TOKEN_\n        #ifdef _WEBSOCKETPP_NULLPTR_\n            // build system says we have nullptr\n            #define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr\n        #else\n            #if __has_feature(cxx_nullptr)\n                // clang feature detect says we have nullptr\n                #define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr\n            #elif defined(_MSC_VER) &&_MSC_VER >= 1600\n                // Visual Studio version that has nullptr\n                #define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr\n            #else\n                // assume we don't have nullptr\n                #define _WEBSOCKETPP_NULLPTR_TOKEN_ 0\n            #endif\n        #endif\n    #endif\n#endif\n\n#endif // WEBSOCKETPP_COMMON_CPP11_HPP\n"
  },
  {
    "path": "websocketpp/common/functional.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_FUNCTIONAL_HPP\n#define WEBSOCKETPP_COMMON_FUNCTIONAL_HPP\n\n#include <websocketpp/common/cpp11.hpp>\n\n// If we've determined that we're in full C++11 mode and the user hasn't\n// explicitly disabled the use of C++11 functional header, then prefer it to\n// boost.\n#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_\n    #ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_\n        #define _WEBSOCKETPP_CPP11_FUNCTIONAL_\n    #endif\n#endif\n\n// If we're on Visual Studio 2010 or higher and haven't explicitly disabled\n// the use of C++11 functional header then prefer it to boost.\n#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_\n    #ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_\n        #define _WEBSOCKETPP_CPP11_FUNCTIONAL_\n    #endif\n#endif\n\n\n\n#ifdef _WEBSOCKETPP_CPP11_FUNCTIONAL_\n    #include <functional>\n#else\n    #include <boost/bind.hpp>\n    #include <boost/function.hpp>\n    #include <boost/ref.hpp>\n#endif\n\n\n\nnamespace websocketpp {\nnamespace lib {\n\n#ifdef _WEBSOCKETPP_CPP11_FUNCTIONAL_\n    using std::function;\n    using std::bind;\n    using std::ref;\n    namespace placeholders = std::placeholders;\n\n    // There are some cases where a C++11 compiler balks at using std::ref\n    // but a C++03 compiler using boost function requires boost::ref. As such\n    // lib::ref is not useful in these cases. Instead this macro allows the use\n    // of boost::ref in the case of a boost compile or no reference wrapper at\n    // all in the case of a C++11 compile\n    #define _WEBSOCKETPP_REF(x) x\n\n    template <typename T>\n    void clear_function(T & x) {\n        x = nullptr;\n    }\n#else\n    using boost::function;\n    using boost::bind;\n    using boost::ref;\n    namespace placeholders {\n        /// \\todo this feels hacky, is there a better way?\n        using ::_1;\n        using ::_2;\n        using ::_3;\n    }\n\n    // See above definition for more details on what this is and why it exists\n    #define _WEBSOCKETPP_REF(x) boost::ref(x)\n\n    template <typename T>\n    void clear_function(T & x) {\n        x.clear();\n    }\n#endif\n\n} // namespace lib\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_COMMON_FUNCTIONAL_HPP\n"
  },
  {
    "path": "websocketpp/common/md5.hpp",
    "content": "/*\n  md5.hpp is a reformulation of the md5.h and md5.c code from\n  http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to\n  function as a component of a header only library. This conversion was done by\n  Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The\n  changes are released under the same license as the original (listed below)\n*/\n/*\n  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  L. Peter Deutsch\n  ghost@aladdin.com\n\n */\n/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */\n/*\n  Independent implementation of MD5 (RFC 1321).\n\n  This code implements the MD5 Algorithm defined in RFC 1321, whose\n  text is available at\n    http://www.ietf.org/rfc/rfc1321.txt\n  The code is derived from the text of the RFC, including the test suite\n  (section A.5) but excluding the rest of Appendix A.  It does not include\n  any code or documentation that is identified in the RFC as being\n  copyrighted.\n\n  The original and principal author of md5.h is L. Peter Deutsch\n  <ghost@aladdin.com>.  Other authors are noted in the change history\n  that follows (in reverse chronological order):\n\n  2002-04-13 lpd Removed support for non-ANSI compilers; removed\n    references to Ghostscript; clarified derivation from RFC 1321;\n    now handles byte order either statically or dynamically.\n  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.\n  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);\n    added conditionalization for C++ compilation from Martin\n    Purschke <purschke@bnl.gov>.\n  1999-05-03 lpd Original version.\n */\n\n#ifndef WEBSOCKETPP_COMMON_MD5_HPP\n#define WEBSOCKETPP_COMMON_MD5_HPP\n\n/*\n * This package supports both compile-time and run-time determination of CPU\n * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be\n * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is\n * defined as non-zero, the code will be compiled to run only on big-endian\n * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to\n * run on either big- or little-endian CPUs, but will run slightly less\n * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.\n */\n\n#include <stddef.h>\n#include <string>\n#include <cstring>\n\nnamespace websocketpp {\n/// Provides MD5 hashing functionality\nnamespace md5 {\n\ntypedef unsigned char md5_byte_t; /* 8-bit byte */\ntypedef unsigned int md5_word_t; /* 32-bit word */\n\n/* Define the state of the MD5 Algorithm. */\ntypedef struct md5_state_s {\n    md5_word_t count[2];    /* message length in bits, lsw first */\n    md5_word_t abcd[4];     /* digest buffer */\n    md5_byte_t buf[64];     /* accumulate block */\n} md5_state_t;\n\n/* Initialize the algorithm. */\ninline void md5_init(md5_state_t *pms);\n\n/* Append a string to the message. */\ninline void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes);\n\n/* Finish the message and return the digest. */\ninline void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);\n\n#undef ZSW_MD5_BYTE_ORDER   /* 1 = big-endian, -1 = little-endian, 0 = unknown */\n#ifdef ARCH_IS_BIG_ENDIAN\n#  define ZSW_MD5_BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)\n#else\n#  define ZSW_MD5_BYTE_ORDER 0\n#endif\n\n#define ZSW_MD5_T_MASK ((md5_word_t)~0)\n#define ZSW_MD5_T1 /* 0xd76aa478 */ (ZSW_MD5_T_MASK ^ 0x28955b87)\n#define ZSW_MD5_T2 /* 0xe8c7b756 */ (ZSW_MD5_T_MASK ^ 0x173848a9)\n#define ZSW_MD5_T3    0x242070db\n#define ZSW_MD5_T4 /* 0xc1bdceee */ (ZSW_MD5_T_MASK ^ 0x3e423111)\n#define ZSW_MD5_T5 /* 0xf57c0faf */ (ZSW_MD5_T_MASK ^ 0x0a83f050)\n#define ZSW_MD5_T6    0x4787c62a\n#define ZSW_MD5_T7 /* 0xa8304613 */ (ZSW_MD5_T_MASK ^ 0x57cfb9ec)\n#define ZSW_MD5_T8 /* 0xfd469501 */ (ZSW_MD5_T_MASK ^ 0x02b96afe)\n#define ZSW_MD5_T9    0x698098d8\n#define ZSW_MD5_T10 /* 0x8b44f7af */ (ZSW_MD5_T_MASK ^ 0x74bb0850)\n#define ZSW_MD5_T11 /* 0xffff5bb1 */ (ZSW_MD5_T_MASK ^ 0x0000a44e)\n#define ZSW_MD5_T12 /* 0x895cd7be */ (ZSW_MD5_T_MASK ^ 0x76a32841)\n#define ZSW_MD5_T13    0x6b901122\n#define ZSW_MD5_T14 /* 0xfd987193 */ (ZSW_MD5_T_MASK ^ 0x02678e6c)\n#define ZSW_MD5_T15 /* 0xa679438e */ (ZSW_MD5_T_MASK ^ 0x5986bc71)\n#define ZSW_MD5_T16    0x49b40821\n#define ZSW_MD5_T17 /* 0xf61e2562 */ (ZSW_MD5_T_MASK ^ 0x09e1da9d)\n#define ZSW_MD5_T18 /* 0xc040b340 */ (ZSW_MD5_T_MASK ^ 0x3fbf4cbf)\n#define ZSW_MD5_T19    0x265e5a51\n#define ZSW_MD5_T20 /* 0xe9b6c7aa */ (ZSW_MD5_T_MASK ^ 0x16493855)\n#define ZSW_MD5_T21 /* 0xd62f105d */ (ZSW_MD5_T_MASK ^ 0x29d0efa2)\n#define ZSW_MD5_T22    0x02441453\n#define ZSW_MD5_T23 /* 0xd8a1e681 */ (ZSW_MD5_T_MASK ^ 0x275e197e)\n#define ZSW_MD5_T24 /* 0xe7d3fbc8 */ (ZSW_MD5_T_MASK ^ 0x182c0437)\n#define ZSW_MD5_T25    0x21e1cde6\n#define ZSW_MD5_T26 /* 0xc33707d6 */ (ZSW_MD5_T_MASK ^ 0x3cc8f829)\n#define ZSW_MD5_T27 /* 0xf4d50d87 */ (ZSW_MD5_T_MASK ^ 0x0b2af278)\n#define ZSW_MD5_T28    0x455a14ed\n#define ZSW_MD5_T29 /* 0xa9e3e905 */ (ZSW_MD5_T_MASK ^ 0x561c16fa)\n#define ZSW_MD5_T30 /* 0xfcefa3f8 */ (ZSW_MD5_T_MASK ^ 0x03105c07)\n#define ZSW_MD5_T31    0x676f02d9\n#define ZSW_MD5_T32 /* 0x8d2a4c8a */ (ZSW_MD5_T_MASK ^ 0x72d5b375)\n#define ZSW_MD5_T33 /* 0xfffa3942 */ (ZSW_MD5_T_MASK ^ 0x0005c6bd)\n#define ZSW_MD5_T34 /* 0x8771f681 */ (ZSW_MD5_T_MASK ^ 0x788e097e)\n#define ZSW_MD5_T35    0x6d9d6122\n#define ZSW_MD5_T36 /* 0xfde5380c */ (ZSW_MD5_T_MASK ^ 0x021ac7f3)\n#define ZSW_MD5_T37 /* 0xa4beea44 */ (ZSW_MD5_T_MASK ^ 0x5b4115bb)\n#define ZSW_MD5_T38    0x4bdecfa9\n#define ZSW_MD5_T39 /* 0xf6bb4b60 */ (ZSW_MD5_T_MASK ^ 0x0944b49f)\n#define ZSW_MD5_T40 /* 0xbebfbc70 */ (ZSW_MD5_T_MASK ^ 0x4140438f)\n#define ZSW_MD5_T41    0x289b7ec6\n#define ZSW_MD5_T42 /* 0xeaa127fa */ (ZSW_MD5_T_MASK ^ 0x155ed805)\n#define ZSW_MD5_T43 /* 0xd4ef3085 */ (ZSW_MD5_T_MASK ^ 0x2b10cf7a)\n#define ZSW_MD5_T44    0x04881d05\n#define ZSW_MD5_T45 /* 0xd9d4d039 */ (ZSW_MD5_T_MASK ^ 0x262b2fc6)\n#define ZSW_MD5_T46 /* 0xe6db99e5 */ (ZSW_MD5_T_MASK ^ 0x1924661a)\n#define ZSW_MD5_T47    0x1fa27cf8\n#define ZSW_MD5_T48 /* 0xc4ac5665 */ (ZSW_MD5_T_MASK ^ 0x3b53a99a)\n#define ZSW_MD5_T49 /* 0xf4292244 */ (ZSW_MD5_T_MASK ^ 0x0bd6ddbb)\n#define ZSW_MD5_T50    0x432aff97\n#define ZSW_MD5_T51 /* 0xab9423a7 */ (ZSW_MD5_T_MASK ^ 0x546bdc58)\n#define ZSW_MD5_T52 /* 0xfc93a039 */ (ZSW_MD5_T_MASK ^ 0x036c5fc6)\n#define ZSW_MD5_T53    0x655b59c3\n#define ZSW_MD5_T54 /* 0x8f0ccc92 */ (ZSW_MD5_T_MASK ^ 0x70f3336d)\n#define ZSW_MD5_T55 /* 0xffeff47d */ (ZSW_MD5_T_MASK ^ 0x00100b82)\n#define ZSW_MD5_T56 /* 0x85845dd1 */ (ZSW_MD5_T_MASK ^ 0x7a7ba22e)\n#define ZSW_MD5_T57    0x6fa87e4f\n#define ZSW_MD5_T58 /* 0xfe2ce6e0 */ (ZSW_MD5_T_MASK ^ 0x01d3191f)\n#define ZSW_MD5_T59 /* 0xa3014314 */ (ZSW_MD5_T_MASK ^ 0x5cfebceb)\n#define ZSW_MD5_T60    0x4e0811a1\n#define ZSW_MD5_T61 /* 0xf7537e82 */ (ZSW_MD5_T_MASK ^ 0x08ac817d)\n#define ZSW_MD5_T62 /* 0xbd3af235 */ (ZSW_MD5_T_MASK ^ 0x42c50dca)\n#define ZSW_MD5_T63    0x2ad7d2bb\n#define ZSW_MD5_T64 /* 0xeb86d391 */ (ZSW_MD5_T_MASK ^ 0x14792c6e)\n\nstatic void md5_process(md5_state_t *pms, md5_byte_t const * data /*[64]*/) {\n    md5_word_t\n    a = pms->abcd[0], b = pms->abcd[1],\n    c = pms->abcd[2], d = pms->abcd[3];\n    md5_word_t t;\n#if ZSW_MD5_BYTE_ORDER > 0\n    /* Define storage only for big-endian CPUs. */\n    md5_word_t X[16];\n#else\n    /* Define storage for little-endian or both types of CPUs. */\n    md5_word_t xbuf[16];\n    md5_word_t const * X;\n#endif\n\n    {\n#if ZSW_MD5_BYTE_ORDER == 0\n    /*\n     * Determine dynamically whether this is a big-endian or\n     * little-endian machine, since we can use a more efficient\n     * algorithm on the latter.\n     */\n    static int const w = 1;\n\n    if (*((md5_byte_t const *)&w)) /* dynamic little-endian */\n#endif\n#if ZSW_MD5_BYTE_ORDER <= 0     /* little-endian */\n    {\n        /*\n         * On little-endian machines, we can process properly aligned\n         * data without copying it.\n         */\n        if (!((data - (md5_byte_t const *)0) & 3)) {\n        /* data are properly aligned */\n        X = (md5_word_t const *)data;\n        } else {\n        /* not aligned */\n        std::memcpy(xbuf, data, 64);\n        X = xbuf;\n        }\n    }\n#endif\n#if ZSW_MD5_BYTE_ORDER == 0\n    else            /* dynamic big-endian */\n#endif\n#if ZSW_MD5_BYTE_ORDER >= 0     /* big-endian */\n    {\n        /*\n         * On big-endian machines, we must arrange the bytes in the\n         * right order.\n         */\n        const md5_byte_t *xp = data;\n        int i;\n\n#  if ZSW_MD5_BYTE_ORDER == 0\n        X = xbuf;       /* (dynamic only) */\n#  else\n#    define xbuf X      /* (static only) */\n#  endif\n        for (i = 0; i < 16; ++i, xp += 4)\n        xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);\n    }\n#endif\n    }\n\n#define ZSW_MD5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))\n\n    /* Round 1. */\n    /* Let [abcd k s i] denote the operation\n       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */\n#define ZSW_MD5_F(x, y, z) (((x) & (y)) | (~(x) & (z)))\n#define SET(a, b, c, d, k, s, Ti)\\\n  t = a + ZSW_MD5_F(b,c,d) + X[k] + Ti;\\\n  a = ZSW_MD5_ROTATE_LEFT(t, s) + b\n    /* Do the following 16 operations. */\n    SET(a, b, c, d,  0,  7,  ZSW_MD5_T1);\n    SET(d, a, b, c,  1, 12,  ZSW_MD5_T2);\n    SET(c, d, a, b,  2, 17,  ZSW_MD5_T3);\n    SET(b, c, d, a,  3, 22,  ZSW_MD5_T4);\n    SET(a, b, c, d,  4,  7,  ZSW_MD5_T5);\n    SET(d, a, b, c,  5, 12,  ZSW_MD5_T6);\n    SET(c, d, a, b,  6, 17,  ZSW_MD5_T7);\n    SET(b, c, d, a,  7, 22,  ZSW_MD5_T8);\n    SET(a, b, c, d,  8,  7,  ZSW_MD5_T9);\n    SET(d, a, b, c,  9, 12, ZSW_MD5_T10);\n    SET(c, d, a, b, 10, 17, ZSW_MD5_T11);\n    SET(b, c, d, a, 11, 22, ZSW_MD5_T12);\n    SET(a, b, c, d, 12,  7, ZSW_MD5_T13);\n    SET(d, a, b, c, 13, 12, ZSW_MD5_T14);\n    SET(c, d, a, b, 14, 17, ZSW_MD5_T15);\n    SET(b, c, d, a, 15, 22, ZSW_MD5_T16);\n#undef SET\n\n     /* Round 2. */\n     /* Let [abcd k s i] denote the operation\n          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */\n#define ZSW_MD5_G(x, y, z) (((x) & (z)) | ((y) & ~(z)))\n#define SET(a, b, c, d, k, s, Ti)\\\n  t = a + ZSW_MD5_G(b,c,d) + X[k] + Ti;\\\n  a = ZSW_MD5_ROTATE_LEFT(t, s) + b\n     /* Do the following 16 operations. */\n    SET(a, b, c, d,  1,  5, ZSW_MD5_T17);\n    SET(d, a, b, c,  6,  9, ZSW_MD5_T18);\n    SET(c, d, a, b, 11, 14, ZSW_MD5_T19);\n    SET(b, c, d, a,  0, 20, ZSW_MD5_T20);\n    SET(a, b, c, d,  5,  5, ZSW_MD5_T21);\n    SET(d, a, b, c, 10,  9, ZSW_MD5_T22);\n    SET(c, d, a, b, 15, 14, ZSW_MD5_T23);\n    SET(b, c, d, a,  4, 20, ZSW_MD5_T24);\n    SET(a, b, c, d,  9,  5, ZSW_MD5_T25);\n    SET(d, a, b, c, 14,  9, ZSW_MD5_T26);\n    SET(c, d, a, b,  3, 14, ZSW_MD5_T27);\n    SET(b, c, d, a,  8, 20, ZSW_MD5_T28);\n    SET(a, b, c, d, 13,  5, ZSW_MD5_T29);\n    SET(d, a, b, c,  2,  9, ZSW_MD5_T30);\n    SET(c, d, a, b,  7, 14, ZSW_MD5_T31);\n    SET(b, c, d, a, 12, 20, ZSW_MD5_T32);\n#undef SET\n\n     /* Round 3. */\n     /* Let [abcd k s t] denote the operation\n          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */\n#define ZSW_MD5_H(x, y, z) ((x) ^ (y) ^ (z))\n#define SET(a, b, c, d, k, s, Ti)\\\n  t = a + ZSW_MD5_H(b,c,d) + X[k] + Ti;\\\n  a = ZSW_MD5_ROTATE_LEFT(t, s) + b\n     /* Do the following 16 operations. */\n    SET(a, b, c, d,  5,  4, ZSW_MD5_T33);\n    SET(d, a, b, c,  8, 11, ZSW_MD5_T34);\n    SET(c, d, a, b, 11, 16, ZSW_MD5_T35);\n    SET(b, c, d, a, 14, 23, ZSW_MD5_T36);\n    SET(a, b, c, d,  1,  4, ZSW_MD5_T37);\n    SET(d, a, b, c,  4, 11, ZSW_MD5_T38);\n    SET(c, d, a, b,  7, 16, ZSW_MD5_T39);\n    SET(b, c, d, a, 10, 23, ZSW_MD5_T40);\n    SET(a, b, c, d, 13,  4, ZSW_MD5_T41);\n    SET(d, a, b, c,  0, 11, ZSW_MD5_T42);\n    SET(c, d, a, b,  3, 16, ZSW_MD5_T43);\n    SET(b, c, d, a,  6, 23, ZSW_MD5_T44);\n    SET(a, b, c, d,  9,  4, ZSW_MD5_T45);\n    SET(d, a, b, c, 12, 11, ZSW_MD5_T46);\n    SET(c, d, a, b, 15, 16, ZSW_MD5_T47);\n    SET(b, c, d, a,  2, 23, ZSW_MD5_T48);\n#undef SET\n\n     /* Round 4. */\n     /* Let [abcd k s t] denote the operation\n          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */\n#define ZSW_MD5_I(x, y, z) ((y) ^ ((x) | ~(z)))\n#define SET(a, b, c, d, k, s, Ti)\\\n  t = a + ZSW_MD5_I(b,c,d) + X[k] + Ti;\\\n  a = ZSW_MD5_ROTATE_LEFT(t, s) + b\n     /* Do the following 16 operations. */\n    SET(a, b, c, d,  0,  6, ZSW_MD5_T49);\n    SET(d, a, b, c,  7, 10, ZSW_MD5_T50);\n    SET(c, d, a, b, 14, 15, ZSW_MD5_T51);\n    SET(b, c, d, a,  5, 21, ZSW_MD5_T52);\n    SET(a, b, c, d, 12,  6, ZSW_MD5_T53);\n    SET(d, a, b, c,  3, 10, ZSW_MD5_T54);\n    SET(c, d, a, b, 10, 15, ZSW_MD5_T55);\n    SET(b, c, d, a,  1, 21, ZSW_MD5_T56);\n    SET(a, b, c, d,  8,  6, ZSW_MD5_T57);\n    SET(d, a, b, c, 15, 10, ZSW_MD5_T58);\n    SET(c, d, a, b,  6, 15, ZSW_MD5_T59);\n    SET(b, c, d, a, 13, 21, ZSW_MD5_T60);\n    SET(a, b, c, d,  4,  6, ZSW_MD5_T61);\n    SET(d, a, b, c, 11, 10, ZSW_MD5_T62);\n    SET(c, d, a, b,  2, 15, ZSW_MD5_T63);\n    SET(b, c, d, a,  9, 21, ZSW_MD5_T64);\n#undef SET\n\n     /* Then perform the following additions. (That is increment each\n        of the four registers by the value it had before this block\n        was started.) */\n    pms->abcd[0] += a;\n    pms->abcd[1] += b;\n    pms->abcd[2] += c;\n    pms->abcd[3] += d;\n}\n\nvoid md5_init(md5_state_t *pms) {\n    pms->count[0] = pms->count[1] = 0;\n    pms->abcd[0] = 0x67452301;\n    pms->abcd[1] = /*0xefcdab89*/ ZSW_MD5_T_MASK ^ 0x10325476;\n    pms->abcd[2] = /*0x98badcfe*/ ZSW_MD5_T_MASK ^ 0x67452301;\n    pms->abcd[3] = 0x10325476;\n}\n\nvoid md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes) {\n    md5_byte_t const * p = data;\n    size_t left = nbytes;\n    int offset = (pms->count[0] >> 3) & 63;\n    md5_word_t nbits = (md5_word_t)(nbytes << 3);\n\n    if (nbytes <= 0)\n    return;\n\n    /* Update the message length. */\n    pms->count[1] += nbytes >> 29;\n    pms->count[0] += nbits;\n    if (pms->count[0] < nbits)\n    pms->count[1]++;\n\n    /* Process an initial partial block. */\n    if (offset) {\n    int copy = (offset + nbytes > 64 ? 64 - offset : static_cast<int>(nbytes));\n\n    std::memcpy(pms->buf + offset, p, copy);\n    if (offset + copy < 64)\n        return;\n    p += copy;\n    left -= copy;\n    md5_process(pms, pms->buf);\n    }\n\n    /* Process full blocks. */\n    for (; left >= 64; p += 64, left -= 64)\n    md5_process(pms, p);\n\n    /* Process a final partial block. */\n    if (left)\n    std::memcpy(pms->buf, p, left);\n}\n\nvoid md5_finish(md5_state_t *pms, md5_byte_t digest[16]) {\n    static md5_byte_t const pad[64] = {\n    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n    };\n    md5_byte_t data[8];\n    int i;\n\n    /* Save the length before padding. */\n    for (i = 0; i < 8; ++i)\n    data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));\n    /* Pad to 56 bytes mod 64. */\n    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);\n    /* Append the length. */\n    md5_append(pms, data, 8);\n    for (i = 0; i < 16; ++i)\n    digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));\n}\n\n// some convenience c++ functions\ninline std::string md5_hash_string(std::string const & s) {\n    char digest[16];\n\n    md5_state_t state;\n\n    md5_init(&state);\n    md5_append(&state, (md5_byte_t const *)s.c_str(), s.size());\n    md5_finish(&state, (md5_byte_t *)digest);\n\n    std::string ret;\n    ret.resize(16);\n    std::copy(digest,digest+16,ret.begin());\n\n    return ret;\n}\n\nconst char hexval[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};\n\ninline std::string md5_hash_hex(std::string const & input) {\n    std::string hash = md5_hash_string(input);\n    std::string hex;\n\n    for (size_t i = 0; i < hash.size(); i++) {\n        hex.push_back(hexval[((hash[i] >> 4) & 0xF)]);\n        hex.push_back(hexval[(hash[i]) & 0x0F]);\n    }\n\n    return hex;\n}\n\n} // md5\n} // websocketpp\n\n#endif // WEBSOCKETPP_COMMON_MD5_HPP\n"
  },
  {
    "path": "websocketpp/common/memory.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_MEMORY_HPP\n#define WEBSOCKETPP_COMMON_MEMORY_HPP\n\n#include <websocketpp/common/cpp11.hpp>\n\n// If we've determined that we're in full C++11 mode and the user hasn't\n// explicitly disabled the use of C++11 memory header, then prefer it to\n// boost.\n#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_\n    #ifndef _WEBSOCKETPP_CPP11_MEMORY_\n        #define _WEBSOCKETPP_CPP11_MEMORY_\n    #endif\n#endif\n\n// If we're on Visual Studio 2010 or higher and haven't explicitly disabled\n// the use of C++11 functional header then prefer it to boost.\n#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_\n    #ifndef _WEBSOCKETPP_CPP11_MEMORY_\n        #define _WEBSOCKETPP_CPP11_MEMORY_\n    #endif\n#endif\n\n\n\n#ifdef _WEBSOCKETPP_CPP11_MEMORY_\n    #include <memory>\n#else\n    #include <boost/shared_ptr.hpp>\n\t#include <boost/make_shared.hpp>\n    #include <boost/scoped_array.hpp>\n    #include <boost/enable_shared_from_this.hpp>\n    #include <boost/pointer_cast.hpp>\n#endif\n\nnamespace websocketpp {\nnamespace lib {\n\n#ifdef _WEBSOCKETPP_CPP11_MEMORY_\n    using std::shared_ptr;\n    using std::weak_ptr;\n    using std::enable_shared_from_this;\n    using std::static_pointer_cast;\n    using std::make_shared;\n    using std::unique_ptr;\n\n    typedef std::unique_ptr<unsigned char[]> unique_ptr_uchar_array;\n#else\n    using boost::shared_ptr;\n    using boost::weak_ptr;\n    using std::auto_ptr;\n    using boost::enable_shared_from_this;\n    using boost::static_pointer_cast;\n    using boost::make_shared;\n\n    typedef boost::scoped_array<unsigned char> unique_ptr_uchar_array;\n#endif\n\n} // namespace lib\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_COMMON_MEMORY_HPP\n"
  },
  {
    "path": "websocketpp/common/network.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_NETWORK_HPP\n#define WEBSOCKETPP_COMMON_NETWORK_HPP\n\n// For ntohs and htons\n#if defined(_WIN32)\n    #include <winsock2.h>\n#else\n    //#include <arpa/inet.h>\n    #include <netinet/in.h>\n#endif\n\n#include <websocketpp/common/stdint.hpp>\n\nnamespace websocketpp {\nnamespace lib {\nnamespace net {\n\ninline bool is_little_endian() {\n    short int val = 0x1;\n    char *ptr = reinterpret_cast<char *>(&val);\n    return (ptr[0] == 1);\n}\n\n#define TYP_INIT 0\n#define TYP_SMLE 1\n#define TYP_BIGE 2\n\n/// Convert 64 bit value to network byte order\n/**\n * This method is prefixed to avoid conflicts with operating system level\n * macros for this functionality.\n *\n * TODO: figure out if it would be beneficial to use operating system level\n * macros for this.\n *\n * @param src The integer in host byte order\n * @return src converted to network byte order\n */\ninline uint64_t _htonll(uint64_t src) {\n    static int typ = TYP_INIT;\n    unsigned char c;\n    union {\n        uint64_t ull;\n        unsigned char c[8];\n    } x;\n    if (typ == TYP_INIT) {\n        x.ull = 0x01;\n        typ = (x.c[7] == 0x01ULL) ? TYP_BIGE : TYP_SMLE;\n    }\n    if (typ == TYP_BIGE)\n        return src;\n    x.ull = src;\n    c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;\n    c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;\n    c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;\n    c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;\n    return x.ull;\n}\n\n/// Convert 64 bit value to host byte order\n/**\n * This method is prefixed to avoid conflicts with operating system level\n * macros for this functionality.\n *\n * TODO: figure out if it would be beneficial to use operating system level\n * macros for this.\n *\n * @param src The integer in network byte order\n * @return src converted to host byte order\n */\ninline uint64_t _ntohll(uint64_t src) {\n    return _htonll(src);\n}\n\n} // net\n} // lib\n} // websocketpp\n\n#endif // WEBSOCKETPP_COMMON_NETWORK_HPP\n"
  },
  {
    "path": "websocketpp/common/platforms.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_PLATFORMS_HPP\n#define WEBSOCKETPP_COMMON_PLATFORMS_HPP\n\n/**\n * This header contains any platform specific preprocessor adjustments that\n * don't fit somewhere else better.\n */\n\n#if defined(_WIN32) && !defined(NOMINMAX)\n    // don't define min and max macros that conflict with std::min and std::max\n    #define NOMINMAX\n#endif\n\n// Bump up the variadic parameter max for Visual Studio 2012\n#if defined(_MSC_VER) && _MSC_VER == 1700\n    #define _VARIADIC_MAX 8\n#endif\n\n#endif // WEBSOCKETPP_COMMON_PLATFORMS_HPP\n"
  },
  {
    "path": "websocketpp/common/random.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP\n#define WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP\n\n#include <websocketpp/common/cpp11.hpp>\n\n// If we've determined that we're in full C++11 mode and the user hasn't\n// explicitly disabled the use of C++11 random header, then prefer it to\n// boost.\n#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_RANDOM_DEVICE_\n    #ifndef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_\n        #define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_\n    #endif\n#endif\n\n\n// If we're on Visual Studio 2010 or higher and haven't explicitly disabled\n// the use of C++11 random header then prefer it to boost.\n#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_\n    #ifndef _WEBSOCKETPP_CPP11_MEMORY_\n        #define _WEBSOCKETPP_CPP11_MEMORY_\n    #endif\n#endif\n\n\n\n#ifdef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_\n    #include <random>\n#else\n    #include <boost/version.hpp>\n\n    #if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 46\n        #include <boost/random/uniform_int_distribution.hpp>\n        #include <boost/random/random_device.hpp>\n    #elif (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) >= 43\n        #include <boost/nondet_random.hpp>\n    #else\n        // TODO: static_assert(false, \"Could not find a suitable random_device\")\n    #endif\n#endif\n\nnamespace websocketpp {\nnamespace lib {\n\n#ifdef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_\n    using std::random_device;\n    using std::uniform_int_distribution;\n#else\n    using boost::random::random_device;\n    using boost::random::uniform_int_distribution;\n#endif\n\n} // namespace lib\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP\n"
  },
  {
    "path": "websocketpp/common/regex.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_REGEX_HPP\n#define WEBSOCKETPP_COMMON_REGEX_HPP\n\n#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_REGEX_\n    #ifndef _WEBSOCKETPP_CPP11_REGEX_\n        #define _WEBSOCKETPP_CPP11_REGEX_\n    #endif\n#endif\n\n#ifdef _WEBSOCKETPP_CPP11_REGEX_\n    #include <regex>\n#else\n    #include <boost/regex.hpp>\n#endif\n\nnamespace websocketpp {\nnamespace lib {\n\n#ifdef _WEBSOCKETPP_CPP11_REGEX_\n    using std::cmatch;\n    using std::regex;\n    using std::regex_match;\n#else\n    using boost::cmatch;\n    using boost::regex;\n    using boost::regex_match;\n#endif\n\n} // namespace lib\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_COMMON_REGEX_HPP\n"
  },
  {
    "path": "websocketpp/common/stdint.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_STDINT_HPP\n#define WEBSOCKETPP_COMMON_STDINT_HPP\n\n#ifndef __STDC_LIMIT_MACROS\n    #define __STDC_LIMIT_MACROS 1\n#endif\n\n#if defined (_WIN32) && defined (_MSC_VER) && (_MSC_VER < 1600)\n    #include <boost/cstdint.hpp>\n\n    using boost::int8_t;\n    using boost::int_least8_t;\n    using boost::int_fast8_t;\n    using boost::uint8_t;\n    using boost::uint_least8_t;\n    using boost::uint_fast8_t;\n\n    using boost::int16_t;\n    using boost::int_least16_t;\n    using boost::int_fast16_t;\n    using boost::uint16_t;\n    using boost::uint_least16_t;\n    using boost::uint_fast16_t;\n\n    using boost::int32_t;\n    using boost::int_least32_t;\n    using boost::int_fast32_t;\n    using boost::uint32_t;\n    using boost::uint_least32_t;\n    using boost::uint_fast32_t;\n\n    #ifndef BOOST_NO_INT64_T\n    using boost::int64_t;\n    using boost::int_least64_t;\n    using boost::int_fast64_t;\n    using boost::uint64_t;\n    using boost::uint_least64_t;\n    using boost::uint_fast64_t;\n    #endif\n    using boost::intmax_t;\n    using boost::uintmax_t;\n#else\n    #include <stdint.h>\n#endif\n\n#endif // WEBSOCKETPP_COMMON_STDINT_HPP\n"
  },
  {
    "path": "websocketpp/common/system_error.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP\n#define WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP\n\n\n#include <websocketpp/common/cpp11.hpp>\n\n// If we've determined that we're in full C++11 mode and the user hasn't\n// explicitly disabled the use of C++11 system_error header, then prefer it to\n// boost.\n#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_\n    #ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_\n        #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_\n    #endif\n#endif\n\n// If we're on Visual Studio 2010 or higher and haven't explicitly disabled\n// the use of C++11 system_error header then prefer it to boost.\n#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_\n    #ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_\n        #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_\n    #endif\n#endif\n\n\n\n#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_\n    #include <system_error>\n#else\n    #include <boost/system/error_code.hpp>\n    #include <boost/system/system_error.hpp>\n#endif\n\nnamespace websocketpp {\nnamespace lib {\n\n#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_\n    using std::errc;\n    using std::error_code;\n    using std::error_category;\n    using std::error_condition;\n    using std::system_error;\n    #define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ namespace std {\n    #define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ }\n#else\n    namespace errc = boost::system::errc;\n    using boost::system::error_code;\n    using boost::system::error_category;\n    using boost::system::error_condition;\n    using boost::system::system_error;\n    #define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ namespace boost { namespace system {\n    #define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ }}\n#endif\n\n} // namespace lib\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP\n"
  },
  {
    "path": "websocketpp/common/thread.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_THREAD_HPP\n#define WEBSOCKETPP_COMMON_THREAD_HPP\n\n#include <websocketpp/common/cpp11.hpp>\n\n// If we autodetect C++11 and haven't been explicitly instructed to not use\n// C++11 threads, then set the defines that instructs the rest of this header\n// to use C++11 <thread> and <mutex>\n#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_THREAD_\n    // MinGW by default does not support C++11 thread/mutex so even if the\n    // internal check for C++11 passes, ignore it if we are on MinGW\n    #if (!defined(__MINGW32__) && !defined(__MINGW64__))\n        #ifndef _WEBSOCKETPP_CPP11_THREAD_\n            #define _WEBSOCKETPP_CPP11_THREAD_\n        #endif\n    #endif\n#endif\n\n// If we're on Visual Studio 2013 or higher and haven't explicitly disabled\n// the use of C++11 thread header then prefer it to boost.\n#if defined(_MSC_VER) && _MSC_VER >= 1800 && !defined _WEBSOCKETPP_NO_CPP11_THREAD_\n    #ifndef _WEBSOCKETPP_CPP11_THREAD_\n        #define _WEBSOCKETPP_CPP11_THREAD_\n    #endif\n#endif\n\n#if defined(_WEBSOCKETPP_MINGW_THREAD_)\n    #include <mingw-threads/mingw.thread.h>\n    #include <mingw-threads/mingw.mutex.h>\n    #include <mingw-threads/mingw.condition_variable.h>\n#elif defined(_WEBSOCKETPP_CPP11_THREAD_)\n    #include <thread>\n    #include <mutex>\n    #include <condition_variable>\n#else\n    #include <boost/thread.hpp>\n    #include <boost/thread/mutex.hpp>\n    #include <boost/thread/condition_variable.hpp>\n#endif\n\nnamespace websocketpp {\nnamespace lib {\n\n#if defined(_WEBSOCKETPP_CPP11_THREAD_) || defined(_WEBSOCKETPP_MINGW_THREAD_)\n    using std::mutex;\n    using std::lock_guard;\n    using std::thread;\n    using std::unique_lock;\n    using std::condition_variable;\n#else\n    using boost::mutex;\n    using boost::lock_guard;\n    using boost::thread;\n    using boost::unique_lock;\n    using boost::condition_variable;\n#endif\n\n} // namespace lib\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_COMMON_THREAD_HPP\n"
  },
  {
    "path": "websocketpp/common/time.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_TIME_HPP\n#define WEBSOCKETPP_COMMON_TIME_HPP\n\n#include <ctime>\n\nnamespace websocketpp {\nnamespace lib {\n\n// Code in this header was inspired by the following article and includes some\n// code from the related project g2log. The g2log code is public domain licensed\n// http://kjellkod.wordpress.com/2013/01/22/exploring-c11-part-2-localtime-and-time-again/\n\n/// Thread safe cross platform localtime\ninline std::tm localtime(std::time_t const & time) {\n    std::tm tm_snapshot;\n#if (defined(__MINGW32__) || defined(__MINGW64__))\n    memcpy(&tm_snapshot, ::localtime(&time), sizeof(std::tm));\n#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))\n    localtime_s(&tm_snapshot, &time); \n#else\n    localtime_r(&time, &tm_snapshot); // POSIX  \n#endif\n    return tm_snapshot;\n}\n\n} // lib\n} // websocketpp\n\n#endif // WEBSOCKETPP_COMMON_TIME_HPP\n"
  },
  {
    "path": "websocketpp/common/type_traits.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP\n#define WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP\n\n#include <websocketpp/common/cpp11.hpp>\n\n// If we've determined that we're in full C++11 mode and the user hasn't\n// explicitly disabled the use of C++11 functional header, then prefer it to\n// boost.\n#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_TYPE_TRAITS_\n    #ifndef _WEBSOCKETPP_CPP11_TYPE_TRAITS_\n        #define _WEBSOCKETPP_CPP11_TYPE_TRAITS_\n    #endif\n#endif\n\n\n#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_\n    #include <type_traits>\n#else\n    #include <boost/aligned_storage.hpp>\n#endif\n\n\n\nnamespace websocketpp {\nnamespace lib {\n\n#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_\n    using std::aligned_storage;\n    using std::is_same;\n#else\n    using boost::aligned_storage;\n    using boost::is_same;\n#endif\n\n} // namespace lib\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP\n"
  },
  {
    "path": "websocketpp/concurrency/basic.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONCURRENCY_BASIC_HPP\n#define WEBSOCKETPP_CONCURRENCY_BASIC_HPP\n\n#include <websocketpp/common/thread.hpp>\n\nnamespace websocketpp {\nnamespace concurrency {\n\n/// Concurrency policy that uses std::mutex / boost::mutex\nclass basic {\npublic:\n    typedef lib::mutex mutex_type;\n    typedef lib::lock_guard<mutex_type> scoped_lock_type;\n};\n\n} // namespace concurrency\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONCURRENCY_BASIC_HPP\n"
  },
  {
    "path": "websocketpp/concurrency/none.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONCURRENCY_NONE_HPP\n#define WEBSOCKETPP_CONCURRENCY_NONE_HPP\n\nnamespace websocketpp {\n\n/// Concurrency handling support\nnamespace concurrency {\n\n/// Implementation for no-op locking primitives\nnamespace none_impl {\n/// A fake mutex implementation that does nothing\nclass fake_mutex {\npublic:\n    fake_mutex() {}\n    ~fake_mutex() {}\n};\n\n/// A fake lock guard implementation that does nothing\nclass fake_lock_guard {\npublic:\n    explicit fake_lock_guard(fake_mutex) {}\n    ~fake_lock_guard() {}\n};\n} // namespace none_impl\n\n/// Stub concurrency policy that implements the interface using no-ops.\n/**\n * This policy documents the concurrency policy interface using no-ops. It can\n * be used as a reference or base for building a new concurrency policy. It can\n * also be used as is to disable all locking for endpoints used in purely single\n * threaded programs.\n */\nclass none {\npublic:\n    /// The type of a mutex primitive\n    /**\n     * std::mutex is an example.\n     */\n    typedef none_impl::fake_mutex mutex_type;\n\n    /// The type of a scoped/RAII lock primitive.\n    /**\n     * The scoped lock constructor should take a mutex_type as a parameter,\n     * acquire that lock, and release it in its destructor. std::lock_guard is\n     * an example.\n     */\n    typedef none_impl::fake_lock_guard scoped_lock_type;\n};\n\n} // namespace concurrency\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONCURRENCY_ASYNC_HPP\n"
  },
  {
    "path": "websocketpp/config/asio.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_ASIO_TLS_HPP\n#define WEBSOCKETPP_CONFIG_ASIO_TLS_HPP\n\n#include <websocketpp/config/core.hpp>\n#include <websocketpp/transport/asio/endpoint.hpp>\n#include <websocketpp/transport/asio/security/tls.hpp>\n\n// Pull in non-tls config\n#include <websocketpp/config/asio_no_tls.hpp>\n\n// Define TLS config\nnamespace websocketpp {\nnamespace config {\n\n/// Server config with asio transport and TLS enabled\nstruct asio_tls : public core {\n    typedef asio_tls type;\n    typedef core base;\n\n    typedef base::concurrency_type concurrency_type;\n\n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n\n    typedef base::rng_type rng_type;\n\n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config>\n        transport_type;\n};\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_HPP\n"
  },
  {
    "path": "websocketpp/config/asio_client.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_ASIO_TLS_CLIENT_HPP\n#define WEBSOCKETPP_CONFIG_ASIO_TLS_CLIENT_HPP\n\n#include <websocketpp/config/core_client.hpp>\n#include <websocketpp/transport/asio/endpoint.hpp>\n#include <websocketpp/transport/asio/security/tls.hpp>\n\n// Pull in non-tls config\n#include <websocketpp/config/asio_no_tls_client.hpp>\n\n// Define TLS config\nnamespace websocketpp {\nnamespace config {\n\n/// Client config with asio transport and TLS enabled\nstruct asio_tls_client : public core_client {\n    typedef asio_tls_client type;\n    typedef core_client base;\n\n    typedef base::concurrency_type concurrency_type;\n\n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n\n    typedef base::rng_type rng_type;\n\n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config>\n        transport_type;\n};\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_CLIENT_HPP\n"
  },
  {
    "path": "websocketpp/config/asio_no_tls.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_ASIO_HPP\n#define WEBSOCKETPP_CONFIG_ASIO_HPP\n\n#include <websocketpp/config/core.hpp>\n#include <websocketpp/transport/asio/endpoint.hpp>\n\nnamespace websocketpp {\nnamespace config {\n\n/// Server config with asio transport and TLS disabled\nstruct asio : public core {\n    typedef asio type;\n    typedef core base;\n\n    typedef base::concurrency_type concurrency_type;\n\n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n\n    typedef base::rng_type rng_type;\n\n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::basic_socket::endpoint\n            socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config>\n        transport_type;\n};\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_ASIO_HPP\n"
  },
  {
    "path": "websocketpp/config/asio_no_tls_client.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_ASIO_CLIENT_HPP\n#define WEBSOCKETPP_CONFIG_ASIO_CLIENT_HPP\n\n#include <websocketpp/config/core_client.hpp>\n#include <websocketpp/transport/asio/endpoint.hpp>\n\nnamespace websocketpp {\nnamespace config {\n\n/// Client config with asio transport and TLS disabled\nstruct asio_client : public core_client {\n    typedef asio_client type;\n    typedef core_client base;\n\n    typedef base::concurrency_type concurrency_type;\n\n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n\n    typedef base::rng_type rng_type;\n\n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::basic_socket::endpoint\n            socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config>\n        transport_type;\n};\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_ASIO_CLIENT_HPP\n"
  },
  {
    "path": "websocketpp/config/boost_config.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n // This header defines WebSocket++ macros for C++11 compatibility based on the \n // Boost.Config library. This will correctly configure most target platforms\n // simply by including this header before any other WebSocket++ header.\n\n#ifndef WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP\n#define WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP\n\n#include <boost/config.hpp>\n\n//  _WEBSOCKETPP_CPP11_MEMORY_ and _WEBSOCKETPP_CPP11_FUNCTIONAL_ presently\n//  only work if either both or neither is defined.\n#if !defined BOOST_NO_CXX11_SMART_PTR && !defined BOOST_NO_CXX11_HDR_FUNCTIONAL\n    #define _WEBSOCKETPP_CPP11_MEMORY_\n    #define _WEBSOCKETPP_CPP11_FUNCTIONAL_\n#endif\n\n#ifdef BOOST_ASIO_HAS_STD_CHRONO\n    #define _WEBSOCKETPP_CPP11_CHRONO_\n#endif\n\n#ifndef BOOST_NO_CXX11_HDR_RANDOM\n    #define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_\n#endif\n\n#ifndef BOOST_NO_CXX11_HDR_REGEX\n    #define _WEBSOCKETPP_CPP11_REGEX_\n#endif\n\n#ifndef BOOST_NO_CXX11_HDR_SYSTEM_ERROR\n    #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_\n#endif\n\n#ifndef BOOST_NO_CXX11_HDR_THREAD\n    #define _WEBSOCKETPP_CPP11_THREAD_\n#endif\n\n#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST\n    #define _WEBSOCKETPP_INITIALIZER_LISTS_\n#endif\n\n#define _WEBSOCKETPP_NOEXCEPT_TOKEN_  BOOST_NOEXCEPT\n#define _WEBSOCKETPP_CONSTEXPR_TOKEN_  BOOST_CONSTEXPR\n// TODO: nullptr support\n\n#endif // WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP\n"
  },
  {
    "path": "websocketpp/config/core.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_CORE_HPP\n#define WEBSOCKETPP_CONFIG_CORE_HPP\n\n// Non-Policy common stuff\n#include <websocketpp/common/platforms.hpp>\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/stdint.hpp>\n\n// Concurrency\n#include <websocketpp/concurrency/basic.hpp>\n\n// Transport\n#include <websocketpp/transport/iostream/endpoint.hpp>\n\n// HTTP\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n\n// Messages\n#include <websocketpp/message_buffer/message.hpp>\n#include <websocketpp/message_buffer/alloc.hpp>\n\n// Loggers\n#include <websocketpp/logger/basic.hpp>\n#include <websocketpp/logger/levels.hpp>\n\n// RNG\n#include <websocketpp/random/none.hpp>\n\n// User stub base classes\n#include <websocketpp/endpoint_base.hpp>\n#include <websocketpp/connection_base.hpp>\n\n// Extensions\n#include <websocketpp/extensions/permessage_deflate/disabled.hpp>\n\nnamespace websocketpp {\nnamespace config {\n\n/// Server config with iostream transport\nstruct core {\n    typedef core type;\n\n    // Concurrency policy\n    typedef websocketpp::concurrency::basic concurrency_type;\n\n    // HTTP Parser Policies\n    typedef http::parser::request request_type;\n    typedef http::parser::response response_type;\n\n    // Message Policies\n    typedef message_buffer::message<message_buffer::alloc::con_msg_manager>\n        message_type;\n    typedef message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_manager_type;\n    typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>\n        endpoint_msg_manager_type;\n\n    /// Logging policies\n    typedef websocketpp::log::basic<concurrency_type,\n        websocketpp::log::elevel> elog_type;\n    typedef websocketpp::log::basic<concurrency_type,\n        websocketpp::log::alevel> alog_type;\n\n    /// RNG policies\n    typedef websocketpp::random::none::int_generator<uint32_t> rng_type;\n\n    /// Controls compile time enabling/disabling of thread syncronization\n    /// code Disabling can provide a minor performance improvement to single\n    /// threaded applications\n    static bool const enable_multithreading = true;\n\n    struct transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::elog_type elog_type;\n        typedef type::alog_type alog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n\n        /// Controls compile time enabling/disabling of thread syncronization\n        /// code Disabling can provide a minor performance improvement to single\n        /// threaded applications\n        static bool const enable_multithreading = true;\n\n        /// Default timer values (in ms)\n\n        /// Length of time to wait for socket pre-initialization\n        /**\n         * Exactly what this includes depends on the socket policy in use\n         */\n        static const long timeout_socket_pre_init = 5000;\n\n        /// Length of time to wait before a proxy handshake is aborted\n        static const long timeout_proxy = 5000;\n\n        /// Length of time to wait for socket post-initialization\n        /**\n         * Exactly what this includes depends on the socket policy in use.\n         * Often this means the TLS handshake\n         */\n        static const long timeout_socket_post_init = 5000;\n\n        /// Length of time to wait for dns resolution\n        static const long timeout_dns_resolve = 5000;\n\n        /// Length of time to wait for TCP connect\n        static const long timeout_connect = 5000;\n\n        /// Length of time to wait for socket shutdown\n        static const long timeout_socket_shutdown = 5000;\n    };\n\n    /// Transport Endpoint Component\n    typedef websocketpp::transport::iostream::endpoint<transport_config>\n        transport_type;\n\n    /// User overridable Endpoint base class\n    typedef websocketpp::endpoint_base endpoint_base;\n    /// User overridable Connection base class\n    typedef websocketpp::connection_base connection_base;\n\n    /// Default timer values (in ms)\n\n    /// Length of time before an opening handshake is aborted\n    static const long timeout_open_handshake = 5000;\n    /// Length of time before a closing handshake is aborted\n    static const long timeout_close_handshake = 5000;\n    /// Length of time to wait for a pong after a ping\n    static const long timeout_pong = 5000;\n\n    /// WebSocket Protocol version to use as a client\n    /**\n     * What version of the WebSocket Protocol to use for outgoing client\n     * connections. Setting this to a value other than 13 (RFC6455) is not\n     * recommended.\n     */\n    static const int client_version = 13; // RFC6455\n\n    /// Default static error logging channels\n    /**\n     * Which error logging channels to enable at compile time. Channels not\n     * enabled here will be unable to be selected by programs using the library.\n     * This option gives an optimizing compiler the ability to remove entirely\n     * code to test whether or not to print out log messages on a certain\n     * channel\n     *\n     * Default is all except for development/debug level errors\n     */\n    static const websocketpp::log::level elog_level =\n        websocketpp::log::elevel::all ^ websocketpp::log::elevel::devel;\n\n    /// Default static access logging channels\n    /**\n     * Which access logging channels to enable at compile time. Channels not\n     * enabled here will be unable to be selected by programs using the library.\n     * This option gives an optimizing compiler the ability to remove entirely\n     * code to test whether or not to print out log messages on a certain\n     * channel\n     *\n     * Default is all except for development/debug level access messages\n     */\n    static const websocketpp::log::level alog_level =\n        websocketpp::log::alevel::all ^ websocketpp::log::alevel::devel;\n\n    /// Size of the per-connection read buffer\n    /**\n     * Each connection has an internal buffer of this size. A larger value will\n     * result in fewer trips through the library and less CPU overhead at the\n     * expense of increased memory usage per connection.\n     *\n     * If your application primarily deals in very large messages you may want\n     * to try setting this value higher.\n     *\n     * If your application has a lot of connections or primarily deals in small\n     * messages you may want to try setting this smaller.\n     */\n    static const size_t connection_read_buffer_size = 16384;\n\n    /// Drop connections immediately on protocol error.\n    /**\n     * Drop connections on protocol error rather than sending a close frame.\n     * Off by default. This may result in legit messages near the error being\n     * dropped as well. It may free up resources otherwise spent dealing with\n     * misbehaving clients.\n     */\n    static const bool drop_on_protocol_error = false;\n\n    /// Suppresses the return of detailed connection close information\n    /**\n     * Silence close suppresses the return of detailed connection close\n     * information during the closing handshake. This information is useful\n     * for debugging and presenting useful errors to end users but may be\n     * undesirable for security reasons in some production environments.\n     * Close reasons could be used by an attacker to confirm that the endpoint\n     * is out of resources or be used to identify the WebSocket implementation\n     * in use.\n     *\n     * Note: this will suppress *all* close codes, including those explicitly\n     * sent by local applications.\n     */\n    static const bool silent_close = false;\n\n    /// Default maximum message size\n    /**\n     * Default value for the processor's maximum message size. Maximum message size\n     * determines the point at which the library will fail a connection with the \n     * message_too_big protocol error.\n     *\n     * The default is 32MB\n     *\n     * @since 0.3.0\n     */\n    static const size_t max_message_size = 32000000;\n    \n    /// Default maximum http body size\n    /**\n     * Default value for the http parser's maximum body size. Maximum body size\n     * determines the point at which the library will abort reading an HTTP\n     * connection with the 413/request entity too large error.\n     *\n     * The default is 32MB\n     *\n     * @since 0.5.0\n     */\n    static const size_t max_http_body_size = 32000000;\n\n    /// Global flag for enabling/disabling extensions\n    static const bool enable_extensions = true;\n\n    /// Extension specific settings:\n\n    /// permessage_compress extension\n    struct permessage_deflate_config {\n        typedef core::request_type request_type;\n\n        /// If the remote endpoint requests that we reset the compression\n        /// context after each message should we honor the request?\n        static const bool allow_disabling_context_takeover = true;\n\n        /// If the remote endpoint requests that we reduce the size of the\n        /// LZ77 sliding window size this is the lowest value that will be\n        /// allowed. Values range from 8 to 15. A value of 8 means we will\n        /// allow any possible window size. A value of 15 means do not allow\n        /// negotiation of the window size (ie require the default).\n        static const uint8_t minimum_outgoing_window_bits = 8;\n    };\n\n    typedef websocketpp::extensions::permessage_deflate::disabled\n        <permessage_deflate_config> permessage_deflate_type;\n\n    /// Autonegotiate permessage-deflate\n    /**\n     * Automatically enables the permessage-deflate extension.\n     *\n     * For clients this results in a permessage-deflate extension request being\n     * sent with every request rather than requiring it to be requested manually\n     *\n     * For servers this results in accepting the first set of extension settings\n     * requested by the client that we understand being used. The alternative is\n     * requiring the extension to be manually negotiated in `validate`. With\n     * auto-negotiate on, you may still override the auto-negotiate manually if\n     * needed.\n     */\n    //static const bool autonegotiate_compression = false;\n};\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_CORE_HPP\n"
  },
  {
    "path": "websocketpp/config/core_client.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_CORE_CLIENT_HPP\n#define WEBSOCKETPP_CONFIG_CORE_CLIENT_HPP\n\n// Non-Policy common stuff\n#include <websocketpp/common/platforms.hpp>\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/stdint.hpp>\n\n// Concurrency\n#ifndef _WEBSOCKETPP_NO_THREADING_\n#include <websocketpp/concurrency/basic.hpp>\n#else\n#include <websocketpp/concurrency/none.hpp>\n#endif\n\n// Transport\n#include <websocketpp/transport/iostream/endpoint.hpp>\n\n// HTTP\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n\n// Messages\n#include <websocketpp/message_buffer/message.hpp>\n#include <websocketpp/message_buffer/alloc.hpp>\n\n// Loggers\n#include <websocketpp/logger/basic.hpp>\n\n// RNG\n#include <websocketpp/random/random_device.hpp>\n\n// User stub base classes\n#include <websocketpp/endpoint_base.hpp>\n#include <websocketpp/connection_base.hpp>\n\n// Extensions\n#include <websocketpp/extensions/permessage_deflate/disabled.hpp>\n\nnamespace websocketpp {\nnamespace config {\n\n/// Client config with iostream transport\nstruct core_client {\n    typedef core_client type;\n\n    // Concurrency policy\n#ifndef _WEBSOCKETPP_NO_THREADING_\n    typedef websocketpp::concurrency::basic concurrency_type;\n#else\n    typedef websocketpp::concurrency::none concurrency_type;\n#endif\n\n    // HTTP Parser Policies\n    typedef http::parser::request request_type;\n    typedef http::parser::response response_type;\n\n    // Message Policies\n    typedef message_buffer::message<message_buffer::alloc::con_msg_manager>\n        message_type;\n    typedef message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_manager_type;\n    typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>\n        endpoint_msg_manager_type;\n\n    /// Logging policies\n    typedef websocketpp::log::basic<concurrency_type,\n        websocketpp::log::elevel> elog_type;\n    typedef websocketpp::log::basic<concurrency_type,\n        websocketpp::log::alevel> alog_type;\n\n    /// RNG policies\n    typedef websocketpp::random::random_device::int_generator<uint32_t,\n        concurrency_type> rng_type;\n\n    /// Controls compile time enabling/disabling of thread syncronization code\n    /// Disabling can provide a minor performance improvement to single threaded\n    /// applications\n    static bool const enable_multithreading = true;\n\n    struct transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::elog_type elog_type;\n        typedef type::alog_type alog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n\n        /// Controls compile time enabling/disabling of thread syncronization\n        /// code Disabling can provide a minor performance improvement to single\n        /// threaded applications\n        static bool const enable_multithreading = true;\n\n        /// Default timer values (in ms)\n\n        /// Length of time to wait for socket pre-initialization\n        /**\n         * Exactly what this includes depends on the socket policy in use\n         */\n        static const long timeout_socket_pre_init = 5000;\n\n        /// Length of time to wait before a proxy handshake is aborted\n        static const long timeout_proxy = 5000;\n\n        /// Length of time to wait for socket post-initialization\n        /**\n         * Exactly what this includes depends on the socket policy in use.\n         * Often this means the TLS handshake\n         */\n        static const long timeout_socket_post_init = 5000;\n\n        /// Length of time to wait for dns resolution\n        static const long timeout_dns_resolve = 5000;\n\n        /// Length of time to wait for TCP connect\n        static const long timeout_connect = 5000;\n\n        /// Length of time to wait for socket shutdown\n        static const long timeout_socket_shutdown = 5000;\n    };\n\n    /// Transport Endpoint Component\n    typedef websocketpp::transport::iostream::endpoint<transport_config>\n        transport_type;\n\n    /// User overridable Endpoint base class\n    typedef websocketpp::endpoint_base endpoint_base;\n    /// User overridable Connection base class\n    typedef websocketpp::connection_base connection_base;\n\n    /// Default timer values (in ms)\n\n    /// Length of time before an opening handshake is aborted\n    static const long timeout_open_handshake = 5000;\n    /// Length of time before a closing handshake is aborted\n    static const long timeout_close_handshake = 5000;\n    /// Length of time to wait for a pong after a ping\n    static const long timeout_pong = 5000;\n\n    /// WebSocket Protocol version to use as a client\n    /**\n     * What version of the WebSocket Protocol to use for outgoing client\n     * connections. Setting this to a value other than 13 (RFC6455) is not\n     * recommended.\n     */\n    static const int client_version = 13; // RFC6455\n\n    /// Default static error logging channels\n    /**\n     * Which error logging channels to enable at compile time. Channels not\n     * enabled here will be unable to be selected by programs using the library.\n     * This option gives an optimizing compiler the ability to remove entirely\n     * code to test whether or not to print out log messages on a certain\n     * channel\n     *\n     * Default is all except for development/debug level errors\n     */\n    static const websocketpp::log::level elog_level =\n        websocketpp::log::elevel::all ^ websocketpp::log::elevel::devel;\n\n    /// Default static access logging channels\n    /**\n     * Which access logging channels to enable at compile time. Channels not\n     * enabled here will be unable to be selected by programs using the library.\n     * This option gives an optimizing compiler the ability to remove entirely\n     * code to test whether or not to print out log messages on a certain\n     * channel\n     *\n     * Default is all except for development/debug level access messages\n     */\n    static const websocketpp::log::level alog_level =\n        websocketpp::log::alevel::all ^ websocketpp::log::alevel::devel;\n\n    ///\n    static const size_t connection_read_buffer_size = 16384;\n\n    /// Drop connections immediately on protocol error.\n    /**\n     * Drop connections on protocol error rather than sending a close frame.\n     * Off by default. This may result in legit messages near the error being\n     * dropped as well. It may free up resources otherwise spent dealing with\n     * misbehaving clients.\n     */\n    static const bool drop_on_protocol_error = false;\n\n    /// Suppresses the return of detailed connection close information\n    /**\n     * Silence close suppresses the return of detailed connection close\n     * information during the closing handshake. This information is useful\n     * for debugging and presenting useful errors to end users but may be\n     * undesirable for security reasons in some production environments.\n     * Close reasons could be used by an attacker to confirm that the endpoint\n     * is out of resources or be used to identify the WebSocket implementation\n     * in use.\n     *\n     * Note: this will suppress *all* close codes, including those explicitly\n     * sent by local applications.\n     */\n    static const bool silent_close = false;\n\n    /// Default maximum message size\n    /**\n     * Default value for the processor's maximum message size. Maximum message size\n     * determines the point at which the library will fail a connection with the \n     * message_too_big protocol error.\n     *\n     * The default is 32MB\n     *\n     * @since 0.3.0\n     */\n    static const size_t max_message_size = 32000000;\n\n    /// Default maximum http body size\n    /**\n     * Default value for the http parser's maximum body size. Maximum body size\n     * determines the point at which the library will abort reading an HTTP\n     * connection with the 413/request entity too large error.\n     *\n     * The default is 32MB\n     *\n     * @since 0.5.0\n     */\n    static const size_t max_http_body_size = 32000000;\n\n    /// Global flag for enabling/disabling extensions\n    static const bool enable_extensions = true;\n\n    /// Extension specific settings:\n\n    /// permessage_deflate extension\n    struct permessage_deflate_config {\n        typedef core_client::request_type request_type;\n\n        /// If the remote endpoint requests that we reset the compression\n        /// context after each message should we honor the request?\n        static const bool allow_disabling_context_takeover = true;\n\n        /// If the remote endpoint requests that we reduce the size of the\n        /// LZ77 sliding window size this is the lowest value that will be\n        /// allowed. Values range from 8 to 15. A value of 8 means we will\n        /// allow any possible window size. A value of 15 means do not allow\n        /// negotiation of the window size (ie require the default).\n        static const uint8_t minimum_outgoing_window_bits = 8;\n    };\n\n    typedef websocketpp::extensions::permessage_deflate::disabled\n        <permessage_deflate_config> permessage_deflate_type;\n\n    /// Autonegotiate permessage-compress\n    /**\n     * Automatically enables the permessage-compress extension.\n     *\n     * For clients this results in a permessage-compress extension request being\n     * sent with every request rather than requiring it to be requested manually\n     *\n     * For servers this results in accepting the first set of extension settings\n     * requested by the client that we understand being used. The alternative is\n     * requiring the extension to be manually negotiated in `validate`. With\n     * auto-negotiate on, you may still override the auto-negotiate manually if\n     * needed.\n     */\n    //static const bool autonegotiate_compression = false;\n};\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_CORE_CLIENT_HPP\n"
  },
  {
    "path": "websocketpp/config/debug.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_DEBUG_HPP\n#define WEBSOCKETPP_CONFIG_DEBUG_HPP\n\n\n\n// Non-Policy common stuff\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/stdint.hpp>\n\n// Concurrency\n#include <websocketpp/concurrency/basic.hpp>\n\n// Transport\n#include <websocketpp/transport/iostream/endpoint.hpp>\n\n// HTTP\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n\n// Messages\n#include <websocketpp/message_buffer/message.hpp>\n#include <websocketpp/message_buffer/alloc.hpp>\n\n// Loggers\n#include <websocketpp/logger/basic.hpp>\n\n// RNG\n#include <websocketpp/random/none.hpp>\n\n// User stub base classes\n#include <websocketpp/endpoint_base.hpp>\n#include <websocketpp/connection_base.hpp>\n\n// Extensions\n#include <websocketpp/extensions/permessage_deflate/disabled.hpp>\n\nnamespace websocketpp {\nnamespace config {\n\n/// Client/Server debug config with iostream transport\nstruct debug_core {\n    typedef debug_core type;\n\n    // Concurrency policy\n    typedef websocketpp::concurrency::basic concurrency_type;\n\n    // HTTP Parser Policies\n    typedef http::parser::request request_type;\n    typedef http::parser::response response_type;\n\n    // Message Policies\n    typedef message_buffer::message<message_buffer::alloc::con_msg_manager>\n        message_type;\n    typedef message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_manager_type;\n    typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>\n        endpoint_msg_manager_type;\n\n    /// Logging policies\n    typedef websocketpp::log::basic<concurrency_type,\n        websocketpp::log::elevel> elog_type;\n    typedef websocketpp::log::basic<concurrency_type,\n        websocketpp::log::alevel> alog_type;\n\n    /// RNG policies\n    typedef websocketpp::random::none::int_generator<uint32_t> rng_type;\n\n    /// Controls compile time enabling/disabling of thread syncronization\n    /// code Disabling can provide a minor performance improvement to single\n    /// threaded applications\n    static bool const enable_multithreading = true;\n\n    struct transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::elog_type elog_type;\n        typedef type::alog_type alog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n\n        /// Controls compile time enabling/disabling of thread syncronization\n        /// code Disabling can provide a minor performance improvement to single\n        /// threaded applications\n        static bool const enable_multithreading = true;\n\n        /// Default timer values (in ms)\n\n        /// Length of time to wait for socket pre-initialization\n        /**\n         * Exactly what this includes depends on the socket policy in use\n         */\n        static const long timeout_socket_pre_init = 5000;\n\n        /// Length of time to wait before a proxy handshake is aborted\n        static const long timeout_proxy = 5000;\n\n        /// Length of time to wait for socket post-initialization\n        /**\n         * Exactly what this includes depends on the socket policy in use.\n         * Often this means the TLS handshake\n         */\n        static const long timeout_socket_post_init = 5000;\n\n        /// Length of time to wait for dns resolution\n        static const long timeout_dns_resolve = 5000;\n\n        /// Length of time to wait for TCP connect\n        static const long timeout_connect = 5000;\n\n        /// Length of time to wait for socket shutdown\n        static const long timeout_socket_shutdown = 5000;\n    };\n\n    /// Transport Endpoint Component\n    typedef websocketpp::transport::iostream::endpoint<transport_config>\n        transport_type;\n\n    /// User overridable Endpoint base class\n    typedef websocketpp::endpoint_base endpoint_base;\n    /// User overridable Connection base class\n    typedef websocketpp::connection_base connection_base;\n\n    /// Default timer values (in ms)\n\n    /// Length of time before an opening handshake is aborted\n    static const long timeout_open_handshake = 5000;\n    /// Length of time before a closing handshake is aborted\n    static const long timeout_close_handshake = 5000;\n    /// Length of time to wait for a pong after a ping\n    static const long timeout_pong = 5000;\n\n    /// WebSocket Protocol version to use as a client\n    /**\n     * What version of the WebSocket Protocol to use for outgoing client\n     * connections. Setting this to a value other than 13 (RFC6455) is not\n     * recommended.\n     */\n    static const int client_version = 13; // RFC6455\n\n    /// Default static error logging channels\n    /**\n     * Which error logging channels to enable at compile time. Channels not\n     * enabled here will be unable to be selected by programs using the library.\n     * This option gives an optimizing compiler the ability to remove entirely\n     * code to test whether or not to print out log messages on a certain\n     * channel\n     *\n     * Default is all except for development/debug level errors\n     */\n    static const websocketpp::log::level elog_level =\n        websocketpp::log::elevel::all;\n\n    /// Default static access logging channels\n    /**\n     * Which access logging channels to enable at compile time. Channels not\n     * enabled here will be unable to be selected by programs using the library.\n     * This option gives an optimizing compiler the ability to remove entirely\n     * code to test whether or not to print out log messages on a certain\n     * channel\n     *\n     * Default is all except for development/debug level access messages\n     */\n    static const websocketpp::log::level alog_level =\n        websocketpp::log::alevel::all;\n\n    ///\n    static const size_t connection_read_buffer_size = 16384;\n\n    /// Drop connections immediately on protocol error.\n    /**\n     * Drop connections on protocol error rather than sending a close frame.\n     * Off by default. This may result in legit messages near the error being\n     * dropped as well. It may free up resources otherwise spent dealing with\n     * misbehaving clients.\n     */\n    static const bool drop_on_protocol_error = false;\n\n    /// Suppresses the return of detailed connection close information\n    /**\n     * Silence close suppresses the return of detailed connection close\n     * information during the closing handshake. This information is useful\n     * for debugging and presenting useful errors to end users but may be\n     * undesirable for security reasons in some production environments.\n     * Close reasons could be used by an attacker to confirm that the endpoint\n     * is out of resources or be used to identify the WebSocket implementation\n     * in use.\n     *\n     * Note: this will suppress *all* close codes, including those explicitly\n     * sent by local applications.\n     */\n    static const bool silent_close = false;\n\n    /// Default maximum message size\n    /**\n     * Default value for the processor's maximum message size. Maximum message size\n     * determines the point at which the library will fail a connection with the \n     * message_too_big protocol error.\n     *\n     * The default is 32MB\n     *\n     * @since 0.3.0\n     */\n    static const size_t max_message_size = 32000000;\n\n    /// Default maximum http body size\n    /**\n     * Default value for the http parser's maximum body size. Maximum body size\n     * determines the point at which the library will abort reading an HTTP\n     * connection with the 413/request entity too large error.\n     *\n     * The default is 32MB\n     *\n     * @since 0.5.0\n     */\n    static const size_t max_http_body_size = 32000000;\n\n    /// Global flag for enabling/disabling extensions\n    static const bool enable_extensions = true;\n\n    /// Extension specific settings:\n\n    /// permessage_compress extension\n    struct permessage_deflate_config {\n        typedef type::request_type request_type;\n\n        /// If the remote endpoint requests that we reset the compression\n        /// context after each message should we honor the request?\n        static const bool allow_disabling_context_takeover = true;\n\n        /// If the remote endpoint requests that we reduce the size of the\n        /// LZ77 sliding window size this is the lowest value that will be\n        /// allowed. Values range from 8 to 15. A value of 8 means we will\n        /// allow any possible window size. A value of 15 means do not allow\n        /// negotiation of the window size (ie require the default).\n        static const uint8_t minimum_outgoing_window_bits = 8;\n    };\n\n    typedef websocketpp::extensions::permessage_deflate::disabled\n        <permessage_deflate_config> permessage_deflate_type;\n\n    /// Autonegotiate permessage-deflate\n    /**\n     * Automatically enables the permessage-deflate extension.\n     *\n     * For clients this results in a permessage-deflate extension request being\n     * sent with every request rather than requiring it to be requested manually\n     *\n     * For servers this results in accepting the first set of extension settings\n     * requested by the client that we understand being used. The alternative is\n     * requiring the extension to be manually negotiated in `validate`. With\n     * auto-negotiate on, you may still override the auto-negotiate manually if\n     * needed.\n     */\n    //static const bool autonegotiate_compression = false;\n};\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_CORE_HPP\n"
  },
  {
    "path": "websocketpp/config/debug_asio.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_ASIO_TLS_DEBUG_HPP\n#define WEBSOCKETPP_CONFIG_ASIO_TLS_DEBUG_HPP\n\n#include <websocketpp/config/debug.hpp>\n#include <websocketpp/transport/asio/endpoint.hpp>\n#include <websocketpp/transport/asio/security/tls.hpp>\n\n// Pull in non-tls config\n#include <websocketpp/config/debug_asio_no_tls.hpp>\n\n// Define TLS config\nnamespace websocketpp {\nnamespace config {\n\n/// Client/Server debug config with asio transport and TLS enabled\nstruct debug_asio_tls : public debug_core {\n    typedef debug_asio_tls type;\n    typedef debug_core base;\n\n    typedef base::concurrency_type concurrency_type;\n\n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n\n    typedef base::rng_type rng_type;\n\n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config>\n        transport_type;\n};\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_DEBUG_HPP\n"
  },
  {
    "path": "websocketpp/config/debug_asio_no_tls.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_ASIO_DEBUG_HPP\n#define WEBSOCKETPP_CONFIG_ASIO_DEBUG_HPP\n\n#include <websocketpp/config/debug.hpp>\n#include <websocketpp/transport/asio/endpoint.hpp>\n\nnamespace websocketpp {\nnamespace config {\n\n/// Client/Server debug config with asio transport and TLS disabled\nstruct debug_asio : public debug_core {\n    typedef debug_asio type;\n    typedef debug_core base;\n\n    typedef base::concurrency_type concurrency_type;\n\n    typedef base::request_type request_type;\n    typedef base::response_type response_type;\n\n    typedef base::message_type message_type;\n    typedef base::con_msg_manager_type con_msg_manager_type;\n    typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;\n\n    typedef base::alog_type alog_type;\n    typedef base::elog_type elog_type;\n\n    typedef base::rng_type rng_type;\n\n    struct transport_config : public base::transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::alog_type alog_type;\n        typedef type::elog_type elog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n        typedef websocketpp::transport::asio::basic_socket::endpoint\n            socket_type;\n    };\n\n    typedef websocketpp::transport::asio::endpoint<transport_config>\n        transport_type;\n};\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_ASIO_DEBUG_HPP\n"
  },
  {
    "path": "websocketpp/config/minimal_client.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_MINIMAL_CLIENT_HPP\n#define WEBSOCKETPP_CONFIG_MINIMAL_CLIENT_HPP\n\n#include <websocketpp/config/minimal_server.hpp>\n\nnamespace websocketpp {\nnamespace config {\n\n/// Client config with minimal dependencies\n/**\n * This config strips out as many dependencies as possible. It is suitable for\n * use as a base class for custom configs that want to implement or choose their\n * own policies for components that even the core config includes.\n *\n * NOTE: this config stubs out enough that it cannot be used directly. You must\n * supply at least a transport policy and a cryptographically secure random \n * number generation policy for a config based on `minimal_client` to do \n * anything useful.\n *\n * Present dependency list for minimal_server config:\n *\n * C++98 STL:\n * <algorithm>\n * <map>\n * <sstream>\n * <string>\n * <vector>\n *\n * C++11 STL or Boost\n * <memory>\n * <functional>\n * <system_error>\n *\n * Operating System:\n * <stdint.h> or <boost/cstdint.hpp>\n * <netinet/in.h> or <winsock2.h> (for ntohl.. could potentially bundle this)\n *\n * @since 0.4.0-dev\n */\ntypedef minimal_server minimal_client;\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_MINIMAL_CLIENT_HPP\n"
  },
  {
    "path": "websocketpp/config/minimal_server.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONFIG_MINIMAL_HPP\n#define WEBSOCKETPP_CONFIG_MINIMAL_HPP\n\n// Non-Policy common stuff\n#include <websocketpp/common/platforms.hpp>\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/stdint.hpp>\n\n// Concurrency\n#include <websocketpp/concurrency/none.hpp>\n\n// Transport\n#include <websocketpp/transport/stub/endpoint.hpp>\n\n// HTTP\n#include <websocketpp/http/request.hpp>\n#include <websocketpp/http/response.hpp>\n\n// Messages\n#include <websocketpp/message_buffer/message.hpp>\n#include <websocketpp/message_buffer/alloc.hpp>\n\n// Loggers\n#include <websocketpp/logger/stub.hpp>\n\n// RNG\n#include <websocketpp/random/none.hpp>\n\n// User stub base classes\n#include <websocketpp/endpoint_base.hpp>\n#include <websocketpp/connection_base.hpp>\n\n// Extensions\n#include <websocketpp/extensions/permessage_deflate/disabled.hpp>\n\nnamespace websocketpp {\nnamespace config {\n\n/// Server config with minimal dependencies\n/**\n * This config strips out as many dependencies as possible. It is suitable for\n * use as a base class for custom configs that want to implement or choose their\n * own policies for components that even the core config includes.\n *\n * NOTE: this config stubs out enough that it cannot be used directly. You must\n * supply at least a transport policy for a config based on `minimal_server` to\n * do anything useful.\n *\n * Present dependency list for minimal_server config:\n *\n * C++98 STL:\n * <algorithm>\n * <map>\n * <sstream>\n * <string>\n * <vector>\n *\n * C++11 STL or Boost\n * <memory>\n * <functional>\n * <system_error>\n *\n * Operating System:\n * <stdint.h> or <boost/cstdint.hpp>\n * <netinet/in.h> or <winsock2.h> (for ntohl.. could potentially bundle this)\n *\n * @since 0.4.0-dev\n */\nstruct minimal_server {\n    typedef minimal_server type;\n\n    // Concurrency policy\n    typedef websocketpp::concurrency::none concurrency_type;\n\n    // HTTP Parser Policies\n    typedef http::parser::request request_type;\n    typedef http::parser::response response_type;\n\n    // Message Policies\n    typedef message_buffer::message<message_buffer::alloc::con_msg_manager>\n        message_type;\n    typedef message_buffer::alloc::con_msg_manager<message_type>\n        con_msg_manager_type;\n    typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>\n        endpoint_msg_manager_type;\n\n    /// Logging policies\n    typedef websocketpp::log::stub elog_type;\n    typedef websocketpp::log::stub alog_type;\n\n    /// RNG policies\n    typedef websocketpp::random::none::int_generator<uint32_t> rng_type;\n\n    /// Controls compile time enabling/disabling of thread syncronization\n    /// code Disabling can provide a minor performance improvement to single\n    /// threaded applications\n    static bool const enable_multithreading = true;\n\n    struct transport_config {\n        typedef type::concurrency_type concurrency_type;\n        typedef type::elog_type elog_type;\n        typedef type::alog_type alog_type;\n        typedef type::request_type request_type;\n        typedef type::response_type response_type;\n\n        /// Controls compile time enabling/disabling of thread syncronization\n        /// code Disabling can provide a minor performance improvement to single\n        /// threaded applications\n        static bool const enable_multithreading = true;\n\n        /// Default timer values (in ms)\n\n        /// Length of time to wait for socket pre-initialization\n        /**\n         * Exactly what this includes depends on the socket policy in use\n         */\n        static const long timeout_socket_pre_init = 5000;\n\n        /// Length of time to wait before a proxy handshake is aborted\n        static const long timeout_proxy = 5000;\n\n        /// Length of time to wait for socket post-initialization\n        /**\n         * Exactly what this includes depends on the socket policy in use.\n         * Often this means the TLS handshake\n         */\n        static const long timeout_socket_post_init = 5000;\n\n        /// Length of time to wait for dns resolution\n        static const long timeout_dns_resolve = 5000;\n\n        /// Length of time to wait for TCP connect\n        static const long timeout_connect = 5000;\n\n        /// Length of time to wait for socket shutdown\n        static const long timeout_socket_shutdown = 5000;\n    };\n\n    /// Transport Endpoint Component\n    typedef websocketpp::transport::stub::endpoint<transport_config>\n        transport_type;\n\n    /// User overridable Endpoint base class\n    typedef websocketpp::endpoint_base endpoint_base;\n    /// User overridable Connection base class\n    typedef websocketpp::connection_base connection_base;\n\n    /// Default timer values (in ms)\n\n    /// Length of time before an opening handshake is aborted\n    static const long timeout_open_handshake = 5000;\n    /// Length of time before a closing handshake is aborted\n    static const long timeout_close_handshake = 5000;\n    /// Length of time to wait for a pong after a ping\n    static const long timeout_pong = 5000;\n\n    /// WebSocket Protocol version to use as a client\n    /**\n     * What version of the WebSocket Protocol to use for outgoing client\n     * connections. Setting this to a value other than 13 (RFC6455) is not\n     * recommended.\n     */\n    static const int client_version = 13; // RFC6455\n\n    /// Default static error logging channels\n    /**\n     * Which error logging channels to enable at compile time. Channels not\n     * enabled here will be unable to be selected by programs using the library.\n     * This option gives an optimizing compiler the ability to remove entirely\n     * code to test whether or not to print out log messages on a certain\n     * channel\n     *\n     * Default is all except for development/debug level errors\n     */\n    static const websocketpp::log::level elog_level =\n        websocketpp::log::elevel::none;\n\n    /// Default static access logging channels\n    /**\n     * Which access logging channels to enable at compile time. Channels not\n     * enabled here will be unable to be selected by programs using the library.\n     * This option gives an optimizing compiler the ability to remove entirely\n     * code to test whether or not to print out log messages on a certain\n     * channel\n     *\n     * Default is all except for development/debug level access messages\n     */\n    static const websocketpp::log::level alog_level =\n        websocketpp::log::alevel::none;\n\n    ///\n    static const size_t connection_read_buffer_size = 16384;\n\n    /// Drop connections immediately on protocol error.\n    /**\n     * Drop connections on protocol error rather than sending a close frame.\n     * Off by default. This may result in legit messages near the error being\n     * dropped as well. It may free up resources otherwise spent dealing with\n     * misbehaving clients.\n     */\n    static const bool drop_on_protocol_error = false;\n\n    /// Suppresses the return of detailed connection close information\n    /**\n     * Silence close suppresses the return of detailed connection close\n     * information during the closing handshake. This information is useful\n     * for debugging and presenting useful errors to end users but may be\n     * undesirable for security reasons in some production environments.\n     * Close reasons could be used by an attacker to confirm that the endpoint\n     * is out of resources or be used to identify the WebSocket implementation\n     * in use.\n     *\n     * Note: this will suppress *all* close codes, including those explicitly\n     * sent by local applications.\n     */\n    static const bool silent_close = false;\n\n    /// Default maximum message size\n    /**\n     * Default value for the processor's maximum message size. Maximum message size\n     * determines the point at which the library will fail a connection with the \n     * message_too_big protocol error.\n     *\n     * The default is 32MB\n     *\n     * @since 0.4.0-alpha1\n     */\n    static const size_t max_message_size = 32000000;\n\n    /// Default maximum http body size\n    /**\n     * Default value for the http parser's maximum body size. Maximum body size\n     * determines the point at which the library will abort reading an HTTP\n     * connection with the 413/request entity too large error.\n     *\n     * The default is 32MB\n     *\n     * @since 0.5.0\n     */\n    static const size_t max_http_body_size = 32000000;\n\n    /// Global flag for enabling/disabling extensions\n    static const bool enable_extensions = true;\n\n    /// Extension specific settings:\n\n    /// permessage_compress extension\n    struct permessage_deflate_config {\n        typedef core::request_type request_type;\n\n        /// If the remote endpoint requests that we reset the compression\n        /// context after each message should we honor the request?\n        static const bool allow_disabling_context_takeover = true;\n\n        /// If the remote endpoint requests that we reduce the size of the\n        /// LZ77 sliding window size this is the lowest value that will be\n        /// allowed. Values range from 8 to 15. A value of 8 means we will\n        /// allow any possible window size. A value of 15 means do not allow\n        /// negotiation of the window size (ie require the default).\n        static const uint8_t minimum_outgoing_window_bits = 8;\n    };\n\n    typedef websocketpp::extensions::permessage_deflate::disabled\n        <permessage_deflate_config> permessage_deflate_type;\n\n    /// Autonegotiate permessage-deflate\n    /**\n     * Automatically enables the permessage-deflate extension.\n     *\n     * For clients this results in a permessage-deflate extension request being\n     * sent with every request rather than requiring it to be requested manually\n     *\n     * For servers this results in accepting the first set of extension settings\n     * requested by the client that we understand being used. The alternative is\n     * requiring the extension to be manually negotiated in `validate`. With\n     * auto-negotiate on, you may still override the auto-negotiate manually if\n     * needed.\n     */\n    //static const bool autonegotiate_compression = false;\n};\n\n} // namespace config\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONFIG_MINIMAL_HPP\n"
  },
  {
    "path": "websocketpp/connection.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONNECTION_HPP\n#define WEBSOCKETPP_CONNECTION_HPP\n\n#include <websocketpp/close.hpp>\n#include <websocketpp/error.hpp>\n#include <websocketpp/frame.hpp>\n\n#include <websocketpp/logger/levels.hpp>\n#include <websocketpp/processors/processor.hpp>\n#include <websocketpp/transport/base/connection.hpp>\n#include <websocketpp/http/constants.hpp>\n\n#include <websocketpp/common/connection_hdl.hpp>\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/functional.hpp>\n\n#include <queue>\n#include <sstream>\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\n\n/// The type and function signature of an open handler\n/**\n * The open handler is called once for every successful WebSocket connection\n * attempt. Either the fail handler or the open handler will be called for each\n * WebSocket connection attempt. HTTP Connections that did not attempt to\n * upgrade the connection to the WebSocket protocol will trigger the http\n * handler instead of fail/open.\n */\ntypedef lib::function<void(connection_hdl)> open_handler;\n\n/// The type and function signature of a close handler\n/**\n * The close handler is called once for every successfully established\n * connection after it is no longer capable of sending or receiving new messages\n *\n * The close handler will be called exactly once for every connection for which\n * the open handler was called.\n */\ntypedef lib::function<void(connection_hdl)> close_handler;\n\n/// The type and function signature of a fail handler\n/**\n * The fail handler is called once for every unsuccessful WebSocket connection\n * attempt. Either the fail handler or the open handler will be called for each\n * WebSocket connection attempt. HTTP Connections that did not attempt to\n * upgrade the connection to the WebSocket protocol will trigger the http\n * handler instead of fail/open.\n */\ntypedef lib::function<void(connection_hdl)> fail_handler;\n\n/// The type and function signature of an interrupt handler\n/**\n * The interrupt handler is called when a connection receives an interrupt\n * request from the application. Interrupts allow the application to trigger a\n * handler to be run in the absense of a WebSocket level handler trigger (like\n * a new message).\n *\n * This is typically used by another application thread to schedule some tasks\n * that can only be run from within the handler chain for thread safety reasons.\n */\ntypedef lib::function<void(connection_hdl)> interrupt_handler;\n\n/// The type and function signature of a ping handler\n/**\n * The ping handler is called when the connection receives a WebSocket ping\n * control frame. The string argument contains the ping payload. The payload is\n * a binary string up to 126 bytes in length. The ping handler returns a bool,\n * true if a pong response should be sent, false if the pong response should be\n * suppressed.\n */\ntypedef lib::function<bool(connection_hdl,std::string)> ping_handler;\n\n/// The type and function signature of a pong handler\n/**\n * The pong handler is called when the connection receives a WebSocket pong\n * control frame. The string argument contains the pong payload. The payload is\n * a binary string up to 126 bytes in length.\n */\ntypedef lib::function<void(connection_hdl,std::string)> pong_handler;\n\n/// The type and function signature of a pong timeout handler\n/**\n * The pong timeout handler is called when a ping goes unanswered by a pong for\n * longer than the locally specified timeout period.\n */\ntypedef lib::function<void(connection_hdl,std::string)> pong_timeout_handler;\n\n/// The type and function signature of a validate handler\n/**\n * The validate handler is called after a WebSocket handshake has been received\n * and processed but before it has been accepted. This gives the application a\n * chance to implement connection details specific policies for accepting\n * connections and the ability to negotiate extensions and subprotocols.\n *\n * The validate handler return value indicates whether or not the connection\n * should be accepted. Additional methods may be called during the function to\n * set response headers, set HTTP return/error codes, etc.\n */\ntypedef lib::function<bool(connection_hdl)> validate_handler;\n\n/// The type and function signature of a http handler\n/**\n * The http handler is called when an HTTP connection is made that does not\n * attempt to upgrade the connection to the WebSocket protocol. This allows\n * WebSocket++ servers to respond to these requests with regular HTTP responses.\n *\n * This can be used to deliver error pages & dashboards and to deliver static\n * files such as the base HTML & JavaScript for an otherwise single page\n * WebSocket application.\n *\n * Note: WebSocket++ is designed to be a high performance WebSocket server. It\n * is not tuned to provide a full featured, high performance, HTTP web server\n * solution. The HTTP handler is appropriate only for low volume HTTP traffic.\n * If you expect to serve high volumes of HTTP traffic a dedicated HTTP web\n * server is strongly recommended.\n *\n * The default HTTP handler will return a 426 Upgrade Required error. Custom\n * handlers may override the response status code to deliver any type of\n * response.\n */\ntypedef lib::function<void(connection_hdl)> http_handler;\n\n//\ntypedef lib::function<void(lib::error_code const & ec, size_t bytes_transferred)> read_handler;\ntypedef lib::function<void(lib::error_code const & ec)> write_frame_handler;\n\n// constants related to the default WebSocket protocol versions available\n#ifdef _WEBSOCKETPP_INITIALIZER_LISTS_ // simplified C++11 version\n    /// Container that stores the list of protocol versions supported\n    /**\n     * @todo Move this to configs to allow compile/runtime disabling or enabling\n     * of protocol versions\n     */\n    static std::vector<int> const versions_supported = {0,7,8,13};\n#else\n    /// Helper array to get around lack of initializer lists pre C++11\n    static int const helper[] = {0,7,8,13};\n    /// Container that stores the list of protocol versions supported\n    /**\n     * @todo Move this to configs to allow compile/runtime disabling or enabling\n     * of protocol versions\n     */\n    static std::vector<int> const versions_supported(helper,helper+4);\n#endif\n\nnamespace session {\nnamespace state {\n    // externally visible session state (states based on the RFC)\n    enum value {\n        connecting = 0,\n        open = 1,\n        closing = 2,\n        closed = 3\n    };\n} // namespace state\n\n\nnamespace fail {\nnamespace status {\n    enum value {\n        GOOD = 0,           // no failure yet!\n        SYSTEM = 1,         // system call returned error, check that code\n        WEBSOCKET = 2,      // websocket close codes contain error\n        UNKNOWN = 3,        // No failure information is available\n        TIMEOUT_TLS = 4,    // TLS handshake timed out\n        TIMEOUT_WS = 5      // WS handshake timed out\n    };\n} // namespace status\n} // namespace fail\n\nnamespace internal_state {\n    // More granular internal states. These are used for multi-threaded\n    // connection synchronization and preventing values that are not yet or no\n    // longer available from being used.\n\n    enum value {\n        USER_INIT = 0,\n        TRANSPORT_INIT = 1,\n        READ_HTTP_REQUEST = 2,\n        WRITE_HTTP_REQUEST = 3,\n        READ_HTTP_RESPONSE = 4,\n        WRITE_HTTP_RESPONSE = 5,\n        PROCESS_HTTP_REQUEST = 6,\n        PROCESS_CONNECTION = 7\n    };\n} // namespace internal_state\n\n\nnamespace http_state {\n    // states to keep track of the progress of http connections\n\n    enum value {\n        init = 0,\n        deferred = 1,\n        headers_written = 2,\n        body_written = 3,\n        closed = 4\n    };\n} // namespace http_state\n\n} // namespace session\n\n/// Represents an individual WebSocket connection\ntemplate <typename config>\nclass connection\n : public config::transport_type::transport_con_type\n , public config::connection_base\n{\npublic:\n    /// Type of this connection\n    typedef connection<config> type;\n    /// Type of a shared pointer to this connection\n    typedef lib::shared_ptr<type> ptr;\n    /// Type of a weak pointer to this connection\n    typedef lib::weak_ptr<type> weak_ptr;\n\n    /// Type of the concurrency component of this connection\n    typedef typename config::concurrency_type concurrency_type;\n    /// Type of the access logging policy\n    typedef typename config::alog_type alog_type;\n    /// Type of the error logging policy\n    typedef typename config::elog_type elog_type;\n\n    /// Type of the transport component of this connection\n    typedef typename config::transport_type::transport_con_type\n        transport_con_type;\n    /// Type of a shared pointer to the transport component of this connection\n    typedef typename transport_con_type::ptr transport_con_ptr;\n\n    typedef lib::function<void(ptr)> termination_handler;\n\n    typedef typename concurrency_type::scoped_lock_type scoped_lock_type;\n    typedef typename concurrency_type::mutex_type mutex_type;\n\n    typedef typename config::request_type request_type;\n    typedef typename config::response_type response_type;\n\n    typedef typename config::message_type message_type;\n    typedef typename message_type::ptr message_ptr;\n\n    typedef typename config::con_msg_manager_type con_msg_manager_type;\n    typedef typename con_msg_manager_type::ptr con_msg_manager_ptr;\n\n    /// Type of RNG\n    typedef typename config::rng_type rng_type;\n\n    typedef processor::processor<config> processor_type;\n    typedef lib::shared_ptr<processor_type> processor_ptr;\n\n    // Message handler (needs to know message type)\n    typedef lib::function<void(connection_hdl,message_ptr)> message_handler;\n\n    /// Type of a pointer to a transport timer handle\n    typedef typename transport_con_type::timer_ptr timer_ptr;\n\n    // Misc Convenience Types\n    typedef session::internal_state::value istate_type;\n\nprivate:\n    enum terminate_status {\n        failed = 1,\n        closed,\n        unknown\n    };\npublic:\n\n    explicit connection(bool p_is_server, std::string const & ua, const lib::shared_ptr<alog_type>& alog,\n                        const lib::shared_ptr<elog_type>& elog, rng_type & rng)\n      : transport_con_type(p_is_server, alog, elog)\n      , m_handle_read_frame(lib::bind(\n            &type::handle_read_frame,\n            this,\n            lib::placeholders::_1,\n            lib::placeholders::_2\n        ))\n      , m_write_frame_handler(lib::bind(\n            &type::handle_write_frame,\n            this,\n            lib::placeholders::_1\n        ))\n      , m_user_agent(ua)\n      , m_open_handshake_timeout_dur(config::timeout_open_handshake)\n      , m_close_handshake_timeout_dur(config::timeout_close_handshake)\n      , m_pong_timeout_dur(config::timeout_pong)\n      , m_max_message_size(config::max_message_size)\n      , m_state(session::state::connecting)\n      , m_internal_state(session::internal_state::USER_INIT)\n      , m_msg_manager(new con_msg_manager_type())\n      , m_send_buffer_size(0)\n      , m_write_flag(false)\n      , m_read_flag(true)\n      , m_is_server(p_is_server)\n      , m_alog(alog)\n      , m_elog(elog)\n      , m_rng(rng)\n      , m_local_close_code(close::status::abnormal_close)\n      , m_remote_close_code(close::status::abnormal_close)\n      , m_is_http(false)\n      , m_http_state(session::http_state::init)\n      , m_was_clean(false)\n    {\n        m_alog->write(log::alevel::devel,\"connection constructor\");\n    }\n\n    /// Get a shared pointer to this component\n    ptr get_shared() {\n        return lib::static_pointer_cast<type>(transport_con_type::get_shared());\n    }\n\n    ///////////////////////////\n    // Set Handler Callbacks //\n    ///////////////////////////\n\n    /// Set open handler\n    /**\n     * The open handler is called after the WebSocket handshake is complete and\n     * the connection is considered OPEN.\n     *\n     * @param h The new open_handler\n     */\n    void set_open_handler(open_handler h) {\n        m_open_handler = h;\n    }\n\n    /// Set close handler\n    /**\n     * The close handler is called immediately after the connection is closed.\n     *\n     * @param h The new close_handler\n     */\n    void set_close_handler(close_handler h) {\n        m_close_handler = h;\n    }\n\n    /// Set fail handler\n    /**\n     * The fail handler is called whenever the connection fails while the\n     * handshake is bring processed.\n     *\n     * @param h The new fail_handler\n     */\n    void set_fail_handler(fail_handler h) {\n        m_fail_handler = h;\n    }\n\n    /// Set ping handler\n    /**\n     * The ping handler is called whenever the connection receives a ping\n     * control frame. The ping payload is included.\n     *\n     * The ping handler's return time controls whether or not a pong is\n     * sent in response to this ping. Returning false will suppress the\n     * return pong. If no ping handler is set a pong will be sent.\n     *\n     * @param h The new ping_handler\n     */\n    void set_ping_handler(ping_handler h) {\n        m_ping_handler = h;\n    }\n\n    /// Set pong handler\n    /**\n     * The pong handler is called whenever the connection receives a pong\n     * control frame. The pong payload is included.\n     *\n     * @param h The new pong_handler\n     */\n    void set_pong_handler(pong_handler h) {\n        m_pong_handler = h;\n    }\n\n    /// Set pong timeout handler\n    /**\n     * If the transport component being used supports timers, the pong timeout\n     * handler is called whenever a pong control frame is not received with the\n     * configured timeout period after the application sends a ping.\n     *\n     * The config setting `timeout_pong` controls the length of the timeout\n     * period. It is specified in milliseconds.\n     *\n     * This can be used to probe the health of the remote endpoint's WebSocket\n     * implementation. This does not guarantee that the remote application\n     * itself is still healthy but can be a useful diagnostic.\n     *\n     * Note: receipt of this callback doesn't mean the pong will never come.\n     * This functionality will not suppress delivery of the pong in question\n     * should it arrive after the timeout.\n     *\n     * @param h The new pong_timeout_handler\n     */\n    void set_pong_timeout_handler(pong_timeout_handler h) {\n        m_pong_timeout_handler = h;\n    }\n\n    /// Set interrupt handler\n    /**\n     * The interrupt handler is called whenever the connection is manually\n     * interrupted by the application.\n     *\n     * @param h The new interrupt_handler\n     */\n    void set_interrupt_handler(interrupt_handler h) {\n        m_interrupt_handler = h;\n    }\n\n    /// Set http handler\n    /**\n     * The http handler is called after an HTTP request other than a WebSocket\n     * upgrade request is received. It allows a WebSocket++ server to respond\n     * to regular HTTP requests on the same port as it processes WebSocket\n     * connections. This can be useful for hosting error messages, flash\n     * policy files, status pages, and other simple HTTP responses. It is not\n     * intended to be used as a primary web server.\n     *\n     * @param h The new http_handler\n     */\n    void set_http_handler(http_handler h) {\n        m_http_handler = h;\n    }\n\n    /// Set validate handler\n    /**\n     * The validate handler is called after a WebSocket handshake has been\n     * parsed but before a response is returned. It provides the application\n     * a chance to examine the request and determine whether or not it wants\n     * to accept the connection.\n     *\n     * Returning false from the validate handler will reject the connection.\n     * If no validate handler is present, all connections will be allowed.\n     *\n     * @param h The new validate_handler\n     */\n    void set_validate_handler(validate_handler h) {\n        m_validate_handler = h;\n    }\n\n    /// Set message handler\n    /**\n     * The message handler is called after a new message has been received.\n     *\n     * @param h The new message_handler\n     */\n    void set_message_handler(message_handler h) {\n        m_message_handler = h;\n    }\n\n    //////////////////////////////////////////\n    // Connection timeouts and other limits //\n    //////////////////////////////////////////\n\n    /// Set open handshake timeout\n    /**\n     * Sets the length of time the library will wait after an opening handshake\n     * has been initiated before cancelling it. This can be used to prevent\n     * excessive wait times for outgoing clients or excessive resource usage\n     * from broken clients or DoS attacks on servers.\n     *\n     * Connections that time out will have their fail handlers called with the\n     * open_handshake_timeout error code.\n     *\n     * The default value is specified via the compile time config value\n     * 'timeout_open_handshake'. The default value in the core config\n     * is 5000ms. A value of 0 will disable the timer entirely.\n     *\n     * To be effective, the transport you are using must support timers. See\n     * the documentation for your transport policy for details about its\n     * timer support.\n     *\n     * @param dur The length of the open handshake timeout in ms\n     */\n    void set_open_handshake_timeout(long dur) {\n        m_open_handshake_timeout_dur = dur;\n    }\n\n    /// Set close handshake timeout\n    /**\n     * Sets the length of time the library will wait after a closing handshake\n     * has been initiated before cancelling it. This can be used to prevent\n     * excessive wait times for outgoing clients or excessive resource usage\n     * from broken clients or DoS attacks on servers.\n     *\n     * Connections that time out will have their close handlers called with the\n     * close_handshake_timeout error code.\n     *\n     * The default value is specified via the compile time config value\n     * 'timeout_close_handshake'. The default value in the core config\n     * is 5000ms. A value of 0 will disable the timer entirely.\n     *\n     * To be effective, the transport you are using must support timers. See\n     * the documentation for your transport policy for details about its\n     * timer support.\n     *\n     * @param dur The length of the close handshake timeout in ms\n     */\n    void set_close_handshake_timeout(long dur) {\n        m_close_handshake_timeout_dur = dur;\n    }\n\n    /// Set pong timeout\n    /**\n     * Sets the length of time the library will wait for a pong response to a\n     * ping. This can be used as a keepalive or to detect broken  connections.\n     *\n     * Pong responses that time out will have the pong timeout handler called.\n     *\n     * The default value is specified via the compile time config value\n     * 'timeout_pong'. The default value in the core config\n     * is 5000ms. A value of 0 will disable the timer entirely.\n     *\n     * To be effective, the transport you are using must support timers. See\n     * the documentation for your transport policy for details about its\n     * timer support.\n     *\n     * @param dur The length of the pong timeout in ms\n     */\n    void set_pong_timeout(long dur) {\n        m_pong_timeout_dur = dur;\n    }\n\n    /// Get maximum message size\n    /**\n     * Get maximum message size. Maximum message size determines the point at \n     * which the connection will fail with the message_too_big protocol error.\n     *\n     * The default is set by the endpoint that creates the connection.\n     *\n     * @since 0.3.0\n     */\n    size_t get_max_message_size() const {\n        return m_max_message_size;\n    }\n    \n    /// Set maximum message size\n    /**\n     * Set maximum message size. Maximum message size determines the point at \n     * which the connection will fail with the message_too_big protocol error. \n     * This value may be changed during the connection.\n     *\n     * The default is set by the endpoint that creates the connection.\n     *\n     * @since 0.3.0\n     *\n     * @param new_value The value to set as the maximum message size.\n     */\n    void set_max_message_size(size_t new_value) {\n        m_max_message_size = new_value;\n        if (m_processor) {\n            m_processor->set_max_message_size(new_value);\n        }\n    }\n    \n    /// Get maximum HTTP message body size\n    /**\n     * Get maximum HTTP message body size. Maximum message body size determines\n     * the point at which the connection will stop reading an HTTP request whose\n     * body is too large.\n     *\n     * The default is set by the endpoint that creates the connection.\n     *\n     * @since 0.5.0\n     *\n     * @return The maximum HTTP message body size\n     */\n    size_t get_max_http_body_size() const {\n        return m_request.get_max_body_size();\n    }\n    \n    /// Set maximum HTTP message body size\n    /**\n     * Set maximum HTTP message body size. Maximum message body size determines\n     * the point at which the connection will stop reading an HTTP request whose\n     * body is too large.\n     *\n     * The default is set by the endpoint that creates the connection.\n     *\n     * @since 0.5.0\n     *\n     * @param new_value The value to set as the maximum message size.\n     */\n    void set_max_http_body_size(size_t new_value) {\n        m_request.set_max_body_size(new_value);\n    }\n\n    //////////////////////////////////\n    // Uncategorized public methods //\n    //////////////////////////////////\n\n    /// Get the size of the outgoing write buffer (in payload bytes)\n    /**\n     * Retrieves the number of bytes in the outgoing write buffer that have not\n     * already been dispatched to the transport layer. This represents the bytes\n     * that are presently cancelable without uncleanly ending the websocket\n     * connection\n     *\n     * This method invokes the m_write_lock mutex\n     *\n     * @return The current number of bytes in the outgoing send buffer.\n     */\n    size_t get_buffered_amount() const;\n\n    /// Get the size of the outgoing write buffer (in payload bytes)\n    /**\n     * @deprecated use `get_buffered_amount` instead\n     */\n    size_t buffered_amount() const {\n        return get_buffered_amount();\n    }\n\n    ////////////////////\n    // Action Methods //\n    ////////////////////\n\n    /// Create a message and then add it to the outgoing send queue\n    /**\n     * Convenience method to send a message given a payload string and\n     * optionally an opcode. Default opcode is utf8 text.\n     *\n     * This method locks the m_write_lock mutex\n     *\n     * @param payload The payload string to generated the message with\n     *\n     * @param op The opcode to generated the message with. Default is\n     * frame::opcode::text\n     */\n    lib::error_code send(std::string const & payload, frame::opcode::value op =\n        frame::opcode::text);\n\n    /// Send a message (raw array overload)\n    /**\n     * Convenience method to send a message given a raw array and optionally an\n     * opcode. Default opcode is binary.\n     *\n     * This method locks the m_write_lock mutex\n     *\n     * @param payload A pointer to the array containing the bytes to send.\n     *\n     * @param len Length of the array.\n     *\n     * @param op The opcode to generated the message with. Default is\n     * frame::opcode::binary\n     */\n    lib::error_code send(void const * payload, size_t len, frame::opcode::value\n        op = frame::opcode::binary);\n\n    /// Add a message to the outgoing send queue\n    /**\n     * If presented with a prepared message it is added without validation or\n     * framing. If presented with an unprepared message it is validated, framed,\n     * and then added\n     *\n     * Errors are returned via an exception\n     * \\todo make exception system_error rather than error_code\n     *\n     * This method invokes the m_write_lock mutex\n     *\n     * @param msg A message_ptr to the message to send.\n     */\n    lib::error_code send(message_ptr msg);\n\n    /// Asyncronously invoke handler::on_inturrupt\n    /**\n     * Signals to the connection to asyncronously invoke the on_inturrupt\n     * callback for this connection's handler once it is safe to do so.\n     *\n     * When the on_inturrupt handler callback is called it will be from\n     * within the transport event loop with all the thread safety features\n     * guaranteed by the transport to regular handlers\n     *\n     * Multiple inturrupt signals can be active at once on the same connection\n     *\n     * @return An error code\n     */\n    lib::error_code interrupt();\n    \n    /// Transport inturrupt callback\n    void handle_interrupt();\n    \n    /// Pause reading of new data\n    /**\n     * Signals to the connection to halt reading of new data. While reading is paused, \n     * the connection will stop reading from its associated socket. In turn this will \n     * result in TCP based flow control kicking in and slowing data flow from the remote\n     * endpoint.\n     *\n     * This is useful for applications that push new requests to a queue to be processed\n     * by another thread and need a way to signal when their request queue is full without\n     * blocking the network processing thread.\n     *\n     * Use `resume_reading()` to resume.\n     *\n     * If supported by the transport this is done asynchronously. As such reading may not\n     * stop until the current read operation completes. Typically you can expect to\n     * receive no more bytes after initiating a read pause than the size of the read \n     * buffer.\n     *\n     * If reading is paused for this connection already nothing is changed.\n     */\n    lib::error_code pause_reading();\n\n    /// Pause reading callback\n    void handle_pause_reading();\n\n    /// Resume reading of new data\n    /**\n     * Signals to the connection to resume reading of new data after it was paused by\n     * `pause_reading()`.\n     *\n     * If reading is not paused for this connection already nothing is changed.\n     */\n    lib::error_code resume_reading();\n\n    /// Resume reading callback\n    void handle_resume_reading();\n\n    /// Send a ping\n    /**\n     * Initiates a ping with the given payload/\n     *\n     * There is no feedback directly from ping except in cases of immediately\n     * detectable errors. Feedback will be provided via on_pong or\n     * on_pong_timeout callbacks.\n     *\n     * Ping locks the m_write_lock mutex\n     *\n     * @param payload Payload to be used for the ping\n     */\n    void ping(std::string const & payload);\n\n    /// exception free variant of ping\n    void ping(std::string const & payload, lib::error_code & ec);\n\n    /// Utility method that gets called back when the ping timer expires\n    void handle_pong_timeout(std::string payload, lib::error_code const & ec);\n\n    /// Send a pong\n    /**\n     * Initiates a pong with the given payload.\n     *\n     * There is no feedback from a pong once sent.\n     *\n     * Pong locks the m_write_lock mutex\n     *\n     * @param payload Payload to be used for the pong\n     */\n    void pong(std::string const & payload);\n\n    /// exception free variant of pong\n    void pong(std::string const & payload, lib::error_code & ec);\n\n    /// Close the connection\n    /**\n     * Initiates the close handshake process.\n     *\n     * If close returns successfully the connection will be in the closing\n     * state and no additional messages may be sent. All messages sent prior\n     * to calling close will be written out before the connection is closed.\n     *\n     * If no reason is specified none will be sent. If no code is specified\n     * then no code will be sent.\n     *\n     * The handler's on_close callback will be called once the close handshake\n     * is complete.\n     *\n     * Reasons will be automatically truncated to the maximum length (123 bytes)\n     * if necessary.\n     *\n     * @param code The close code to send\n     * @param reason The close reason to send\n     */\n    void close(close::status::value const code, std::string const & reason);\n\n    /// exception free variant of close\n    void close(close::status::value const code, std::string const & reason,\n        lib::error_code & ec);\n\n    ////////////////////////////////////////////////\n    // Pass-through access to the uri information //\n    ////////////////////////////////////////////////\n\n    /// Returns the secure flag from the connection URI\n    /**\n     * This value is available after the HTTP request has been fully read and\n     * may be called from any thread.\n     *\n     * @return Whether or not the connection URI is flagged secure.\n     */\n    bool get_secure() const;\n\n    /// Returns the host component of the connection URI\n    /**\n     * This value is available after the HTTP request has been fully read and\n     * may be called from any thread.\n     *\n     * @return The host component of the connection URI\n     */\n    std::string const & get_host() const;\n\n    /// Returns the resource component of the connection URI\n    /**\n     * This value is available after the HTTP request has been fully read and\n     * may be called from any thread.\n     *\n     * @return The resource component of the connection URI\n     */\n    std::string const & get_resource() const;\n\n    /// Returns the port component of the connection URI\n    /**\n     * This value is available after the HTTP request has been fully read and\n     * may be called from any thread.\n     *\n     * @return The port component of the connection URI\n     */\n    uint16_t get_port() const;\n\n    /// Gets the connection URI\n    /**\n     * This should really only be called by internal library methods unless you\n     * really know what you are doing.\n     *\n     * @return A pointer to the connection's URI\n     */\n    uri_ptr get_uri() const;\n\n    /// Sets the connection URI\n    /**\n     * This should really only be called by internal library methods unless you\n     * really know what you are doing.\n     *\n     * @param uri The new URI to set\n     */\n    void set_uri(uri_ptr uri);\n\n    /////////////////////////////\n    // Subprotocol negotiation //\n    /////////////////////////////\n\n    /// Gets the negotated subprotocol\n    /**\n     * Retrieves the subprotocol that was negotiated during the handshake. This\n     * method is valid in the open handler and later.\n     *\n     * @return The negotiated subprotocol\n     */\n    std::string const & get_subprotocol() const;\n\n    /// Gets all of the subprotocols requested by the client\n    /**\n     * Retrieves the subprotocols that were requested during the handshake. This\n     * method is valid in the validate handler and later.\n     *\n     * @return A vector of the requested subprotocol\n     */\n    std::vector<std::string> const & get_requested_subprotocols() const;\n\n    /// Adds the given subprotocol string to the request list (exception free)\n    /**\n     * Adds a subprotocol to the list to send with the opening handshake. This\n     * may be called multiple times to request more than one. If the server\n     * supports one of these, it may choose one. If so, it will return it\n     * in it's handshake reponse and the value will be available via\n     * get_subprotocol(). Subprotocol requests should be added in order of\n     * preference.\n     *\n     * @param request The subprotocol to request\n     * @param ec A reference to an error code that will be filled in the case of\n     * errors\n     */\n    void add_subprotocol(std::string const & request, lib::error_code & ec);\n\n    /// Adds the given subprotocol string to the request list\n    /**\n     * Adds a subprotocol to the list to send with the opening handshake. This\n     * may be called multiple times to request more than one. If the server\n     * supports one of these, it may choose one. If so, it will return it\n     * in it's handshake reponse and the value will be available via\n     * get_subprotocol(). Subprotocol requests should be added in order of\n     * preference.\n     *\n     * @param request The subprotocol to request\n     */\n    void add_subprotocol(std::string const & request);\n\n    /// Select a subprotocol to use (exception free)\n    /**\n     * Indicates which subprotocol should be used for this connection. Valid\n     * only during the validate handler callback. Subprotocol selected must have\n     * been requested by the client. Consult get_requested_subprotocols() for a\n     * list of valid subprotocols.\n     *\n     * This member function is valid on server endpoints/connections only\n     *\n     * @param value The subprotocol to select\n     * @param ec A reference to an error code that will be filled in the case of\n     * errors\n     */\n    void select_subprotocol(std::string const & value, lib::error_code & ec);\n\n    /// Select a subprotocol to use\n    /**\n     * Indicates which subprotocol should be used for this connection. Valid\n     * only during the validate handler callback. Subprotocol selected must have\n     * been requested by the client. Consult get_requested_subprotocols() for a\n     * list of valid subprotocols.\n     *\n     * This member function is valid on server endpoints/connections only\n     *\n     * @param value The subprotocol to select\n     */\n    void select_subprotocol(std::string const & value);\n\n    /////////////////////////////////////////////////////////////\n    // Pass-through access to the request and response objects //\n    /////////////////////////////////////////////////////////////\n\n    /// Retrieve a request header\n    /**\n     * Retrieve the value of a header from the handshake HTTP request.\n     *\n     * @param key Name of the header to get\n     * @return The value of the header\n     */\n    std::string const & get_request_header(std::string const & key) const;\n\n    /// Retrieve a request body\n    /**\n     * Retrieve the value of the request body. This value is typically used with\n     * PUT and POST requests to upload files or other data. Only HTTP\n     * connections will ever have bodies. WebSocket connection's will always\n     * have blank bodies.\n     *\n     * @return The value of the request body.\n     */\n    std::string const & get_request_body() const;\n\n    /// Retrieve a response header\n    /**\n     * Retrieve the value of a header from the handshake HTTP request.\n     *\n     * @param key Name of the header to get\n     * @return The value of the header\n     */\n    std::string const & get_response_header(std::string const & key) const;\n\n    /// Get response HTTP status code\n    /**\n     * Gets the response status code \n     *\n     * @since 0.7.0\n     *\n     * @return The response status code sent\n     */\n    http::status_code::value get_response_code() const {\n        return m_response.get_status_code();\n    }\n\n    /// Get response HTTP status message\n    /**\n     * Gets the response status message \n     *\n     * @since 0.7.0\n     *\n     * @return The response status message sent\n     */\n    std::string const & get_response_msg() const {\n        return m_response.get_status_msg();\n    }\n    \n    /// Set response status code and message\n    /**\n     * Sets the response status code to `code` and looks up the corresponding\n     * message for standard codes. Non-standard codes will be entered as Unknown\n     * use set_status(status_code::value,std::string) overload to set both\n     * values explicitly.\n     *\n     * This member function is valid only from the http() and validate() handler\n     * callbacks.\n     *\n     * @param code Code to set\n     * @param msg Message to set\n     * @see websocketpp::http::response::set_status\n     */\n    void set_status(http::status_code::value code);\n\n    /// Set response status code and message\n    /**\n     * Sets the response status code and message to independent custom values.\n     * use set_status(status_code::value) to set the code and have the standard\n     * message be automatically set.\n     *\n     * This member function is valid only from the http() and validate() handler\n     * callbacks.\n     *\n     * @param code Code to set\n     * @param msg Message to set\n     * @see websocketpp::http::response::set_status\n     */\n    void set_status(http::status_code::value code, std::string const & msg);\n\n    /// Set response body content\n    /**\n     * Set the body content of the HTTP response to the parameter string. Note\n     * set_body will also set the Content-Length HTTP header to the appropriate\n     * value. If you want the Content-Length header to be something else set it\n     * to something else after calling set_body\n     *\n     * This member function is valid only from the http() and validate() handler\n     * callbacks.\n     *\n     * @param value String data to include as the body content.\n     * @see websocketpp::http::response::set_body\n     */\n    void set_body(std::string const & value);\n\n    /// Append a header\n    /**\n     * If a header with this name already exists the value will be appended to\n     * the existing header to form a comma separated list of values. Use\n     * `connection::replace_header` to overwrite existing values.\n     *\n     * This member function is valid only from the http() and validate() handler\n     * callbacks, or to a client connection before connect has been called.\n     *\n     * @param key Name of the header to set\n     * @param val Value to add\n     * @see replace_header\n     * @see websocketpp::http::parser::append_header\n     */\n    void append_header(std::string const & key, std::string const & val);\n\n    /// Replace a header\n    /**\n     * If a header with this name already exists the old value will be replaced\n     * Use `connection::append_header` to append to a list of existing values.\n     *\n     * This member function is valid only from the http() and validate() handler\n     * callbacks, or to a client connection before connect has been called.\n     *\n     * @param key Name of the header to set\n     * @param val Value to set\n     * @see append_header\n     * @see websocketpp::http::parser::replace_header\n     */\n    void replace_header(std::string const & key, std::string const & val);\n\n    /// Remove a header\n    /**\n     * Removes a header from the response.\n     *\n     * This member function is valid only from the http() and validate() handler\n     * callbacks, or to a client connection before connect has been called.\n     *\n     * @param key The name of the header to remove\n     * @see websocketpp::http::parser::remove_header\n     */\n    void remove_header(std::string const & key);\n\n    /// Get request object\n    /**\n     * Direct access to request object. This can be used to call methods of the\n     * request object that are not part of the standard request API that\n     * connection wraps.\n     *\n     * Note use of this method involves using behavior specific to the\n     * configured HTTP policy. Such behavior may not work with alternate HTTP\n     * policies.\n     *\n     * @since 0.3.0-alpha3\n     *\n     * @return A const reference to the raw request object\n     */\n    request_type const & get_request() const {\n        return m_request;\n    }\n    \n    /// Get response object\n    /**\n     * Direct access to the HTTP response sent or received as a part of the\n     * opening handshake. This can be used to call methods of the response\n     * object that are not part of the standard request API that connection\n     * wraps.\n     *\n     * Note use of this method involves using behavior specific to the\n     * configured HTTP policy. Such behavior may not work with alternate HTTP\n     * policies.\n     *\n     * @since 0.7.0\n     *\n     * @return A const reference to the raw response object\n     */\n    response_type const & get_response() const {\n        return m_response;\n    }\n    \n    /// Defer HTTP Response until later (Exception free)\n    /**\n     * Used in the http handler to defer the HTTP response for this connection\n     * until later. Handshake timers will be canceled and the connection will be\n     * left open until `send_http_response` or an equivalent is called.\n     *\n     * Warning: deferred connections won't time out and as a result can tie up\n     * resources.\n     *\n     * @since 0.6.0\n     *\n     * @return A status code, zero on success, non-zero otherwise\n     */\n    lib::error_code defer_http_response();\n    \n    /// Send deferred HTTP Response (exception free)\n    /**\n     * Sends an http response to an HTTP connection that was deferred. This will\n     * send a complete response including all headers, status line, and body\n     * text. The connection will be closed afterwards.\n     *\n     * @since 0.6.0\n     *\n     * @param ec A status code, zero on success, non-zero otherwise\n     */\n    void send_http_response(lib::error_code & ec);\n    \n    /// Send deferred HTTP Response\n    void send_http_response();\n    \n    // TODO HTTPNBIO: write_headers\n    // function that processes headers + status so far and writes it to the wire\n    // beginning the HTTP response body state. This method will ignore anything\n    // in the response body.\n    \n    // TODO HTTPNBIO: write_body_message\n    // queues the specified message_buffer for async writing\n    \n    // TODO HTTPNBIO: finish connection\n    //\n    \n    // TODO HTTPNBIO: write_response\n    // Writes the whole response, headers + body and closes the connection\n    \n    \n\n    /////////////////////////////////////////////////////////////\n    // Pass-through access to the other connection information //\n    /////////////////////////////////////////////////////////////\n\n    /// Get Connection Handle\n    /**\n     * The connection handle is a token that can be shared outside the\n     * WebSocket++ core for the purposes of identifying a connection and\n     * sending it messages.\n     *\n     * @return A handle to the connection\n     */\n    connection_hdl get_handle() const {\n        return m_connection_hdl;\n    }\n\n    /// Get whether or not this connection is part of a server or client\n    /**\n     * @return whether or not the connection is attached to a server endpoint\n     */\n    bool is_server() const {\n        return m_is_server;\n    }\n\n    /// Return the same origin policy origin value from the opening request.\n    /**\n     * This value is available after the HTTP request has been fully read and\n     * may be called from any thread.\n     *\n     * @return The connection's origin value from the opening handshake.\n     */\n    std::string const & get_origin() const;\n\n    /// Return the connection state.\n    /**\n     * Values can be connecting, open, closing, and closed\n     *\n     * @return The connection's current state.\n     */\n    session::state::value get_state() const;\n\n\n    /// Get the WebSocket close code sent by this endpoint.\n    /**\n     * @return The WebSocket close code sent by this endpoint.\n     */\n    close::status::value get_local_close_code() const {\n        return m_local_close_code;\n    }\n\n    /// Get the WebSocket close reason sent by this endpoint.\n    /**\n     * @return The WebSocket close reason sent by this endpoint.\n     */\n    std::string const & get_local_close_reason() const {\n        return m_local_close_reason;\n    }\n\n    /// Get the WebSocket close code sent by the remote endpoint.\n    /**\n     * @return The WebSocket close code sent by the remote endpoint.\n     */\n    close::status::value get_remote_close_code() const {\n        return m_remote_close_code;\n    }\n\n    /// Get the WebSocket close reason sent by the remote endpoint.\n    /**\n     * @return The WebSocket close reason sent by the remote endpoint.\n     */\n    std::string const & get_remote_close_reason() const {\n        return m_remote_close_reason;\n    }\n\n    /// Get the internal error code for a closed/failed connection\n    /**\n     * Retrieves a machine readable detailed error code indicating the reason\n     * that the connection was closed or failed. Valid only after the close or\n     * fail handler is called.\n     *\n     * @return Error code indicating the reason the connection was closed or\n     * failed\n     */\n    lib::error_code get_ec() const {\n        return m_ec;\n    }\n\n    /// Get a message buffer\n    /**\n     * Warning: The API related to directly sending message buffers may change\n     * before the 1.0 release. If you plan to use it, please keep an eye on any\n     * breaking changes notifications in future release notes. Also if you have\n     * any feedback about usage and capabilities now is a great time to provide\n     * it.\n     *\n     * Message buffers are used to store message payloads and other message\n     * metadata.\n     *\n     * The size parameter is a hint only. Your final payload does not need to\n     * match it. There may be some performance benefits if the initial size\n     * guess is equal to or slightly higher than the final payload size.\n     *\n     * @param op The opcode for the new message\n     * @param size A hint to optimize the initial allocation of payload space.\n     * @return A new message buffer\n     */\n    message_ptr get_message(websocketpp::frame::opcode::value op, size_t size)\n        const\n    {\n        return m_msg_manager->get_message(op, size);\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // The remaining public member functions are for internal/policy use  //\n    // only. Do not call from application code unless you understand what //\n    // you are doing.                                                     //\n    ////////////////////////////////////////////////////////////////////////\n\n    \n\n    void read_handshake(size_t num_bytes);\n\n    void handle_read_handshake(lib::error_code const & ec,\n        size_t bytes_transferred);\n    void handle_read_http_response(lib::error_code const & ec,\n        size_t bytes_transferred);\n\n    \n    void handle_write_http_response(lib::error_code const & ec);\n    void handle_send_http_request(lib::error_code const & ec);\n\n    void handle_open_handshake_timeout(lib::error_code const & ec);\n    void handle_close_handshake_timeout(lib::error_code const & ec);\n\n    void handle_read_frame(lib::error_code const & ec, size_t bytes_transferred);\n    void read_frame();\n\n    /// Get array of WebSocket protocol versions that this connection supports.\n    std::vector<int> const & get_supported_versions() const;\n\n    /// Sets the handler for a terminating connection. Should only be used\n    /// internally by the endpoint class.\n    void set_termination_handler(termination_handler new_handler);\n\n    void terminate(lib::error_code const & ec);\n    void handle_terminate(terminate_status tstat, lib::error_code const & ec);\n\n    /// Checks if there are frames in the send queue and if there are sends one\n    /**\n     * \\todo unit tests\n     *\n     * This method locks the m_write_lock mutex\n     */\n    void write_frame();\n\n    /// Process the results of a frame write operation and start the next write\n    /**\n     * \\todo unit tests\n     *\n     * This method locks the m_write_lock mutex\n     *\n     * @param terminate Whether or not to terminate the connection upon\n     * completion of this write.\n     *\n     * @param ec A status code from the transport layer, zero on success,\n     * non-zero otherwise.\n     */\n    void handle_write_frame(lib::error_code const & ec);\n// protected:\n    // This set of methods would really like to be protected, but doing so \n    // requires that the endpoint be able to friend the connection. This is \n    // allowed with C++11, but not prior versions\n\n    /// Start the connection state machine\n    void start();\n\n    /// Set Connection Handle\n    /**\n     * The connection handle is a token that can be shared outside the\n     * WebSocket++ core for the purposes of identifying a connection and\n     * sending it messages.\n     *\n     * @param hdl A connection_hdl that the connection will use to refer\n     * to itself.\n     */\n    void set_handle(connection_hdl hdl) {\n        m_connection_hdl = hdl;\n        transport_con_type::set_handle(hdl);\n    }\nprotected:\n    void handle_transport_init(lib::error_code const & ec);\n\n    /// Set m_processor based on information in m_request. Set m_response\n    /// status and return an error code indicating status.\n    lib::error_code initialize_processor();\n\n    /// Perform WebSocket handshake validation of m_request using m_processor.\n    /// set m_response and return an error code indicating status.\n    lib::error_code process_handshake_request();\nprivate:\n    \n\n    /// Completes m_response, serializes it, and sends it out on the wire.\n    void write_http_response(lib::error_code const & ec);\n\n    /// Sends an opening WebSocket connect request\n    void send_http_request();\n\n    /// Alternate path for write_http_response in error conditions\n    void write_http_response_error(lib::error_code const & ec);\n\n    /// Process control message\n    /**\n     *\n     */\n    void process_control_frame(message_ptr msg);\n\n    /// Send close acknowledgement\n    /**\n     * If no arguments are present no close code/reason will be specified.\n     *\n     * Note: the close code/reason values provided here may be overrided by\n     * other settings (such as silent close).\n     *\n     * @param code The close code to send\n     * @param reason The close reason to send\n     * @return A status code, zero on success, non-zero otherwise\n     */\n    lib::error_code send_close_ack(close::status::value code =\n        close::status::blank, std::string const & reason = std::string());\n\n    /// Send close frame\n    /**\n     * If no arguments are present no close code/reason will be specified.\n     *\n     * Note: the close code/reason values provided here may be overrided by\n     * other settings (such as silent close).\n     *\n     * The ack flag determines what to do in the case of a blank status and\n     * whether or not to terminate the TCP connection after sending it.\n     *\n     * @param code The close code to send\n     * @param reason The close reason to send\n     * @param ack Whether or not this is an acknowledgement close frame\n     * @return A status code, zero on success, non-zero otherwise\n     */\n    lib::error_code send_close_frame(close::status::value code =\n        close::status::blank, std::string const & reason = std::string(), bool ack = false,\n        bool terminal = false);\n\n    /// Get a pointer to a new WebSocket protocol processor for a given version\n    /**\n     * @param version Version number of the WebSocket protocol to get a\n     * processor for. Negative values indicate invalid/unknown versions and will\n     * always return a null ptr\n     *\n     * @return A shared_ptr to a new instance of the appropriate processor or a\n     * null ptr if there is no installed processor that matches the version\n     * number.\n     */\n    processor_ptr get_processor(int version) const;\n\n    /// Add a message to the write queue\n    /**\n     * Adds a message to the write queue and updates any associated shared state\n     *\n     * Must be called while holding m_write_lock\n     *\n     * @todo unit tests\n     *\n     * @param msg The message to push\n     */\n    void write_push(message_ptr msg);\n\n    /// Pop a message from the write queue\n    /**\n     * Removes and returns a message from the write queue and updates any\n     * associated shared state.\n     *\n     * Must be called while holding m_write_lock\n     *\n     * @todo unit tests\n     *\n     * @return the message_ptr at the front of the queue\n     */\n    message_ptr write_pop();\n\n    /// Prints information about the incoming connection to the access log\n    /**\n     * Prints information about the incoming connection to the access log.\n     * Includes: connection type, websocket version, remote endpoint, user agent\n     * path, status code.\n     */\n    void log_open_result();\n\n    /// Prints information about a connection being closed to the access log\n    /**\n     * Includes: local and remote close codes and reasons\n     */\n    void log_close_result();\n\n    /// Prints information about a connection being failed to the access log\n    /**\n     * Includes: error code and message for why it was failed\n     */\n    void log_fail_result();\n    \n    /// Prints information about HTTP connections\n    /**\n     * Includes: TODO\n     */\n    void log_http_result();\n\n    /// Prints information about an arbitrary error code on the specified channel\n    template <typename error_type>\n    void log_err(log::level l, char const * msg, error_type const & ec) {\n        std::stringstream s;\n        s << msg << \" error: \" << ec << \" (\" << ec.message() << \")\";\n        m_elog->write(l, s.str());\n    }\n\n    // internal handler functions\n    read_handler            m_handle_read_frame;\n    write_frame_handler     m_write_frame_handler;\n\n    // static settings\n    std::string const       m_user_agent;\n\n    /// Pointer to the connection handle\n    connection_hdl          m_connection_hdl;\n\n    /// Handler objects\n    open_handler            m_open_handler;\n    close_handler           m_close_handler;\n    fail_handler            m_fail_handler;\n    ping_handler            m_ping_handler;\n    pong_handler            m_pong_handler;\n    pong_timeout_handler    m_pong_timeout_handler;\n    interrupt_handler       m_interrupt_handler;\n    http_handler            m_http_handler;\n    validate_handler        m_validate_handler;\n    message_handler         m_message_handler;\n\n    /// constant values\n    long                    m_open_handshake_timeout_dur;\n    long                    m_close_handshake_timeout_dur;\n    long                    m_pong_timeout_dur;\n    size_t                  m_max_message_size;\n\n    /// External connection state\n    /**\n     * Lock: m_connection_state_lock\n     */\n    session::state::value   m_state;\n\n    /// Internal connection state\n    /**\n     * Lock: m_connection_state_lock\n     */\n    istate_type             m_internal_state;\n\n    mutable mutex_type      m_connection_state_lock;\n\n    /// The lock used to protect the message queue\n    /**\n     * Serializes access to the write queue as well as shared state within the\n     * processor.\n     */\n    mutex_type              m_write_lock;\n\n    // connection resources\n    char                    m_buf[config::connection_read_buffer_size];\n    size_t                  m_buf_cursor;\n    termination_handler     m_termination_handler;\n    con_msg_manager_ptr     m_msg_manager;\n    timer_ptr               m_handshake_timer;\n    timer_ptr               m_ping_timer;\n\n    /// @todo this is not memory efficient. this value is not used after the\n    /// handshake.\n    std::string m_handshake_buffer;\n\n    /// Pointer to the processor object for this connection\n    /**\n     * The processor provides functionality that is specific to the WebSocket\n     * protocol version that the client has negotiated. It also contains all of\n     * the state necessary to encode and decode the incoming and outgoing\n     * WebSocket byte streams\n     *\n     * Use of the prepare_data_frame method requires lock: m_write_lock\n     */\n    processor_ptr           m_processor;\n\n    /// Queue of unsent outgoing messages\n    /**\n     * Lock: m_write_lock\n     */\n    std::queue<message_ptr> m_send_queue;\n\n    /// Size in bytes of the outstanding payloads in the write queue\n    /**\n     * Lock: m_write_lock\n     */\n    size_t m_send_buffer_size;\n\n    /// buffer holding the various parts of the current message being writen\n    /**\n     * Lock m_write_lock\n     */\n    std::vector<transport::buffer> m_send_buffer;\n\n    /// a list of pointers to hold on to the messages being written to keep them\n    /// from going out of scope before the write is complete.\n    std::vector<message_ptr> m_current_msgs;\n\n    /// True if there is currently an outstanding transport write\n    /**\n     * Lock m_write_lock\n     */\n    bool m_write_flag;\n\n    /// True if this connection is presently reading new data\n    bool m_read_flag;\n\n    // connection data\n    request_type            m_request;\n    response_type           m_response;\n    uri_ptr                 m_uri;\n    std::string             m_subprotocol;\n\n    // connection data that might not be necessary to keep around for the life\n    // of the whole connection.\n    std::vector<std::string> m_requested_subprotocols;\n\n    bool const              m_is_server;\n    const lib::shared_ptr<alog_type> m_alog;\n    const lib::shared_ptr<elog_type> m_elog;\n\n    rng_type & m_rng;\n\n    // Close state\n    /// Close code that was sent on the wire by this endpoint\n    close::status::value    m_local_close_code;\n\n    /// Close reason that was sent on the wire by this endpoint\n    std::string             m_local_close_reason;\n\n    /// Close code that was received on the wire from the remote endpoint\n    close::status::value    m_remote_close_code;\n\n    /// Close reason that was received on the wire from the remote endpoint\n    std::string             m_remote_close_reason;\n\n    /// Detailed internal error code\n    lib::error_code m_ec;\n    \n    /// A flag that gets set once it is determined that the connection is an\n    /// HTTP connection and not a WebSocket one.\n    bool m_is_http;\n    \n    /// A flag that gets set when the completion of an http connection is\n    /// deferred until later.\n    session::http_state::value m_http_state;\n\n    bool m_was_clean;\n};\n\n} // namespace websocketpp\n\n#include <websocketpp/impl/connection_impl.hpp>\n\n#endif // WEBSOCKETPP_CONNECTION_HPP\n"
  },
  {
    "path": "websocketpp/connection_base.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONNECTION_BASE_HPP\n#define WEBSOCKETPP_CONNECTION_BASE_HPP\n\nnamespace websocketpp {\n\n/// Stub for user supplied base class.\nclass connection_base {};\n\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONNECTION_BASE_HPP\n"
  },
  {
    "path": "websocketpp/endpoint.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_ENDPOINT_HPP\n#define WEBSOCKETPP_ENDPOINT_HPP\n\n#include <websocketpp/connection.hpp>\n\n#include <websocketpp/logger/levels.hpp>\n#include <websocketpp/version.hpp>\n\n#include <string>\n\nnamespace websocketpp {\n\n/// Creates and manages connections associated with a WebSocket endpoint\ntemplate <typename connection, typename config>\nclass endpoint : public config::transport_type, public config::endpoint_base {\npublic:\n    // Import appropriate types from our helper class\n    // See endpoint_types for more details.\n    typedef endpoint<connection,config> type;\n\n    /// Type of the transport component of this endpoint\n    typedef typename config::transport_type transport_type;\n    /// Type of the concurrency component of this endpoint\n    typedef typename config::concurrency_type concurrency_type;\n\n    /// Type of the connections that this endpoint creates\n    typedef connection connection_type;\n    /// Shared pointer to connection_type\n    typedef typename connection_type::ptr connection_ptr;\n    /// Weak pointer to connection type\n    typedef typename connection_type::weak_ptr connection_weak_ptr;\n\n    /// Type of the transport component of the connections that this endpoint\n    /// creates\n    typedef typename transport_type::transport_con_type transport_con_type;\n    /// Type of a shared pointer to the transport component of the connections\n    /// that this endpoint creates.\n    typedef typename transport_con_type::ptr transport_con_ptr;\n\n    /// Type of message_handler\n    typedef typename connection_type::message_handler message_handler;\n    /// Type of message pointers that this endpoint uses\n    typedef typename connection_type::message_ptr message_ptr;\n\n    /// Type of error logger\n    typedef typename config::elog_type elog_type;\n    /// Type of access logger\n    typedef typename config::alog_type alog_type;\n\n    /// Type of our concurrency policy's scoped lock object\n    typedef typename concurrency_type::scoped_lock_type scoped_lock_type;\n    /// Type of our concurrency policy's mutex object\n    typedef typename concurrency_type::mutex_type mutex_type;\n\n    /// Type of RNG\n    typedef typename config::rng_type rng_type;\n\n    // TODO: organize these\n    typedef typename connection_type::termination_handler termination_handler;\n\n    // This would be ideal. Requires C++11 though\n    //friend connection;\n\n    explicit endpoint(bool p_is_server)\n      : m_alog(new alog_type(config::alog_level, log::channel_type_hint::access))\n      , m_elog(new elog_type(config::elog_level, log::channel_type_hint::error))\n      , m_user_agent(::websocketpp::user_agent)\n      , m_open_handshake_timeout_dur(config::timeout_open_handshake)\n      , m_close_handshake_timeout_dur(config::timeout_close_handshake)\n      , m_pong_timeout_dur(config::timeout_pong)\n      , m_max_message_size(config::max_message_size)\n      , m_max_http_body_size(config::max_http_body_size)\n      , m_is_server(p_is_server)\n    {\n        m_alog->set_channels(config::alog_level);\n        m_elog->set_channels(config::elog_level);\n\n        m_alog->write(log::alevel::devel, \"endpoint constructor\");\n\n        transport_type::init_logging(m_alog, m_elog);\n    }\n\n\n    /// Destructor\n    ~endpoint<connection,config>() {}\n\n    #ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n        // no copy constructor because endpoints are not copyable\n        endpoint(endpoint &) = delete;\n    \n        // no copy assignment operator because endpoints are not copyable\n        endpoint & operator=(endpoint const &) = delete;\n    #endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n\n    #ifdef _WEBSOCKETPP_MOVE_SEMANTICS_\n        /// Move constructor\n        endpoint(endpoint && o) \n         : config::transport_type(std::move(o))\n         , config::endpoint_base(std::move(o))\n         , m_alog(std::move(o.m_alog))\n         , m_elog(std::move(o.m_elog))\n         , m_user_agent(std::move(o.m_user_agent))\n         , m_open_handler(std::move(o.m_open_handler))\n         \n         , m_close_handler(std::move(o.m_close_handler))\n         , m_fail_handler(std::move(o.m_fail_handler))\n         , m_ping_handler(std::move(o.m_ping_handler))\n         , m_pong_handler(std::move(o.m_pong_handler))\n         , m_pong_timeout_handler(std::move(o.m_pong_timeout_handler))\n         , m_interrupt_handler(std::move(o.m_interrupt_handler))\n         , m_http_handler(std::move(o.m_http_handler))\n         , m_validate_handler(std::move(o.m_validate_handler))\n         , m_message_handler(std::move(o.m_message_handler))\n\n         , m_open_handshake_timeout_dur(o.m_open_handshake_timeout_dur)\n         , m_close_handshake_timeout_dur(o.m_close_handshake_timeout_dur)\n         , m_pong_timeout_dur(o.m_pong_timeout_dur)\n         , m_max_message_size(o.m_max_message_size)\n         , m_max_http_body_size(o.m_max_http_body_size)\n\n         , m_rng(std::move(o.m_rng))\n         , m_is_server(o.m_is_server)         \n        {}\n\n    #ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n        // no move assignment operator because of const member variables\n        endpoint & operator=(endpoint &&) = delete;\n    #endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n\n    #endif // _WEBSOCKETPP_MOVE_SEMANTICS_\n\n\n    /// Returns the user agent string that this endpoint will use\n    /**\n     * Returns the user agent string that this endpoint will use when creating\n     * new connections.\n     *\n     * The default value for this version is stored in websocketpp::user_agent\n     *\n     * @return The user agent string.\n     */\n    std::string get_user_agent() const {\n        scoped_lock_type guard(m_mutex);\n        return m_user_agent;\n    }\n\n    /// Sets the user agent string that this endpoint will use\n    /**\n     * Sets the identifier that this endpoint will use when creating new\n     * connections. Changing this value will only affect future connections.\n     * For client endpoints this will be sent as the \"User-Agent\" header in\n     * outgoing requests. For server endpoints this will be sent in the \"Server\"\n     * response header.\n     *\n     * Setting this value to the empty string will suppress the use of the\n     * Server and User-Agent headers. This is typically done to hide\n     * implementation details for security purposes.\n     *\n     * For best results set this before accepting or opening connections.\n     *\n     * The default value for this version is stored in websocketpp::user_agent\n     *\n     * This can be overridden on an individual connection basis by setting a\n     * custom \"Server\" header during the validate handler or \"User-Agent\"\n     * header on a connection before calling connect().\n     *\n     * @param ua The string to set the user agent to.\n     */\n    void set_user_agent(std::string const & ua) {\n        scoped_lock_type guard(m_mutex);\n        m_user_agent = ua;\n    }\n\n    /// Returns whether or not this endpoint is a server.\n    /**\n     * @return Whether or not this endpoint is a server\n     */\n    bool is_server() const {\n        return m_is_server;\n    }\n\n    /********************************/\n    /* Pass-through logging adaptor */\n    /********************************/\n\n    /// Set Access logging channel\n    /**\n     * Set the access logger's channel value. The value is a number whose\n     * interpretation depends on the logging policy in use.\n     *\n     * @param channels The channel value(s) to set\n     */\n    void set_access_channels(log::level channels) {\n        m_alog->set_channels(channels);\n    }\n\n    /// Clear Access logging channels\n    /**\n     * Clear the access logger's channel value. The value is a number whose\n     * interpretation depends on the logging policy in use.\n     *\n     * @param channels The channel value(s) to clear\n     */\n    void clear_access_channels(log::level channels) {\n        m_alog->clear_channels(channels);\n    }\n\n    /// Set Error logging channel\n    /**\n     * Set the error logger's channel value. The value is a number whose\n     * interpretation depends on the logging policy in use.\n     *\n     * @param channels The channel value(s) to set\n     */\n    void set_error_channels(log::level channels) {\n        m_elog->set_channels(channels);\n    }\n\n    /// Clear Error logging channels\n    /**\n     * Clear the error logger's channel value. The value is a number whose\n     * interpretation depends on the logging policy in use.\n     *\n     * @param channels The channel value(s) to clear\n     */\n    void clear_error_channels(log::level channels) {\n        m_elog->clear_channels(channels);\n    }\n\n    /// Get reference to access logger\n    /**\n     * @return A reference to the access logger\n     */\n    alog_type & get_alog() {\n        return *m_alog;\n    }\n\n    /// Get reference to error logger\n    /**\n     * @return A reference to the error logger\n     */\n    elog_type & get_elog() {\n        return *m_elog;\n    }\n\n    /*************************/\n    /* Set Handler functions */\n    /*************************/\n\n    void set_open_handler(open_handler h) {\n        m_alog->write(log::alevel::devel,\"set_open_handler\");\n        scoped_lock_type guard(m_mutex);\n        m_open_handler = h;\n    }\n    void set_close_handler(close_handler h) {\n        m_alog->write(log::alevel::devel,\"set_close_handler\");\n        scoped_lock_type guard(m_mutex);\n        m_close_handler = h;\n    }\n    void set_fail_handler(fail_handler h) {\n        m_alog->write(log::alevel::devel,\"set_fail_handler\");\n        scoped_lock_type guard(m_mutex);\n        m_fail_handler = h;\n    }\n    void set_ping_handler(ping_handler h) {\n        m_alog->write(log::alevel::devel,\"set_ping_handler\");\n        scoped_lock_type guard(m_mutex);\n        m_ping_handler = h;\n    }\n    void set_pong_handler(pong_handler h) {\n        m_alog->write(log::alevel::devel,\"set_pong_handler\");\n        scoped_lock_type guard(m_mutex);\n        m_pong_handler = h;\n    }\n    void set_pong_timeout_handler(pong_timeout_handler h) {\n        m_alog->write(log::alevel::devel,\"set_pong_timeout_handler\");\n        scoped_lock_type guard(m_mutex);\n        m_pong_timeout_handler = h;\n    }\n    void set_interrupt_handler(interrupt_handler h) {\n        m_alog->write(log::alevel::devel,\"set_interrupt_handler\");\n        scoped_lock_type guard(m_mutex);\n        m_interrupt_handler = h;\n    }\n    void set_http_handler(http_handler h) {\n        m_alog->write(log::alevel::devel,\"set_http_handler\");\n        scoped_lock_type guard(m_mutex);\n        m_http_handler = h;\n    }\n    void set_validate_handler(validate_handler h) {\n        m_alog->write(log::alevel::devel,\"set_validate_handler\");\n        scoped_lock_type guard(m_mutex);\n        m_validate_handler = h;\n    }\n    void set_message_handler(message_handler h) {\n        m_alog->write(log::alevel::devel,\"set_message_handler\");\n        scoped_lock_type guard(m_mutex);\n        m_message_handler = h;\n    }\n\n    //////////////////////////////////////////\n    // Connection timeouts and other limits //\n    //////////////////////////////////////////\n\n    /// Set open handshake timeout\n    /**\n     * Sets the length of time the library will wait after an opening handshake\n     * has been initiated before cancelling it. This can be used to prevent\n     * excessive wait times for outgoing clients or excessive resource usage\n     * from broken clients or DoS attacks on servers.\n     *\n     * Connections that time out will have their fail handlers called with the\n     * open_handshake_timeout error code.\n     *\n     * The default value is specified via the compile time config value\n     * 'timeout_open_handshake'. The default value in the core config\n     * is 5000ms. A value of 0 will disable the timer entirely.\n     *\n     * To be effective, the transport you are using must support timers. See\n     * the documentation for your transport policy for details about its\n     * timer support.\n     *\n     * @param dur The length of the open handshake timeout in ms\n     */\n    void set_open_handshake_timeout(long dur) {\n        scoped_lock_type guard(m_mutex);\n        m_open_handshake_timeout_dur = dur;\n    }\n\n    /// Set close handshake timeout\n    /**\n     * Sets the length of time the library will wait after a closing handshake\n     * has been initiated before cancelling it. This can be used to prevent\n     * excessive wait times for outgoing clients or excessive resource usage\n     * from broken clients or DoS attacks on servers.\n     *\n     * Connections that time out will have their close handlers called with the\n     * close_handshake_timeout error code.\n     *\n     * The default value is specified via the compile time config value\n     * 'timeout_close_handshake'. The default value in the core config\n     * is 5000ms. A value of 0 will disable the timer entirely.\n     *\n     * To be effective, the transport you are using must support timers. See\n     * the documentation for your transport policy for details about its\n     * timer support.\n     *\n     * @param dur The length of the close handshake timeout in ms\n     */\n    void set_close_handshake_timeout(long dur) {\n        scoped_lock_type guard(m_mutex);\n        m_close_handshake_timeout_dur = dur;\n    }\n\n    /// Set pong timeout\n    /**\n     * Sets the length of time the library will wait for a pong response to a\n     * ping. This can be used as a keepalive or to detect broken  connections.\n     *\n     * Pong responses that time out will have the pong timeout handler called.\n     *\n     * The default value is specified via the compile time config value\n     * 'timeout_pong'. The default value in the core config\n     * is 5000ms. A value of 0 will disable the timer entirely.\n     *\n     * To be effective, the transport you are using must support timers. See\n     * the documentation for your transport policy for details about its\n     * timer support.\n     *\n     * @param dur The length of the pong timeout in ms\n     */\n    void set_pong_timeout(long dur) {\n        scoped_lock_type guard(m_mutex);\n        m_pong_timeout_dur = dur;\n    }\n\n    /// Get default maximum message size\n    /**\n     * Get the default maximum message size that will be used for new \n     * connections created by this endpoint. The maximum message size determines\n     * the point at which the connection will fail a connection with the \n     * message_too_big protocol error.\n     *\n     * The default is set by the max_message_size value from the template config\n     *\n     * @since 0.3.0\n     */\n    size_t get_max_message_size() const {\n        return m_max_message_size;\n    }\n    \n    /// Set default maximum message size\n    /**\n     * Set the default maximum message size that will be used for new \n     * connections created by this endpoint. Maximum message size determines the\n     * point at which the connection will fail a connection with the\n     * message_too_big protocol error.\n     *\n     * The default is set by the max_message_size value from the template config\n     *\n     * @since 0.3.0\n     *\n     * @param new_value The value to set as the maximum message size.\n     */\n    void set_max_message_size(size_t new_value) {\n        m_max_message_size = new_value;\n    }\n\n    /// Get maximum HTTP message body size\n    /**\n     * Get maximum HTTP message body size. Maximum message body size determines\n     * the point at which the connection will stop reading an HTTP request whose\n     * body is too large.\n     *\n     * The default is set by the max_http_body_size value from the template\n     * config\n     *\n     * @since 0.5.0\n     *\n     * @return The maximum HTTP message body size\n     */\n    size_t get_max_http_body_size() const {\n        return m_max_http_body_size;\n    }\n    \n    /// Set maximum HTTP message body size\n    /**\n     * Set maximum HTTP message body size. Maximum message body size determines\n     * the point at which the connection will stop reading an HTTP request whose\n     * body is too large.\n     *\n     * The default is set by the max_http_body_size value from the template\n     * config\n     *\n     * @since 0.5.1\n     *\n     * @param new_value The value to set as the maximum message size.\n     */\n    void set_max_http_body_size(size_t new_value) {\n        m_max_http_body_size = new_value;\n    }\n\n    /*************************************/\n    /* Connection pass through functions */\n    /*************************************/\n\n    /**\n     * These functions act as adaptors to their counterparts in connection. They\n     * can produce one additional type of error, the bad_connection error, that\n     * indicates that the conversion from connection_hdl to connection_ptr\n     * failed due to the connection not existing anymore. Each method has a\n     * default and an exception free varient.\n     */\n\n    void interrupt(connection_hdl hdl, lib::error_code & ec);\n    void interrupt(connection_hdl hdl);\n\n    /// Pause reading of new data (exception free)\n    /**\n     * Signals to the connection to halt reading of new data. While reading is \n     * paused, the connection will stop reading from its associated socket. In\n     * turn this will result in TCP based flow control kicking in and slowing\n     * data flow from the remote endpoint.\n     *\n     * This is useful for applications that push new requests to a queue to be \n     * processed by another thread and need a way to signal when their request\n     * queue is full without blocking the network processing thread.\n     *\n     * Use `resume_reading()` to resume.\n     *\n     * If supported by the transport this is done asynchronously. As such\n     * reading may not stop until the current read operation completes. \n     * Typically you can expect to receive no more bytes after initiating a read\n     * pause than the size of the read buffer.\n     *\n     * If reading is paused for this connection already nothing is changed.\n     */\n    void pause_reading(connection_hdl hdl, lib::error_code & ec);\n    \n    /// Pause reading of new data\n    void pause_reading(connection_hdl hdl);\n\n    /// Resume reading of new data (exception free)\n    /**\n     * Signals to the connection to resume reading of new data after it was \n     * paused by `pause_reading()`.\n     *\n     * If reading is not paused for this connection already nothing is changed.\n     */\n    void resume_reading(connection_hdl hdl, lib::error_code & ec);\n\n    /// Resume reading of new data\n    void resume_reading(connection_hdl hdl);\n\n    /// Send deferred HTTP Response\n    /**\n     * Sends an http response to an HTTP connection that was deferred. This will\n     * send a complete response including all headers, status line, and body\n     * text. The connection will be closed afterwards.\n     *\n     * Exception free variant\n     *\n     * @since 0.6.0\n     *\n     * @param hdl The connection to send the response on\n     * @param ec A status code, zero on success, non-zero otherwise\n     */\n    void send_http_response(connection_hdl hdl, lib::error_code & ec);\n        \n    /// Send deferred HTTP Response (exception free)\n    /**\n     * Sends an http response to an HTTP connection that was deferred. This will\n     * send a complete response including all headers, status line, and body\n     * text. The connection will be closed afterwards.\n     *\n     * Exception variant\n     *\n     * @since 0.6.0\n     *\n     * @param hdl The connection to send the response on\n     */\n    void send_http_response(connection_hdl hdl);\n\n    /// Create a message and add it to the outgoing send queue (exception free)\n    /**\n     * Convenience method to send a message given a payload string and an opcode\n     *\n     * @param [in] hdl The handle identifying the connection to send via.\n     * @param [in] payload The payload string to generated the message with\n     * @param [in] op The opcode to generated the message with.\n     * @param [out] ec A code to fill in for errors\n     */\n    void send(connection_hdl hdl, std::string const & payload,\n        frame::opcode::value op, lib::error_code & ec);\n    /// Create a message and add it to the outgoing send queue\n    /**\n     * Convenience method to send a message given a payload string and an opcode\n     *\n     * @param [in] hdl The handle identifying the connection to send via.\n     * @param [in] payload The payload string to generated the message with\n     * @param [in] op The opcode to generated the message with.\n     * @param [out] ec A code to fill in for errors\n     */\n    void send(connection_hdl hdl, std::string const & payload,\n        frame::opcode::value op);\n\n    void send(connection_hdl hdl, void const * payload, size_t len,\n        frame::opcode::value op, lib::error_code & ec);\n    void send(connection_hdl hdl, void const * payload, size_t len,\n        frame::opcode::value op);\n\n    void send(connection_hdl hdl, message_ptr msg, lib::error_code & ec);\n    void send(connection_hdl hdl, message_ptr msg);\n\n    void close(connection_hdl hdl, close::status::value const code,\n        std::string const & reason, lib::error_code & ec);\n    void close(connection_hdl hdl, close::status::value const code,\n        std::string const & reason);\n\n    /// Send a ping to a specific connection\n    /**\n     * @since 0.3.0-alpha3\n     *\n     * @param [in] hdl The connection_hdl of the connection to send to.\n     * @param [in] payload The payload string to send.\n     * @param [out] ec A reference to an error code to fill in\n     */\n    void ping(connection_hdl hdl, std::string const & payload,\n        lib::error_code & ec);\n    /// Send a ping to a specific connection\n    /**\n     * Exception variant of `ping`\n     *\n     * @since 0.3.0-alpha3\n     *\n     * @param [in] hdl The connection_hdl of the connection to send to.\n     * @param [in] payload The payload string to send.\n     */\n    void ping(connection_hdl hdl, std::string const & payload);\n\n    /// Send a pong to a specific connection\n    /**\n     * @since 0.3.0-alpha3\n     *\n     * @param [in] hdl The connection_hdl of the connection to send to.\n     * @param [in] payload The payload string to send.\n     * @param [out] ec A reference to an error code to fill in\n     */\n    void pong(connection_hdl hdl, std::string const & payload,\n        lib::error_code & ec);\n    /// Send a pong to a specific connection\n    /**\n     * Exception variant of `pong`\n     *\n     * @since 0.3.0-alpha3\n     *\n     * @param [in] hdl The connection_hdl of the connection to send to.\n     * @param [in] payload The payload string to send.\n     */\n    void pong(connection_hdl hdl, std::string const & payload);\n\n    /// Retrieves a connection_ptr from a connection_hdl (exception free)\n    /**\n     * Converting a weak pointer to shared_ptr is not thread safe because the\n     * pointer could be deleted at any time.\n     *\n     * NOTE: This method may be called by handler to upgrade its handle to a\n     * full connection_ptr. That full connection may then be used safely for the\n     * remainder of the handler body. get_con_from_hdl and the resulting\n     * connection_ptr are NOT safe to use outside the handler loop.\n     *\n     * @param hdl The connection handle to translate\n     *\n     * @return the connection_ptr. May be NULL if the handle was invalid.\n     */\n    connection_ptr get_con_from_hdl(connection_hdl hdl, lib::error_code & ec) {\n        connection_ptr con = lib::static_pointer_cast<connection_type>(\n            hdl.lock());\n        if (!con) {\n            ec = error::make_error_code(error::bad_connection);\n        }\n        return con;\n    }\n\n    /// Retrieves a connection_ptr from a connection_hdl (exception version)\n    connection_ptr get_con_from_hdl(connection_hdl hdl) {\n        lib::error_code ec;\n        connection_ptr con = this->get_con_from_hdl(hdl,ec);\n        if (ec) {\n            throw exception(ec);\n        }\n        return con;\n    }\nprotected:\n    connection_ptr create_connection();\n\n    lib::shared_ptr<alog_type> m_alog;\n    lib::shared_ptr<elog_type> m_elog;\nprivate:\n    // dynamic settings\n    std::string                 m_user_agent;\n\n    open_handler                m_open_handler;\n    close_handler               m_close_handler;\n    fail_handler                m_fail_handler;\n    ping_handler                m_ping_handler;\n    pong_handler                m_pong_handler;\n    pong_timeout_handler        m_pong_timeout_handler;\n    interrupt_handler           m_interrupt_handler;\n    http_handler                m_http_handler;\n    validate_handler            m_validate_handler;\n    message_handler             m_message_handler;\n\n    long                        m_open_handshake_timeout_dur;\n    long                        m_close_handshake_timeout_dur;\n    long                        m_pong_timeout_dur;\n    size_t                      m_max_message_size;\n    size_t                      m_max_http_body_size;\n\n    rng_type m_rng;\n\n    // static settings\n    bool const                  m_is_server;\n\n    // endpoint state\n    mutable mutex_type          m_mutex;\n};\n\n} // namespace websocketpp\n\n#include <websocketpp/impl/endpoint_impl.hpp>\n\n#endif // WEBSOCKETPP_ENDPOINT_HPP\n"
  },
  {
    "path": "websocketpp/endpoint_base.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_ENDPOINT_BASE_HPP\n#define WEBSOCKETPP_ENDPOINT_BASE_HPP\n\nnamespace websocketpp {\n\n/// Stub for user supplied base class.\nclass endpoint_base {};\n\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_ENDPOINT_BASE_HPP\n"
  },
  {
    "path": "websocketpp/error.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_ERROR_HPP\n#define WEBSOCKETPP_ERROR_HPP\n\n#include <exception>\n#include <string>\n#include <utility>\n\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/system_error.hpp>\n\nnamespace websocketpp {\n\n/// Combination error code / string type for returning two values\ntypedef std::pair<lib::error_code,std::string> err_str_pair;\n\n/// Library level error codes\nnamespace error {\nenum value {\n    /// Catch-all library error\n    general = 1,\n\n    /// send attempted when endpoint write queue was full\n    send_queue_full,\n\n    /// Attempted an operation using a payload that was improperly formatted\n    /// ex: invalid UTF8 encoding on a text message.\n    payload_violation,\n\n    /// Attempted to open a secure connection with an insecure endpoint\n    endpoint_not_secure,\n\n    /// Attempted an operation that required an endpoint that is no longer\n    /// available. This is usually because the endpoint went out of scope\n    /// before a connection that it created.\n    endpoint_unavailable,\n\n    /// An invalid uri was supplied\n    invalid_uri,\n\n    /// The endpoint is out of outgoing message buffers\n    no_outgoing_buffers,\n\n    /// The endpoint is out of incoming message buffers\n    no_incoming_buffers,\n\n    /// The connection was in the wrong state for this operation\n    invalid_state,\n\n    /// Unable to parse close code\n    bad_close_code,\n\n    /// Close code is in a reserved range\n    reserved_close_code,\n\n    /// Close code is invalid\n    invalid_close_code,\n\n    /// Invalid UTF-8\n    invalid_utf8,\n\n    /// Invalid subprotocol\n    invalid_subprotocol,\n\n    /// An operation was attempted on a connection that did not exist or was\n    /// already deleted.\n    bad_connection,\n\n    /// Unit testing utility error code\n    test,\n\n    /// Connection creation attempted failed\n    con_creation_failed,\n\n    /// Selected subprotocol was not requested by the client\n    unrequested_subprotocol,\n\n    /// Attempted to use a client specific feature on a server endpoint\n    client_only,\n\n    /// Attempted to use a server specific feature on a client endpoint\n    server_only,\n\n    /// HTTP connection ended\n    http_connection_ended,\n\n    /// WebSocket opening handshake timed out\n    open_handshake_timeout,\n\n    /// WebSocket close handshake timed out\n    close_handshake_timeout,\n\n    /// Invalid port in URI\n    invalid_port,\n\n    /// An async accept operation failed because the underlying transport has been\n    /// requested to not listen for new connections anymore.\n    async_accept_not_listening,\n\n    /// The requested operation was canceled\n    operation_canceled,\n\n    /// Connection rejected\n    rejected,\n\n    /// Upgrade Required. This happens if an HTTP request is made to a\n    /// WebSocket++ server that doesn't implement an http handler\n    upgrade_required,\n\n    /// Invalid WebSocket protocol version\n    invalid_version,\n\n    /// Unsupported WebSocket protocol version\n    unsupported_version,\n\n    /// HTTP parse error\n    http_parse_error,\n    \n    /// Extension negotiation failed\n    extension_neg_failed\n}; // enum value\n\n\nclass category : public lib::error_category {\npublic:\n    category() {}\n\n    char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {\n        return \"websocketpp\";\n    }\n\n    std::string message(int value) const {\n        switch(value) {\n            case error::general:\n                return \"Generic error\";\n            case error::send_queue_full:\n                return \"send queue full\";\n            case error::payload_violation:\n                return \"payload violation\";\n            case error::endpoint_not_secure:\n                return \"endpoint not secure\";\n            case error::endpoint_unavailable:\n                return \"endpoint not available\";\n            case error::invalid_uri:\n                return \"invalid uri\";\n            case error::no_outgoing_buffers:\n                return \"no outgoing message buffers\";\n            case error::no_incoming_buffers:\n                return \"no incoming message buffers\";\n            case error::invalid_state:\n                return \"invalid state\";\n            case error::bad_close_code:\n                return \"Unable to extract close code\";\n            case error::invalid_close_code:\n                return \"Extracted close code is in an invalid range\";\n            case error::reserved_close_code:\n                return \"Extracted close code is in a reserved range\";\n            case error::invalid_utf8:\n                return \"Invalid UTF-8\";\n            case error::invalid_subprotocol:\n                return \"Invalid subprotocol\";\n            case error::bad_connection:\n                return \"Bad Connection\";\n            case error::test:\n                return \"Test Error\";\n            case error::con_creation_failed:\n                return \"Connection creation attempt failed\";\n            case error::unrequested_subprotocol:\n                return \"Selected subprotocol was not requested by the client\";\n            case error::client_only:\n                return \"Feature not available on server endpoints\";\n            case error::server_only:\n                return \"Feature not available on client endpoints\";\n            case error::http_connection_ended:\n                return \"HTTP connection ended\";\n            case error::open_handshake_timeout:\n                return \"The opening handshake timed out\";\n            case error::close_handshake_timeout:\n                return \"The closing handshake timed out\";\n            case error::invalid_port:\n                return \"Invalid URI port\";\n            case error::async_accept_not_listening:\n                return \"Async Accept not listening\";\n            case error::operation_canceled:\n                return \"Operation canceled\";\n            case error::rejected:\n                return \"Connection rejected\";\n            case error::upgrade_required:\n                return \"Upgrade required\";\n            case error::invalid_version:\n                return \"Invalid version\";\n            case error::unsupported_version:\n                return \"Unsupported version\";\n            case error::http_parse_error:\n                return \"HTTP parse error\";\n            case error::extension_neg_failed:\n                return \"Extension negotiation failed\";\n            default:\n                return \"Unknown\";\n        }\n    }\n};\n\ninline const lib::error_category& get_category() {\n    static category instance;\n    return instance;\n}\n\ninline lib::error_code make_error_code(error::value e) {\n    return lib::error_code(static_cast<int>(e), get_category());\n}\n\n} // namespace error\n} // namespace websocketpp\n\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_\ntemplate<> struct is_error_code_enum<websocketpp::error::value>\n{\n    static bool const value = true;\n};\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_\n\nnamespace websocketpp {\n\nclass exception : public std::exception {\npublic:\n    exception(std::string const & msg, lib::error_code ec = make_error_code(error::general))\n      : m_msg(msg.empty() ? ec.message() : msg), m_code(ec)\n    {}\n\n    explicit exception(lib::error_code ec)\n      : m_msg(ec.message()), m_code(ec)\n    {}\n\n    ~exception() throw() {}\n\n    virtual char const * what() const throw() {\n        return m_msg.c_str();\n    }\n\n    lib::error_code code() const throw() {\n        return m_code;\n    }\n\n    const std::string m_msg;\n    lib::error_code m_code;\n};\n\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_ERROR_HPP\n"
  },
  {
    "path": "websocketpp/extensions/extension.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_EXTENSION_HPP\n#define WEBSOCKETPP_EXTENSION_HPP\n\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/system_error.hpp>\n\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\n\n/**\n * Some generic information about extensions\n *\n * Each extension object has an implemented flag. It can be retrieved by calling\n * is_implemented(). This compile time flag indicates whether or not the object\n * in question actually implements the extension or if it is a placeholder stub\n *\n * Each extension object also has an enabled flag. It can be retrieved by\n * calling is_enabled(). This runtime flag indicates whether or not the\n * extension has been negotiated for this connection.\n */\nnamespace extensions {\n\nnamespace error {\nenum value {\n    /// Catch all\n    general = 1,\n\n    /// Extension disabled\n    disabled\n};\n\nclass category : public lib::error_category {\npublic:\n    category() {}\n\n    const char *name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {\n        return \"websocketpp.extension\";\n    }\n\n    std::string message(int value) const {\n        switch(value) {\n            case general:\n                return \"Generic extension error\";\n            case disabled:\n                return \"Use of methods from disabled extension\";\n            default:\n                return \"Unknown permessage-compress error\";\n        }\n    }\n};\n\ninline lib::error_category const & get_category() {\n    static category instance;\n    return instance;\n}\n\ninline lib::error_code make_error_code(error::value e) {\n    return lib::error_code(static_cast<int>(e), get_category());\n}\n\n} // namespace error\n} // namespace extensions\n} // namespace websocketpp\n\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_\ntemplate<> struct is_error_code_enum\n    <websocketpp::extensions::error::value>\n{\n    static const bool value = true;\n};\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_\n\n#endif // WEBSOCKETPP_EXTENSION_HPP\n"
  },
  {
    "path": "websocketpp/extensions/permessage_deflate/disabled.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_EXTENSION_PERMESSAGE_DEFLATE_DISABLED_HPP\n#define WEBSOCKETPP_EXTENSION_PERMESSAGE_DEFLATE_DISABLED_HPP\n\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/stdint.hpp>\n#include <websocketpp/common/system_error.hpp>\n\n#include <websocketpp/http/constants.hpp>\n#include <websocketpp/extensions/extension.hpp>\n\n#include <map>\n#include <string>\n#include <utility>\n\nnamespace websocketpp {\nnamespace extensions {\nnamespace permessage_deflate {\n\n/// Stub class for use when disabling permessage_deflate extension\n/**\n * This class is a stub that implements the permessage_deflate interface\n * with minimal dependencies. It is used to disable permessage_deflate\n * functionality at compile time without loading any unnecessary code.\n */\ntemplate <typename config>\nclass disabled {\n    typedef std::pair<lib::error_code,std::string> err_str_pair;\n\npublic:\n    /// Negotiate extension\n    /**\n     * The disabled extension always fails the negotiation with a disabled\n     * error.\n     *\n     * @param offer Attribute from client's offer\n     * @return Status code and value to return to remote endpoint\n     */\n    err_str_pair negotiate(http::attribute_list const &) {\n        return make_pair(make_error_code(error::disabled),std::string());\n    }\n\n    /// Initialize state\n    /**\n     * For the disabled extension state initialization is a no-op.\n     *\n     * @param is_server True to initialize as a server, false for a client.\n     * @return A code representing the error that occurred, if any\n     */\n    lib::error_code init(bool) {\n        return lib::error_code();\n    }\n\n    /// Returns true if the extension is capable of providing\n    /// permessage_deflate functionality\n    bool is_implemented() const {\n        return false;\n    }\n\n    /// Returns true if permessage_deflate functionality is active for this\n    /// connection\n    bool is_enabled() const {\n        return false;\n    }\n\n    /// Generate extension offer\n    /**\n     * Creates an offer string to include in the Sec-WebSocket-Extensions\n     * header of outgoing client requests.\n     *\n     * @return A WebSocket extension offer string for this extension\n     */\n    std::string generate_offer() const {\n        return \"\";\n    }\n\n    /// Compress bytes\n    /**\n     * @param [in] in String to compress\n     * @param [out] out String to append compressed bytes to\n     * @return Error or status code\n     */\n    lib::error_code compress(std::string const &, std::string &) {\n        return make_error_code(error::disabled);\n    }\n\n    /// Decompress bytes\n    /**\n     * @param buf Byte buffer to decompress\n     * @param len Length of buf\n     * @param out String to append decompressed bytes to\n     * @return Error or status code\n     */\n    lib::error_code decompress(uint8_t const *, size_t, std::string &) {\n        return make_error_code(error::disabled);\n    }\n};\n\n} // namespace permessage_deflate\n} // namespace extensions\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_EXTENSION_PERMESSAGE_DEFLATE_DISABLED_HPP\n"
  },
  {
    "path": "websocketpp/extensions/permessage_deflate/enabled.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP\n#define WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP\n\n\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/common/platforms.hpp>\n#include <websocketpp/common/stdint.hpp>\n#include <websocketpp/common/system_error.hpp>\n#include <websocketpp/error.hpp>\n\n#include <websocketpp/extensions/extension.hpp>\n\n#include \"zlib.h\"\n\n#include <algorithm>\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\nnamespace extensions {\n\n/// Implementation of RFC 7692, the permessage-deflate WebSocket extension\n/**\n * ### permessage-deflate interface\n *\n * **init**\\n\n * `lib::error_code init(bool is_server)`\\n\n * Performs initialization\n *\n * **is_implimented**\\n\n * `bool is_implimented()`\\n\n * Returns whether or not the object impliments the extension or not\n *\n * **is_enabled**\\n\n * `bool is_enabled()`\\n\n * Returns whether or not the extension was negotiated for the current\n * connection\n *\n * **generate_offer**\\n\n * `std::string generate_offer() const`\\n\n * Create an extension offer string based on local policy\n *\n * **validate_response**\\n\n * `lib::error_code validate_response(http::attribute_list const & response)`\\n\n * Negotiate the parameters of extension use\n *\n * **negotiate**\\n\n * `err_str_pair negotiate(http::attribute_list const & attributes)`\\n\n * Negotiate the parameters of extension use\n *\n * **compress**\\n\n * `lib::error_code compress(std::string const & in, std::string & out)`\\n\n * Compress the bytes in `in` and append them to `out`\n *\n * **decompress**\\n\n * `lib::error_code decompress(uint8_t const * buf, size_t len, std::string &\n * out)`\\n\n * Decompress `len` bytes from `buf` and append them to string `out`\n */\nnamespace permessage_deflate {\n\n/// Permessage deflate error values\nnamespace error {\nenum value {\n    /// Catch all\n    general = 1,\n\n    /// Invalid extension attributes\n    invalid_attributes,\n\n    /// Invalid extension attribute value\n    invalid_attribute_value,\n\n    /// Invalid megotiation mode\n    invalid_mode,\n\n    /// Unsupported extension attributes\n    unsupported_attributes,\n\n    /// Invalid value for max_window_bits\n    invalid_max_window_bits,\n\n    /// ZLib Error\n    zlib_error,\n\n    /// Uninitialized\n    uninitialized,\n};\n\n/// Permessage-deflate error category\nclass category : public lib::error_category {\npublic:\n    category() {}\n\n    char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {\n        return \"websocketpp.extension.permessage-deflate\";\n    }\n\n    std::string message(int value) const {\n        switch(value) {\n            case general:\n                return \"Generic permessage-compress error\";\n            case invalid_attributes:\n                return \"Invalid extension attributes\";\n            case invalid_attribute_value:\n                return \"Invalid extension attribute value\";\n            case invalid_mode:\n                return \"Invalid permessage-deflate negotiation mode\";\n            case unsupported_attributes:\n                return \"Unsupported extension attributes\";\n            case invalid_max_window_bits:\n                return \"Invalid value for max_window_bits\";\n            case zlib_error:\n                return \"A zlib function returned an error\";\n            case uninitialized:\n                return \"Deflate extension must be initialized before use\";\n            default:\n                return \"Unknown permessage-compress error\";\n        }\n    }\n};\n\n/// Get a reference to a static copy of the permessage-deflate error category\ninline lib::error_category const & get_category() {\n    static category instance;\n    return instance;\n}\n\n/// Create an error code in the permessage-deflate category\ninline lib::error_code make_error_code(error::value e) {\n    return lib::error_code(static_cast<int>(e), get_category());\n}\n\n} // namespace error\n} // namespace permessage_deflate\n} // namespace extensions\n} // namespace websocketpp\n\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_\ntemplate<> struct is_error_code_enum\n    <websocketpp::extensions::permessage_deflate::error::value>\n{\n    static bool const value = true;\n};\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_\nnamespace websocketpp {\nnamespace extensions {\nnamespace permessage_deflate {\n\n/// Default value for server_max_window_bits as defined by RFC 7692\nstatic uint8_t const default_server_max_window_bits = 15;\n/// Minimum value for server_max_window_bits as defined by RFC 7692\n/**\n * NOTE: A value of 8 is not actually supported by zlib, the deflate\n * library that WebSocket++ uses. To preserve backwards compatibility\n * with RFC 7692 and previous versions of the library a value of 8\n * is accepted by the library but will always be negotiated as 9.\n */\nstatic uint8_t const min_server_max_window_bits = 8;\n/// Maximum value for server_max_window_bits as defined by RFC 7692\nstatic uint8_t const max_server_max_window_bits = 15;\n\n/// Default value for client_max_window_bits as defined by RFC 7692\nstatic uint8_t const default_client_max_window_bits = 15;\n/// Minimum value for client_max_window_bits as defined by RFC 7692\n/**\n * NOTE: A value of 8 is not actually supported by zlib, the deflate\n * library that WebSocket++ uses. To preserve backwards compatibility\n * with RFC 7692 and previous versions of the library a value of 8\n * is accepted by the library but will always be negotiated as 9.\n */\nstatic uint8_t const min_client_max_window_bits = 8;\n/// Maximum value for client_max_window_bits as defined by RFC 7692\nstatic uint8_t const max_client_max_window_bits = 15;\n\nnamespace mode {\nenum value {\n    /// Accept any value the remote endpoint offers\n    accept = 1,\n    /// Decline any value the remote endpoint offers. Insist on defaults.\n    decline,\n    /// Use the largest value common to both offers\n    largest,\n    /// Use the smallest value common to both offers\n    smallest\n};\n} // namespace mode\n\ntemplate <typename config>\nclass enabled {\npublic:\n    enabled()\n      : m_enabled(false)\n      , m_server_no_context_takeover(false)\n      , m_client_no_context_takeover(false)\n      , m_server_max_window_bits(15)\n      , m_client_max_window_bits(15)\n      , m_server_max_window_bits_mode(mode::accept)\n      , m_client_max_window_bits_mode(mode::accept)\n      , m_initialized(false)\n      , m_compress_buffer_size(8192)\n    {\n        m_dstate.zalloc = Z_NULL;\n        m_dstate.zfree = Z_NULL;\n        m_dstate.opaque = Z_NULL;\n\n        m_istate.zalloc = Z_NULL;\n        m_istate.zfree = Z_NULL;\n        m_istate.opaque = Z_NULL;\n        m_istate.avail_in = 0;\n        m_istate.next_in = Z_NULL;\n    }\n\n    ~enabled() {\n        if (!m_initialized) {\n            return;\n        }\n\n        int ret = deflateEnd(&m_dstate);\n\n        if (ret != Z_OK) {\n            //std::cout << \"error cleaning up zlib compression state\"\n            //          << std::endl;\n        }\n\n        ret = inflateEnd(&m_istate);\n\n        if (ret != Z_OK) {\n            //std::cout << \"error cleaning up zlib decompression state\"\n            //          << std::endl;\n        }\n    }\n\n    /// Initialize zlib state\n    /**\n     * Note: this should be called *after* the negotiation methods. It will use\n     * information from the negotiation to determine how to initialize the zlib\n     * data structures.\n     *\n     * @todo memory level, strategy, etc are hardcoded\n     *\n     * @param is_server True to initialize as a server, false for a client.\n     * @return A code representing the error that occurred, if any\n     */\n    lib::error_code init(bool is_server) {\n        uint8_t deflate_bits;\n        uint8_t inflate_bits;\n\n        if (is_server) {\n            deflate_bits = m_server_max_window_bits;\n            inflate_bits = m_client_max_window_bits;\n        } else {\n            deflate_bits = m_client_max_window_bits;\n            inflate_bits = m_server_max_window_bits;\n        }\n\n        int ret = deflateInit2(\n            &m_dstate,\n            Z_DEFAULT_COMPRESSION,\n            Z_DEFLATED,\n            -1*deflate_bits,\n            4, // memory level 1-9\n            Z_DEFAULT_STRATEGY\n        );\n\n        if (ret != Z_OK) {\n            return make_error_code(error::zlib_error);\n        }\n\n        ret = inflateInit2(\n            &m_istate,\n            -1*inflate_bits\n        );\n\n        if (ret != Z_OK) {\n            return make_error_code(error::zlib_error);\n        }\n\n        m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]);\n        m_decompress_buffer.reset(new unsigned char[m_compress_buffer_size]);\n        if ((m_server_no_context_takeover && is_server) ||\n            (m_client_no_context_takeover && !is_server))\n        {\n            m_flush = Z_FULL_FLUSH;\n        } else {\n            m_flush = Z_SYNC_FLUSH;\n        }\n        m_initialized = true;\n        return lib::error_code();\n    }\n\n    /// Test if this object implements the permessage-deflate specification\n    /**\n     * Because this object does implieent it, it will always return true.\n     *\n     * @return Whether or not this object implements permessage-deflate\n     */\n    bool is_implemented() const {\n        return true;\n    }\n\n    /// Test if the extension was negotiated for this connection\n    /**\n     * Retrieves whether or not this extension is in use based on the initial\n     * handshake extension negotiations.\n     *\n     * @return Whether or not the extension is in use\n     */\n    bool is_enabled() const {\n        return m_enabled;\n    }\n\n    /// Reset server's outgoing LZ77 sliding window for each new message\n    /**\n     * Enabling this setting will cause the server's compressor to reset the\n     * compression state (the LZ77 sliding window) for every message. This\n     * means that the compressor will not look back to patterns in previous\n     * messages to improve compression. This will reduce the compression\n     * efficiency for large messages somewhat and small messages drastically.\n     *\n     * This option may reduce server compressor memory usage and client\n     * decompressor memory usage.\n     * @todo Document to what extent memory usage will be reduced\n     *\n     * For clients, this option is dependent on server support. Enabling it\n     * via this method does not guarantee that it will be successfully\n     * negotiated, only that it will be requested.\n     *\n     * For servers, no client support is required. Enabling this option on a\n     * server will result in its use. The server will signal to clients that\n     * the option will be in use so they can optimize resource usage if they\n     * are able.\n     */\n    void enable_server_no_context_takeover() {\n        m_server_no_context_takeover = true;\n    }\n\n    /// Reset client's outgoing LZ77 sliding window for each new message\n    /**\n     * Enabling this setting will cause the client's compressor to reset the\n     * compression state (the LZ77 sliding window) for every message. This\n     * means that the compressor will not look back to patterns in previous\n     * messages to improve compression. This will reduce the compression\n     * efficiency for large messages somewhat and small messages drastically.\n     *\n     * This option may reduce client compressor memory usage and server\n     * decompressor memory usage.\n     * @todo Document to what extent memory usage will be reduced\n     *\n     * This option is supported by all compliant clients and servers. Enabling\n     * it via either endpoint should be sufficient to ensure it is used.\n     */\n    void enable_client_no_context_takeover() {\n        m_client_no_context_takeover = true;\n    }\n\n    /// Limit server LZ77 sliding window size\n    /**\n     * The bits setting is the base 2 logarithm of the maximum window size that\n     * the server must use to compress outgoing messages. The permitted range\n     * is 9 to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB\n     * window. The default setting is 15.\n     *\n     * Mode Options:\n     * - accept: Accept whatever the remote endpoint offers.\n     * - decline: Decline any offers to deviate from the defaults\n     * - largest: Accept largest window size acceptable to both endpoints\n     * - smallest: Accept smallest window size acceptiable to both endpoints\n     *\n     * This setting is dependent on server support. A client requesting this\n     * setting may be rejected by the server or have the exact value used\n     * adjusted by the server. A server may unilaterally set this value without\n     * client support.\n     *\n     * NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.\n     * Prior to version 0.8.0 a value of 8 was also allowed by this library.\n     * zlib, the deflate compression library that WebSocket++ uses has always\n     * silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9 \n     * and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0\n     * continues to perform the 8->9 conversion for backwards compatibility\n     * purposes but this should be considered deprecated functionality.\n     *\n     * @param bits The size to request for the outgoing window size\n     * @param mode The mode to use for negotiating this parameter\n     * @return A status code\n     */\n    lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode) {\n        if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {\n            return error::make_error_code(error::invalid_max_window_bits);\n        }\n\n        // See note in doc comment above about what is happening here\n        if (bits == 8) {\n            bits = 9;\n        }\n\n        m_server_max_window_bits = bits;\n        m_server_max_window_bits_mode = mode;\n\n        return lib::error_code();\n    }\n\n    /// Limit client LZ77 sliding window size\n    /**\n     * The bits setting is the base 2 logarithm of the window size that the\n     * client must use to compress outgoing messages. The permitted range is 9\n     * to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB window.\n     * The default setting is 15.\n     *\n     * Mode Options:\n     * - accept: Accept whatever the remote endpoint offers.\n     * - decline: Decline any offers to deviate from the defaults\n     * - largest: Accept largest window size acceptable to both endpoints\n     * - smallest: Accept smallest window size acceptiable to both endpoints\n     *\n     * This setting is dependent on client support. A client may limit its own\n     * outgoing window size unilaterally. A server may only limit the client's\n     * window size if the remote client supports that feature.\n     *\n     * NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.\n     * Prior to version 0.8.0 a value of 8 was also allowed by this library.\n     * zlib, the deflate compression library that WebSocket++ uses has always\n     * silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9 \n     * and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0\n     * continues to perform the 8->9 conversion for backwards compatibility\n     * purposes but this should be considered deprecated functionality.\n     *\n     * @param bits The size to request for the outgoing window size\n     * @param mode The mode to use for negotiating this parameter\n     * @return A status code\n     */\n    lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode) {\n        if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) {\n            return error::make_error_code(error::invalid_max_window_bits);\n        }\n\n        // See note in doc comment above about what is happening here\n        if (bits == 8) {\n            bits = 9;\n        }\n\n        m_client_max_window_bits = bits;\n        m_client_max_window_bits_mode = mode;\n\n        return lib::error_code();\n    }\n\n    /// Generate extension offer\n    /**\n     * Creates an offer string to include in the Sec-WebSocket-Extensions\n     * header of outgoing client requests.\n     *\n     * @return A WebSocket extension offer string for this extension\n     */\n    std::string generate_offer() const {\n        // TODO: this should be dynamically generated based on user settings\n        return \"permessage-deflate; client_no_context_takeover; client_max_window_bits\";\n    }\n\n    /// Validate extension response\n    /**\n     * Confirm that the server has negotiated settings compatible with our\n     * original offer and apply those settings to the extension state.\n     *\n     * @param response The server response attribute list to validate\n     * @return Validation error or 0 on success\n     */\n    lib::error_code validate_offer(http::attribute_list const &) {\n        return lib::error_code();\n    }\n\n    /// Negotiate extension\n    /**\n     * Confirm that the client's extension negotiation offer has settings\n     * compatible with local policy. If so, generate a reply and apply those\n     * settings to the extension state.\n     *\n     * @param offer Attribute from client's offer\n     * @return Status code and value to return to remote endpoint\n     */\n    err_str_pair negotiate(http::attribute_list const & offer) {\n        err_str_pair ret;\n\n        http::attribute_list::const_iterator it;\n        for (it = offer.begin(); it != offer.end(); ++it) {\n            if (it->first == \"server_no_context_takeover\") {\n                negotiate_server_no_context_takeover(it->second,ret.first);\n            } else if (it->first == \"client_no_context_takeover\") {\n                negotiate_client_no_context_takeover(it->second,ret.first);\n            } else if (it->first == \"server_max_window_bits\") {\n                negotiate_server_max_window_bits(it->second,ret.first);\n            } else if (it->first == \"client_max_window_bits\") {\n                negotiate_client_max_window_bits(it->second,ret.first);\n            } else {\n                ret.first = make_error_code(error::invalid_attributes);\n            }\n\n            if (ret.first) {\n                break;\n            }\n        }\n\n        if (ret.first == lib::error_code()) {\n            m_enabled = true;\n            ret.second = generate_response();\n        }\n\n        return ret;\n    }\n\n    /// Compress bytes\n    /**\n     * @todo: avail_in/out is 32 bit, need to fix for cases of >32 bit frames\n     * on 64 bit machines.\n     *\n     * @param [in] in String to compress\n     * @param [out] out String to append compressed bytes to\n     * @return Error or status code\n     */\n    lib::error_code compress(std::string const & in, std::string & out) {\n        if (!m_initialized) {\n            return make_error_code(error::uninitialized);\n        }\n\n        size_t output;\n\n        if (in.empty()) {\n            uint8_t buf[6] = {0x02, 0x00, 0x00, 0x00, 0xff, 0xff};\n            out.append((char *)(buf),6);\n            return lib::error_code();\n        }\n\n        m_dstate.avail_in = in.size();\n        m_dstate.next_in = (unsigned char *)(const_cast<char *>(in.data()));\n\n        do {\n            // Output to local buffer\n            m_dstate.avail_out = m_compress_buffer_size;\n            m_dstate.next_out = m_compress_buffer.get();\n\n            deflate(&m_dstate, m_flush);\n\n            output = m_compress_buffer_size - m_dstate.avail_out;\n\n            out.append((char *)(m_compress_buffer.get()),output);\n        } while (m_dstate.avail_out == 0);\n\n        return lib::error_code();\n    }\n\n    /// Decompress bytes\n    /**\n     * @param buf Byte buffer to decompress\n     * @param len Length of buf\n     * @param out String to append decompressed bytes to\n     * @return Error or status code\n     */\n    lib::error_code decompress(uint8_t const * buf, size_t len, std::string &\n        out)\n    {\n        if (!m_initialized) {\n            return make_error_code(error::uninitialized);\n        }\n\n        int ret;\n\n        m_istate.avail_in = len;\n        m_istate.next_in = const_cast<unsigned char *>(buf);\n\n        do {\n            m_istate.avail_out = m_compress_buffer_size;\n            m_istate.next_out = m_decompress_buffer.get();\n\n            ret = inflate(&m_istate, Z_SYNC_FLUSH);\n\n            if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {\n                return make_error_code(error::zlib_error);\n            }\n\n            out.append(\n                reinterpret_cast<char *>(m_decompress_buffer.get()),\n                m_compress_buffer_size - m_istate.avail_out\n            );\n        } while (m_istate.avail_out == 0);\n\n        return lib::error_code();\n    }\nprivate:\n    /// Generate negotiation response\n    /**\n     * @return Generate extension negotiation reponse string to send to client\n     */\n    std::string generate_response() {\n        std::string ret = \"permessage-deflate\";\n\n        if (m_server_no_context_takeover) {\n            ret += \"; server_no_context_takeover\";\n        }\n\n        if (m_client_no_context_takeover) {\n            ret += \"; client_no_context_takeover\";\n        }\n\n        if (m_server_max_window_bits < default_server_max_window_bits) {\n            std::stringstream s;\n            s << int(m_server_max_window_bits);\n            ret += \"; server_max_window_bits=\"+s.str();\n        }\n\n        if (m_client_max_window_bits < default_client_max_window_bits) {\n            std::stringstream s;\n            s << int(m_client_max_window_bits);\n            ret += \"; client_max_window_bits=\"+s.str();\n        }\n\n        return ret;\n    }\n\n    /// Negotiate server_no_context_takeover attribute\n    /**\n     * @param [in] value The value of the attribute from the offer\n     * @param [out] ec A reference to the error code to return errors via\n     */\n    void negotiate_server_no_context_takeover(std::string const & value,\n        lib::error_code & ec)\n    {\n        if (!value.empty()) {\n            ec = make_error_code(error::invalid_attribute_value);\n            return;\n        }\n\n        m_server_no_context_takeover = true;\n    }\n\n    /// Negotiate client_no_context_takeover attribute\n    /**\n     * @param [in] value The value of the attribute from the offer\n     * @param [out] ec A reference to the error code to return errors via\n     */\n    void negotiate_client_no_context_takeover(std::string const & value,\n        lib::error_code & ec)\n    {\n        if (!value.empty()) {\n            ec = make_error_code(error::invalid_attribute_value);\n            return;\n        }\n\n        m_client_no_context_takeover = true;\n    }\n\n    /// Negotiate server_max_window_bits attribute\n    /**\n     * When this method starts, m_server_max_window_bits will contain the server's\n     * preferred value and m_server_max_window_bits_mode will contain the mode the\n     * server wants to use to for negotiation. `value` contains the value the\n     * client requested that we use.\n     *\n     * options:\n     * - decline (ignore value, offer our default instead)\n     * - accept (use the value requested by the client)\n     * - largest (use largest value acceptable to both)\n     * - smallest (use smallest possible value)\n     *\n     * NOTE: As a value of 8 is no longer explicitly supported by zlib but might\n     * be requested for negotiation by an older client/server, if the result of\n     * the negotiation would be to send a value of 8, a value of 9 is offered\n     * instead. This ensures that WebSocket++ will only ever negotiate connections\n     * with compression settings explicitly supported by zlib.\n     *\n     * @param [in] value The value of the attribute from the offer\n     * @param [out] ec A reference to the error code to return errors via\n     */\n    void negotiate_server_max_window_bits(std::string const & value,\n        lib::error_code & ec)\n    {\n        uint8_t bits = uint8_t(atoi(value.c_str()));\n\n        if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {\n            ec = make_error_code(error::invalid_attribute_value);\n            m_server_max_window_bits = default_server_max_window_bits;\n            return;\n        }\n\n        switch (m_server_max_window_bits_mode) {\n            case mode::decline:\n                m_server_max_window_bits = default_server_max_window_bits;\n                break;\n            case mode::accept:\n                m_server_max_window_bits = bits;\n                break;\n            case mode::largest:\n                m_server_max_window_bits = std::min(bits,m_server_max_window_bits);\n                break;\n            case mode::smallest:\n                m_server_max_window_bits = min_server_max_window_bits;\n                break;\n            default:\n                ec = make_error_code(error::invalid_mode);\n                m_server_max_window_bits = default_server_max_window_bits;\n        }\n\n        // See note in doc comment\n        if (m_server_max_window_bits == 8) {\n            m_server_max_window_bits = 9;\n        }\n    }\n\n    /// Negotiate client_max_window_bits attribute\n    /**\n     * When this method starts, m_client_max_window_bits and m_c2s_max_window_mode\n     * will contain the server's preferred values for window size and\n     * negotiation mode.\n     *\n     * options:\n     * - decline (ignore value, offer our default instead)\n     * - accept (use the value requested by the client)\n     * - largest (use largest value acceptable to both)\n     * - smallest (use smallest possible value)\n     *\n     * NOTE: As a value of 8 is no longer explicitly supported by zlib but might\n     * be requested for negotiation by an older client/server, if the result of\n     * the negotiation would be to send a value of 8, a value of 9 is offered\n     * instead. This ensures that WebSocket++ will only ever negotiate connections\n     * with compression settings explicitly supported by zlib.\n     *\n     * @param [in] value The value of the attribute from the offer\n     * @param [out] ec A reference to the error code to return errors via\n     */\n    void negotiate_client_max_window_bits(std::string const & value,\n            lib::error_code & ec)\n    {\n        uint8_t bits = uint8_t(atoi(value.c_str()));\n\n        if (value.empty()) {\n            bits = default_client_max_window_bits;\n        } else if (bits < min_client_max_window_bits ||\n                   bits > max_client_max_window_bits)\n        {\n            ec = make_error_code(error::invalid_attribute_value);\n            m_client_max_window_bits = default_client_max_window_bits;\n            return;\n        }\n\n        switch (m_client_max_window_bits_mode) {\n            case mode::decline:\n                m_client_max_window_bits = default_client_max_window_bits;\n                break;\n            case mode::accept:\n                m_client_max_window_bits = bits;\n                break;\n            case mode::largest:\n                m_client_max_window_bits = std::min(bits,m_client_max_window_bits);\n                break;\n            case mode::smallest:\n                m_client_max_window_bits = min_client_max_window_bits;\n                break;\n            default:\n                ec = make_error_code(error::invalid_mode);\n                m_client_max_window_bits = default_client_max_window_bits;\n        }\n\n        // See note in doc comment\n        if (m_client_max_window_bits == 8) {\n            m_client_max_window_bits = 9;\n        }\n    }\n\n    bool m_enabled;\n    bool m_server_no_context_takeover;\n    bool m_client_no_context_takeover;\n    uint8_t m_server_max_window_bits;\n    uint8_t m_client_max_window_bits;\n    mode::value m_server_max_window_bits_mode;\n    mode::value m_client_max_window_bits_mode;\n\n    bool m_initialized;\n    int m_flush;\n    size_t m_compress_buffer_size;\n    lib::unique_ptr_uchar_array m_compress_buffer;\n    lib::unique_ptr_uchar_array m_decompress_buffer;\n    z_stream m_dstate;\n    z_stream m_istate;\n};\n\n} // namespace permessage_deflate\n} // namespace extensions\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP\n"
  },
  {
    "path": "websocketpp/frame.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_FRAME_HPP\n#define WEBSOCKETPP_FRAME_HPP\n\n#include <algorithm>\n#include <string>\n\n#include <websocketpp/common/system_error.hpp>\n#include <websocketpp/common/network.hpp>\n\n#include <websocketpp/utilities.hpp>\n\nnamespace websocketpp {\n/// Data structures and utility functions for manipulating WebSocket frames\n/**\n * namespace frame provides a number of data structures and utility functions\n * for reading, writing, and manipulating binary encoded WebSocket frames.\n */\nnamespace frame {\n\n/// Minimum length of a WebSocket frame header.\nstatic unsigned int const BASIC_HEADER_LENGTH = 2;\n/// Maximum length of a WebSocket header\nstatic unsigned int const MAX_HEADER_LENGTH = 14;\n/// Maximum length of the variable portion of the WebSocket header\nstatic unsigned int const MAX_EXTENDED_HEADER_LENGTH = 12;\n\n/// Two byte conversion union\nunion uint16_converter {\n    uint16_t i;\n    uint8_t  c[2];\n};\n\n/// Four byte conversion union\nunion uint32_converter {\n    uint32_t i;\n    uint8_t c[4];\n};\n\n/// Eight byte conversion union\nunion uint64_converter {\n    uint64_t i;\n    uint8_t  c[8];\n};\n\n/// Constants and utility functions related to WebSocket opcodes\n/**\n * WebSocket Opcodes are 4 bits. See RFC6455 section 5.2.\n */\nnamespace opcode {\n    enum value {\n        continuation = 0x0,\n        text = 0x1,\n        binary = 0x2,\n        rsv3 = 0x3,\n        rsv4 = 0x4,\n        rsv5 = 0x5,\n        rsv6 = 0x6,\n        rsv7 = 0x7,\n        close = 0x8,\n        ping = 0x9,\n        pong = 0xA,\n        control_rsvb = 0xB,\n        control_rsvc = 0xC,\n        control_rsvd = 0xD,\n        control_rsve = 0xE,\n        control_rsvf = 0xF,\n\n        CONTINUATION = 0x0,\n        TEXT = 0x1,\n        BINARY = 0x2,\n        RSV3 = 0x3,\n        RSV4 = 0x4,\n        RSV5 = 0x5,\n        RSV6 = 0x6,\n        RSV7 = 0x7,\n        CLOSE = 0x8,\n        PING = 0x9,\n        PONG = 0xA,\n        CONTROL_RSVB = 0xB,\n        CONTROL_RSVC = 0xC,\n        CONTROL_RSVD = 0xD,\n        CONTROL_RSVE = 0xE,\n        CONTROL_RSVF = 0xF\n    };\n\n    /// Check if an opcode is reserved\n    /**\n     * @param v The opcode to test.\n     * @return Whether or not the opcode is reserved.\n     */\n    inline bool reserved(value v) {\n        return (v >= rsv3 && v <= rsv7) ||\n               (v >= control_rsvb && v <= control_rsvf);\n    }\n\n    /// Check if an opcode is invalid\n    /**\n     * Invalid opcodes are negative or require greater than 4 bits to store.\n     *\n     * @param v The opcode to test.\n     * @return Whether or not the opcode is invalid.\n     */\n    inline bool invalid(value v) {\n        return (v > 0xF || v < 0);\n    }\n\n    /// Check if an opcode is for a control frame\n    /**\n     * @param v The opcode to test.\n     * @return Whether or not the opcode is a control opcode.\n     */\n    inline bool is_control(value v) {\n        return v >= 0x8;\n    }\n}\n\n/// Constants related to frame and payload limits\nnamespace limits {\n    /// Minimum length of a WebSocket frame header.\n    static unsigned int const basic_header_length = 2;\n\n    /// Maximum length of a WebSocket header\n    static unsigned int const max_header_length = 14;\n\n    /// Maximum length of the variable portion of the WebSocket header\n    static unsigned int const max_extended_header_length = 12;\n\n    /// Maximum size of a basic WebSocket payload\n    static uint8_t const payload_size_basic = 125;\n\n    /// Maximum size of an extended WebSocket payload (basic payload = 126)\n    static uint16_t const payload_size_extended = 0xFFFF; // 2^16, 65535\n\n    /// Maximum size of a jumbo WebSocket payload (basic payload = 127)\n    static uint64_t const payload_size_jumbo = 0x7FFFFFFFFFFFFFFFLL;//2^63\n\n    /// Maximum size of close frame reason\n    /**\n     * This is payload_size_basic - 2 bytes (as first two bytes are used for\n     * the close code\n     */\n    static uint8_t const close_reason_size = 123;\n}\n\n\n// masks for fields in the basic header\nstatic uint8_t const BHB0_OPCODE = 0x0F;\nstatic uint8_t const BHB0_RSV3 = 0x10;\nstatic uint8_t const BHB0_RSV2 = 0x20;\nstatic uint8_t const BHB0_RSV1 = 0x40;\nstatic uint8_t const BHB0_FIN = 0x80;\n\nstatic uint8_t const BHB1_PAYLOAD = 0x7F;\nstatic uint8_t const BHB1_MASK = 0x80;\n\nstatic uint8_t const payload_size_code_16bit = 0x7E; // 126\nstatic uint8_t const payload_size_code_64bit = 0x7F; // 127\n\ntypedef uint32_converter masking_key_type;\n\n/// The constant size component of a WebSocket frame header\nstruct basic_header {\n    basic_header() : b0(0x00),b1(0x00) {}\n\n    basic_header(uint8_t p0, uint8_t p1) : b0(p0), b1(p1) {}\n\n    basic_header(opcode::value op, uint64_t size, bool fin, bool mask,\n        bool rsv1 = false, bool rsv2 = false, bool rsv3 = false) : b0(0x00),\n        b1(0x00)\n    {\n        if (fin) {\n            b0 |= BHB0_FIN;\n        }\n        if (rsv1) {\n            b0 |= BHB0_RSV1;\n        }\n        if (rsv2) {\n            b0 |= BHB0_RSV2;\n        }\n        if (rsv3) {\n            b0 |= BHB0_RSV3;\n        }\n        b0 |= (op & BHB0_OPCODE);\n\n        if (mask) {\n            b1 |= BHB1_MASK;\n        }\n\n        uint8_t basic_value;\n\n        if (size <= limits::payload_size_basic) {\n            basic_value = static_cast<uint8_t>(size);\n        } else if (size <= limits::payload_size_extended) {\n            basic_value = payload_size_code_16bit;\n        } else {\n            basic_value = payload_size_code_64bit;\n        }\n\n\n        b1 |= basic_value;\n    }\n\n    uint8_t b0;\n    uint8_t b1;\n};\n\n/// The variable size component of a WebSocket frame header\nstruct extended_header {\n    extended_header() {\n        std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);\n    }\n\n    extended_header(uint64_t payload_size) {\n        std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);\n\n        copy_payload(payload_size);\n    }\n\n    extended_header(uint64_t payload_size, uint32_t masking_key) {\n        std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);\n\n        // Copy payload size\n        int offset = copy_payload(payload_size);\n\n        // Copy Masking Key\n        uint32_converter temp32;\n        temp32.i = masking_key;\n        std::copy(temp32.c,temp32.c+4,bytes+offset);\n    }\n\n    uint8_t bytes[MAX_EXTENDED_HEADER_LENGTH];\nprivate:\n    int copy_payload(uint64_t payload_size) {\n        int payload_offset = 0;\n\n        if (payload_size <= limits::payload_size_basic) {\n            payload_offset = 8;\n        } else if (payload_size <= limits::payload_size_extended) {\n            payload_offset = 6;\n        }\n\n        uint64_converter temp64;\n        temp64.i = lib::net::_htonll(payload_size);\n        std::copy(temp64.c+payload_offset,temp64.c+8,bytes);\n\n        return 8-payload_offset;\n    }\n};\n\nbool get_fin(basic_header const &h);\nvoid set_fin(basic_header &h, bool value);\nbool get_rsv1(basic_header const &h);\nvoid set_rsv1(basic_header &h, bool value);\nbool get_rsv2(basic_header const &h);\nvoid set_rsv2(basic_header &h, bool value);\nbool get_rsv3(basic_header const &h);\nvoid set_rsv3(basic_header &h, bool value);\nopcode::value get_opcode(basic_header const &h);\nbool get_masked(basic_header const &h);\nvoid set_masked(basic_header &h, bool value);\nuint8_t get_basic_size(basic_header const &);\nsize_t get_header_len(basic_header const &);\nunsigned int get_masking_key_offset(basic_header const &);\n\nstd::string write_header(basic_header const &, extended_header const &);\nmasking_key_type get_masking_key(basic_header const &, extended_header const &);\nuint16_t get_extended_size(extended_header const &);\nuint64_t get_jumbo_size(extended_header const &);\nuint64_t get_payload_size(basic_header const &, extended_header const &);\n\nsize_t prepare_masking_key(masking_key_type const & key);\nsize_t circshift_prepared_key(size_t prepared_key, size_t offset);\n\n// Functions for performing xor based masking and unmasking\ntemplate <typename input_iter, typename output_iter>\nvoid byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type\n    const & key, size_t key_offset = 0);\ntemplate <typename iter_type>\nvoid byte_mask(iter_type b, iter_type e, masking_key_type const & key,\n    size_t key_offset = 0);\nvoid word_mask_exact(uint8_t * input, uint8_t * output, size_t length,\n    masking_key_type const & key);\nvoid word_mask_exact(uint8_t * data, size_t length, masking_key_type const &\n    key);\nsize_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,\n    size_t prepared_key);\nsize_t word_mask_circ(uint8_t * data, size_t length, size_t prepared_key);\n\n/// Check whether the frame's FIN bit is set.\n/**\n * @param [in] h The basic header to extract from.\n * @return True if the header's fin bit is set.\n */\ninline bool get_fin(basic_header const & h) {\n    return ((h.b0 & BHB0_FIN) == BHB0_FIN);\n}\n\n/// Set the frame's FIN bit\n/**\n * @param [out] h Header to set.\n * @param [in] value Value to set it to.\n */\ninline void set_fin(basic_header & h, bool value) {\n    h.b0 = (value ? h.b0 | BHB0_FIN : h.b0 & ~BHB0_FIN);\n}\n\n/// check whether the frame's RSV1 bit is set\n/**\n * @param [in] h The basic header to extract from.\n * @return True if the header's RSV1 bit is set.\n */\ninline bool get_rsv1(const basic_header &h) {\n    return ((h.b0 & BHB0_RSV1) == BHB0_RSV1);\n}\n\n/// Set the frame's RSV1 bit\n/**\n * @param [out] h Header to set.\n * @param [in] value Value to set it to.\n */\ninline void set_rsv1(basic_header &h, bool value) {\n    h.b0 = (value ? h.b0 | BHB0_RSV1 : h.b0 & ~BHB0_RSV1);\n}\n\n/// check whether the frame's RSV2 bit is set\n/**\n * @param [in] h The basic header to extract from.\n * @return True if the header's RSV2 bit is set.\n */\ninline bool get_rsv2(const basic_header &h) {\n    return ((h.b0 & BHB0_RSV2) == BHB0_RSV2);\n}\n\n/// Set the frame's RSV2 bit\n/**\n * @param [out] h Header to set.\n * @param [in] value Value to set it to.\n */\ninline void set_rsv2(basic_header &h, bool value) {\n    h.b0 = (value ? h.b0 | BHB0_RSV2 : h.b0 & ~BHB0_RSV2);\n}\n\n/// check whether the frame's RSV3 bit is set\n/**\n * @param [in] h The basic header to extract from.\n * @return True if the header's RSV3 bit is set.\n */\ninline bool get_rsv3(const basic_header &h) {\n    return ((h.b0 & BHB0_RSV3) == BHB0_RSV3);\n}\n\n/// Set the frame's RSV3 bit\n/**\n * @param [out] h Header to set.\n * @param [in] value Value to set it to.\n */\ninline void set_rsv3(basic_header &h, bool value) {\n    h.b0 = (value ? h.b0 | BHB0_RSV3 : h.b0 & ~BHB0_RSV3);\n}\n\n/// Extract opcode from basic header\n/**\n * @param [in] h The basic header to extract from.\n * @return The opcode value of the header.\n */\ninline opcode::value get_opcode(const basic_header &h) {\n    return opcode::value(h.b0 & BHB0_OPCODE);\n}\n\n/// check whether the frame is masked\n/**\n * @param [in] h The basic header to extract from.\n * @return True if the header mask bit is set.\n */\ninline bool get_masked(basic_header const & h) {\n    return ((h.b1 & BHB1_MASK) == BHB1_MASK);\n}\n\n/// Set the frame's MASK bit\n/**\n * @param [out] h Header to set.\n * @param value Value to set it to.\n */\ninline void set_masked(basic_header & h, bool value) {\n    h.b1 = (value ? h.b1 | BHB1_MASK : h.b1 & ~BHB1_MASK);\n}\n\n/// Extracts the raw payload length specified in the basic header\n/**\n * A basic WebSocket frame header contains a 7 bit value that represents the\n * payload size. There are two reserved values that are used to indicate that\n * the actual payload size will not fit in 7 bits and that the full payload\n * size is included in a separate field. The values are as follows:\n *\n * PAYLOAD_SIZE_CODE_16BIT (0x7E) indicates that the actual payload is less\n * than 16 bit\n *\n * PAYLOAD_SIZE_CODE_64BIT (0x7F) indicates that the actual payload is less\n * than 63 bit\n *\n * @param [in] h Basic header to read value from.\n * @return The exact size encoded in h.\n */\ninline uint8_t get_basic_size(const basic_header &h) {\n    return h.b1 & BHB1_PAYLOAD;\n}\n\n/// Calculates the full length of the header based on the first bytes.\n/**\n * A WebSocket frame header always has at least two bytes. Encoded within the\n * first two bytes is all the information necessary to calculate the full\n * (variable) header length. get_header_len() calculates the full header\n * length for the given two byte basic header.\n *\n * @param h Basic frame header to extract size from.\n * @return Full length of the extended header.\n */\ninline size_t get_header_len(basic_header const & h) {\n    // TODO: check extensions?\n\n    // masking key offset represents the space used for the extended length\n    // fields\n    size_t size = BASIC_HEADER_LENGTH + get_masking_key_offset(h);\n\n    // If the header is masked there is a 4 byte masking key\n    if (get_masked(h)) {\n        size += 4;\n    }\n\n    return size;\n}\n\n/// Calculate the offset location of the masking key within the extended header\n/**\n * Calculate the offset location of the masking key within the extended header\n * using information from its corresponding basic header\n *\n * @param h Corresponding basic header to calculate from.\n *\n * @return byte offset of the first byte of the masking key\n */\ninline unsigned int get_masking_key_offset(const basic_header &h) {\n    if (get_basic_size(h) == payload_size_code_16bit) {\n        return 2;\n    } else if (get_basic_size(h) == payload_size_code_64bit) {\n        return 8;\n    } else {\n        return 0;\n    }\n}\n\n/// Generate a properly sized contiguous string that encodes a full frame header\n/**\n * Copy the basic header h and extended header e into a properly sized\n * contiguous frame header string for the purposes of writing out to the wire.\n *\n * @param h The basic header to include\n * @param e The extended header to include\n *\n * @return A contiguous string containing h and e\n */\ninline std::string prepare_header(const basic_header &h, const\n    extended_header &e)\n{\n    std::string ret;\n\n    ret.push_back(char(h.b0));\n    ret.push_back(char(h.b1));\n    ret.append(\n        reinterpret_cast<const char*>(e.bytes),\n        get_header_len(h)-BASIC_HEADER_LENGTH\n    );\n\n    return ret;\n}\n\n/// Extract the masking key from a frame header\n/**\n * Note that while read and written as an integer at times, this value is not\n * an integer and should never be interpreted as one. Big and little endian\n * machines will generate and store masking keys differently without issue as\n * long as the integer values remain irrelivant.\n *\n * @param h The basic header to extract from\n * @param e The extended header to extract from\n *\n * @return The masking key as an integer.\n */\ninline masking_key_type get_masking_key(const basic_header &h, const\n    extended_header &e)\n{\n    masking_key_type temp32;\n\n    if (!get_masked(h)) {\n        temp32.i = 0;\n    } else {\n        unsigned int offset = get_masking_key_offset(h);\n        std::copy(e.bytes+offset,e.bytes+offset+4,temp32.c);\n    }\n\n    return temp32;\n}\n\n/// Extract the extended size field from an extended header\n/**\n * It is the responsibility of the caller to verify that e is a valid extended\n * header. This function assumes that e contains an extended payload size.\n *\n * @param e The extended header to extract from\n *\n * @return The size encoded in the extended header in host byte order\n */\ninline uint16_t get_extended_size(const extended_header &e) {\n    uint16_converter temp16;\n    std::copy(e.bytes,e.bytes+2,temp16.c);\n    return ntohs(temp16.i);\n}\n\n/// Extract the jumbo size field from an extended header\n/**\n * It is the responsibility of the caller to verify that e is a valid extended\n * header. This function assumes that e contains a jumbo payload size.\n *\n * @param e The extended header to extract from\n *\n * @return The size encoded in the extended header in host byte order\n */\ninline uint64_t get_jumbo_size(const extended_header &e) {\n    uint64_converter temp64;\n    std::copy(e.bytes,e.bytes+8,temp64.c);\n    return lib::net::_ntohll(temp64.i);\n}\n\n/// Extract the full payload size field from a WebSocket header\n/**\n * It is the responsibility of the caller to verify that h and e together\n * represent a valid WebSocket frame header. This function assumes only that h\n * and e are valid. It uses information in the basic header to determine where\n * to look for the payload_size\n *\n * @param h The basic header to extract from\n * @param e The extended header to extract from\n *\n * @return The size encoded in the combined header in host byte order.\n */\ninline uint64_t get_payload_size(const basic_header &h, const\n    extended_header &e)\n{\n    uint8_t val = get_basic_size(h);\n\n    if (val <= limits::payload_size_basic) {\n        return val;\n    } else if (val == payload_size_code_16bit) {\n        return get_extended_size(e);\n    } else {\n        return get_jumbo_size(e);\n    }\n}\n\n/// Extract a masking key into a value the size of a machine word.\n/**\n * Machine word size must be 4 or 8.\n *\n * @param key Masking key to extract from\n *\n * @return prepared key as a machine word\n */\ninline size_t prepare_masking_key(const masking_key_type& key) {\n    size_t low_bits = static_cast<size_t>(key.i);\n\n    if (sizeof(size_t) == 8) {\n        uint64_t high_bits = static_cast<size_t>(key.i);\n        return static_cast<size_t>((high_bits << 32) | low_bits);\n    } else {\n        return low_bits;\n    }\n}\n\n/// circularly shifts the supplied prepared masking key by offset bytes\n/**\n * Prepared_key must be the output of prepare_masking_key with the associated\n * restrictions on the machine word size. offset must be greater than or equal\n * to zero and less than sizeof(size_t).\n */\ninline size_t circshift_prepared_key(size_t prepared_key, size_t offset) {\n    if (offset == 0) {\n        return prepared_key;\n    }\n    if (lib::net::is_little_endian()) {\n        size_t temp = prepared_key << (sizeof(size_t)-offset)*8;\n        return (prepared_key >> offset*8) | temp;\n    } else {\n        size_t temp = prepared_key >> (sizeof(size_t)-offset)*8;\n        return (prepared_key << offset*8) | temp;\n    }\n}\n\n/// Byte by byte mask/unmask\n/**\n * Iterator based byte by byte masking and unmasking for WebSocket payloads.\n * Performs masking in place using the supplied key offset by the supplied\n * offset number of bytes.\n *\n * This function is simple and can be done in place on input with arbitrary\n * lengths and does not vary based on machine word size. It is slow.\n *\n * @param b Beginning iterator to start masking\n *\n * @param e Ending iterator to end masking\n *\n * @param o Beginning iterator to store masked results\n *\n * @param key 32 bit key to mask with.\n *\n * @param key_offset offset value to start masking at.\n */\ntemplate <typename input_iter, typename output_iter>\nvoid byte_mask(input_iter first, input_iter last, output_iter result,\n    masking_key_type const & key, size_t key_offset)\n{\n    size_t key_index = key_offset%4;\n    while (first != last) {\n        *result = *first ^ key.c[key_index++];\n        key_index %= 4;\n        ++result;\n        ++first;\n    }\n}\n\n/// Byte by byte mask/unmask (in place)\n/**\n * Iterator based byte by byte masking and unmasking for WebSocket payloads.\n * Performs masking in place using the supplied key offset by the supplied\n * offset number of bytes.\n *\n * This function is simple and can be done in place on input with arbitrary\n * lengths and does not vary based on machine word size. It is slow.\n *\n * @param b Beginning iterator to start masking\n *\n * @param e Ending iterator to end masking\n *\n * @param key 32 bit key to mask with.\n *\n * @param key_offset offset value to start masking at.\n */\ntemplate <typename iter_type>\nvoid byte_mask(iter_type b, iter_type e, masking_key_type const & key,\n    size_t key_offset)\n{\n    byte_mask(b,e,b,key,key_offset);\n}\n\n/// Exact word aligned mask/unmask\n/**\n * Balanced combination of byte by byte and circular word by word masking.\n * Best used to mask complete messages at once. Has much higher setup costs than\n * word_mask_circ but works with exact sized buffers.\n *\n * Buffer based word by word masking and unmasking for WebSocket payloads.\n * Masking is done in word by word chunks with the remainder not divisible by\n * the word size done byte by byte.\n *\n * input and output must both be at least length bytes. Exactly length bytes\n * will be written.\n *\n * @param input buffer to mask or unmask\n *\n * @param output buffer to store the output. May be the same as input.\n *\n * @param length length of data buffer\n *\n * @param key Masking key to use\n */\ninline void word_mask_exact(uint8_t* input, uint8_t* output, size_t length,\n    const masking_key_type& key)\n{\n    size_t prepared_key = prepare_masking_key(key);\n    size_t n = length/sizeof(size_t);\n    size_t* input_word = reinterpret_cast<size_t*>(input);\n    size_t* output_word = reinterpret_cast<size_t*>(output);\n\n    for (size_t i = 0; i < n; i++) {\n        output_word[i] = input_word[i] ^ prepared_key;\n    }\n\n    for (size_t i = n*sizeof(size_t); i < length; i++) {\n        output[i] = input[i] ^ key.c[i%4];\n    }\n}\n\n/// Exact word aligned mask/unmask (in place)\n/**\n * In place version of word_mask_exact\n *\n * @see word_mask_exact\n *\n * @param data buffer to read and write from\n *\n * @param length length of data buffer\n *\n * @param key Masking key to use\n */\ninline void word_mask_exact(uint8_t* data, size_t length, const\n    masking_key_type& key)\n{\n    word_mask_exact(data,data,length,key);\n}\n\n/// Circular word aligned mask/unmask\n/**\n * Performs a circular mask/unmask in word sized chunks using pre-prepared keys\n * that store state between calls. Best for providing streaming masking or\n * unmasking of small chunks at a time of a larger message. Requires that the\n * underlying allocated size of the data buffer be a multiple of the word size.\n * Data in the buffer after `length` will be overwritten only with the same\n * values that were originally present.\n *\n * Buffer based word by word masking and unmasking for WebSocket payloads.\n * Performs masking in place using the supplied key. Casts the data buffer to\n * an array of size_t's and performs masking word by word. The underlying\n * buffer size must be a muliple of the word size.\n *\n * word_mask returns a copy of prepared_key circularly shifted based on the\n * length value. The returned value may be fed back into word_mask when more\n * data is available.\n *\n * input and output must both have length at least:\n *    ceil(length/sizeof(size_t))*sizeof(size_t)\n * Exactly that many bytes will be written, although only exactly length bytes\n * will be changed (trailing bytes will be replaced without masking)\n *\n * @param data Character buffer to mask\n *\n * @param length Length of data\n *\n * @param prepared_key Prepared key to use.\n *\n * @return the prepared_key shifted to account for the input length\n */\ninline size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,\n    size_t prepared_key)\n{\n    size_t n = length / sizeof(size_t); // whole words\n    size_t l = length - (n * sizeof(size_t)); // remaining bytes\n    size_t * input_word = reinterpret_cast<size_t *>(input);\n    size_t * output_word = reinterpret_cast<size_t *>(output);\n\n    // mask word by word\n    for (size_t i = 0; i < n; i++) {\n        output_word[i] = input_word[i] ^ prepared_key;\n    }\n\n    // mask partial word at the end\n    size_t start = length - l;\n    uint8_t * byte_key = reinterpret_cast<uint8_t *>(&prepared_key);\n    for (size_t i = 0; i < l; ++i) {\n        output[start+i] = input[start+i] ^ byte_key[i];\n    }\n\n    return circshift_prepared_key(prepared_key,l);\n}\n\n/// Circular word aligned mask/unmask (in place)\n/**\n * In place version of word_mask_circ\n *\n * @see word_mask_circ\n *\n * @param data Character buffer to read from and write to\n *\n * @param length Length of data\n *\n * @param prepared_key Prepared key to use.\n *\n * @return the prepared_key shifted to account for the input length\n */\ninline size_t word_mask_circ(uint8_t* data, size_t length, size_t prepared_key){\n    return word_mask_circ(data,data,length,prepared_key);\n}\n\n/// Circular byte aligned mask/unmask\n/**\n * Performs a circular mask/unmask in byte sized chunks using pre-prepared keys\n * that store state between calls. Best for providing streaming masking or\n * unmasking of small chunks at a time of a larger message. Requires that the\n * underlying allocated size of the data buffer be a multiple of the word size.\n * Data in the buffer after `length` will be overwritten only with the same\n * values that were originally present.\n *\n * word_mask returns a copy of prepared_key circularly shifted based on the\n * length value. The returned value may be fed back into byte_mask when more\n * data is available.\n *\n * @param data Character buffer to mask\n *\n * @param length Length of data\n *\n * @param prepared_key Prepared key to use.\n *\n * @return the prepared_key shifted to account for the input length\n */\ninline size_t byte_mask_circ(uint8_t * input, uint8_t * output, size_t length,\n    size_t prepared_key)\n{\n    uint32_converter key;\n    key.i = prepared_key;\n\n    for (size_t i = 0; i < length; ++i) {\n        output[i] = input[i] ^ key.c[i % 4];\n    }\n\n    return circshift_prepared_key(prepared_key,length % 4);\n}\n\n/// Circular byte aligned mask/unmask (in place)\n/**\n * In place version of byte_mask_circ\n *\n * @see byte_mask_circ\n *\n * @param data Character buffer to read from and write to\n *\n * @param length Length of data\n *\n * @param prepared_key Prepared key to use.\n *\n * @return the prepared_key shifted to account for the input length\n */\ninline size_t byte_mask_circ(uint8_t* data, size_t length, size_t prepared_key){\n    return byte_mask_circ(data,data,length,prepared_key);\n}\n\n} // namespace frame\n} // namespace websocketpp\n\n#endif //WEBSOCKETPP_FRAME_HPP\n"
  },
  {
    "path": "websocketpp/http/constants.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef HTTP_CONSTANTS_HPP\n#define HTTP_CONSTANTS_HPP\n\n#include <exception>\n#include <map>\n#include <string>\n#include <vector>\n#include <utility>\n\nnamespace websocketpp {\n/// HTTP handling support\nnamespace http {\n    /// The type of an HTTP attribute list\n    /**\n     * The attribute list is an unordered key/value map. Encoded attribute\n     * values are delimited by semicolons.\n     */\n    typedef std::map<std::string,std::string> attribute_list;\n\n    /// The type of an HTTP parameter list\n    /**\n     * The parameter list is an ordered pairing of a parameter and its\n     * associated attribute list. Encoded parameter values are delimited by\n     * commas.\n     */\n    typedef std::vector< std::pair<std::string,attribute_list> > parameter_list;\n\n    /// Literal value of the HTTP header delimiter\n    static char const header_delimiter[] = \"\\r\\n\";\n\n    /// Literal value of the HTTP header separator\n    static char const header_separator[] = \":\";\n\n    /// Literal value of an empty header\n    static std::string const empty_header;\n\n    /// Maximum size in bytes before rejecting an HTTP header as too big.\n    size_t const max_header_size = 16000;\n    \n    /// Default Maximum size in bytes for HTTP message bodies.\n    size_t const max_body_size = 32000000;\n\n    /// Number of bytes to use for temporary istream read buffers\n    size_t const istream_buffer = 512;\n\n    /// invalid HTTP token characters\n    /**\n     * 0x00 - 0x32, 0x7f-0xff\n     * ( ) < > @ , ; : \\ \" / [ ] ? = { }\n     */\n    static char const header_token[] = {\n        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..0f\n        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 10..1f\n        0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0, // 20..2f\n        1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, // 30..3f\n        0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 40..4f\n        1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1, // 50..5f\n        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 60..6f\n        1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0, // 70..7f\n        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 80..8f\n        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 90..9f\n        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // a0..af\n        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // b0..bf\n        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // c0..cf\n        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // d0..df\n        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // e0..ef\n        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // f0..ff\n    };\n\n    /// Is the character a token\n    inline bool is_token_char(unsigned char c) {\n        return (header_token[c] == 1);\n    }\n\n    /// Is the character a non-token\n    inline bool is_not_token_char(unsigned char c) {\n        return !header_token[c];\n    }\n\n    /// Is the character whitespace\n    /**\n     * whitespace is space (32) or horizontal tab (9)\n     */\n    inline bool is_whitespace_char(unsigned char c) {\n        return (c == 9 || c == 32);\n    }\n\n    /// Is the character non-whitespace\n    inline bool is_not_whitespace_char(unsigned char c) {\n        return (c != 9 && c != 32);\n    }\n\n    /// HTTP Status codes\n    namespace status_code {\n        enum value {\n            uninitialized = 0,\n\n            continue_code = 100,\n            switching_protocols = 101,\n\n            ok = 200,\n            created = 201,\n            accepted = 202,\n            non_authoritative_information = 203,\n            no_content = 204,\n            reset_content = 205,\n            partial_content = 206,\n\n            multiple_choices = 300,\n            moved_permanently = 301,\n            found = 302,\n            see_other = 303,\n            not_modified = 304,\n            use_proxy = 305,\n            temporary_redirect = 307,\n\n            bad_request = 400,\n            unauthorized = 401,\n            payment_required = 402,\n            forbidden = 403,\n            not_found = 404,\n            method_not_allowed = 405,\n            not_acceptable = 406,\n            proxy_authentication_required = 407,\n            request_timeout = 408,\n            conflict = 409,\n            gone = 410,\n            length_required = 411,\n            precondition_failed = 412,\n            request_entity_too_large = 413,\n            request_uri_too_long = 414,\n            unsupported_media_type = 415,\n            request_range_not_satisfiable = 416,\n            expectation_failed = 417,\n            im_a_teapot = 418,\n            upgrade_required = 426,\n            precondition_required = 428,\n            too_many_requests = 429,\n            request_header_fields_too_large = 431,\n\n            internal_server_error = 500,\n            not_implemented = 501,\n            bad_gateway = 502,\n            service_unavailable = 503,\n            gateway_timeout = 504,\n            http_version_not_supported = 505,\n            not_extended = 510,\n            network_authentication_required = 511\n        };\n\n        // TODO: should this be inline?\n        inline std::string get_string(value c) {\n            switch (c) {\n                case uninitialized:\n                    return \"Uninitialized\";\n                case continue_code:\n                    return \"Continue\";\n                case switching_protocols:\n                    return \"Switching Protocols\";\n                case ok:\n                    return \"OK\";\n                case created:\n                    return \"Created\";\n                case accepted:\n                    return \"Accepted\";\n                case non_authoritative_information:\n                    return \"Non Authoritative Information\";\n                case no_content:\n                    return \"No Content\";\n                case reset_content:\n                    return \"Reset Content\";\n                case partial_content:\n                    return \"Partial Content\";\n                case multiple_choices:\n                    return \"Multiple Choices\";\n                case moved_permanently:\n                    return \"Moved Permanently\";\n                case found:\n                    return \"Found\";\n                case see_other:\n                    return \"See Other\";\n                case not_modified:\n                    return \"Not Modified\";\n                case use_proxy:\n                    return \"Use Proxy\";\n                case temporary_redirect:\n                    return \"Temporary Redirect\";\n                case bad_request:\n                    return \"Bad Request\";\n                case unauthorized:\n                    return \"Unauthorized\";\n                case payment_required:\n                    return \"Payment Required\";\n                case forbidden:\n                    return \"Forbidden\";\n                case not_found:\n                    return \"Not Found\";\n                case method_not_allowed:\n                    return \"Method Not Allowed\";\n                case not_acceptable:\n                    return \"Not Acceptable\";\n                case proxy_authentication_required:\n                    return \"Proxy Authentication Required\";\n                case request_timeout:\n                    return \"Request Timeout\";\n                case conflict:\n                    return \"Conflict\";\n                case gone:\n                    return \"Gone\";\n                case length_required:\n                    return \"Length Required\";\n                case precondition_failed:\n                    return \"Precondition Failed\";\n                case request_entity_too_large:\n                    return \"Request Entity Too Large\";\n                case request_uri_too_long:\n                    return \"Request-URI Too Long\";\n                case unsupported_media_type:\n                    return \"Unsupported Media Type\";\n                case request_range_not_satisfiable:\n                    return \"Requested Range Not Satisfiable\";\n                case expectation_failed:\n                    return \"Expectation Failed\";\n                case im_a_teapot:\n                    return \"I'm a teapot\";\n                case upgrade_required:\n                    return \"Upgrade Required\";\n                case precondition_required:\n                    return \"Precondition Required\";\n                case too_many_requests:\n                    return \"Too Many Requests\";\n                case request_header_fields_too_large:\n                    return \"Request Header Fields Too Large\";\n                case internal_server_error:\n                    return \"Internal Server Error\";\n                case not_implemented:\n                    return \"Not Implemented\";\n                case bad_gateway:\n                    return \"Bad Gateway\";\n                case service_unavailable:\n                    return \"Service Unavailable\";\n                case gateway_timeout:\n                    return \"Gateway Timeout\";\n                case http_version_not_supported:\n                    return \"HTTP Version Not Supported\";\n                case not_extended:\n                    return \"Not Extended\";\n                case network_authentication_required:\n                    return \"Network Authentication Required\";\n                default:\n                    return \"Unknown\";\n            }\n        }\n    }\n\n    class exception : public std::exception {\n    public:\n        exception(const std::string& log_msg,\n                  status_code::value error_code,\n                  const std::string& error_msg = std::string(),\n                  const std::string& body = std::string())\n          : m_msg(log_msg)\n          , m_error_msg(error_msg)\n          , m_body(body)\n          , m_error_code(error_code) {}\n\n        ~exception() throw() {}\n\n        virtual const char* what() const throw() {\n            return m_msg.c_str();\n        }\n\n        std::string         m_msg;\n        std::string         m_error_msg;\n        std::string         m_body;\n        status_code::value  m_error_code;\n    };\n}\n}\n\n#endif // HTTP_CONSTANTS_HPP\n"
  },
  {
    "path": "websocketpp/http/impl/parser.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef HTTP_PARSER_IMPL_HPP\n#define HTTP_PARSER_IMPL_HPP\n\n#include <algorithm>\n#include <cstdlib>\n#include <istream>\n#include <sstream>\n#include <string>\n\nnamespace websocketpp {\nnamespace http {\nnamespace parser {\n\ninline void parser::set_version(std::string const & version) {\n    m_version = version;\n}\n\ninline std::string const & parser::get_header(std::string const & key) const {\n    header_list::const_iterator h = m_headers.find(key);\n\n    if (h == m_headers.end()) {\n        return empty_header;\n    } else {\n        return h->second;\n    }\n}\n\ninline bool parser::get_header_as_plist(std::string const & key,\n    parameter_list & out) const\n{\n    header_list::const_iterator it = m_headers.find(key);\n\n    if (it == m_headers.end() || it->second.size() == 0) {\n        return false;\n    }\n\n    return this->parse_parameter_list(it->second,out);\n}\n\ninline void parser::append_header(std::string const & key, std::string const &\n    val)\n{\n    if (std::find_if(key.begin(),key.end(),is_not_token_char) != key.end()) {\n        throw exception(\"Invalid header name\",status_code::bad_request);\n    }\n\n    if (this->get_header(key).empty()) {\n        m_headers[key] = val;\n    } else {\n        m_headers[key] += \", \" + val;\n    }\n}\n\ninline void parser::replace_header(std::string const & key, std::string const &\n    val)\n{\n    m_headers[key] = val;\n}\n\ninline void parser::remove_header(std::string const & key) {\n    m_headers.erase(key);\n}\n\ninline void parser::set_body(std::string const & value) {\n    if (value.size() == 0) {\n        remove_header(\"Content-Length\");\n        m_body.clear();\n        return;\n    }\n\n    // TODO: should this method respect the max size? If so how should errors\n    // be indicated?\n\n    std::stringstream len;\n    len << value.size();\n    replace_header(\"Content-Length\", len.str());\n    m_body = value;\n}\n\ninline bool parser::parse_parameter_list(std::string const & in,\n    parameter_list & out) const\n{\n    if (in.size() == 0) {\n        return false;\n    }\n\n    std::string::const_iterator it;\n    it = extract_parameters(in.begin(),in.end(),out);\n    return (it == in.begin());\n}\n\ninline bool parser::prepare_body() {\n    if (!get_header(\"Content-Length\").empty()) {\n        std::string const & cl_header = get_header(\"Content-Length\");\n        char * end;\n        \n        // TODO: not 100% sure what the compatibility of this method is. Also,\n        // I believe this will only work up to 32bit sizes. Is there a need for\n        // > 4GiB HTTP payloads?\n        m_body_bytes_needed = std::strtoul(cl_header.c_str(),&end,10);\n        \n        if (m_body_bytes_needed > m_body_bytes_max) {\n            throw exception(\"HTTP message body too large\",\n                status_code::request_entity_too_large);\n        }\n        \n        m_body_encoding = body_encoding::plain;\n        return true;\n    } else if (get_header(\"Transfer-Encoding\") == \"chunked\") {\n        // TODO\n        //m_body_encoding = body_encoding::chunked;\n        return false;\n    } else {\n        return false;\n    }\n}\n\ninline size_t parser::process_body(char const * buf, size_t len) {\n    if (m_body_encoding == body_encoding::plain) {\n        size_t processed = (std::min)(m_body_bytes_needed,len);\n        m_body.append(buf,processed);\n        m_body_bytes_needed -= processed;\n        return processed;\n    } else if (m_body_encoding == body_encoding::chunked) {\n        // TODO: \n        throw exception(\"Unexpected body encoding\",\n            status_code::internal_server_error);\n    } else {\n        throw exception(\"Unexpected body encoding\",\n            status_code::internal_server_error);\n    }\n}\n\ninline void parser::process_header(std::string::iterator begin,\n    std::string::iterator end)\n{\n    std::string::iterator cursor = std::search(\n        begin,\n        end,\n        header_separator,\n        header_separator + sizeof(header_separator) - 1\n    );\n\n    if (cursor == end) {\n        throw exception(\"Invalid header line\",status_code::bad_request);\n    }\n\n    append_header(strip_lws(std::string(begin,cursor)),\n                  strip_lws(std::string(cursor+sizeof(header_separator)-1,end)));\n}\n\ninline header_list const & parser::get_headers() const {\n    return m_headers;\n}\n\ninline std::string parser::raw_headers() const {\n    std::stringstream raw;\n\n    header_list::const_iterator it;\n    for (it = m_headers.begin(); it != m_headers.end(); it++) {\n        raw << it->first << \": \" << it->second << \"\\r\\n\";\n    }\n\n    return raw.str();\n}\n\n\n\n} // namespace parser\n} // namespace http\n} // namespace websocketpp\n\n#endif // HTTP_PARSER_IMPL_HPP\n"
  },
  {
    "path": "websocketpp/http/impl/request.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef HTTP_PARSER_REQUEST_IMPL_HPP\n#define HTTP_PARSER_REQUEST_IMPL_HPP\n\n#include <algorithm>\n#include <sstream>\n#include <string>\n\n#include <websocketpp/http/parser.hpp>\n\nnamespace websocketpp {\nnamespace http {\nnamespace parser {\n\ninline size_t request::consume(char const * buf, size_t len) {\n    size_t bytes_processed;\n    \n    if (m_ready) {return 0;}\n    \n    if (m_body_bytes_needed > 0) {\n        bytes_processed = process_body(buf,len);\n        if (body_ready()) {\n            m_ready = true;\n        }\n        return bytes_processed;\n    }\n\n    // copy new header bytes into buffer\n    m_buf->append(buf,len);\n\n    // Search for delimiter in buf. If found read until then. If not read all\n    std::string::iterator begin = m_buf->begin();\n    std::string::iterator end;\n\n    for (;;) {\n        // search for line delimiter\n        end = std::search(\n            begin,\n            m_buf->end(),\n            header_delimiter,\n            header_delimiter+sizeof(header_delimiter)-1\n        );\n        \n        m_header_bytes += (end-begin+sizeof(header_delimiter));\n        \n        if (m_header_bytes > max_header_size) {\n            // exceeded max header size\n            throw exception(\"Maximum header size exceeded.\",\n                status_code::request_header_fields_too_large);\n        }\n\n        if (end == m_buf->end()) {\n            // we are out of bytes. Discard the processed bytes and copy the\n            // remaining unprecessed bytes to the beginning of the buffer\n            std::copy(begin,end,m_buf->begin());\n            m_buf->resize(static_cast<std::string::size_type>(end-begin));\n            m_header_bytes -= m_buf->size();\n\n            return len;\n        }\n\n        //the range [begin,end) now represents a line to be processed.\n        if (end-begin == 0) {\n            // we got a blank line\n            if (m_method.empty() || get_header(\"Host\").empty()) {\n                throw exception(\"Incomplete Request\",status_code::bad_request);\n            }\n\n            bytes_processed = (\n                len - static_cast<std::string::size_type>(m_buf->end()-end)\n                    + sizeof(header_delimiter) - 1\n            );\n\n            // frees memory used temporarily during request parsing\n            m_buf.reset();\n\n            // if this was not an upgrade request and has a content length\n            // continue capturing content-length bytes and expose them as a \n            // request body.\n            \n            if (prepare_body()) {\n                bytes_processed += process_body(buf+bytes_processed,len-bytes_processed);\n                if (body_ready()) {\n                    m_ready = true;\n                }\n                return bytes_processed;\n            } else {\n                m_ready = true;\n\n                // return number of bytes processed (starting bytes - bytes left)\n                return bytes_processed;\n            }\n        } else {\n            if (m_method.empty()) {\n                this->process(begin,end);\n            } else {\n                this->process_header(begin,end);\n            }\n        }\n\n        begin = end+(sizeof(header_delimiter)-1);\n    }\n}\n\ninline std::string request::raw() const {\n    // TODO: validation. Make sure all required fields have been set?\n    std::stringstream ret;\n\n    ret << m_method << \" \" << m_uri << \" \" << get_version() << \"\\r\\n\";\n    ret << raw_headers() << \"\\r\\n\" << m_body;\n\n    return ret.str();\n}\n\ninline std::string request::raw_head() const {\n    // TODO: validation. Make sure all required fields have been set?\n    std::stringstream ret;\n\n    ret << m_method << \" \" << m_uri << \" \" << get_version() << \"\\r\\n\";\n    ret << raw_headers() << \"\\r\\n\";\n\n    return ret.str();\n}\n\ninline void request::set_method(std::string const & method) {\n    if (std::find_if(method.begin(),method.end(),is_not_token_char) != method.end()) {\n        throw exception(\"Invalid method token.\",status_code::bad_request);\n    }\n\n    m_method = method;\n}\n\ninline void request::set_uri(std::string const & uri) {\n    // TODO: validation?\n    m_uri = uri;\n}\n\ninline void request::process(std::string::iterator begin, std::string::iterator\n    end)\n{\n    std::string::iterator cursor_start = begin;\n    std::string::iterator cursor_end = std::find(begin,end,' ');\n\n    if (cursor_end == end) {\n        throw exception(\"Invalid request line1\",status_code::bad_request);\n    }\n\n    set_method(std::string(cursor_start,cursor_end));\n\n    cursor_start = cursor_end+1;\n    cursor_end = std::find(cursor_start,end,' ');\n\n    if (cursor_end == end) {\n        throw exception(\"Invalid request line2\",status_code::bad_request);\n    }\n\n    set_uri(std::string(cursor_start,cursor_end));\n    set_version(std::string(cursor_end+1,end));\n}\n\n} // namespace parser\n} // namespace http\n} // namespace websocketpp\n\n#endif // HTTP_PARSER_REQUEST_IMPL_HPP\n"
  },
  {
    "path": "websocketpp/http/impl/response.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef HTTP_PARSER_RESPONSE_IMPL_HPP\n#define HTTP_PARSER_RESPONSE_IMPL_HPP\n\n#include <algorithm>\n#include <istream>\n#include <sstream>\n#include <string>\n\n#include <websocketpp/http/parser.hpp>\n\nnamespace websocketpp {\nnamespace http {\nnamespace parser {\n\ninline size_t response::consume(char const * buf, size_t len) {\n    if (m_state == DONE) {return 0;}\n\n    if (m_state == BODY) {\n        return this->process_body(buf,len);\n    }\n\n    // copy new header bytes into buffer\n    m_buf->append(buf,len);\n\n    // Search for delimiter in buf. If found read until then. If not read all\n    std::string::iterator begin = m_buf->begin();\n    std::string::iterator end = begin;\n\n\n    for (;;) {\n        // search for delimiter\n        end = std::search(\n            begin,\n            m_buf->end(),\n            header_delimiter,\n            header_delimiter + sizeof(header_delimiter) - 1\n        );\n\n        m_header_bytes += (end-begin+sizeof(header_delimiter));\n        \n        if (m_header_bytes > max_header_size) {\n            // exceeded max header size\n            throw exception(\"Maximum header size exceeded.\",\n                status_code::request_header_fields_too_large);\n        }\n\n        if (end == m_buf->end()) {\n            // we are out of bytes. Discard the processed bytes and copy the\n            // remaining unprecessed bytes to the beginning of the buffer\n            std::copy(begin,end,m_buf->begin());\n            m_buf->resize(static_cast<std::string::size_type>(end-begin));\n\n            m_read += len;\n            m_header_bytes -= m_buf->size();\n\n            return len;\n        }\n\n        //the range [begin,end) now represents a line to be processed.\n\n        if (end-begin == 0) {\n            // we got a blank line\n            if (m_state == RESPONSE_LINE) {\n                throw exception(\"Incomplete Request\",status_code::bad_request);\n            }\n\n            // TODO: grab content-length\n            std::string length = get_header(\"Content-Length\");\n\n            if (length.empty()) {\n                // no content length found, read indefinitely\n                m_read = 0;\n            } else {\n                std::istringstream ss(length);\n\n                if ((ss >> m_read).fail()) {\n                    throw exception(\"Unable to parse Content-Length header\",\n                                    status_code::bad_request);\n                }\n            }\n\n            m_state = BODY;\n\n            // calc header bytes processed (starting bytes - bytes left)\n            size_t read = (\n                len - static_cast<std::string::size_type>(m_buf->end() - end)\n                + sizeof(header_delimiter) - 1\n            );\n\n            // if there were bytes left process them as body bytes\n            if (read < len) {\n                read += this->process_body(buf+read,(len-read));\n            }\n\n            // frees memory used temporarily during header parsing\n            m_buf.reset();\n\n            return read;\n        } else {\n            if (m_state == RESPONSE_LINE) {\n                this->process(begin,end);\n                m_state = HEADERS;\n            } else {\n                this->process_header(begin,end);\n            }\n        }\n\n        begin = end+(sizeof(header_delimiter) - 1);\n    }\n}\n\ninline size_t response::consume(std::istream & s) {\n    char buf[istream_buffer];\n    size_t bytes_read;\n    size_t bytes_processed;\n    size_t total = 0;\n\n    while (s.good()) {\n        s.getline(buf,istream_buffer);\n        bytes_read = static_cast<size_t>(s.gcount());\n\n        if (s.fail() || s.eof()) {\n            bytes_processed = this->consume(buf,bytes_read);\n            total += bytes_processed;\n\n            if (bytes_processed != bytes_read) {\n                // problem\n                break;\n            }\n        } else if (s.bad()) {\n            // problem\n            break;\n        } else {\n            // the delimiting newline was found. Replace the trailing null with\n            // the newline that was discarded, since our raw consume function\n            // expects the newline to be be there.\n            buf[bytes_read-1] = '\\n';\n            bytes_processed = this->consume(buf,bytes_read);\n            total += bytes_processed;\n\n            if (bytes_processed != bytes_read) {\n                // problem\n                break;\n            }\n        }\n    }\n\n    return total;\n}\n\ninline std::string response::raw() const {\n    // TODO: validation. Make sure all required fields have been set?\n\n    std::stringstream ret;\n\n    ret << get_version() << \" \" << m_status_code << \" \" << m_status_msg;\n    ret << \"\\r\\n\" << raw_headers() << \"\\r\\n\";\n\n    ret << m_body;\n\n    return ret.str();\n}\n\ninline void response::set_status(status_code::value code) {\n    // TODO: validation?\n    m_status_code = code;\n    m_status_msg = get_string(code);\n}\n\ninline void response::set_status(status_code::value code, std::string const &\n    msg)\n{\n    // TODO: validation?\n    m_status_code = code;\n    m_status_msg = msg;\n}\n\ninline void response::process(std::string::iterator begin,\n    std::string::iterator end)\n{\n    std::string::iterator cursor_start = begin;\n    std::string::iterator cursor_end = std::find(begin,end,' ');\n\n    if (cursor_end == end) {\n        throw exception(\"Invalid response line\",status_code::bad_request);\n    }\n\n    set_version(std::string(cursor_start,cursor_end));\n\n    cursor_start = cursor_end+1;\n    cursor_end = std::find(cursor_start,end,' ');\n\n    if (cursor_end == end) {\n        throw exception(\"Invalid request line\",status_code::bad_request);\n    }\n\n    int code;\n\n    std::istringstream ss(std::string(cursor_start,cursor_end));\n\n    if ((ss >> code).fail()) {\n        throw exception(\"Unable to parse response code\",status_code::bad_request);\n    }\n\n    set_status(status_code::value(code),std::string(cursor_end+1,end));\n}\n\ninline size_t response::process_body(char const * buf, size_t len) {\n    // If no content length was set then we read forever and never set m_ready\n    if (m_read == 0) {\n        //m_body.append(buf,len);\n        //return len;\n        m_state = DONE;\n        return 0;\n    }\n\n    // Otherwise m_read is the number of bytes left.\n    size_t to_read;\n\n    if (len >= m_read) {\n        // if we have more bytes than we need read, read only the amount needed\n        // then set done state\n        to_read = m_read;\n        m_state = DONE;\n    } else {\n        // we need more bytes than are available, read them all\n        to_read = len;\n    }\n\n    m_body.append(buf,to_read);\n    m_read -= to_read;\n    return to_read;\n}\n\n} // namespace parser\n} // namespace http\n} // namespace websocketpp\n\n#endif // HTTP_PARSER_RESPONSE_IMPL_HPP\n"
  },
  {
    "path": "websocketpp/http/parser.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef HTTP_PARSER_HPP\n#define HTTP_PARSER_HPP\n\n#include <algorithm>\n#include <map>\n#include <string>\n#include <utility>\n\n#include <websocketpp/utilities.hpp>\n#include <websocketpp/http/constants.hpp>\n\nnamespace websocketpp {\nnamespace http {\nnamespace parser {\n\nnamespace state {\n    enum value {\n        method,\n        resource,\n        version,\n        headers\n    };\n}\n\nnamespace body_encoding {\n    enum value {\n        unknown,\n        plain,\n        chunked\n    };\n}\n\ntypedef std::map<std::string, std::string, utility::ci_less > header_list;\n\n/// Read and return the next token in the stream\n/**\n * Read until a non-token character is found and then return the token and\n * iterator to the next character to read\n *\n * @param begin An iterator to the beginning of the sequence\n * @param end An iterator to the end of the sequence\n * @return A pair containing the token and an iterator to the next character in\n * the stream\n */\ntemplate <typename InputIterator>\nstd::pair<std::string,InputIterator> extract_token(InputIterator begin,\n    InputIterator end)\n{\n    InputIterator it = std::find_if(begin,end,&is_not_token_char);\n    return std::make_pair(std::string(begin,it),it);\n}\n\n/// Read and return the next quoted string in the stream\n/**\n * Read a double quoted string starting at `begin`. The quotes themselves are\n * stripped. The quoted value is returned along with an iterator to the next\n * character to read\n *\n * @param begin An iterator to the beginning of the sequence\n * @param end An iterator to the end of the sequence\n * @return A pair containing the string read and an iterator to the next\n * character in the stream\n */\ntemplate <typename InputIterator>\nstd::pair<std::string,InputIterator> extract_quoted_string(InputIterator begin,\n    InputIterator end)\n{\n    std::string s;\n\n    if (end == begin) {\n        return std::make_pair(s,begin);\n    }\n\n    if (*begin != '\"') {\n        return std::make_pair(s,begin);\n    }\n\n    InputIterator cursor = begin+1;\n    InputIterator marker = cursor;\n\n    cursor = std::find(cursor,end,'\"');\n\n    while (cursor != end) {\n        // either this is the end or a quoted string\n        if (*(cursor-1) == '\\\\') {\n            s.append(marker,cursor-1);\n            s.append(1,'\"');\n            ++cursor;\n            marker = cursor;\n        } else {\n            s.append(marker,cursor);\n            ++cursor;\n            return std::make_pair(s,cursor);\n        }\n\n        cursor = std::find(cursor,end,'\"');\n    }\n\n    return std::make_pair(\"\",begin);\n}\n\n/// Read and discard one unit of linear whitespace\n/**\n * Read one unit of linear white space and return the iterator to the character\n * afterwards. If `begin` is returned, no whitespace was extracted.\n *\n * @param begin An iterator to the beginning of the sequence\n * @param end An iterator to the end of the sequence\n * @return An iterator to the character after the linear whitespace read\n */\ntemplate <typename InputIterator>\nInputIterator extract_lws(InputIterator begin, InputIterator end) {\n    InputIterator it = begin;\n\n    // strip leading CRLF\n    if (end-begin > 2 && *begin == '\\r' && *(begin+1) == '\\n' &&\n        is_whitespace_char(static_cast<unsigned char>(*(begin+2))))\n    {\n        it+=3;\n    }\n\n    it = std::find_if(it,end,&is_not_whitespace_char);\n    return it;\n}\n\n/// Read and discard linear whitespace\n/**\n * Read linear white space until a non-lws character is read and return an\n * iterator to that character. If `begin` is returned, no whitespace was\n * extracted.\n *\n * @param begin An iterator to the beginning of the sequence\n * @param end An iterator to the end of the sequence\n * @return An iterator to the character after the linear whitespace read\n */\ntemplate <typename InputIterator>\nInputIterator extract_all_lws(InputIterator begin, InputIterator end) {\n    InputIterator old_it;\n    InputIterator new_it = begin;\n\n    do {\n        // Pull value from previous iteration\n        old_it = new_it;\n\n        // look ahead another pass\n        new_it = extract_lws(old_it,end);\n    } while (new_it != end && old_it != new_it);\n\n    return new_it;\n}\n\n/// Extract HTTP attributes\n/**\n * An http attributes list is a semicolon delimited list of key value pairs in\n * the format: *( \";\" attribute \"=\" value ) where attribute is a token and value\n * is a token or quoted string.\n *\n * Attributes extracted are appended to the supplied attributes list\n * `attributes`.\n *\n * @param [in] begin An iterator to the beginning of the sequence\n * @param [in] end An iterator to the end of the sequence\n * @param [out] attributes A reference to the attributes list to append\n * attribute/value pairs extracted to\n * @return An iterator to the character after the last atribute read\n */\ntemplate <typename InputIterator>\nInputIterator extract_attributes(InputIterator begin, InputIterator end,\n    attribute_list & attributes)\n{\n    InputIterator cursor;\n    bool first = true;\n\n    if (begin == end) {\n        return begin;\n    }\n\n    cursor = begin;\n    std::pair<std::string,InputIterator> ret;\n\n    while (cursor != end) {\n        std::string name;\n\n        cursor = http::parser::extract_all_lws(cursor,end);\n        if (cursor == end) {\n            break;\n        }\n\n        if (first) {\n            // ignore this check for the very first pass\n            first = false;\n        } else {\n            if (*cursor == ';') {\n                // advance past the ';'\n                ++cursor;\n            } else {\n                // non-semicolon in this position indicates end end of the\n                // attribute list, break and return.\n                break;\n            }\n        }\n\n        cursor = http::parser::extract_all_lws(cursor,end);\n        ret = http::parser::extract_token(cursor,end);\n\n        if (ret.first.empty()) {\n            // error: expected a token\n            return begin;\n        } else {\n            name = ret.first;\n            cursor = ret.second;\n        }\n\n        cursor = http::parser::extract_all_lws(cursor,end);\n        if (cursor == end || *cursor != '=') {\n            // if there is an equals sign, read the attribute value. Otherwise\n            // record a blank value and continue\n            attributes[name].clear();\n            continue;\n        }\n\n        // advance past the '='\n        ++cursor;\n\n        cursor = http::parser::extract_all_lws(cursor,end);\n        if (cursor == end) {\n            // error: expected a token or quoted string\n            return begin;\n        }\n\n        ret = http::parser::extract_quoted_string(cursor,end);\n        if (ret.second != cursor) {\n            attributes[name] = ret.first;\n            cursor = ret.second;\n            continue;\n        }\n\n        ret = http::parser::extract_token(cursor,end);\n        if (ret.first.empty()) {\n            // error : expected token or quoted string\n            return begin;\n        } else {\n            attributes[name] = ret.first;\n            cursor = ret.second;\n        }\n    }\n\n    return cursor;\n}\n\n/// Extract HTTP parameters\n/**\n * An http parameters list is a comma delimited list of tokens followed by\n * optional semicolon delimited attributes lists.\n *\n * Parameters extracted are appended to the supplied parameters list\n * `parameters`.\n *\n * @param [in] begin An iterator to the beginning of the sequence\n * @param [in] end An iterator to the end of the sequence\n * @param [out] parameters A reference to the parameters list to append\n * paramter values extracted to\n * @return An iterator to the character after the last parameter read\n */\ntemplate <typename InputIterator>\nInputIterator extract_parameters(InputIterator begin, InputIterator end,\n    parameter_list &parameters)\n{\n    InputIterator cursor;\n\n    if (begin == end) {\n        // error: expected non-zero length range\n        return begin;\n    }\n\n    cursor = begin;\n    std::pair<std::string,InputIterator> ret;\n\n    /**\n     * LWS\n     * token\n     * LWS\n     * *(\";\" method-param)\n     * LWS\n     * ,=loop again\n     */\n    while (cursor != end) {\n        std::string parameter_name;\n        attribute_list attributes;\n\n        // extract any stray whitespace\n        cursor = http::parser::extract_all_lws(cursor,end);\n        if (cursor == end) {break;}\n\n        ret = http::parser::extract_token(cursor,end);\n\n        if (ret.first.empty()) {\n            // error: expected a token\n            return begin;\n        } else {\n            parameter_name = ret.first;\n            cursor = ret.second;\n        }\n\n        // Safe break point, insert parameter with blank attributes and exit\n        cursor = http::parser::extract_all_lws(cursor,end);\n        if (cursor == end) {\n            //parameters[parameter_name] = attributes;\n            parameters.push_back(std::make_pair(parameter_name,attributes));\n            break;\n        }\n\n        // If there is an attribute list, read it in\n        if (*cursor == ';') {\n            InputIterator acursor;\n\n            ++cursor;\n            acursor = http::parser::extract_attributes(cursor,end,attributes);\n\n            if (acursor == cursor) {\n                // attribute extraction ended in syntax error\n                return begin;\n            }\n\n            cursor = acursor;\n        }\n\n        // insert parameter into output list\n        //parameters[parameter_name] = attributes;\n        parameters.push_back(std::make_pair(parameter_name,attributes));\n\n        cursor = http::parser::extract_all_lws(cursor,end);\n        if (cursor == end) {break;}\n\n        // if next char is ',' then read another parameter, else stop\n        if (*cursor != ',') {\n            break;\n        }\n\n        // advance past comma\n        ++cursor;\n\n        if (cursor == end) {\n            // expected more bytes after a comma\n            return begin;\n        }\n    }\n\n    return cursor;\n}\n\ninline std::string strip_lws(std::string const & input) {\n    std::string::const_iterator begin = extract_all_lws(input.begin(),input.end());\n    if (begin == input.end()) {\n        return std::string();\n    }\n\n    std::string::const_reverse_iterator rbegin = extract_all_lws(input.rbegin(),input.rend());\n    if (rbegin == input.rend()) {\n        return std::string();\n    }\n\n    return std::string(begin,rbegin.base());\n}\n\n/// Base HTTP parser\n/**\n * Includes methods and data elements common to all types of HTTP messages such\n * as headers, versions, bodies, etc.\n */\nclass parser {\npublic:\n    parser()\n      : m_header_bytes(0)\n      , m_body_bytes_needed(0)\n      , m_body_bytes_max(max_body_size)\n      , m_body_encoding(body_encoding::unknown) {}\n    \n    /// Get the HTTP version string\n    /**\n     * @return The version string for this parser\n     */\n    std::string const & get_version() const {\n        return m_version;\n    }\n\n    /// Set HTTP parser Version\n    /**\n     * Input should be in format: HTTP/x.y where x and y are positive integers.\n     * @todo Does this method need any validation?\n     *\n     * @param [in] version The value to set the HTTP version to.\n     */\n    void set_version(std::string const & version);\n\n    /// Get the value of an HTTP header\n    /**\n     * @todo Make this method case insensitive.\n     *\n     * @param [in] key The name/key of the header to get.\n     * @return The value associated with the given HTTP header key.\n     */\n    std::string const & get_header(std::string const & key) const;\n\n    /// Extract an HTTP parameter list from a parser header.\n    /**\n     * If the header requested doesn't exist or exists and is empty the\n     * parameter list is valid (but empty).\n     *\n     * @param [in] key The name/key of the HTTP header to use as input.\n     * @param [out] out The parameter list to store extracted parameters in.\n     * @return Whether or not the input was a valid parameter list.\n     */\n    bool get_header_as_plist(std::string const & key, parameter_list & out)\n        const;\n\n    /// Return a list of all HTTP headers\n    /**\n     * Return a list of all HTTP headers\n     *\n     * @since 0.8.0\n     *\n     * @return A list of all HTTP headers\n     */\n    header_list const & get_headers() const;\n\n    /// Append a value to an existing HTTP header\n    /**\n     * This method will set the value of the HTTP header `key` with the\n     * indicated value. If a header with the name `key` already exists, `val`\n     * will be appended to the existing value.\n     *\n     * @todo Make this method case insensitive.\n     * @todo Should there be any restrictions on which keys are allowed?\n     * @todo Exception free varient\n     *\n     * @see replace_header\n     *\n     * @param [in] key The name/key of the header to append to.\n     * @param [in] val The value to append.\n     */\n    void append_header(std::string const & key, std::string const & val);\n\n    /// Set a value for an HTTP header, replacing an existing value\n    /**\n     * This method will set the value of the HTTP header `key` with the\n     * indicated value. If a header with the name `key` already exists, `val`\n     * will replace the existing value.\n     *\n     * @todo Make this method case insensitive.\n     * @todo Should there be any restrictions on which keys are allowed?\n     * @todo Exception free varient\n     *\n     * @see append_header\n     *\n     * @param [in] key The name/key of the header to append to.\n     * @param [in] val The value to append.\n     */\n    void replace_header(std::string const & key, std::string const & val);\n\n    /// Remove a header from the parser\n    /**\n     * Removes the header entirely from the parser. This is different than\n     * setting the value of the header to blank.\n     *\n     * @todo Make this method case insensitive.\n     *\n     * @param [in] key The name/key of the header to remove.\n     */\n    void remove_header(std::string const & key);\n\n    /// Get HTTP body\n    /**\n     * Gets the body of the HTTP object\n     *\n     * @return The body of the HTTP message.\n     */\n    std::string const & get_body() const {\n        return m_body;\n    }\n\n    /// Set body content\n    /**\n     * Set the body content of the HTTP response to the parameter string. Note\n     * set_body will also set the Content-Length HTTP header to the appropriate\n     * value. If you want the Content-Length header to be something else, do so\n     * via replace_header(\"Content-Length\") after calling set_body()\n     *\n     * @param value String data to include as the body content.\n     */\n    void set_body(std::string const & value);\n\n    /// Get body size limit\n    /**\n     * Retrieves the maximum number of bytes to parse & buffer before canceling\n     * a request.\n     *\n     * @since 0.5.0\n     *\n     * @return The maximum length of a message body.\n     */\n    size_t get_max_body_size() const {\n        return m_body_bytes_max;\n    }\n\n    /// Set body size limit\n    /**\n     * Set the maximum number of bytes to parse and buffer before canceling a\n     * request.\n     *\n     * @since 0.5.0\n     *\n     * @param value The size to set the max body length to.\n     */\n    void set_max_body_size(size_t value) {\n        m_body_bytes_max = value;\n    }\n\n    /// Extract an HTTP parameter list from a string.\n    /**\n     * @param [in] in The input string.\n     * @param [out] out The parameter list to store extracted parameters in.\n     * @return Whether or not the input was a valid parameter list.\n     */\n    bool parse_parameter_list(std::string const & in, parameter_list & out)\n        const;\nprotected:\n    /// Process a header line\n    /**\n     * @todo Update this method to be exception free.\n     *\n     * @param [in] begin An iterator to the beginning of the sequence.\n     * @param [in] end An iterator to the end of the sequence.\n     */\n    void process_header(std::string::iterator begin, std::string::iterator end);\n\n    /// Prepare the parser to begin parsing body data\n    /**\n     * Inspects headers to determine if the message has a body that needs to be\n     * read. If so, sets up the necessary state, otherwise returns false. If\n     * this method returns true and loading the message body is desired call\n     * `process_body` until it returns zero bytes or an error.\n     *\n     * Must not be called until after all headers have been processed.\n     *\n     * @since 0.5.0\n     *\n     * @return True if more bytes are needed to load the body, false otherwise.\n     */\n    bool prepare_body();\n\n    /// Process body data\n    /**\n     * Parses body data.\n     *\n     * @since 0.5.0\n     *\n     * @param [in] begin An iterator to the beginning of the sequence.\n     * @param [in] end An iterator to the end of the sequence.\n     * @return The number of bytes processed\n     */\n    size_t process_body(char const * buf, size_t len);\n\n    /// Check if the parser is done parsing the body\n    /**\n     * Behavior before a call to `prepare_body` is undefined.\n     *\n     * @since 0.5.0\n     *\n     * @return True if the message body has been completed loaded.\n     */\n    bool body_ready() const {\n        return (m_body_bytes_needed == 0);\n    }\n\n    /// Generate and return the HTTP headers as a string\n    /**\n     * Each headers will be followed by the \\r\\n sequence including the last one.\n     * A second \\r\\n sequence (blank header) is not appended by this method\n     *\n     * @return The HTTP headers as a string.\n     */\n    std::string raw_headers() const;\n\n    std::string m_version;\n    header_list m_headers;\n    \n    size_t                  m_header_bytes;\n    \n    std::string             m_body;\n    size_t                  m_body_bytes_needed;\n    size_t                  m_body_bytes_max;\n    body_encoding::value    m_body_encoding;\n};\n\n} // namespace parser\n} // namespace http\n} // namespace websocketpp\n\n#include <websocketpp/http/impl/parser.hpp>\n\n#endif // HTTP_PARSER_HPP\n"
  },
  {
    "path": "websocketpp/http/request.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef HTTP_PARSER_REQUEST_HPP\n#define HTTP_PARSER_REQUEST_HPP\n\n#include <string>\n\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/http/parser.hpp>\n\nnamespace websocketpp {\nnamespace http {\nnamespace parser {\n\n/// Stores, parses, and manipulates HTTP requests\n/**\n * http::request provides the following functionality for working with HTTP\n * requests.\n *\n * - Initialize request via manually setting each element\n * - Initialize request via reading raw bytes and parsing\n * - Once initialized, access individual parsed elements\n * - Once initialized, read entire request as raw bytes\n */\nclass request : public parser {\npublic:\n    typedef request type;\n    typedef lib::shared_ptr<type> ptr;\n\n    request()\n      : m_buf(lib::make_shared<std::string>())\n      , m_ready(false) {}\n\n    /// Process bytes in the input buffer\n    /**\n     * Process up to len bytes from input buffer buf. Returns the number of\n     * bytes processed. Bytes left unprocessed means bytes left over after the\n     * final header delimiters.\n     *\n     * Consume is a streaming processor. It may be called multiple times on one\n     * request and the full headers need not be available before processing can\n     * begin. If the end of the request was reached during this call to consume\n     * the ready flag will be set. Further calls to consume once ready will be\n     * ignored.\n     *\n     * Consume will throw an http::exception in the case of an error. Typical\n     * error reasons include malformed requests, incomplete requests, and max\n     * header size being reached.\n     *\n     * @param buf Pointer to byte buffer\n     * @param len Size of byte buffer\n     * @return Number of bytes processed.\n     */\n    size_t consume(char const * buf, size_t len);\n\n    /// Returns whether or not the request is ready for reading.\n    bool ready() const {\n        return m_ready;\n    }\n\n    /// Returns the full raw request (including the body)\n    std::string raw() const;\n    \n    /// Returns the raw request headers only (similar to an HTTP HEAD request)\n    std::string raw_head() const;\n\n    /// Set the HTTP method. Must be a valid HTTP token\n    void set_method(std::string const & method);\n\n    /// Return the request method\n    std::string const & get_method() const {\n        return m_method;\n    }\n\n    /// Set the HTTP uri. Must be a valid HTTP uri\n    void set_uri(std::string const & uri);\n\n    /// Return the requested URI\n    std::string const & get_uri() const {\n        return m_uri;\n    }\n\nprivate:\n    /// Helper function for message::consume. Process request line\n    void process(std::string::iterator begin, std::string::iterator end);\n\n    lib::shared_ptr<std::string>    m_buf;\n    std::string                     m_method;\n    std::string                     m_uri;\n    bool                            m_ready;\n};\n\n} // namespace parser\n} // namespace http\n} // namespace websocketpp\n\n#include <websocketpp/http/impl/request.hpp>\n\n#endif // HTTP_PARSER_REQUEST_HPP\n"
  },
  {
    "path": "websocketpp/http/response.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef HTTP_PARSER_RESPONSE_HPP\n#define HTTP_PARSER_RESPONSE_HPP\n\n#include <iostream>\n#include <string>\n\n#include <websocketpp/http/parser.hpp>\n\nnamespace websocketpp {\nnamespace http {\nnamespace parser {\n\n/// Stores, parses, and manipulates HTTP responses\n/**\n * http::response provides the following functionality for working with HTTP\n * responses.\n *\n * - Initialize response via manually setting each element\n * - Initialize response via reading raw bytes and parsing\n * - Once initialized, access individual parsed elements\n * - Once initialized, read entire response as raw bytes\n *\n * http::response checks for header completeness separately from the full\n * response. Once the header is complete, the Content-Length header is read to\n * determine when to stop reading body bytes. If no Content-Length is present\n * ready() will never return true. It is the responsibility of the caller to\n * consume to determine when the response is complete (ie when the connection\n * terminates, or some other metric).\n */\nclass response : public parser {\npublic:\n    typedef response type;\n    typedef lib::shared_ptr<type> ptr;\n\n    response()\n      : m_read(0)\n      , m_buf(lib::make_shared<std::string>())\n      , m_status_code(status_code::uninitialized)\n      , m_state(RESPONSE_LINE) {}\n\n    /// Process bytes in the input buffer\n    /**\n     * Process up to len bytes from input buffer buf. Returns the number of\n     * bytes processed. Bytes left unprocessed means bytes left over after the\n     * final header delimiters.\n     *\n     * Consume is a streaming processor. It may be called multiple times on one\n     * response and the full headers need not be available before processing can\n     * begin. If the end of the response was reached during this call to consume\n     * the ready flag will be set. Further calls to consume once ready will be\n     * ignored.\n     *\n     * Consume will throw an http::exception in the case of an error. Typical\n     * error reasons include malformed responses, incomplete responses, and max\n     * header size being reached.\n     *\n     * @param buf Pointer to byte buffer\n     * @param len Size of byte buffer\n     * @return Number of bytes processed.\n     */\n    size_t consume(char const * buf, size_t len);\n\n    /// Process bytes in the input buffer (istream version)\n    /**\n     * Process bytes from istream s. Returns the number of bytes processed. \n     * Bytes left unprocessed means bytes left over after the final header\n     * delimiters.\n     *\n     * Consume is a streaming processor. It may be called multiple times on one\n     * response and the full headers need not be available before processing can\n     * begin. If the end of the response was reached during this call to consume\n     * the ready flag will be set. Further calls to consume once ready will be\n     * ignored.\n     *\n     * Consume will throw an http::exception in the case of an error. Typical\n     * error reasons include malformed responses, incomplete responses, and max\n     * header size being reached.\n     *\n     * @param buf Pointer to byte buffer\n     * @param len Size of byte buffer\n     * @return Number of bytes processed.\n     */\n    size_t consume(std::istream & s);\n\n    /// Returns true if the response is ready.\n    /**\n     * @note will never return true if the content length header is not present\n     */\n    bool ready() const {\n        return m_state == DONE;\n    }\n\n    /// Returns true if the response headers are fully parsed.\n    bool headers_ready() const {\n        return (m_state == BODY || m_state == DONE);\n    }\n\n    /// Returns the full raw response\n    std::string raw() const;\n\n    /// Set response status code and message\n    /**\n     * Sets the response status code to `code` and looks up the corresponding\n     * message for standard codes. Non-standard codes will be entered as Unknown\n     * use set_status(status_code::value,std::string) overload to set both\n     * values explicitly.\n     *\n     * @param code Code to set\n     * @param msg Message to set\n     */\n    void set_status(status_code::value code);\n\n    /// Set response status code and message\n    /**\n     * Sets the response status code and message to independent custom values.\n     * use set_status(status_code::value) to set the code and have the standard\n     * message be automatically set.\n     *\n     * @param code Code to set\n     * @param msg Message to set\n     */\n    void set_status(status_code::value code, std::string const & msg);\n\n    /// Return the response status code\n    status_code::value get_status_code() const {\n        return m_status_code;\n    }\n\n    /// Return the response status message\n    const std::string& get_status_msg() const {\n        return m_status_msg;\n    }\nprivate:\n    /// Helper function for consume. Process response line\n    void process(std::string::iterator begin, std::string::iterator end);\n\n    /// Helper function for processing body bytes\n    size_t process_body(char const * buf, size_t len);\n\n    enum state {\n        RESPONSE_LINE = 0,\n        HEADERS = 1,\n        BODY = 2,\n        DONE = 3\n    };\n\n    std::string                     m_status_msg;\n    size_t                          m_read;\n    lib::shared_ptr<std::string>    m_buf;\n    status_code::value              m_status_code;\n    state                           m_state;\n\n};\n\n} // namespace parser\n} // namespace http\n} // namespace websocketpp\n\n#include <websocketpp/http/impl/response.hpp>\n\n#endif // HTTP_PARSER_RESPONSE_HPP\n"
  },
  {
    "path": "websocketpp/impl/connection_impl.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CONNECTION_IMPL_HPP\n#define WEBSOCKETPP_CONNECTION_IMPL_HPP\n\n#include <websocketpp/processors/hybi00.hpp>\n#include <websocketpp/processors/hybi07.hpp>\n#include <websocketpp/processors/hybi08.hpp>\n#include <websocketpp/processors/hybi13.hpp>\n\n#include <websocketpp/processors/processor.hpp>\n\n#include <websocketpp/common/platforms.hpp>\n#include <websocketpp/common/system_error.hpp>\n\n#include <algorithm>\n#include <exception>\n#include <sstream>\n#include <string>\n#include <utility>\n#include <vector>\n\nnamespace websocketpp {\n\nnamespace istate = session::internal_state;\n\ntemplate <typename config>\nvoid connection<config>::set_termination_handler(\n    termination_handler new_handler)\n{\n    m_alog->write(log::alevel::devel,\n        \"connection set_termination_handler\");\n\n    //scoped_lock_type lock(m_connection_state_lock);\n\n    m_termination_handler = new_handler;\n}\n\ntemplate <typename config>\nstd::string const & connection<config>::get_origin() const {\n    //scoped_lock_type lock(m_connection_state_lock);\n    return m_processor->get_origin(m_request);\n}\n\ntemplate <typename config>\nsize_t connection<config>::get_buffered_amount() const {\n    //scoped_lock_type lock(m_connection_state_lock);\n    return m_send_buffer_size;\n}\n\ntemplate <typename config>\nsession::state::value connection<config>::get_state() const {\n    //scoped_lock_type lock(m_connection_state_lock);\n    return m_state;\n}\n\ntemplate <typename config>\nlib::error_code connection<config>::send(std::string const & payload,\n    frame::opcode::value op)\n{\n    message_ptr msg = m_msg_manager->get_message(op,payload.size());\n    msg->append_payload(payload);\n    msg->set_compressed(true);\n\n    return send(msg);\n}\n\ntemplate <typename config>\nlib::error_code connection<config>::send(void const * payload, size_t len,\n    frame::opcode::value op)\n{\n    message_ptr msg = m_msg_manager->get_message(op,len);\n    msg->append_payload(payload,len);\n\n    return send(msg);\n}\n\ntemplate <typename config>\nlib::error_code connection<config>::send(typename config::message_type::ptr msg)\n{\n    if (m_alog->static_test(log::alevel::devel)) {\n        m_alog->write(log::alevel::devel,\"connection send\");\n    }\n\n    {\n        scoped_lock_type lock(m_connection_state_lock);\n        if (m_state != session::state::open) {\n           return error::make_error_code(error::invalid_state);\n        }\n    }\n\n    message_ptr outgoing_msg;\n    bool needs_writing = false;\n\n    if (msg->get_prepared()) {\n        outgoing_msg = msg;\n\n        scoped_lock_type lock(m_write_lock);\n        write_push(outgoing_msg);\n        needs_writing = !m_write_flag && !m_send_queue.empty();\n    } else {\n        outgoing_msg = m_msg_manager->get_message();\n\n        if (!outgoing_msg) {\n            return error::make_error_code(error::no_outgoing_buffers);\n        }\n\n        scoped_lock_type lock(m_write_lock);\n        lib::error_code ec = m_processor->prepare_data_frame(msg,outgoing_msg);\n\n        if (ec) {\n            return ec;\n        }\n\n        write_push(outgoing_msg);\n        needs_writing = !m_write_flag && !m_send_queue.empty();\n    }\n\n    if (needs_writing) {\n        transport_con_type::dispatch(lib::bind(\n            &type::write_frame,\n            type::get_shared()\n        ));\n    }\n\n    return lib::error_code();\n}\n\ntemplate <typename config>\nvoid connection<config>::ping(std::string const& payload, lib::error_code& ec) {\n    if (m_alog->static_test(log::alevel::devel)) {\n        m_alog->write(log::alevel::devel,\"connection ping\");\n    }\n\n    {\n        scoped_lock_type lock(m_connection_state_lock);\n        if (m_state != session::state::open) {\n            std::stringstream ss;\n            ss << \"connection::ping called from invalid state \" << m_state;\n            m_alog->write(log::alevel::devel,ss.str());\n            ec = error::make_error_code(error::invalid_state);\n            return;\n        }\n    }\n\n    message_ptr msg = m_msg_manager->get_message();\n    if (!msg) {\n        ec = error::make_error_code(error::no_outgoing_buffers);\n        return;\n    }\n\n    ec = m_processor->prepare_ping(payload,msg);\n    if (ec) {return;}\n\n    // set ping timer if we are listening for one\n    if (m_pong_timeout_handler) {\n        // Cancel any existing timers\n        if (m_ping_timer) {\n            m_ping_timer->cancel();\n        }\n\n        if (m_pong_timeout_dur > 0) {\n            m_ping_timer = transport_con_type::set_timer(\n                m_pong_timeout_dur,\n                lib::bind(\n                    &type::handle_pong_timeout,\n                    type::get_shared(),\n                    payload,\n                    lib::placeholders::_1\n                )\n            );\n        }\n\n        if (!m_ping_timer) {\n            // Our transport doesn't support timers\n            m_elog->write(log::elevel::warn,\"Warning: a pong_timeout_handler is \\\n                set but the transport in use does not support timeouts.\");\n        }\n    }\n\n    bool needs_writing = false;\n    {\n        scoped_lock_type lock(m_write_lock);\n        write_push(msg);\n        needs_writing = !m_write_flag && !m_send_queue.empty();\n    }\n\n    if (needs_writing) {\n        transport_con_type::dispatch(lib::bind(\n            &type::write_frame,\n            type::get_shared()\n        ));\n    }\n\n    ec = lib::error_code();\n}\n\ntemplate<typename config>\nvoid connection<config>::ping(std::string const & payload) {\n    lib::error_code ec;\n    ping(payload,ec);\n    if (ec) {\n        throw exception(ec);\n    }\n}\n\ntemplate<typename config>\nvoid connection<config>::handle_pong_timeout(std::string payload,\n    lib::error_code const & ec)\n{\n    if (ec) {\n        if (ec == transport::error::operation_aborted) {\n            // ignore, this is expected\n            return;\n        }\n\n        m_elog->write(log::elevel::devel,\"pong_timeout error: \"+ec.message());\n        return;\n    }\n\n    if (m_pong_timeout_handler) {\n        m_pong_timeout_handler(m_connection_hdl,payload);\n    }\n}\n\ntemplate <typename config>\nvoid connection<config>::pong(std::string const& payload, lib::error_code& ec) {\n    if (m_alog->static_test(log::alevel::devel)) {\n        m_alog->write(log::alevel::devel,\"connection pong\");\n    }\n\n    {\n        scoped_lock_type lock(m_connection_state_lock);\n        if (m_state != session::state::open) {\n            std::stringstream ss;\n            ss << \"connection::pong called from invalid state \" << m_state;\n            m_alog->write(log::alevel::devel,ss.str());\n            ec = error::make_error_code(error::invalid_state);\n            return;\n        }\n    }\n\n    message_ptr msg = m_msg_manager->get_message();\n    if (!msg) {\n        ec = error::make_error_code(error::no_outgoing_buffers);\n        return;\n    }\n\n    ec = m_processor->prepare_pong(payload,msg);\n    if (ec) {return;}\n\n    bool needs_writing = false;\n    {\n        scoped_lock_type lock(m_write_lock);\n        write_push(msg);\n        needs_writing = !m_write_flag && !m_send_queue.empty();\n    }\n\n    if (needs_writing) {\n        transport_con_type::dispatch(lib::bind(\n            &type::write_frame,\n            type::get_shared()\n        ));\n    }\n\n    ec = lib::error_code();\n}\n\ntemplate<typename config>\nvoid connection<config>::pong(std::string const & payload) {\n    lib::error_code ec;\n    pong(payload,ec);\n    if (ec) {\n        throw exception(ec);\n    }\n}\n\ntemplate <typename config>\nvoid connection<config>::close(close::status::value const code,\n    std::string const & reason, lib::error_code & ec)\n{\n    if (m_alog->static_test(log::alevel::devel)) {\n        m_alog->write(log::alevel::devel,\"connection close\");\n    }\n\n    // Truncate reason to maximum size allowable in a close frame.\n    std::string tr(reason,0,std::min<size_t>(reason.size(),\n        frame::limits::close_reason_size));\n\n    scoped_lock_type lock(m_connection_state_lock);\n\n    if (m_state != session::state::open) {\n       ec = error::make_error_code(error::invalid_state);\n       return;\n    }\n\n    ec = this->send_close_frame(code,tr,false,close::status::terminal(code));\n}\n\ntemplate<typename config>\nvoid connection<config>::close(close::status::value const code,\n    std::string const & reason)\n{\n    lib::error_code ec;\n    close(code,reason,ec);\n    if (ec) {\n        throw exception(ec);\n    }\n}\n\n/// Trigger the on_interrupt handler\n/**\n * This is thread safe if the transport is thread safe\n */\ntemplate <typename config>\nlib::error_code connection<config>::interrupt() {\n    m_alog->write(log::alevel::devel,\"connection connection::interrupt\");\n    return transport_con_type::interrupt(\n        lib::bind(\n            &type::handle_interrupt,\n            type::get_shared()\n        )\n    );\n}\n\n\ntemplate <typename config>\nvoid connection<config>::handle_interrupt() {\n    if (m_interrupt_handler) {\n        m_interrupt_handler(m_connection_hdl);\n    }\n}\n\ntemplate <typename config>\nlib::error_code connection<config>::pause_reading() {\n    m_alog->write(log::alevel::devel,\"connection connection::pause_reading\");\n    return transport_con_type::dispatch(\n        lib::bind(\n            &type::handle_pause_reading,\n            type::get_shared()\n        )\n    );\n}\n\n/// Pause reading handler. Not safe to call directly\ntemplate <typename config>\nvoid connection<config>::handle_pause_reading() {\n    m_alog->write(log::alevel::devel,\"connection connection::handle_pause_reading\");\n    m_read_flag = false;\n}\n\ntemplate <typename config>\nlib::error_code connection<config>::resume_reading() {\n    m_alog->write(log::alevel::devel,\"connection connection::resume_reading\");\n    return transport_con_type::dispatch(\n        lib::bind(\n            &type::handle_resume_reading,\n            type::get_shared()\n        )\n    );\n}\n\n/// Resume reading helper method. Not safe to call directly\ntemplate <typename config>\nvoid connection<config>::handle_resume_reading() {\n   m_read_flag = true;\n   read_frame();\n}\n\n\n\n\n\n\n\n\n\n\n\ntemplate <typename config>\nbool connection<config>::get_secure() const {\n    //scoped_lock_type lock(m_connection_state_lock);\n    return m_uri->get_secure();\n}\n\ntemplate <typename config>\nstd::string const & connection<config>::get_host() const {\n    //scoped_lock_type lock(m_connection_state_lock);\n    return m_uri->get_host();\n}\n\ntemplate <typename config>\nstd::string const & connection<config>::get_resource() const {\n    //scoped_lock_type lock(m_connection_state_lock);\n    return m_uri->get_resource();\n}\n\ntemplate <typename config>\nuint16_t connection<config>::get_port() const {\n    //scoped_lock_type lock(m_connection_state_lock);\n    return m_uri->get_port();\n}\n\ntemplate <typename config>\nuri_ptr connection<config>::get_uri() const {\n    //scoped_lock_type lock(m_connection_state_lock);\n    return m_uri;\n}\n\ntemplate <typename config>\nvoid connection<config>::set_uri(uri_ptr uri) {\n    //scoped_lock_type lock(m_connection_state_lock);\n    m_uri = uri;\n}\n\n\n\n\n\n\ntemplate <typename config>\nstd::string const & connection<config>::get_subprotocol() const {\n    return m_subprotocol;\n}\n\ntemplate <typename config>\nstd::vector<std::string> const &\nconnection<config>::get_requested_subprotocols() const {\n    return m_requested_subprotocols;\n}\n\ntemplate <typename config>\nvoid connection<config>::add_subprotocol(std::string const & value,\n    lib::error_code & ec)\n{\n    if (m_is_server) {\n        ec = error::make_error_code(error::client_only);\n        return;\n    }\n\n    // If the value is empty or has a non-RFC2616 token character it is invalid.\n    if (value.empty() || std::find_if(value.begin(),value.end(),\n                                      http::is_not_token_char) != value.end())\n    {\n        ec = error::make_error_code(error::invalid_subprotocol);\n        return;\n    }\n\n    m_requested_subprotocols.push_back(value);\n}\n\ntemplate <typename config>\nvoid connection<config>::add_subprotocol(std::string const & value) {\n    lib::error_code ec;\n    this->add_subprotocol(value,ec);\n    if (ec) {\n        throw exception(ec);\n    }\n}\n\n\ntemplate <typename config>\nvoid connection<config>::select_subprotocol(std::string const & value,\n    lib::error_code & ec)\n{\n    if (!m_is_server) {\n        ec = error::make_error_code(error::server_only);\n        return;\n    }\n\n    if (value.empty()) {\n        ec = lib::error_code();\n        return;\n    }\n\n    std::vector<std::string>::iterator it;\n\n    it = std::find(m_requested_subprotocols.begin(),\n                   m_requested_subprotocols.end(),\n                   value);\n\n    if (it == m_requested_subprotocols.end()) {\n        ec = error::make_error_code(error::unrequested_subprotocol);\n        return;\n    }\n\n    m_subprotocol = value;\n}\n\ntemplate <typename config>\nvoid connection<config>::select_subprotocol(std::string const & value) {\n    lib::error_code ec;\n    this->select_subprotocol(value,ec);\n    if (ec) {\n        throw exception(ec);\n    }\n}\n\n\ntemplate <typename config>\nstd::string const &\nconnection<config>::get_request_header(std::string const & key) const {\n    return m_request.get_header(key);\n}\n\ntemplate <typename config>\nstd::string const &\nconnection<config>::get_request_body() const {\n    return m_request.get_body();\n}\n\ntemplate <typename config>\nstd::string const &\nconnection<config>::get_response_header(std::string const & key) const {\n    return m_response.get_header(key);\n}\n\n// TODO: EXCEPTION_FREE\ntemplate <typename config>\nvoid connection<config>::set_status(http::status_code::value code)\n{\n    if (m_internal_state != istate::PROCESS_HTTP_REQUEST) {\n        throw exception(\"Call to set_status from invalid state\",\n                      error::make_error_code(error::invalid_state));\n    }\n    m_response.set_status(code);\n}\n\n// TODO: EXCEPTION_FREE\ntemplate <typename config>\nvoid connection<config>::set_status(http::status_code::value code,\n    std::string const & msg)\n{\n    if (m_internal_state != istate::PROCESS_HTTP_REQUEST) {\n        throw exception(\"Call to set_status from invalid state\",\n                      error::make_error_code(error::invalid_state));\n    }\n\n    m_response.set_status(code,msg);\n}\n\n// TODO: EXCEPTION_FREE\ntemplate <typename config>\nvoid connection<config>::set_body(std::string const & value) {\n    if (m_internal_state != istate::PROCESS_HTTP_REQUEST) {\n        throw exception(\"Call to set_status from invalid state\",\n                      error::make_error_code(error::invalid_state));\n    }\n\n    m_response.set_body(value);\n}\n\n// TODO: EXCEPTION_FREE\ntemplate <typename config>\nvoid connection<config>::append_header(std::string const & key,\n    std::string const & val)\n{\n    if (m_is_server) {\n        if (m_internal_state == istate::PROCESS_HTTP_REQUEST) {\n            // we are setting response headers for an incoming server connection\n            m_response.append_header(key,val);\n        } else {\n            throw exception(\"Call to append_header from invalid state\",\n                      error::make_error_code(error::invalid_state));\n        }\n    } else {\n        if (m_internal_state == istate::USER_INIT) {\n            // we are setting initial headers for an outgoing client connection\n            m_request.append_header(key,val);\n        } else {\n            throw exception(\"Call to append_header from invalid state\",\n                      error::make_error_code(error::invalid_state));\n        }\n    }\n}\n\n// TODO: EXCEPTION_FREE\ntemplate <typename config>\nvoid connection<config>::replace_header(std::string const & key,\n    std::string const & val)\n{\n    if (m_is_server) {\n        if (m_internal_state == istate::PROCESS_HTTP_REQUEST) {\n            // we are setting response headers for an incoming server connection\n            m_response.replace_header(key,val);\n        } else {\n            throw exception(\"Call to replace_header from invalid state\",\n                        error::make_error_code(error::invalid_state));\n        }\n    } else {\n        if (m_internal_state == istate::USER_INIT) {\n            // we are setting initial headers for an outgoing client connection\n            m_request.replace_header(key,val);\n        } else {\n            throw exception(\"Call to replace_header from invalid state\",\n                        error::make_error_code(error::invalid_state));\n        }\n    }\n}\n\n// TODO: EXCEPTION_FREE\ntemplate <typename config>\nvoid connection<config>::remove_header(std::string const & key)\n{\n    if (m_is_server) {\n        if (m_internal_state == istate::PROCESS_HTTP_REQUEST) {\n            // we are setting response headers for an incoming server connection\n            m_response.remove_header(key);\n        } else {\n            throw exception(\"Call to remove_header from invalid state\",\n                        error::make_error_code(error::invalid_state));\n        }\n    } else {\n        if (m_internal_state == istate::USER_INIT) {\n            // we are setting initial headers for an outgoing client connection\n            m_request.remove_header(key);\n        } else {\n            throw exception(\"Call to remove_header from invalid state\",\n                        error::make_error_code(error::invalid_state));\n        }\n    }\n}\n\n/// Defer HTTP Response until later\n/**\n * Used in the http handler to defer the HTTP response for this connection\n * until later. Handshake timers will be canceled and the connection will be\n * left open until `send_http_response` or an equivalent is called.\n *\n * Warning: deferred connections won't time out and as a result can tie up\n * resources.\n *\n * @return A status code, zero on success, non-zero otherwise\n */\ntemplate <typename config>\nlib::error_code connection<config>::defer_http_response() {\n    // Cancel handshake timer, otherwise the connection will time out and we'll\n    // close the connection before the app has a chance to send a response.\n    if (m_handshake_timer) {\n        m_handshake_timer->cancel();\n        m_handshake_timer.reset();\n    }\n    \n    // Do something to signal deferral\n    m_http_state = session::http_state::deferred;\n    \n    return lib::error_code();\n}\n\n/// Send deferred HTTP Response (exception free)\n/**\n * Sends an http response to an HTTP connection that was deferred. This will\n * send a complete response including all headers, status line, and body\n * text. The connection will be closed afterwards.\n *\n * @since 0.6.0\n *\n * @param ec A status code, zero on success, non-zero otherwise\n */\ntemplate <typename config>\nvoid connection<config>::send_http_response(lib::error_code & ec) {\n    {\n        scoped_lock_type lock(m_connection_state_lock);\n        if (m_http_state != session::http_state::deferred) {\n            ec = error::make_error_code(error::invalid_state);\n            return;\n        }\n    \n        m_http_state = session::http_state::body_written;\n    }\n    \n    this->write_http_response(lib::error_code());\n    ec = lib::error_code();\n}\n\ntemplate <typename config>\nvoid connection<config>::send_http_response() {\n    lib::error_code ec;\n    this->send_http_response(ec);\n    if (ec) {\n        throw exception(ec);\n    }\n}\n\n\n\n\n/******** logic thread ********/\n\ntemplate <typename config>\nvoid connection<config>::start() {\n    m_alog->write(log::alevel::devel,\"connection start\");\n\n    if (m_internal_state != istate::USER_INIT) {\n        m_alog->write(log::alevel::devel,\"Start called in invalid state\");\n        this->terminate(error::make_error_code(error::invalid_state));\n        return;\n    }\n\n    m_internal_state = istate::TRANSPORT_INIT;\n\n    // Depending on how the transport implements init this function may return\n    // immediately and call handle_transport_init later or call\n    // handle_transport_init from this function.\n    transport_con_type::init(\n        lib::bind(\n            &type::handle_transport_init,\n            type::get_shared(),\n            lib::placeholders::_1\n        )\n    );\n}\n\ntemplate <typename config>\nvoid connection<config>::handle_transport_init(lib::error_code const & ec) {\n    m_alog->write(log::alevel::devel,\"connection handle_transport_init\");\n\n    lib::error_code ecm = ec;\n\n    if (m_internal_state != istate::TRANSPORT_INIT) {\n        m_alog->write(log::alevel::devel,\n          \"handle_transport_init must be called from transport init state\");\n        ecm = error::make_error_code(error::invalid_state);\n    }\n\n    if (ecm) {\n        std::stringstream s;\n        s << \"handle_transport_init received error: \"<< ecm.message();\n        m_elog->write(log::elevel::rerror,s.str());\n\n        this->terminate(ecm);\n        return;\n    }\n\n    // At this point the transport is ready to read and write bytes.\n    if (m_is_server) {\n        m_internal_state = istate::READ_HTTP_REQUEST;\n        this->read_handshake(1);\n    } else {\n        // We are a client. Set the processor to the version specified in the\n        // config file and send a handshake request.\n        m_internal_state = istate::WRITE_HTTP_REQUEST;\n        m_processor = get_processor(config::client_version);\n        this->send_http_request();\n    }\n}\n\ntemplate <typename config>\nvoid connection<config>::read_handshake(size_t num_bytes) {\n    m_alog->write(log::alevel::devel,\"connection read_handshake\");\n\n    if (m_open_handshake_timeout_dur > 0) {\n        m_handshake_timer = transport_con_type::set_timer(\n            m_open_handshake_timeout_dur,\n            lib::bind(\n                &type::handle_open_handshake_timeout,\n                type::get_shared(),\n                lib::placeholders::_1\n            )\n        );\n    }\n\n    transport_con_type::async_read_at_least(\n        num_bytes,\n        m_buf,\n        config::connection_read_buffer_size,\n        lib::bind(\n            &type::handle_read_handshake,\n            type::get_shared(),\n            lib::placeholders::_1,\n            lib::placeholders::_2\n        )\n    );\n}\n\n// All exit paths for this function need to call write_http_response() or submit\n// a new read request with this function as the handler.\ntemplate <typename config>\nvoid connection<config>::handle_read_handshake(lib::error_code const & ec,\n    size_t bytes_transferred)\n{\n    m_alog->write(log::alevel::devel,\"connection handle_read_handshake\");\n\n    lib::error_code ecm = ec;\n\n    if (!ecm) {\n        scoped_lock_type lock(m_connection_state_lock);\n        \n        if (m_state == session::state::connecting) {\n             if (m_internal_state != istate::READ_HTTP_REQUEST) {\n                ecm = error::make_error_code(error::invalid_state);\n             }\n        } else if (m_state == session::state::closed) {\n            // The connection was canceled while the response was being sent,\n            // usually by the handshake timer. This is basically expected\n            // (though hopefully rare) and there is nothing we can do so ignore.\n            m_alog->write(log::alevel::devel,\n                \"handle_read_handshake invoked after connection was closed\");\n            return;\n        } else {\n            ecm = error::make_error_code(error::invalid_state);\n        }\n    }\n\n    if (ecm) {\n        if (ecm == transport::error::eof && m_state == session::state::closed) {\n            // we expect to get eof if the connection is closed already\n            m_alog->write(log::alevel::devel,\n                    \"got (expected) eof/state error from closed con\");\n            return;\n        }\n        \n        log_err(log::elevel::rerror,\"handle_read_handshake\",ecm);\n        this->terminate(ecm);\n        return;\n    }\n\n    // Boundaries checking. TODO: How much of this should be done?\n    if (bytes_transferred > config::connection_read_buffer_size) {\n        m_elog->write(log::elevel::fatal,\"Fatal boundaries checking error.\");\n        this->terminate(make_error_code(error::general));\n        return;\n    }\n\n    size_t bytes_processed = 0;\n    try {\n        bytes_processed = m_request.consume(m_buf,bytes_transferred);\n    } catch (http::exception &e) {\n        // All HTTP exceptions will result in this request failing and an error\n        // response being returned. No more bytes will be read in this con.\n        m_response.set_status(e.m_error_code,e.m_error_msg);\n        this->write_http_response_error(error::make_error_code(error::http_parse_error));\n        return;\n    }\n\n    // More paranoid boundaries checking.\n    // TODO: Is this overkill?\n    if (bytes_processed > bytes_transferred) {\n        m_elog->write(log::elevel::fatal,\"Fatal boundaries checking error.\");\n        this->terminate(make_error_code(error::general));\n        return;\n    }\n\n    if (m_alog->static_test(log::alevel::devel)) {\n        std::stringstream s;\n        s << \"bytes_transferred: \" << bytes_transferred\n          << \" bytes, bytes processed: \" << bytes_processed << \" bytes\";\n        m_alog->write(log::alevel::devel,s.str());\n    }\n\n    if (m_request.ready()) {\n        lib::error_code processor_ec = this->initialize_processor();\n        if (processor_ec) {\n            this->write_http_response_error(processor_ec);\n            return;\n        }\n\n        if (m_processor && m_processor->get_version() == 0) {\n            // Version 00 has an extra requirement to read some bytes after the\n            // handshake\n            if (bytes_transferred-bytes_processed >= 8) {\n                m_request.replace_header(\n                    \"Sec-WebSocket-Key3\",\n                    std::string(m_buf+bytes_processed,m_buf+bytes_processed+8)\n                );\n                bytes_processed += 8;\n            } else {\n                // TODO: need more bytes\n                m_alog->write(log::alevel::devel,\"short key3 read\");\n                m_response.set_status(http::status_code::internal_server_error);\n                this->write_http_response_error(processor::error::make_error_code(processor::error::short_key3));\n                return;\n            }\n        }\n\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,m_request.raw());\n            if (!m_request.get_header(\"Sec-WebSocket-Key3\").empty()) {\n                m_alog->write(log::alevel::devel,\n                    utility::to_hex(m_request.get_header(\"Sec-WebSocket-Key3\")));\n            }\n        }\n\n        // The remaining bytes in m_buf are frame data. Copy them to the\n        // beginning of the buffer and note the length. They will be read after\n        // the handshake completes and before more bytes are read.\n        std::copy(m_buf+bytes_processed,m_buf+bytes_transferred,m_buf);\n        m_buf_cursor = bytes_transferred-bytes_processed;\n\n\n        m_internal_state = istate::PROCESS_HTTP_REQUEST;\n        \n        // We have the complete request. Process it.\n        lib::error_code handshake_ec = this->process_handshake_request();\n        \n        // Write a response if this is a websocket connection or if it is an\n        // HTTP connection for which the response has not been deferred or\n        // started yet by a different system (i.e. still in init state).\n        if (!m_is_http || m_http_state == session::http_state::init) {\n            this->write_http_response(handshake_ec);\n        }\n    } else {\n        // read at least 1 more byte\n        transport_con_type::async_read_at_least(\n            1,\n            m_buf,\n            config::connection_read_buffer_size,\n            lib::bind(\n                &type::handle_read_handshake,\n                type::get_shared(),\n                lib::placeholders::_1,\n                lib::placeholders::_2\n            )\n        );\n    }\n}\n\n// write_http_response requires the request to be fully read and the connection\n// to be in the PROCESS_HTTP_REQUEST state. In some cases we can detect errors\n// before the request is fully read (specifically at a point where we aren't\n// sure if the hybi00 key3 bytes need to be read). This method sets the correct\n// state and calls write_http_response\ntemplate <typename config>\nvoid connection<config>::write_http_response_error(lib::error_code const & ec) {\n    if (m_internal_state != istate::READ_HTTP_REQUEST) {\n        m_alog->write(log::alevel::devel,\n            \"write_http_response_error called in invalid state\");\n        this->terminate(error::make_error_code(error::invalid_state));\n        return;\n    }\n    \n    m_internal_state = istate::PROCESS_HTTP_REQUEST;\n    \n    this->write_http_response(ec);\n}\n\n// All exit paths for this function need to call write_http_response() or submit\n// a new read request with this function as the handler.\ntemplate <typename config>\nvoid connection<config>::handle_read_frame(lib::error_code const & ec,\n    size_t bytes_transferred)\n{\n    //m_alog->write(log::alevel::devel,\"connection handle_read_frame\");\n\n    lib::error_code ecm = ec;\n\n    if (!ecm && m_internal_state != istate::PROCESS_CONNECTION) {\n        ecm = error::make_error_code(error::invalid_state);\n    }\n\n    if (ecm) {\n        log::level echannel = log::elevel::rerror;\n        \n        if (ecm == transport::error::eof) {\n            if (m_state == session::state::closed) {\n                // we expect to get eof if the connection is closed already\n                // just ignore it\n                m_alog->write(log::alevel::devel,\"got eof from closed con\");\n                return;\n            } else if (m_state == session::state::closing && !m_is_server) {\n                // If we are a client we expect to get eof in the closing state,\n                // this is a signal to terminate our end of the connection after\n                // the closing handshake\n                terminate(lib::error_code());\n                return;\n            }\n        } else if (ecm == error::invalid_state) {\n            // In general, invalid state errors in the closed state are the\n            // result of handlers that were in the system already when the state\n            // changed and should be ignored as they pose no problems and there\n            // is nothing useful that we can do about them.\n            if (m_state == session::state::closed) {\n                m_alog->write(log::alevel::devel,\n                    \"handle_read_frame: got invalid istate in closed state\");\n                return;\n            }\n        } else if (ecm == transport::error::action_after_shutdown) {\n            echannel = log::elevel::info;\n        } else {\n            // TODO: more generally should we do something different here in the\n            // case that m_state is cosed? Are errors after the connection is\n            // already closed really an rerror?\n        }\n        \n        \n        \n        log_err(echannel, \"handle_read_frame\", ecm);\n        this->terminate(ecm);\n        return;\n    }\n\n    // Boundaries checking. TODO: How much of this should be done?\n    /*if (bytes_transferred > config::connection_read_buffer_size) {\n        m_elog->write(log::elevel::fatal,\"Fatal boundaries checking error\");\n        this->terminate(make_error_code(error::general));\n        return;\n    }*/\n\n    size_t p = 0;\n\n    if (m_alog->static_test(log::alevel::devel)) {\n        std::stringstream s;\n        s << \"p = \" << p << \" bytes transferred = \" << bytes_transferred;\n        m_alog->write(log::alevel::devel,s.str());\n    }\n\n    while (p < bytes_transferred) {\n        if (m_alog->static_test(log::alevel::devel)) {\n            std::stringstream s;\n            s << \"calling consume with \" << bytes_transferred-p << \" bytes\";\n            m_alog->write(log::alevel::devel,s.str());\n        }\n\n        lib::error_code consume_ec;\n\n        if (m_alog->static_test(log::alevel::devel)) {\n            std::stringstream s;\n            s << \"Processing Bytes: \" << utility::to_hex(reinterpret_cast<uint8_t*>(m_buf)+p,bytes_transferred-p);\n            m_alog->write(log::alevel::devel,s.str());\n        }\n\n        p += m_processor->consume(\n            reinterpret_cast<uint8_t*>(m_buf)+p,\n            bytes_transferred-p,\n            consume_ec\n        );\n\n        if (m_alog->static_test(log::alevel::devel)) {\n            std::stringstream s;\n            s << \"bytes left after consume: \" << bytes_transferred-p;\n            m_alog->write(log::alevel::devel,s.str());\n        }\n        if (consume_ec) {\n            log_err(log::elevel::rerror, \"consume\", consume_ec);\n\n            if (config::drop_on_protocol_error) {\n                this->terminate(consume_ec);\n                return;\n            } else {\n                lib::error_code close_ec;\n                this->close(\n                    processor::error::to_ws(consume_ec),\n                    consume_ec.message(),\n                    close_ec\n                );\n\n                if (close_ec) {\n                    log_err(log::elevel::fatal, \"Protocol error close frame \", close_ec);\n                    this->terminate(close_ec);\n                    return;\n                }\n            }\n            return;\n        }\n\n        if (m_processor->ready()) {\n            if (m_alog->static_test(log::alevel::devel)) {\n                std::stringstream s;\n                s << \"Complete message received. Dispatching\";\n                m_alog->write(log::alevel::devel,s.str());\n            }\n\n            message_ptr msg = m_processor->get_message();\n\n            if (!msg) {\n                m_alog->write(log::alevel::devel, \"null message from m_processor\");\n            } else if (!is_control(msg->get_opcode())) {\n                // data message, dispatch to user\n                if (m_state != session::state::open) {\n                    m_elog->write(log::elevel::warn, \"got non-close frame while closing\");\n                } else if (m_message_handler) {\n                    m_message_handler(m_connection_hdl, msg);\n                }\n            } else {\n                process_control_frame(msg);\n            }\n        }\n    }\n\n    read_frame();\n}\n\n/// Issue a new transport read unless reading is paused.\ntemplate <typename config>\nvoid connection<config>::read_frame() {\n    if (!m_read_flag) {\n        return;\n    }\n    \n    transport_con_type::async_read_at_least(\n        // std::min wont work with undefined static const values.\n        // TODO: is there a more elegant way to do this?\n        // Need to determine if requesting 1 byte or the exact number of bytes\n        // is better here. 1 byte lets us be a bit more responsive at a\n        // potential expense of additional runs through handle_read_frame\n        /*(m_processor->get_bytes_needed() > config::connection_read_buffer_size ?\n         config::connection_read_buffer_size : m_processor->get_bytes_needed())*/\n        1,\n        m_buf,\n        config::connection_read_buffer_size,\n        m_handle_read_frame\n    );\n}\n\ntemplate <typename config>\nlib::error_code connection<config>::initialize_processor() {\n    m_alog->write(log::alevel::devel,\"initialize_processor\");\n\n    // if it isn't a websocket handshake nothing to do.\n    if (!processor::is_websocket_handshake(m_request)) {\n        return lib::error_code();\n    }\n\n    int version = processor::get_websocket_version(m_request);\n\n    if (version < 0) {\n        m_alog->write(log::alevel::devel, \"BAD REQUEST: can't determine version\");\n        m_response.set_status(http::status_code::bad_request);\n        return error::make_error_code(error::invalid_version);\n    }\n\n    m_processor = get_processor(version);\n\n    // if the processor is not null we are done\n    if (m_processor) {\n        return lib::error_code();\n    }\n\n    // We don't have a processor for this version. Return bad request\n    // with Sec-WebSocket-Version header filled with values we do accept\n    m_alog->write(log::alevel::devel, \"BAD REQUEST: no processor for version\");\n    m_response.set_status(http::status_code::bad_request);\n\n    std::stringstream ss;\n    std::string sep;\n    std::vector<int>::const_iterator it;\n    for (it = versions_supported.begin(); it != versions_supported.end(); it++)\n    {\n        ss << sep << *it;\n        sep = \",\";\n    }\n\n    m_response.replace_header(\"Sec-WebSocket-Version\",ss.str());\n    return error::make_error_code(error::unsupported_version);\n}\n\ntemplate <typename config>\nlib::error_code connection<config>::process_handshake_request() {\n    m_alog->write(log::alevel::devel,\"process handshake request\");\n\n    if (!processor::is_websocket_handshake(m_request)) {\n        // this is not a websocket handshake. Process as plain HTTP\n        m_alog->write(log::alevel::devel,\"HTTP REQUEST\");\n\n        // extract URI from request\n        m_uri = processor::get_uri_from_host(\n            m_request,\n            (transport_con_type::is_secure() ? \"https\" : \"http\")\n        );\n\n        if (!m_uri->get_valid()) {\n            m_alog->write(log::alevel::devel, \"Bad request: failed to parse uri\");\n            m_response.set_status(http::status_code::bad_request);\n            return error::make_error_code(error::invalid_uri);\n        }\n\n        if (m_http_handler) {\n            m_is_http = true;\n            m_http_handler(m_connection_hdl);\n            \n            if (m_state == session::state::closed) {\n                return error::make_error_code(error::http_connection_ended);\n            }\n        } else {\n            set_status(http::status_code::upgrade_required);\n            return error::make_error_code(error::upgrade_required);\n        }\n\n        return lib::error_code();\n    }\n\n    lib::error_code ec = m_processor->validate_handshake(m_request);\n\n    // Validate: make sure all required elements are present.\n    if (ec){\n        // Not a valid handshake request\n        m_alog->write(log::alevel::devel, \"Bad request \" + ec.message());\n        m_response.set_status(http::status_code::bad_request);\n        return ec;\n    }\n\n    // Read extension parameters and set up values necessary for the end user\n    // to complete extension negotiation.\n    std::pair<lib::error_code,std::string> neg_results;\n    neg_results = m_processor->negotiate_extensions(m_request);\n\n    if (neg_results.first == processor::error::make_error_code(processor::error::extension_parse_error)) {\n        // There was a fatal error in extension parsing that should result in\n        // a failed connection attempt.\n        m_elog->write(log::elevel::info, \"Bad request: \" + neg_results.first.message());\n        m_response.set_status(http::status_code::bad_request);\n        return neg_results.first;\n    } else if (neg_results.first) {\n        // There was a fatal error in extension processing that is probably our\n        // fault. Consider extension negotiation to have failed and continue as\n        // if extensions were not supported\n        m_elog->write(log::elevel::info, \n            \"Extension negotiation failed: \" + neg_results.first.message());\n    } else {\n        // extension negotiation succeeded, set response header accordingly\n        // we don't send an empty extensions header because it breaks many\n        // clients.\n        if (neg_results.second.size() > 0) {\n            m_response.replace_header(\"Sec-WebSocket-Extensions\",\n                neg_results.second);\n        }\n    }\n\n    // extract URI from request\n    m_uri = m_processor->get_uri(m_request);\n\n\n    if (!m_uri->get_valid()) {\n        m_alog->write(log::alevel::devel, \"Bad request: failed to parse uri\");\n        m_response.set_status(http::status_code::bad_request);\n        return error::make_error_code(error::invalid_uri);\n    }\n\n    // extract subprotocols\n    lib::error_code subp_ec = m_processor->extract_subprotocols(m_request,\n        m_requested_subprotocols);\n\n    if (subp_ec) {\n        // should we do anything?\n    }\n\n    // Ask application to validate the connection\n    if (!m_validate_handler || m_validate_handler(m_connection_hdl)) {\n        m_response.set_status(http::status_code::switching_protocols);\n\n        // Write the appropriate response headers based on request and\n        // processor version\n        ec = m_processor->process_handshake(m_request,m_subprotocol,m_response);\n\n        if (ec) {\n            std::stringstream s;\n            s << \"Processing error: \" << ec << \"(\" << ec.message() << \")\";\n            m_alog->write(log::alevel::devel, s.str());\n\n            m_response.set_status(http::status_code::internal_server_error);\n            return ec;\n        }\n    } else {\n        // User application has rejected the handshake\n        m_alog->write(log::alevel::devel, \"USER REJECT\");\n\n        // Use Bad Request if the user handler did not provide a more\n        // specific http response error code.\n        // TODO: is there a better default?\n        if (m_response.get_status_code() == http::status_code::uninitialized) {\n            m_response.set_status(http::status_code::bad_request);\n        }\n        \n        return error::make_error_code(error::rejected);\n    }\n\n    return lib::error_code();\n}\n\ntemplate <typename config>\nvoid connection<config>::write_http_response(lib::error_code const & ec) {\n    m_alog->write(log::alevel::devel,\"connection write_http_response\");\n\n    if (ec == error::make_error_code(error::http_connection_ended)) {\n        m_alog->write(log::alevel::http,\"An HTTP handler took over the connection.\");\n        return;\n    }\n\n    if (m_response.get_status_code() == http::status_code::uninitialized) {\n        m_response.set_status(http::status_code::internal_server_error);\n        m_ec = error::make_error_code(error::general);\n    } else {\n        m_ec = ec;\n    }\n\n    m_response.set_version(\"HTTP/1.1\");\n\n    // Set server header based on the user agent settings\n    if (m_response.get_header(\"Server\").empty()) {\n        if (!m_user_agent.empty()) {\n            m_response.replace_header(\"Server\",m_user_agent);\n        } else {\n            m_response.remove_header(\"Server\");\n        }\n    }\n\n    // have the processor generate the raw bytes for the wire (if it exists)\n    if (m_processor) {\n        m_handshake_buffer = m_processor->get_raw(m_response);\n    } else {\n        // a processor wont exist for raw HTTP responses.\n        m_handshake_buffer = m_response.raw();\n    }\n\n    if (m_alog->static_test(log::alevel::devel)) {\n        m_alog->write(log::alevel::devel,\"Raw Handshake response:\\n\"+m_handshake_buffer);\n        if (!m_response.get_header(\"Sec-WebSocket-Key3\").empty()) {\n            m_alog->write(log::alevel::devel,\n                utility::to_hex(m_response.get_header(\"Sec-WebSocket-Key3\")));\n        }\n    }\n\n    // write raw bytes\n    transport_con_type::async_write(\n        m_handshake_buffer.data(),\n        m_handshake_buffer.size(),\n        lib::bind(\n            &type::handle_write_http_response,\n            type::get_shared(),\n            lib::placeholders::_1\n        )\n    );\n}\n\ntemplate <typename config>\nvoid connection<config>::handle_write_http_response(lib::error_code const & ec) {\n    m_alog->write(log::alevel::devel,\"handle_write_http_response\");\n\n    lib::error_code ecm = ec;\n\n    if (!ecm) {\n        scoped_lock_type lock(m_connection_state_lock);\n        \n        if (m_state == session::state::connecting) {\n             if (m_internal_state != istate::PROCESS_HTTP_REQUEST) {\n                ecm = error::make_error_code(error::invalid_state);\n             }\n        } else if (m_state == session::state::closed) {\n            // The connection was canceled while the response was being sent,\n            // usually by the handshake timer. This is basically expected\n            // (though hopefully rare) and there is nothing we can do so ignore.\n            m_alog->write(log::alevel::devel,\n                \"handle_write_http_response invoked after connection was closed\");\n            return;\n        } else {\n            ecm = error::make_error_code(error::invalid_state);\n        }\n    }\n\n    if (ecm) {\n        if (ecm == transport::error::eof && m_state == session::state::closed) {\n            // we expect to get eof if the connection is closed already\n            m_alog->write(log::alevel::devel,\n                    \"got (expected) eof/state error from closed con\");\n            return;\n        }\n        \n        log_err(log::elevel::rerror,\"handle_write_http_response\",ecm);\n        this->terminate(ecm);\n        return;\n    }\n\n    if (m_handshake_timer) {\n        m_handshake_timer->cancel();\n        m_handshake_timer.reset();\n    }\n\n    if (m_response.get_status_code() != http::status_code::switching_protocols)\n    {\n        /*if (m_processor || m_ec == error::http_parse_error || \n            m_ec == error::invalid_version || m_ec == error::unsupported_version\n            || m_ec == error::upgrade_required)\n        {*/\n        if (!m_is_http) {\n            std::stringstream s;\n            s << \"Handshake ended with HTTP error: \"\n              << m_response.get_status_code();\n            m_elog->write(log::elevel::rerror,s.str());\n        } else {\n            // if this was not a websocket connection, we have written\n            // the expected response and the connection can be closed.\n            \n            this->log_http_result();\n            \n            if (m_ec) {\n                m_alog->write(log::alevel::devel,\n                    \"got to writing HTTP results with m_ec set: \"+m_ec.message());\n            }\n            m_ec = make_error_code(error::http_connection_ended);\n        }        \n        \n        this->terminate(m_ec);\n        return;\n    }\n\n    this->log_open_result();\n\n    m_internal_state = istate::PROCESS_CONNECTION;\n    m_state = session::state::open;\n\n    if (m_open_handler) {\n        m_open_handler(m_connection_hdl);\n    }\n\n    this->handle_read_frame(lib::error_code(), m_buf_cursor);\n}\n\ntemplate <typename config>\nvoid connection<config>::send_http_request() {\n    m_alog->write(log::alevel::devel,\"connection send_http_request\");\n\n    // TODO: origin header?\n\n    // Have the protocol processor fill in the appropriate fields based on the\n    // selected client version\n    if (m_processor) {\n        lib::error_code ec;\n        ec = m_processor->client_handshake_request(m_request,m_uri,\n            m_requested_subprotocols);\n\n        if (ec) {\n            log_err(log::elevel::fatal,\"Internal library error: Processor\",ec);\n            return;\n        }\n    } else {\n        m_elog->write(log::elevel::fatal,\"Internal library error: missing processor\");\n        return;\n    }\n\n    // Unless the user has overridden the user agent, send generic WS++ UA.\n    if (m_request.get_header(\"User-Agent\").empty()) {\n        if (!m_user_agent.empty()) {\n            m_request.replace_header(\"User-Agent\",m_user_agent);\n        } else {\n            m_request.remove_header(\"User-Agent\");\n        }\n    }\n\n    m_handshake_buffer = m_request.raw();\n\n    if (m_alog->static_test(log::alevel::devel)) {\n        m_alog->write(log::alevel::devel,\"Raw Handshake request:\\n\"+m_handshake_buffer);\n    }\n\n    if (m_open_handshake_timeout_dur > 0) {\n        m_handshake_timer = transport_con_type::set_timer(\n            m_open_handshake_timeout_dur,\n            lib::bind(\n                &type::handle_open_handshake_timeout,\n                type::get_shared(),\n                lib::placeholders::_1\n            )\n        );\n    }\n\n    transport_con_type::async_write(\n        m_handshake_buffer.data(),\n        m_handshake_buffer.size(),\n        lib::bind(\n            &type::handle_send_http_request,\n            type::get_shared(),\n            lib::placeholders::_1\n        )\n    );\n}\n\ntemplate <typename config>\nvoid connection<config>::handle_send_http_request(lib::error_code const & ec) {\n    m_alog->write(log::alevel::devel,\"handle_send_http_request\");\n\n    lib::error_code ecm = ec;\n\n    if (!ecm) {\n        scoped_lock_type lock(m_connection_state_lock);\n        \n        if (m_state == session::state::connecting) {\n             if (m_internal_state != istate::WRITE_HTTP_REQUEST) {\n                ecm = error::make_error_code(error::invalid_state);\n             } else {\n                m_internal_state = istate::READ_HTTP_RESPONSE;\n             }\n        } else if (m_state == session::state::closed) {\n            // The connection was canceled while the response was being sent,\n            // usually by the handshake timer. This is basically expected\n            // (though hopefully rare) and there is nothing we can do so ignore.\n            m_alog->write(log::alevel::devel,\n                \"handle_send_http_request invoked after connection was closed\");\n            return;\n        } else {\n            ecm = error::make_error_code(error::invalid_state);\n        }\n    }\n\n    if (ecm) {\n        if (ecm == transport::error::eof && m_state == session::state::closed) {\n            // we expect to get eof if the connection is closed already\n            m_alog->write(log::alevel::devel,\n                    \"got (expected) eof/state error from closed con\");\n            return;\n        }\n        \n        log_err(log::elevel::rerror,\"handle_send_http_request\",ecm);\n        this->terminate(ecm);\n        return;\n    }\n\n    transport_con_type::async_read_at_least(\n        1,\n        m_buf,\n        config::connection_read_buffer_size,\n        lib::bind(\n            &type::handle_read_http_response,\n            type::get_shared(),\n            lib::placeholders::_1,\n            lib::placeholders::_2\n        )\n    );\n}\n\ntemplate <typename config>\nvoid connection<config>::handle_read_http_response(lib::error_code const & ec,\n    size_t bytes_transferred)\n{\n    m_alog->write(log::alevel::devel,\"handle_read_http_response\");\n\n    lib::error_code ecm = ec;\n\n    if (!ecm) {\n        scoped_lock_type lock(m_connection_state_lock);\n        \n        if (m_state == session::state::connecting) {\n            if (m_internal_state != istate::READ_HTTP_RESPONSE) {\n                ecm = error::make_error_code(error::invalid_state);\n            }\n        } else if (m_state == session::state::closed) {\n            // The connection was canceled while the response was being sent,\n            // usually by the handshake timer. This is basically expected\n            // (though hopefully rare) and there is nothing we can do so ignore.\n            m_alog->write(log::alevel::devel,\n                \"handle_read_http_response invoked after connection was closed\");\n            return;\n        } else {\n            ecm = error::make_error_code(error::invalid_state);\n        }\n    }\n\n    if (ecm) {\n        if (ecm == transport::error::eof && m_state == session::state::closed) {\n            // we expect to get eof if the connection is closed already\n            m_alog->write(log::alevel::devel,\n                    \"got (expected) eof/state error from closed con\");\n            return;\n        }\n        \n        log_err(log::elevel::rerror,\"handle_read_http_response\",ecm);\n        this->terminate(ecm);\n        return;\n    }\n    \n    size_t bytes_processed = 0;\n    // TODO: refactor this to use error codes rather than exceptions\n    try {\n        bytes_processed = m_response.consume(m_buf,bytes_transferred);\n    } catch (http::exception & e) {\n        m_elog->write(log::elevel::rerror,\n            std::string(\"error in handle_read_http_response: \")+e.what());\n        this->terminate(make_error_code(error::general));\n        return;\n    }\n\n    m_alog->write(log::alevel::devel,std::string(\"Raw response: \")+m_response.raw());\n\n    if (m_response.headers_ready()) {\n        if (m_handshake_timer) {\n            m_handshake_timer->cancel();\n            m_handshake_timer.reset();\n        }\n\n        lib::error_code validate_ec = m_processor->validate_server_handshake_response(\n            m_request,\n            m_response\n        );\n        if (validate_ec) {\n            log_err(log::elevel::rerror,\"Server handshake response\",validate_ec);\n            this->terminate(validate_ec);\n            return;\n        }\n\n        // Read extension parameters and set up values necessary for the end\n        // user to complete extension negotiation.\n        std::pair<lib::error_code,std::string> neg_results;\n        neg_results = m_processor->negotiate_extensions(m_response);\n\n        if (neg_results.first) {\n            // There was a fatal error in extension negotiation. For the moment\n            // kill all connections that fail extension negotiation.\n            \n            // TODO: deal with cases where the response is well formed but \n            // doesn't match the options requested by the client. Its possible\n            // that the best behavior in this cases is to log and continue with\n            // an unextended connection.\n            m_alog->write(log::alevel::devel, \"Extension negotiation failed: \"\n                + neg_results.first.message());\n            this->terminate(make_error_code(error::extension_neg_failed));\n            // TODO: close connection with reason 1010 (and list extensions)\n        }\n\n        // response is valid, connection can now be assumed to be open      \n        m_internal_state = istate::PROCESS_CONNECTION;\n        m_state = session::state::open;\n\n        this->log_open_result();\n\n        if (m_open_handler) {\n            m_open_handler(m_connection_hdl);\n        }\n\n        // The remaining bytes in m_buf are frame data. Copy them to the\n        // beginning of the buffer and note the length. They will be read after\n        // the handshake completes and before more bytes are read.\n        std::copy(m_buf+bytes_processed,m_buf+bytes_transferred,m_buf);\n        m_buf_cursor = bytes_transferred-bytes_processed;\n\n        this->handle_read_frame(lib::error_code(), m_buf_cursor);\n    } else {\n        transport_con_type::async_read_at_least(\n            1,\n            m_buf,\n            config::connection_read_buffer_size,\n            lib::bind(\n                &type::handle_read_http_response,\n                type::get_shared(),\n                lib::placeholders::_1,\n                lib::placeholders::_2\n            )\n        );\n    }\n}\n\ntemplate <typename config>\nvoid connection<config>::handle_open_handshake_timeout(\n    lib::error_code const & ec)\n{\n    if (ec == transport::error::operation_aborted) {\n        m_alog->write(log::alevel::devel,\"open handshake timer cancelled\");\n    } else if (ec) {\n        m_alog->write(log::alevel::devel,\n            \"open handle_open_handshake_timeout error: \"+ec.message());\n        // TODO: ignore or fail here?\n    } else {\n        m_alog->write(log::alevel::devel,\"open handshake timer expired\");\n        terminate(make_error_code(error::open_handshake_timeout));\n    }\n}\n\ntemplate <typename config>\nvoid connection<config>::handle_close_handshake_timeout(\n    lib::error_code const & ec)\n{\n    if (ec == transport::error::operation_aborted) {\n        m_alog->write(log::alevel::devel,\"asio close handshake timer cancelled\");\n    } else if (ec) {\n        m_alog->write(log::alevel::devel,\n            \"asio open handle_close_handshake_timeout error: \"+ec.message());\n        // TODO: ignore or fail here?\n    } else {\n        m_alog->write(log::alevel::devel, \"asio close handshake timer expired\");\n        terminate(make_error_code(error::close_handshake_timeout));\n    }\n}\n\ntemplate <typename config>\nvoid connection<config>::terminate(lib::error_code const & ec) {\n    if (m_alog->static_test(log::alevel::devel)) {\n        m_alog->write(log::alevel::devel,\"connection terminate\");\n    }\n\n    // Cancel close handshake timer\n    if (m_handshake_timer) {\n        m_handshake_timer->cancel();\n        m_handshake_timer.reset();\n    }\n\n    terminate_status tstat = unknown;\n    if (ec) {\n        m_ec = ec;\n        m_local_close_code = close::status::abnormal_close;\n        m_local_close_reason = ec.message();\n    }\n\n    // TODO: does any of this need a mutex?\n    if (m_is_http) {\n        m_http_state = session::http_state::closed;\n    }\n    if (m_state == session::state::connecting) {\n        m_state = session::state::closed;\n        tstat = failed;\n        \n        // Log fail result here before socket is shut down and we can't get\n        // the remote address, etc anymore\n        if (m_ec != error::http_connection_ended) {\n            log_fail_result();\n        }\n    } else if (m_state != session::state::closed) {\n        m_state = session::state::closed;\n        tstat = closed;\n    } else {\n        m_alog->write(log::alevel::devel,\n            \"terminate called on connection that was already terminated\");\n        return;\n    }\n\n    // TODO: choose between shutdown and close based on error code sent\n\n    transport_con_type::async_shutdown(\n        lib::bind(\n            &type::handle_terminate,\n            type::get_shared(),\n            tstat,\n            lib::placeholders::_1\n        )\n    );\n}\n\ntemplate <typename config>\nvoid connection<config>::handle_terminate(terminate_status tstat,\n    lib::error_code const & ec)\n{\n    if (m_alog->static_test(log::alevel::devel)) {\n        m_alog->write(log::alevel::devel,\"connection handle_terminate\");\n    }\n\n    if (ec) {\n        // there was an error actually shutting down the connection\n        log_err(log::elevel::devel,\"handle_terminate\",ec);\n    }\n\n    // clean shutdown\n    if (tstat == failed) {\n        if (m_ec != error::http_connection_ended) {\n            if (m_fail_handler) {\n                m_fail_handler(m_connection_hdl);\n            }\n        }\n    } else if (tstat == closed) {\n        if (m_close_handler) {\n            m_close_handler(m_connection_hdl);\n        }\n        log_close_result();\n    } else {\n        m_elog->write(log::elevel::rerror,\"Unknown terminate_status\");\n    }\n\n    // call the termination handler if it exists\n    // if it exists it might (but shouldn't) refer to a bad memory location.\n    // If it does, we don't care and should catch and ignore it.\n    if (m_termination_handler) {\n        try {\n            m_termination_handler(type::get_shared());\n        } catch (std::exception const & e) {\n            m_elog->write(log::elevel::warn,\n                std::string(\"termination_handler call failed. Reason was: \")+e.what());\n        }\n    }\n}\n\ntemplate <typename config>\nvoid connection<config>::write_frame() {\n    //m_alog->write(log::alevel::devel,\"connection write_frame\");\n\n    {\n        scoped_lock_type lock(m_write_lock);\n\n        // Check the write flag. If true, there is an outstanding transport\n        // write already. In this case we just return. The write handler will\n        // start a new write if the write queue isn't empty. If false, we set\n        // the write flag and proceed to initiate a transport write.\n        if (m_write_flag) {\n            return;\n        }\n\n        // pull off all the messages that are ready to write.\n        // stop if we get a message marked terminal\n        message_ptr next_message = write_pop();\n        while (next_message) {\n            m_current_msgs.push_back(next_message);\n            if (!next_message->get_terminal()) {\n                next_message = write_pop();\n            } else {\n                next_message = message_ptr();\n            }\n        }\n        \n        if (m_current_msgs.empty()) {\n            // there was nothing to send\n            return;\n        } else {\n            // At this point we own the next messages to be sent and are\n            // responsible for holding the write flag until they are \n            // successfully sent or there is some error\n            m_write_flag = true;\n        }\n    }\n\n    typename std::vector<message_ptr>::iterator it;\n    for (it = m_current_msgs.begin(); it != m_current_msgs.end(); ++it) {\n        std::string const & header = (*it)->get_header();\n        std::string const & payload = (*it)->get_payload();\n\n        m_send_buffer.push_back(transport::buffer(header.c_str(),header.size()));\n        m_send_buffer.push_back(transport::buffer(payload.c_str(),payload.size()));   \n    }\n\n    // Print detailed send stats if those log levels are enabled\n    if (m_alog->static_test(log::alevel::frame_header)) {\n    if (m_alog->dynamic_test(log::alevel::frame_header)) {\n        std::stringstream general,header,payload;\n        \n        general << \"Dispatching write containing \" << m_current_msgs.size()\n                <<\" message(s) containing \";\n        header << \"Header Bytes: \\n\";\n        payload << \"Payload Bytes: \\n\";\n        \n        size_t hbytes = 0;\n        size_t pbytes = 0;\n        \n        for (size_t i = 0; i < m_current_msgs.size(); i++) {\n            hbytes += m_current_msgs[i]->get_header().size();\n            pbytes += m_current_msgs[i]->get_payload().size();\n\n            \n            header << \"[\" << i << \"] (\" \n                   << m_current_msgs[i]->get_header().size() << \") \" \n                   << utility::to_hex(m_current_msgs[i]->get_header()) << \"\\n\";\n\n            if (m_alog->static_test(log::alevel::frame_payload)) {\n            if (m_alog->dynamic_test(log::alevel::frame_payload)) {\n                payload << \"[\" << i << \"] (\" \n                        << m_current_msgs[i]->get_payload().size() << \") [\"<<m_current_msgs[i]->get_opcode()<<\"] \"\n                        << (m_current_msgs[i]->get_opcode() == frame::opcode::text ? \n                                m_current_msgs[i]->get_payload() : \n                                utility::to_hex(m_current_msgs[i]->get_payload())\n                           ) \n                        << \"\\n\";\n            }\n            }  \n        }\n        \n        general << hbytes << \" header bytes and \" << pbytes << \" payload bytes\";\n        \n        m_alog->write(log::alevel::frame_header,general.str());\n        m_alog->write(log::alevel::frame_header,header.str());\n        m_alog->write(log::alevel::frame_payload,payload.str());\n    }\n    }\n\n    transport_con_type::async_write(\n        m_send_buffer,\n        m_write_frame_handler\n    );\n}\n\ntemplate <typename config>\nvoid connection<config>::handle_write_frame(lib::error_code const & ec)\n{\n    if (m_alog->static_test(log::alevel::devel)) {\n        m_alog->write(log::alevel::devel,\"connection handle_write_frame\");\n    }\n\n    bool terminal = m_current_msgs.back()->get_terminal();\n\n    m_send_buffer.clear();\n    m_current_msgs.clear();\n    // TODO: recycle instead of deleting\n\n    if (ec) {\n        log_err(log::elevel::fatal,\"handle_write_frame\",ec);\n        this->terminate(ec);\n        return;\n    }\n\n    if (terminal) {\n        this->terminate(lib::error_code());\n        return;\n    }\n\n    bool needs_writing = false;\n    {\n        scoped_lock_type lock(m_write_lock);\n\n        // release write flag\n        m_write_flag = false;\n\n        needs_writing = !m_send_queue.empty();\n    }\n\n    if (needs_writing) {\n        transport_con_type::dispatch(lib::bind(\n            &type::write_frame,\n            type::get_shared()\n        ));\n    }\n}\n\ntemplate <typename config>\nstd::vector<int> const & connection<config>::get_supported_versions() const\n{\n    return versions_supported;\n}\n\ntemplate <typename config>\nvoid connection<config>::process_control_frame(typename config::message_type::ptr msg)\n{\n    m_alog->write(log::alevel::devel,\"process_control_frame\");\n\n    frame::opcode::value op = msg->get_opcode();\n    lib::error_code ec;\n\n    std::stringstream s;\n    s << \"Control frame received with opcode \" << op;\n    m_alog->write(log::alevel::control,s.str());\n\n    if (m_state == session::state::closed) {\n        m_elog->write(log::elevel::warn,\"got frame in state closed\");\n        return;\n    }\n    if (op != frame::opcode::CLOSE && m_state != session::state::open) {\n        m_elog->write(log::elevel::warn,\"got non-close frame in state closing\");\n        return;\n    }\n\n    if (op == frame::opcode::PING) {\n        bool should_reply = true;\n\n        if (m_ping_handler) {\n            should_reply = m_ping_handler(m_connection_hdl, msg->get_payload());\n        }\n\n        if (should_reply) {\n            this->pong(msg->get_payload(),ec);\n            if (ec) {\n                log_err(log::elevel::devel,\"Failed to send response pong\",ec);\n            }\n        }\n    } else if (op == frame::opcode::PONG) {\n        if (m_pong_handler) {\n            m_pong_handler(m_connection_hdl, msg->get_payload());\n        }\n        if (m_ping_timer) {\n            m_ping_timer->cancel();\n        }\n    } else if (op == frame::opcode::CLOSE) {\n        m_alog->write(log::alevel::devel,\"got close frame\");\n        // record close code and reason somewhere\n\n        m_remote_close_code = close::extract_code(msg->get_payload(),ec);\n        if (ec) {\n            s.str(\"\");\n            if (config::drop_on_protocol_error) {\n                s << \"Received invalid close code \" << m_remote_close_code\n                  << \" dropping connection per config.\";\n                m_elog->write(log::elevel::devel,s.str());\n                this->terminate(ec);\n            } else {\n                s << \"Received invalid close code \" << m_remote_close_code\n                  << \" sending acknowledgement and closing\";\n                m_elog->write(log::elevel::devel,s.str());\n                ec = send_close_ack(close::status::protocol_error,\n                    \"Invalid close code\");\n                if (ec) {\n                    log_err(log::elevel::devel,\"send_close_ack\",ec);\n                }\n            }\n            return;\n        }\n\n        m_remote_close_reason = close::extract_reason(msg->get_payload(),ec);\n        if (ec) {\n            if (config::drop_on_protocol_error) {\n                m_elog->write(log::elevel::devel,\n                    \"Received invalid close reason. Dropping connection per config\");\n                this->terminate(ec);\n            } else {\n                m_elog->write(log::elevel::devel,\n                    \"Received invalid close reason. Sending acknowledgement and closing\");\n                ec = send_close_ack(close::status::protocol_error,\n                    \"Invalid close reason\");\n                if (ec) {\n                    log_err(log::elevel::devel,\"send_close_ack\",ec);\n                }\n            }\n            return;\n        }\n\n        if (m_state == session::state::open) {\n            s.str(\"\");\n            s << \"Received close frame with code \" << m_remote_close_code\n              << \" and reason \" << m_remote_close_reason;\n            m_alog->write(log::alevel::devel,s.str());\n\n            ec = send_close_ack();\n            if (ec) {\n                log_err(log::elevel::devel,\"send_close_ack\",ec);\n            }\n        } else if (m_state == session::state::closing && !m_was_clean) {\n            // ack of our close\n            m_alog->write(log::alevel::devel, \"Got acknowledgement of close\");\n\n            m_was_clean = true;\n\n            // If we are a server terminate the connection now. Clients should\n            // leave the connection open to give the server an opportunity to\n            // initiate the TCP close. The client's timer will handle closing\n            // its side of the connection if the server misbehaves.\n            //\n            // TODO: different behavior if the underlying transport doesn't\n            // support timers?\n            if (m_is_server) {\n                terminate(lib::error_code());\n            }\n        } else {\n            // spurious, ignore\n            m_elog->write(log::elevel::devel, \"Got close frame in wrong state\");\n        }\n    } else {\n        // got an invalid control opcode\n        m_elog->write(log::elevel::devel, \"Got control frame with invalid opcode\");\n        // initiate protocol error shutdown\n    }\n}\n\ntemplate <typename config>\nlib::error_code connection<config>::send_close_ack(close::status::value code,\n    std::string const & reason)\n{\n    return send_close_frame(code,reason,true,m_is_server);\n}\n\ntemplate <typename config>\nlib::error_code connection<config>::send_close_frame(close::status::value code,\n    std::string const & reason, bool ack, bool terminal)\n{\n    m_alog->write(log::alevel::devel,\"send_close_frame\");\n\n    // check for special codes\n\n    // If silent close is set, respect it and blank out close information\n    // Otherwise use whatever has been specified in the parameters. If\n    // parameters specifies close::status::blank then determine what to do\n    // based on whether or not this is an ack. If it is not an ack just\n    // send blank info. If it is an ack then echo the close information from\n    // the remote endpoint.\n    if (config::silent_close) {\n        m_alog->write(log::alevel::devel,\"closing silently\");\n        m_local_close_code = close::status::no_status;\n        m_local_close_reason.clear();\n    } else if (code != close::status::blank) {\n        m_alog->write(log::alevel::devel,\"closing with specified codes\");\n        m_local_close_code = code;\n        m_local_close_reason = reason;\n    } else if (!ack) {\n        m_alog->write(log::alevel::devel,\"closing with no status code\");\n        m_local_close_code = close::status::no_status;\n        m_local_close_reason.clear();\n    } else if (m_remote_close_code == close::status::no_status) {\n        m_alog->write(log::alevel::devel,\n            \"acknowledging a no-status close with normal code\");\n        m_local_close_code = close::status::normal;\n        m_local_close_reason.clear();\n    } else {\n        m_alog->write(log::alevel::devel,\"acknowledging with remote codes\");\n        m_local_close_code = m_remote_close_code;\n        m_local_close_reason = m_remote_close_reason;\n    }\n\n    std::stringstream s;\n    s << \"Closing with code: \" << m_local_close_code << \", and reason: \"\n      << m_local_close_reason;\n    m_alog->write(log::alevel::devel,s.str());\n\n    message_ptr msg = m_msg_manager->get_message();\n    if (!msg) {\n        return error::make_error_code(error::no_outgoing_buffers);\n    }\n\n    lib::error_code ec = m_processor->prepare_close(m_local_close_code,\n        m_local_close_reason,msg);\n    if (ec) {\n        return ec;\n    }\n\n    // Messages flagged terminal will result in the TCP connection being dropped\n    // after the message has been written. This is typically used when servers\n    // send an ack and when any endpoint encounters a protocol error\n    if (terminal) {\n        msg->set_terminal(true);\n    }\n\n    m_state = session::state::closing;\n\n    if (ack) {\n        m_was_clean = true;\n    }\n\n    // Start a timer so we don't wait forever for the acknowledgement close\n    // frame\n    if (m_close_handshake_timeout_dur > 0) {\n        m_handshake_timer = transport_con_type::set_timer(\n            m_close_handshake_timeout_dur,\n            lib::bind(\n                &type::handle_close_handshake_timeout,\n                type::get_shared(),\n                lib::placeholders::_1\n            )\n        );\n    }\n\n    bool needs_writing = false;\n    {\n        scoped_lock_type lock(m_write_lock);\n        write_push(msg);\n        needs_writing = !m_write_flag && !m_send_queue.empty();\n    }\n\n    if (needs_writing) {\n        transport_con_type::dispatch(lib::bind(\n            &type::write_frame,\n            type::get_shared()\n        ));\n    }\n\n    return lib::error_code();\n}\n\ntemplate <typename config>\ntypename connection<config>::processor_ptr\nconnection<config>::get_processor(int version) const {\n    // TODO: allow disabling certain versions\n    \n    processor_ptr p;\n    \n    switch (version) {\n        case 0:\n            p = lib::make_shared<processor::hybi00<config> >(\n                transport_con_type::is_secure(),\n                m_is_server,\n                m_msg_manager\n            );\n            break;\n        case 7:\n            p = lib::make_shared<processor::hybi07<config> >(\n                transport_con_type::is_secure(),\n                m_is_server,\n                m_msg_manager,\n                lib::ref(m_rng)\n            );\n            break;\n        case 8:\n            p = lib::make_shared<processor::hybi08<config> >(\n                transport_con_type::is_secure(),\n                m_is_server,\n                m_msg_manager,\n                lib::ref(m_rng)\n            );\n            break;\n        case 13:\n            p = lib::make_shared<processor::hybi13<config> >(\n                transport_con_type::is_secure(),\n                m_is_server,\n                m_msg_manager,\n                lib::ref(m_rng)\n            );\n            break;\n        default:\n            return p;\n    }\n    \n    // Settings not configured by the constructor\n    p->set_max_message_size(m_max_message_size);\n    \n    return p;\n}\n\ntemplate <typename config>\nvoid connection<config>::write_push(typename config::message_type::ptr msg)\n{\n    if (!msg) {\n        return;\n    }\n\n    m_send_buffer_size += msg->get_payload().size();\n    m_send_queue.push(msg);\n\n    if (m_alog->static_test(log::alevel::devel)) {\n        std::stringstream s;\n        s << \"write_push: message count: \" << m_send_queue.size()\n          << \" buffer size: \" << m_send_buffer_size;\n        m_alog->write(log::alevel::devel,s.str());\n    }\n}\n\ntemplate <typename config>\ntypename config::message_type::ptr connection<config>::write_pop()\n{\n    message_ptr msg;\n\n    if (m_send_queue.empty()) {\n        return msg;\n    }\n\n    msg = m_send_queue.front();\n\n    m_send_buffer_size -= msg->get_payload().size();\n    m_send_queue.pop();\n\n    if (m_alog->static_test(log::alevel::devel)) {\n        std::stringstream s;\n        s << \"write_pop: message count: \" << m_send_queue.size()\n          << \" buffer size: \" << m_send_buffer_size;\n        m_alog->write(log::alevel::devel,s.str());\n    }\n    return msg;\n}\n\ntemplate <typename config>\nvoid connection<config>::log_open_result()\n{\n    std::stringstream s;\n\n    int version;\n    if (!processor::is_websocket_handshake(m_request)) {\n        version = -1;\n    } else {\n        version = processor::get_websocket_version(m_request);\n    }\n\n    // Connection Type\n    s << (version == -1 ? \"HTTP\" : \"WebSocket\") << \" Connection \";\n\n    // Remote endpoint address\n    s << transport_con_type::get_remote_endpoint() << \" \";\n\n    // Version string if WebSocket\n    if (version != -1) {\n        s << \"v\" << version << \" \";\n    }\n\n    // User Agent\n    std::string ua = m_request.get_header(\"User-Agent\");\n    if (ua.empty()) {\n        s << \"\\\"\\\" \";\n    } else {\n        // check if there are any quotes in the user agent\n        s << \"\\\"\" << utility::string_replace_all(ua,\"\\\"\",\"\\\\\\\"\") << \"\\\" \";\n    }\n\n    // URI\n    s << (m_uri ? m_uri->get_resource() : \"NULL\") << \" \";\n\n    // Status code\n    s << m_response.get_status_code();\n\n    m_alog->write(log::alevel::connect,s.str());\n}\n\ntemplate <typename config>\nvoid connection<config>::log_close_result()\n{\n    std::stringstream s;\n\n    s << \"Disconnect \"\n      << \"close local:[\" << m_local_close_code\n      << (m_local_close_reason.empty() ? \"\" : \",\"+m_local_close_reason)\n      << \"] remote:[\" << m_remote_close_code\n      << (m_remote_close_reason.empty() ? \"\" : \",\"+m_remote_close_reason) << \"]\";\n\n    m_alog->write(log::alevel::disconnect,s.str());\n}\n\ntemplate <typename config>\nvoid connection<config>::log_fail_result()\n{\n    std::stringstream s;\n    \n    int version = processor::get_websocket_version(m_request);\n\n    // Connection Type\n    s << \"WebSocket Connection \";\n\n    // Remote endpoint address & WebSocket version\n    s << transport_con_type::get_remote_endpoint();\n    if (version < 0) {\n        s << \" -\";\n    } else {\n        s << \" v\" << version;\n    }\n\n    // User Agent\n    std::string ua = m_request.get_header(\"User-Agent\");\n    if (ua.empty()) {\n        s << \" \\\"\\\" \";\n    } else {\n        // check if there are any quotes in the user agent\n        s << \" \\\"\" << utility::string_replace_all(ua,\"\\\"\",\"\\\\\\\"\") << \"\\\" \";\n    }\n\n    // URI\n    s << (m_uri ? m_uri->get_resource() : \"-\");\n\n    // HTTP Status code\n    s  << \" \" << m_response.get_status_code();\n    \n    // WebSocket++ error code & reason\n    s << \" \" << m_ec << \" \" << m_ec.message();\n\n    m_alog->write(log::alevel::fail,s.str());\n}\n\ntemplate <typename config>\nvoid connection<config>::log_http_result() {\n    std::stringstream s;\n\n    if (processor::is_websocket_handshake(m_request)) {\n        m_alog->write(log::alevel::devel,\"Call to log_http_result for WebSocket\");\n        return;\n    }  \n\n    // Connection Type\n    s << (m_request.get_header(\"host\").empty() ? \"-\" : m_request.get_header(\"host\"))\n      << \" \" << transport_con_type::get_remote_endpoint()\n      << \" \\\"\" << m_request.get_method() \n      << \" \" << (m_uri ? m_uri->get_resource() : \"-\") \n      << \" \" << m_request.get_version() << \"\\\" \" << m_response.get_status_code()\n      << \" \" << m_response.get_body().size();\n    \n    // User Agent\n    std::string ua = m_request.get_header(\"User-Agent\");\n    if (ua.empty()) {\n        s << \" \\\"\\\" \";\n    } else {\n        // check if there are any quotes in the user agent\n        s << \" \\\"\" << utility::string_replace_all(ua,\"\\\"\",\"\\\\\\\"\") << \"\\\" \";\n    }\n\n    m_alog->write(log::alevel::http,s.str());\n}\n\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_CONNECTION_IMPL_HPP\n"
  },
  {
    "path": "websocketpp/impl/endpoint_impl.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_ENDPOINT_IMPL_HPP\n#define WEBSOCKETPP_ENDPOINT_IMPL_HPP\n\n#include <string>\n\nnamespace websocketpp {\n\ntemplate <typename connection, typename config>\ntypename endpoint<connection,config>::connection_ptr\nendpoint<connection,config>::create_connection() {\n    m_alog->write(log::alevel::devel,\"create_connection\");\n    //scoped_lock_type lock(m_state_lock);\n\n    /*if (m_state == STOPPING || m_state == STOPPED) {\n        return connection_ptr();\n    }*/\n\n    //scoped_lock_type guard(m_mutex);\n    // Create a connection on the heap and manage it using a shared pointer\n    connection_ptr con = lib::make_shared<connection_type>(m_is_server,\n        m_user_agent, m_alog, m_elog, lib::ref(m_rng));\n\n    connection_weak_ptr w(con);\n\n    // Create a weak pointer on the heap using that shared_ptr.\n    // Cast that weak pointer to void* and manage it using another shared_ptr\n    // connection_hdl hdl(reinterpret_cast<void*>(new connection_weak_ptr(con)));\n\n    con->set_handle(w);\n\n    // Copy default handlers from the endpoint\n    con->set_open_handler(m_open_handler);\n    con->set_close_handler(m_close_handler);\n    con->set_fail_handler(m_fail_handler);\n    con->set_ping_handler(m_ping_handler);\n    con->set_pong_handler(m_pong_handler);\n    con->set_pong_timeout_handler(m_pong_timeout_handler);\n    con->set_interrupt_handler(m_interrupt_handler);\n    con->set_http_handler(m_http_handler);\n    con->set_validate_handler(m_validate_handler);\n    con->set_message_handler(m_message_handler);\n\n    if (m_open_handshake_timeout_dur != config::timeout_open_handshake) {\n        con->set_open_handshake_timeout(m_open_handshake_timeout_dur);\n    }\n    if (m_close_handshake_timeout_dur != config::timeout_close_handshake) {\n        con->set_close_handshake_timeout(m_close_handshake_timeout_dur);\n    }\n    if (m_pong_timeout_dur != config::timeout_pong) {\n        con->set_pong_timeout(m_pong_timeout_dur);\n    }\n    if (m_max_message_size != config::max_message_size) {\n        con->set_max_message_size(m_max_message_size);\n    }\n    con->set_max_http_body_size(m_max_http_body_size);\n\n    lib::error_code ec;\n\n    ec = transport_type::init(con);\n    if (ec) {\n        m_elog->write(log::elevel::fatal,ec.message());\n        return connection_ptr();\n    }\n\n    return con;\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::interrupt(connection_hdl hdl, lib::error_code & ec)\n{\n    connection_ptr con = get_con_from_hdl(hdl,ec);\n    if (ec) {return;}\n\n    m_alog->write(log::alevel::devel,\"Interrupting connection\");\n\n    ec = con->interrupt();\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::interrupt(connection_hdl hdl) {\n    lib::error_code ec;\n    interrupt(hdl,ec);\n    if (ec) { throw exception(ec); }\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::pause_reading(connection_hdl hdl, lib::error_code & ec)\n{\n    connection_ptr con = get_con_from_hdl(hdl,ec);\n    if (ec) {return;}\n\n    ec = con->pause_reading();\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::pause_reading(connection_hdl hdl) {\n    lib::error_code ec;\n    pause_reading(hdl,ec);\n    if (ec) { throw exception(ec); }\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::resume_reading(connection_hdl hdl, lib::error_code & ec)\n{\n    connection_ptr con = get_con_from_hdl(hdl,ec);\n    if (ec) {return;}\n\n    ec = con->resume_reading();\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::resume_reading(connection_hdl hdl) {\n    lib::error_code ec;\n    resume_reading(hdl,ec);\n    if (ec) { throw exception(ec); }\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::send_http_response(connection_hdl hdl,\n    lib::error_code & ec)\n{\n    connection_ptr con = get_con_from_hdl(hdl,ec);\n    if (ec) {return;}\n    con->send_http_response(ec);\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::send_http_response(connection_hdl hdl) {\n    lib::error_code ec;\n    send_http_response(hdl,ec);\n    if (ec) { throw exception(ec); }\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::send(connection_hdl hdl, std::string const & payload,\n    frame::opcode::value op, lib::error_code & ec)\n{\n    connection_ptr con = get_con_from_hdl(hdl,ec);\n    if (ec) {return;}\n\n    ec = con->send(payload,op);\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::send(connection_hdl hdl, std::string const & payload,\n    frame::opcode::value op)\n{\n    lib::error_code ec;\n    send(hdl,payload,op,ec);\n    if (ec) { throw exception(ec); }\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::send(connection_hdl hdl, void const * payload,\n    size_t len, frame::opcode::value op, lib::error_code & ec)\n{\n    connection_ptr con = get_con_from_hdl(hdl,ec);\n    if (ec) {return;}\n    ec = con->send(payload,len,op);\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::send(connection_hdl hdl, void const * payload,\n    size_t len, frame::opcode::value op)\n{\n    lib::error_code ec;\n    send(hdl,payload,len,op,ec);\n    if (ec) { throw exception(ec); }\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::send(connection_hdl hdl, message_ptr msg,\n    lib::error_code & ec)\n{\n    connection_ptr con = get_con_from_hdl(hdl,ec);\n    if (ec) {return;}\n    ec = con->send(msg);\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::send(connection_hdl hdl, message_ptr msg) {\n    lib::error_code ec;\n    send(hdl,msg,ec);\n    if (ec) { throw exception(ec); }\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::close(connection_hdl hdl, close::status::value\n    const code, std::string const & reason,\n    lib::error_code & ec)\n{\n    connection_ptr con = get_con_from_hdl(hdl,ec);\n    if (ec) {return;}\n    con->close(code,reason,ec);\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::close(connection_hdl hdl, close::status::value\n    const code, std::string const & reason)\n{\n    lib::error_code ec;\n    close(hdl,code,reason,ec);\n    if (ec) { throw exception(ec); }\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::ping(connection_hdl hdl, std::string const &\n    payload, lib::error_code & ec)\n{\n    connection_ptr con = get_con_from_hdl(hdl,ec);\n    if (ec) {return;}\n    con->ping(payload,ec);\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::ping(connection_hdl hdl, std::string const & payload)\n{\n    lib::error_code ec;\n    ping(hdl,payload,ec);\n    if (ec) { throw exception(ec); }\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::pong(connection_hdl hdl, std::string const & payload,\n    lib::error_code & ec)\n{\n    connection_ptr con = get_con_from_hdl(hdl,ec);\n    if (ec) {return;}\n    con->pong(payload,ec);\n}\n\ntemplate <typename connection, typename config>\nvoid endpoint<connection,config>::pong(connection_hdl hdl, std::string const & payload)\n{\n    lib::error_code ec;\n    pong(hdl,payload,ec);\n    if (ec) { throw exception(ec); }\n}\n\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_ENDPOINT_IMPL_HPP\n"
  },
  {
    "path": "websocketpp/impl/utilities_impl.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_UTILITIES_IMPL_HPP\n#define WEBSOCKETPP_UTILITIES_IMPL_HPP\n\n#include <algorithm>\n#include <string>\n\nnamespace websocketpp {\nnamespace utility {\n\ninline std::string to_lower(std::string const & in) {\n    std::string out = in;\n    std::transform(out.begin(),out.end(),out.begin(),::tolower);\n    return out;\n}\n\ninline std::string to_hex(std::string const & input) {\n    std::string output;\n    std::string hex = \"0123456789ABCDEF\";\n\n    for (size_t i = 0; i < input.size(); i++) {\n        output += hex[(input[i] & 0xF0) >> 4];\n        output += hex[input[i] & 0x0F];\n        output += \" \";\n    }\n\n    return output;\n}\n\ninline std::string to_hex(uint8_t const * input, size_t length) {\n    std::string output;\n    std::string hex = \"0123456789ABCDEF\";\n\n    for (size_t i = 0; i < length; i++) {\n        output += hex[(input[i] & 0xF0) >> 4];\n        output += hex[input[i] & 0x0F];\n        output += \" \";\n    }\n\n    return output;\n}\n\ninline std::string to_hex(const char* input,size_t length) {\n    return to_hex(reinterpret_cast<const uint8_t*>(input),length);\n}\n\ninline std::string string_replace_all(std::string subject, std::string const &\n    search, std::string const & replace)\n{\n    size_t pos = 0;\n    while((pos = subject.find(search, pos)) != std::string::npos) {\n         subject.replace(pos, search.length(), replace);\n         pos += replace.length();\n    }\n    return subject;\n}\n\n} // namespace utility\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_UTILITIES_IMPL_HPP\n"
  },
  {
    "path": "websocketpp/logger/basic.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_LOGGER_BASIC_HPP\n#define WEBSOCKETPP_LOGGER_BASIC_HPP\n\n/* Need a way to print a message to the log\n *\n * - timestamps\n * - channels\n * - thread safe\n * - output to stdout or file\n * - selective output channels, both compile time and runtime\n * - named channels\n * - ability to test whether a log message will be printed at compile time\n *\n */\n\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/stdint.hpp>\n#include <websocketpp/common/time.hpp>\n\n#include <ctime>\n#include <iostream>\n#include <iomanip>\n#include <string>\n\nnamespace websocketpp {\nnamespace log {\n\n/// Basic logger that outputs to an ostream\ntemplate <typename concurrency, typename names>\nclass basic {\npublic:\n    basic<concurrency,names>(channel_type_hint::value h =\n        channel_type_hint::access)\n      : m_static_channels(0xffffffff)\n      , m_dynamic_channels(0)\n      , m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {}\n\n    basic<concurrency,names>(std::ostream * out)\n      : m_static_channels(0xffffffff)\n      , m_dynamic_channels(0)\n      , m_out(out) {}\n\n    basic<concurrency,names>(level c, channel_type_hint::value h =\n        channel_type_hint::access)\n      : m_static_channels(c)\n      , m_dynamic_channels(0)\n      , m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {}\n\n    basic<concurrency,names>(level c, std::ostream * out)\n      : m_static_channels(c)\n      , m_dynamic_channels(0)\n      , m_out(out) {}\n\n    /// Destructor\n    ~basic<concurrency,names>() {}\n\n    /// Copy constructor\n    basic<concurrency,names>(basic<concurrency,names> const & other)\n     : m_static_channels(other.m_static_channels)\n     , m_dynamic_channels(other.m_dynamic_channels)\n     , m_out(other.m_out)\n    {}\n    \n#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n    // no copy assignment operator because of const member variables\n    basic<concurrency,names> & operator=(basic<concurrency,names> const &) = delete;\n#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n\n#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_\n    /// Move constructor\n    basic<concurrency,names>(basic<concurrency,names> && other)\n     : m_static_channels(other.m_static_channels)\n     , m_dynamic_channels(other.m_dynamic_channels)\n     , m_out(other.m_out)\n    {}\n\n#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n    // no move assignment operator because of const member variables\n    basic<concurrency,names> & operator=(basic<concurrency,names> &&) = delete;\n#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n\n#endif // _WEBSOCKETPP_MOVE_SEMANTICS_\n\n    void set_ostream(std::ostream * out = &std::cout) {\n        m_out = out;\n    }\n\n    void set_channels(level channels) {\n        if (channels == names::none) {\n            clear_channels(names::all);\n            return;\n        }\n\n        scoped_lock_type lock(m_lock);\n        m_dynamic_channels |= (channels & m_static_channels);\n    }\n\n    void clear_channels(level channels) {\n        scoped_lock_type lock(m_lock);\n        m_dynamic_channels &= ~channels;\n    }\n\n    /// Write a string message to the given channel\n    /**\n     * @param channel The channel to write to\n     * @param msg The message to write\n     */\n    void write(level channel, std::string const & msg) {\n        scoped_lock_type lock(m_lock);\n        if (!this->dynamic_test(channel)) { return; }\n        *m_out << \"[\" << timestamp << \"] \"\n                  << \"[\" << names::channel_name(channel) << \"] \"\n                  << msg << \"\\n\";\n        m_out->flush();\n    }\n\n    /// Write a cstring message to the given channel\n    /**\n     * @param channel The channel to write to\n     * @param msg The message to write\n     */\n    void write(level channel, char const * msg) {\n        scoped_lock_type lock(m_lock);\n        if (!this->dynamic_test(channel)) { return; }\n        *m_out << \"[\" << timestamp << \"] \"\n                  << \"[\" << names::channel_name(channel) << \"] \"\n                  << msg << \"\\n\";\n        m_out->flush();\n    }\n\n    _WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level channel) const {\n        return ((channel & m_static_channels) != 0);\n    }\n\n    bool dynamic_test(level channel) {\n        return ((channel & m_dynamic_channels) != 0);\n    }\n\nprotected:\n    typedef typename concurrency::scoped_lock_type scoped_lock_type;\n    typedef typename concurrency::mutex_type mutex_type;\n    mutex_type m_lock;\n\nprivate:\n    // The timestamp does not include the time zone, because on Windows with the\n    // default registry settings, the time zone would be written out in full,\n    // which would be obnoxiously verbose.\n    //\n    // TODO: find a workaround for this or make this format user settable\n    static std::ostream & timestamp(std::ostream & os) {\n        std::time_t t = std::time(NULL);\n        std::tm lt = lib::localtime(t);\n        #ifdef _WEBSOCKETPP_PUTTIME_\n            return os << std::put_time(&lt,\"%Y-%m-%d %H:%M:%S\");\n        #else // Falls back to strftime, which requires a temporary copy of the string.\n            char buffer[20];\n            size_t result = std::strftime(buffer,sizeof(buffer),\"%Y-%m-%d %H:%M:%S\",&lt);\n            return os << (result == 0 ? \"Unknown\" : buffer);\n        #endif\n    }\n\n    level const m_static_channels;\n    level m_dynamic_channels;\n    std::ostream * m_out;\n};\n\n} // log\n} // websocketpp\n\n#endif // WEBSOCKETPP_LOGGER_BASIC_HPP\n"
  },
  {
    "path": "websocketpp/logger/levels.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_LOGGER_LEVELS_HPP\n#define WEBSOCKETPP_LOGGER_LEVELS_HPP\n\n#include <websocketpp/common/stdint.hpp>\n\nnamespace websocketpp {\nnamespace log {\n\n/// Type of a channel package\ntypedef uint32_t level;\n\n/// Package of values for hinting at the nature of a given logger.\n/**\n * Used by the library to signal to the logging class a hint that it can use to\n * set itself up. For example, the `access` hint indicates that it is an access\n * log that might be suitable for being printed to an access log file or to cout\n * whereas `error` might be suitable for an error log file or cerr. \n */\nstruct channel_type_hint {\n    /// Type of a channel type hint value\n    typedef uint32_t value;\n    \n    /// No information\n    static value const none = 0;\n    /// Access log\n    static value const access = 1;\n    /// Error log\n    static value const error = 2;\n};\n\n/// Package of log levels for logging errors\nstruct elevel {\n    /// Special aggregate value representing \"no levels\"\n    static level const none = 0x0;\n    /// Low level debugging information (warning: very chatty)\n    static level const devel = 0x1;\n    /// Information about unusual system states or other minor internal library\n    /// problems, less chatty than devel.\n    static level const library = 0x2;\n    /// Information about minor configuration problems or additional information\n    /// about other warnings.\n    static level const info = 0x4;\n    /// Information about important problems not severe enough to terminate\n    /// connections.\n    static level const warn = 0x8;\n    /// Recoverable error. Recovery may mean cleanly closing the connection with\n    /// an appropriate error code to the remote endpoint.\n    static level const rerror = 0x10;\n    /// Unrecoverable error. This error will trigger immediate unclean\n    /// termination of the connection or endpoint.\n    static level const fatal = 0x20;\n    /// Special aggregate value representing \"all levels\"\n    static level const all = 0xffffffff;\n\n    /// Get the textual name of a channel given a channel id\n    /**\n     * The id must be that of a single channel. Passing an aggregate channel\n     * package results in undefined behavior.\n     *\n     * @param channel The channel id to look up.\n     *\n     * @return The name of the specified channel.\n     */\n    static char const * channel_name(level channel) {\n        switch(channel) {\n            case devel:\n                return \"devel\";\n            case library:\n                return \"library\";\n            case info:\n                return \"info\";\n            case warn:\n                return \"warning\";\n            case rerror:\n                return \"error\";\n            case fatal:\n                return \"fatal\";\n            default:\n                return \"unknown\";\n        }\n    }\n};\n\n/// Package of log levels for logging access events\nstruct alevel {\n    /// Special aggregate value representing \"no levels\"\n    static level const none = 0x0;\n    /// Information about new connections\n    /**\n     * One line for each new connection that includes a host of information\n     * including: the remote address, websocket version, requested resource,\n     * http code, remote user agent\n     */\n    static level const connect = 0x1;\n    /// One line for each closed connection. Includes closing codes and reasons.\n    static level const disconnect = 0x2;\n    /// One line per control frame\n    static level const control = 0x4;\n    /// One line per frame, includes the full frame header\n    static level const frame_header = 0x8;\n    /// One line per frame, includes the full message payload (warning: chatty)\n    static level const frame_payload = 0x10;\n    /// Reserved\n    static level const message_header = 0x20;\n    /// Reserved\n    static level const message_payload = 0x40;\n    /// Reserved\n    static level const endpoint = 0x80;\n    /// Extra information about opening handshakes\n    static level const debug_handshake = 0x100;\n    /// Extra information about closing handshakes\n    static level const debug_close = 0x200;\n    /// Development messages (warning: very chatty)\n    static level const devel = 0x400;\n    /// Special channel for application specific logs. Not used by the library.\n    static level const app = 0x800;\n    /// Access related to HTTP requests\n    static level const http = 0x1000;\n    /// One line for each failed WebSocket connection with details\n    static level const fail = 0x2000;\n    /// Aggregate package representing the commonly used core access channels\n    /// Connect, Disconnect, Fail, and HTTP\n    static level const access_core = 0x00003003;\n    /// Special aggregate value representing \"all levels\"\n    static level const all = 0xffffffff;\n\n    /// Get the textual name of a channel given a channel id\n    /**\n     * Get the textual name of a channel given a channel id. The id must be that\n     * of a single channel. Passing an aggregate channel package results in\n     * undefined behavior.\n     *\n     * @param channel The channelid to look up.\n     *\n     * @return The name of the specified channel.\n     */\n    static char const * channel_name(level channel) {\n        switch(channel) {\n            case connect:\n                return \"connect\";\n            case disconnect:\n                return \"disconnect\";\n            case control:\n                return \"control\";\n            case frame_header:\n                return \"frame_header\";\n            case frame_payload:\n                return \"frame_payload\";\n            case message_header:\n                return \"message_header\";\n            case message_payload:\n                return \"message_payload\";\n            case endpoint:\n                return \"endpoint\";\n            case debug_handshake:\n                return \"debug_handshake\";\n            case debug_close:\n                return \"debug_close\";\n            case devel:\n                return \"devel\";\n            case app:\n                return \"application\";\n            case http:\n                return \"http\";\n            case fail:\n                return \"fail\";\n            default:\n                return \"unknown\";\n        }\n    }\n};\n\n} // logger\n} // websocketpp\n\n#endif //WEBSOCKETPP_LOGGER_LEVELS_HPP\n"
  },
  {
    "path": "websocketpp/logger/stub.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_LOGGER_STUB_HPP\n#define WEBSOCKETPP_LOGGER_STUB_HPP\n\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/common/cpp11.hpp>\n\n#include <string>\n\nnamespace websocketpp {\nnamespace log {\n\n/// Stub logger that ignores all input\nclass stub {\npublic:\n    /// Construct the logger\n    /**\n     * @param hint A channel type specific hint for how to construct the logger\n     */\n    explicit stub(channel_type_hint::value) {}\n\n    /// Construct the logger\n    /**\n     * @param default_channels A set of channels to statically enable\n     * @param hint A channel type specific hint for how to construct the logger\n     */\n    stub(level, channel_type_hint::value) {}\n    _WEBSOCKETPP_CONSTEXPR_TOKEN_ stub() {}\n\n    /// Dynamically enable the given list of channels\n    /**\n     * All operations on the stub logger are no-ops and all arguments are\n     * ignored\n     *\n     * @param channels The package of channels to enable\n     */\n    void set_channels(level) {}\n\n    /// Dynamically disable the given list of channels\n    /**\n     * All operations on the stub logger are no-ops and all arguments are\n     * ignored\n     *\n     * @param channels The package of channels to disable\n     */\n    void clear_channels(level) {}\n\n    /// Write a string message to the given channel\n    /**\n     * Writing on the stub logger is a no-op and all arguments are ignored\n     *\n     * @param channel The channel to write to\n     * @param msg The message to write\n     */\n    void write(level, std::string const &) {}\n\n    /// Write a cstring message to the given channel\n    /**\n     * Writing on the stub logger is a no-op and all arguments are ignored\n     *\n     * @param channel The channel to write to\n     * @param msg The message to write\n     */\n    void write(level, char const *) {}\n\n    /// Test whether a channel is statically enabled\n    /**\n     * The stub logger has no channels so all arguments are ignored and\n     * `static_test` always returns false.\n     *\n     * @param channel The package of channels to test\n     */\n    _WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level) const {\n        return false;\n    }\n\n    /// Test whether a channel is dynamically enabled\n    /**\n     * The stub logger has no channels so all arguments are ignored and\n     * `dynamic_test` always returns false.\n     *\n     * @param channel The package of channels to test\n     */\n    bool dynamic_test(level) {\n        return false;\n    }\n};\n\n} // log\n} // websocketpp\n\n#endif // WEBSOCKETPP_LOGGER_STUB_HPP\n"
  },
  {
    "path": "websocketpp/logger/syslog.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n *\n * The initial version of this logging policy was contributed to the WebSocket++\n * project by Tom Hughes.\n */\n\n#ifndef WEBSOCKETPP_LOGGER_SYSLOG_HPP\n#define WEBSOCKETPP_LOGGER_SYSLOG_HPP\n\n#include <syslog.h>\n\n#include <websocketpp/logger/basic.hpp>\n\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/logger/levels.hpp>\n\nnamespace websocketpp {\nnamespace log {\n\n/// Basic logger that outputs to syslog\ntemplate <typename concurrency, typename names>\nclass syslog : public basic<concurrency, names> {\npublic:\n    typedef basic<concurrency, names> base;\n\n    /// Construct the logger\n    /**\n     * @param hint A channel type specific hint for how to construct the logger\n     */\n    syslog<concurrency,names>(channel_type_hint::value hint =\n        channel_type_hint::access)\n      : basic<concurrency,names>(hint), m_channel_type_hint(hint) {}\n\n    /// Construct the logger\n    /**\n     * @param channels A set of channels to statically enable\n     * @param hint A channel type specific hint for how to construct the logger\n     */\n    syslog<concurrency,names>(level channels, channel_type_hint::value hint =\n        channel_type_hint::access)\n      : basic<concurrency,names>(channels, hint), m_channel_type_hint(hint) {}\n\n    /// Write a string message to the given channel\n    /**\n     * @param channel The channel to write to\n     * @param msg The message to write\n     */\n    void write(level channel, std::string const & msg) {\n        write(channel, msg.c_str());\n    }\n\n    /// Write a cstring message to the given channel\n    /**\n     * @param channel The channel to write to\n     * @param msg The message to write\n     */\n    void write(level channel, char const * msg) {\n        scoped_lock_type lock(base::m_lock);\n        if (!this->dynamic_test(channel)) { return; }\n        ::syslog(syslog_priority(channel), \"[%s] %s\",\n            names::channel_name(channel), msg);\n    }\nprivate:\n    typedef typename base::scoped_lock_type scoped_lock_type;\n\n    /// The default level is used for all access logs and any error logs that\n    /// don't trivially map to one of the standard syslog levels.\n    static int const default_level = LOG_INFO;\n\n    /// retrieve the syslog priority code given a WebSocket++ channel\n    /**\n     * @param channel The level to look up\n     * @return The syslog level associated with `channel`\n     */\n    int syslog_priority(level channel) const {\n        if (m_channel_type_hint == channel_type_hint::access) {\n            return syslog_priority_access(channel);\n        } else {\n            return syslog_priority_error(channel);\n        }\n    }\n\n    /// retrieve the syslog priority code given a WebSocket++ error channel\n    /**\n     * @param channel The level to look up\n     * @return The syslog level associated with `channel`\n     */\n    int syslog_priority_error(level channel) const {\n        switch (channel) {\n            case elevel::devel:\n                return LOG_DEBUG;\n            case elevel::library:\n                return LOG_DEBUG;\n            case elevel::info:\n                return LOG_INFO;\n            case elevel::warn:\n                return LOG_WARNING;\n            case elevel::rerror:\n                return LOG_ERR;\n            case elevel::fatal:\n                return LOG_CRIT;\n            default:\n                return default_level;\n        }\n    }\n\n    /// retrieve the syslog priority code given a WebSocket++ access channel\n    /**\n     * @param channel The level to look up\n     * @return The syslog level associated with `channel`\n     */\n    _WEBSOCKETPP_CONSTEXPR_TOKEN_ int syslog_priority_access(level) const {\n        return default_level;\n    }\n\n    channel_type_hint::value m_channel_type_hint;\n};\n\n} // log\n} // websocketpp\n\n#endif // WEBSOCKETPP_LOGGER_SYSLOG_HPP\n"
  },
  {
    "path": "websocketpp/message_buffer/alloc.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP\n#define WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP\n\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/frame.hpp>\n\nnamespace websocketpp {\nnamespace message_buffer {\nnamespace alloc {\n\n/// A connection message manager that allocates a new message for each\n/// request.\ntemplate <typename message>\nclass con_msg_manager\n  : public lib::enable_shared_from_this<con_msg_manager<message> >\n{\npublic:\n    typedef con_msg_manager<message> type;\n    typedef lib::shared_ptr<con_msg_manager> ptr;\n    typedef lib::weak_ptr<con_msg_manager> weak_ptr;\n\n    typedef typename message::ptr message_ptr;\n\n    /// Get an empty message buffer\n    /**\n     * @return A shared pointer to an empty new message\n     */\n    message_ptr get_message() {\n        return message_ptr(lib::make_shared<message>(type::shared_from_this()));\n    }\n\n    /// Get a message buffer with specified size and opcode\n    /**\n     * @param op The opcode to use\n     * @param size Minimum size in bytes to request for the message payload.\n     *\n     * @return A shared pointer to a new message with specified size.\n     */\n    message_ptr get_message(frame::opcode::value op,size_t size) {\n        return message_ptr(lib::make_shared<message>(type::shared_from_this(),op,size));\n    }\n\n    /// Recycle a message\n    /**\n     * This method shouldn't be called. If it is, return false to indicate an\n     * error. The rest of the method recycle chain should notice this and free\n     * the memory.\n     *\n     * @param msg The message to be recycled.\n     *\n     * @return true if the message was successfully recycled, false otherwse.\n     */\n    bool recycle(message *) {\n        return false;\n    }\n};\n\n/// An endpoint message manager that allocates a new manager for each\n/// connection.\ntemplate <typename con_msg_manager>\nclass endpoint_msg_manager {\npublic:\n    typedef typename con_msg_manager::ptr con_msg_man_ptr;\n\n    /// Get a pointer to a connection message manager\n    /**\n     * @return A pointer to the requested connection message manager.\n     */\n    con_msg_man_ptr get_manager() const {\n        return con_msg_man_ptr(lib::make_shared<con_msg_manager>());\n    }\n};\n\n} // namespace alloc\n} // namespace message_buffer\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP\n"
  },
  {
    "path": "websocketpp/message_buffer/message.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP\n#define WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP\n\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/frame.hpp>\n\n#include <string>\n\nnamespace websocketpp {\nnamespace message_buffer {\n\n/* # message:\n * object that stores a message while it is being sent or received. Contains\n * the message payload itself, the message header, the extension data, and the\n * opcode.\n *\n * # connection_message_manager:\n * An object that manages all of the message_buffers associated with a given\n * connection. Implements the get_message_buffer(size) method that returns\n * a message buffer at least size bytes long.\n *\n * Message buffers are reference counted with shared ownership semantics. Once\n * requested from the manager the requester and it's associated downstream code\n * may keep a pointer to the message indefinitely at a cost of extra resource\n * usage. Once the reference count drops to the point where the manager is the\n * only reference the messages is recycled using whatever method is implemented\n * in the manager.\n *\n * # endpoint_message_manager:\n * An object that manages connection_message_managers. Implements the\n * get_message_manager() method. This is used once by each connection to\n * request the message manager that they are supposed to use to manage message\n * buffers for their own use.\n *\n * TYPES OF CONNECTION_MESSAGE_MANAGERS\n * - allocate a message with the exact size every time one is requested\n * - maintain a pool of pre-allocated messages and return one when needed.\n *   Recycle previously used messages back into the pool\n *\n * TYPES OF ENDPOINT_MESSAGE_MANAGERS\n *  - allocate a new connection manager for each connection. Message pools\n *    become connection specific. This increases memory usage but improves\n *    concurrency.\n *  - allocate a single connection manager and share a pointer to it with all\n *    connections created by this endpoint. The message pool will be shared\n *    among all connections, improving memory usage and performance at the cost\n *    of reduced concurrency\n */\n\n\n/// Represents a buffer for a single WebSocket message.\n/**\n *\n *\n */\ntemplate <template<class> class con_msg_manager>\nclass message {\npublic:\n    typedef lib::shared_ptr<message> ptr;\n\n    typedef con_msg_manager<message> con_msg_man_type;\n    typedef typename con_msg_man_type::ptr con_msg_man_ptr;\n    typedef typename con_msg_man_type::weak_ptr con_msg_man_weak_ptr;\n\n    /// Construct an empty message\n    /**\n     * Construct an empty message\n     */\n    message(const con_msg_man_ptr manager)\n      : m_manager(manager)\n      , m_prepared(false)\n      , m_fin(true)\n      , m_terminal(false)\n      , m_compressed(false) {}\n\n    /// Construct a message and fill in some values\n    /**\n     *\n     */\n    message(const con_msg_man_ptr manager, frame::opcode::value op, size_t size = 128)\n      : m_manager(manager)\n      , m_opcode(op)\n      , m_prepared(false)\n      , m_fin(true)\n      , m_terminal(false)\n      , m_compressed(false)\n    {\n        m_payload.reserve(size);\n    }\n\n    /// Return whether or not the message has been prepared for sending\n    /**\n     * The prepared flag indicates that the message has been prepared by a\n     * websocket protocol processor and is ready to be written to the wire.\n     *\n     * @return whether or not the message has been prepared for sending\n     */\n    bool get_prepared() const {\n        return m_prepared;\n    }\n\n    /// Set or clear the flag that indicates that the message has been prepared\n    /**\n     * This flag should not be set by end user code without a very good reason.\n     *\n     * @param value The value to set the prepared flag to\n     */\n    void set_prepared(bool value) {\n        m_prepared = value;\n    }\n\n    /// Return whether or not the message is flagged as compressed\n    /**\n     * @return whether or not the message is/should be compressed\n     */\n    bool get_compressed() const {\n        return m_compressed;\n    }\n\n    /// Set or clear the compression flag\n    /**\n     * Setting the compression flag indicates that the data in this message\n     * would benefit from compression. If both endpoints negotiate a compression\n     * extension WebSocket++ will attempt to compress messages with this flag.\n     * Setting this flag does not guarantee that the message will be compressed.\n     *\n     * @param value The value to set the compressed flag to\n     */\n    void set_compressed(bool value) {\n        m_compressed = value;\n    }\n\n    /// Get whether or not the message is terminal\n    /**\n     * Messages can be flagged as terminal, which results in the connection\n     * being close after they are written rather than the implementation going\n     * on to the next message in the queue. This is typically used internally\n     * for close messages only.\n     *\n     * @return Whether or not this message is marked terminal\n     */\n    bool get_terminal() const {\n        return m_terminal;\n    }\n\n    /// Set the terminal flag\n    /**\n     * This flag should not be set by end user code without a very good reason.\n     *\n     * @see get_terminal()\n     *\n     * @param value The value to set the terminal flag to.\n     */\n    void set_terminal(bool value) {\n        m_terminal = value;\n    }\n    /// Read the fin bit\n    /**\n     * A message with the fin bit set will be sent as the last message of its\n     * sequence. A message with the fin bit cleared will require subsequent\n     * frames of opcode continuation until one of them has the fin bit set.\n     *\n     * The remote end likely will not deliver any bytes until the frame with the fin\n     * bit set has been received.\n     *\n     * @return Whether or not the fin bit is set\n     */\n    bool get_fin() const {\n        return m_fin;\n    }\n\n    /// Set the fin bit\n    /**\n     * @see get_fin for a more detailed explaination of the fin bit\n     *\n     * @param value The value to set the fin bit to.\n     */\n    void set_fin(bool value) {\n        m_fin = value;\n    }\n\n    /// Return the message opcode\n    frame::opcode::value get_opcode() const {\n        return m_opcode;\n    }\n\n    /// Set the opcode\n    void set_opcode(frame::opcode::value op) {\n        m_opcode = op;\n    }\n\n    /// Return the prepared frame header\n    /**\n     * This value is typically set by a websocket protocol processor\n     * and shouldn't be tampered with.\n     */\n    std::string const & get_header() const {\n        return m_header;\n    }\n\n    /// Set prepared frame header\n    /**\n     * Under normal circumstances this should not be called by end users\n     *\n     * @param header A string to set the header to.\n     */\n    void set_header(std::string const & header) {\n        m_header = header;\n    }\n\n    std::string const & get_extension_data() const {\n        return m_extension_data;\n    }\n\n    /// Get a reference to the payload string\n    /**\n     * @return A const reference to the message's payload string\n     */\n    std::string const & get_payload() const {\n        return m_payload;\n    }\n\n    /// Get a non-const reference to the payload string\n    /**\n     * @return A reference to the message's payload string\n     */\n    std::string & get_raw_payload() {\n        return m_payload;\n    }\n\n    /// Set payload data\n    /**\n     * Set the message buffer's payload to the given value.\n     *\n     * @param payload A string to set the payload to.\n     */\n    void set_payload(std::string const & payload) {\n        m_payload = payload;\n    }\n\n    /// Set payload data\n    /**\n     * Set the message buffer's payload to the given value.\n     *\n     * @param payload A pointer to a data array to set to.\n     * @param len The length of new payload in bytes.\n     */\n    void set_payload(void const * payload, size_t len) {\n        m_payload.reserve(len);\n        char const * pl = static_cast<char const *>(payload);\n        m_payload.assign(pl, pl + len);\n    }\n\n    /// Append payload data\n    /**\n     * Append data to the message buffer's payload.\n     *\n     * @param payload A string containing the data array to append.\n     */\n    void append_payload(std::string const & payload) {\n        m_payload.append(payload);\n    }\n\n    /// Append payload data\n    /**\n     * Append data to the message buffer's payload.\n     *\n     * @param payload A pointer to a data array to append\n     * @param len The length of payload in bytes\n     */\n    void append_payload(void const * payload, size_t len) {\n        m_payload.reserve(m_payload.size()+len);\n        m_payload.append(static_cast<char const *>(payload),len);\n    }\n\n    /// Recycle the message\n    /**\n     * A request to recycle this message was received. Forward that request to\n     * the connection message manager for processing. Errors and exceptions\n     * from the manager's recycle member function should be passed back up the\n     * call chain. The caller to message::recycle will deal with them.\n     *\n     * Recycle must *only* be called by the message shared_ptr's destructor.\n     * Once recycled successfully, ownership of the memory has been passed to\n     * another system and must not be accessed again.\n     *\n     * @return true if the message was successfully recycled, false otherwise.\n     */\n    bool recycle() {\n        con_msg_man_ptr shared = m_manager.lock();\n\n        if (shared) {\n            return shared->recycle(this);\n        } else {\n            return false;\n        }\n    }\nprivate:\n    con_msg_man_weak_ptr        m_manager;\n    std::string                 m_header;\n    std::string                 m_extension_data;\n    std::string                 m_payload;\n    frame::opcode::value        m_opcode;\n    bool                        m_prepared;\n    bool                        m_fin;\n    bool                        m_terminal;\n    bool                        m_compressed;\n};\n\n} // namespace message_buffer\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP\n"
  },
  {
    "path": "websocketpp/message_buffer/pool.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP\n#define WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP\n\n#include <websocketpp/common/memory.hpp>\n\n#include <string>\n\nnamespace websocketpp {\nnamespace message_buffer {\n\n/* # message:\n * object that stores a message while it is being sent or received. Contains\n * the message payload itself, the message header, the extension data, and the\n * opcode.\n *\n * # connection_message_manager:\n * An object that manages all of the message_buffers associated with a given\n * connection. Implements the get_message_buffer(size) method that returns\n * a message buffer at least size bytes long.\n *\n * Message buffers are reference counted with shared ownership semantics. Once\n * requested from the manager the requester and it's associated downstream code\n * may keep a pointer to the message indefinitely at a cost of extra resource\n * usage. Once the reference count drops to the point where the manager is the\n * only reference the messages is recycled using whatever method is implemented\n * in the manager.\n *\n * # endpoint_message_manager:\n * An object that manages connection_message_managers. Implements the\n * get_message_manager() method. This is used once by each connection to\n * request the message manager that they are supposed to use to manage message\n * buffers for their own use.\n *\n * TYPES OF CONNECTION_MESSAGE_MANAGERS\n * - allocate a message with the exact size every time one is requested\n * - maintain a pool of pre-allocated messages and return one when needed.\n *   Recycle previously used messages back into the pool\n *\n * TYPES OF ENDPOINT_MESSAGE_MANAGERS\n *  - allocate a new connection manager for each connection. Message pools\n *    become connection specific. This increases memory usage but improves\n *    concurrency.\n *  - allocate a single connection manager and share a pointer to it with all\n *    connections created by this endpoint. The message pool will be shared\n *    among all connections, improving memory usage and performance at the cost\n *    of reduced concurrency\n */\n\n/// Custom deleter for use in shared_ptrs to message.\n/**\n * This is used to catch messages about to be deleted and offer the manager the\n * ability to recycle them instead. Message::recycle will return true if it was\n * successfully recycled and false otherwise. In the case of exceptions or error\n * this deleter frees the memory.\n */\ntemplate <typename T>\nvoid message_deleter(T* msg) {\n    try {\n        if (!msg->recycle()) {\n            delete msg;\n        }\n    } catch (...) {\n        // TODO: is there a better way to ensure this function doesn't throw?\n        delete msg;\n    }\n}\n\n/// Represents a buffer for a single WebSocket message.\n/**\n *\n *\n */\ntemplate <typename con_msg_manager>\nclass message {\npublic:\n    typedef lib::shared_ptr<message> ptr;\n\n    typedef typename con_msg_manager::weak_ptr con_msg_man_ptr;\n\n    message(con_msg_man_ptr manager, size_t size = 128)\n      : m_manager(manager)\n      , m_payload(size) {}\n\n    frame::opcode::value get_opcode() const {\n        return m_opcode;\n    }\n    const std::string& get_header() const {\n        return m_header;\n    }\n    const std::string& get_extension_data() const {\n        return m_extension_data;\n    }\n    const std::string& get_payload() const {\n        return m_payload;\n    }\n\n    /// Recycle the message\n    /**\n     * A request to recycle this message was received. Forward that request to\n     * the connection message manager for processing. Errors and exceptions\n     * from the manager's recycle member function should be passed back up the\n     * call chain. The caller to message::recycle will deal with them.\n     *\n     * Recycle must *only* be called by the message shared_ptr's destructor.\n     * Once recycled successfully, ownership of the memory has been passed to\n     * another system and must not be accessed again.\n     *\n     * @return true if the message was successfully recycled, false otherwise.\n     */\n    bool recycle() {\n        typename con_msg_manager::ptr shared = m_manager.lock();\n\n        if (shared) {\n            return shared->(recycle(this));\n        } else {\n            return false;\n        }\n    }\nprivate:\n    con_msg_man_ptr             m_manager;\n\n    frame::opcode::value        m_opcode;\n    std::string                 m_header;\n    std::string                 m_extension_data;\n    std::string                 m_payload;\n};\n\nnamespace alloc {\n\n/// A connection message manager that allocates a new message for each\n/// request.\ntemplate <typename message>\nclass con_msg_manager {\npublic:\n    typedef lib::shared_ptr<con_msg_manager> ptr;\n    typedef lib::weak_ptr<con_msg_manager> weak_ptr;\n\n    typedef typename message::ptr message_ptr;\n\n    /// Get a message buffer with specified size\n    /**\n     * @param size Minimum size in bytes to request for the message payload.\n     *\n     * @return A shared pointer to a new message with specified size.\n     */\n    message_ptr get_message(size_t size) const {\n        return lib::make_shared<message>(size);\n    }\n\n    /// Recycle a message\n    /**\n     * This method shouldn't be called. If it is, return false to indicate an\n     * error. The rest of the method recycle chain should notice this and free\n     * the memory.\n     *\n     * @param msg The message to be recycled.\n     *\n     * @return true if the message was successfully recycled, false otherwse.\n     */\n    bool recycle(message * msg) {\n        return false;\n    }\n};\n\n/// An endpoint message manager that allocates a new manager for each\n/// connection.\ntemplate <typename con_msg_manager>\nclass endpoint_msg_manager {\npublic:\n    typedef typename con_msg_manager::ptr con_msg_man_ptr;\n\n    /// Get a pointer to a connection message manager\n    /**\n     * @return A pointer to the requested connection message manager.\n     */\n    con_msg_man_ptr get_manager() const {\n        return lib::make_shared<con_msg_manager>();\n    }\n};\n\n} // namespace alloc\n\nnamespace pool {\n\n/// A connection messages manager that maintains a pool of messages that is\n/// used to fulfill get_message requests.\nclass con_msg_manager {\n\n};\n\n/// An endpoint manager that maintains a shared pool of connection managers\n/// and returns an appropriate one for the requesting connection.\nclass endpoint_msg_manager {\n\n};\n\n} // namespace pool\n\n} // namespace message_buffer\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP\n"
  },
  {
    "path": "websocketpp/processors/base.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_PROCESSOR_BASE_HPP\n#define WEBSOCKETPP_PROCESSOR_BASE_HPP\n\n#include <websocketpp/close.hpp>\n#include <websocketpp/utilities.hpp>\n#include <websocketpp/uri.hpp>\n\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/system_error.hpp>\n\n#include <string>\n\nnamespace websocketpp {\nnamespace processor {\n\n/// Constants related to processing WebSocket connections\nnamespace constants {\n\nstatic char const upgrade_token[] = \"websocket\";\nstatic char const connection_token[] = \"Upgrade\";\nstatic char const handshake_guid[] = \"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\";\n\n} // namespace constants\n\n\n/// Processor class related error codes\nnamespace error_cat {\nenum value {\n    BAD_REQUEST = 0, // Error was the result of improperly formatted user input\n    INTERNAL_ERROR = 1, // Error was a logic error internal to WebSocket++\n    PROTOCOL_VIOLATION = 2,\n    MESSAGE_TOO_BIG = 3,\n    PAYLOAD_VIOLATION = 4 // Error was due to receiving invalid payload data\n};\n} // namespace error_cat\n\n/// Error code category and codes used by all processor types\nnamespace error {\nenum processor_errors {\n    /// Catch-all error for processor policy errors that don't fit in other\n    /// categories\n    general = 1,\n\n    /// Error was the result of improperly formatted user input\n    bad_request,\n\n    /// Processor encountered a protocol violation in an incoming message\n    protocol_violation,\n\n    /// Processor encountered a message that was too large\n    message_too_big,\n\n    /// Processor encountered invalid payload data.\n    invalid_payload,\n\n    /// The processor method was called with invalid arguments\n    invalid_arguments,\n\n    /// Opcode was invalid for requested operation\n    invalid_opcode,\n\n    /// Control frame too large\n    control_too_big,\n\n    /// Illegal use of reserved bit\n    invalid_rsv_bit,\n\n    /// Fragmented control message\n    fragmented_control,\n\n    /// Continuation without message\n    invalid_continuation,\n\n    /// Clients may not send unmasked frames\n    masking_required,\n\n    /// Servers may not send masked frames\n    masking_forbidden,\n\n    /// Payload length not minimally encoded\n    non_minimal_encoding,\n\n    /// Not supported on 32 bit systems\n    requires_64bit,\n\n    /// Invalid UTF-8 encoding\n    invalid_utf8,\n\n    /// Operation required not implemented functionality\n    not_implemented,\n\n    /// Invalid HTTP method\n    invalid_http_method,\n\n    /// Invalid HTTP version\n    invalid_http_version,\n\n    /// Invalid HTTP status\n    invalid_http_status,\n\n    /// Missing Required Header\n    missing_required_header,\n\n    /// Embedded SHA-1 library error\n    sha1_library,\n\n    /// No support for this feature in this protocol version.\n    no_protocol_support,\n\n    /// Reserved close code used\n    reserved_close_code,\n\n    /// Invalid close code used\n    invalid_close_code,\n\n    /// Using a reason requires a close code\n    reason_requires_code,\n\n    /// Error parsing subprotocols\n    subprotocol_parse_error,\n\n    /// Error parsing extensions\n    extension_parse_error,\n\n    /// Extension related operation was ignored because extensions are disabled\n    extensions_disabled,\n    \n    /// Short Ke3 read. Hybi00 requires a third key to be read from the 8 bytes\n    /// after the handshake. Less than 8 bytes were read.\n    short_key3\n};\n\n/// Category for processor errors\nclass processor_category : public lib::error_category {\npublic:\n    processor_category() {}\n\n    char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {\n        return \"websocketpp.processor\";\n    }\n\n    std::string message(int value) const {\n        switch(value) {\n            case error::general:\n                return \"Generic processor error\";\n            case error::bad_request:\n                return \"invalid user input\";\n            case error::protocol_violation:\n                return \"Generic protocol violation\";\n            case error::message_too_big:\n                return \"A message was too large\";\n            case error::invalid_payload:\n                return \"A payload contained invalid data\";\n            case error::invalid_arguments:\n                return \"invalid function arguments\";\n            case error::invalid_opcode:\n                return \"invalid opcode\";\n            case error::control_too_big:\n                return \"Control messages are limited to fewer than 125 characters\";\n            case error::invalid_rsv_bit:\n                return \"Invalid use of reserved bits\";\n            case error::fragmented_control:\n                return \"Control messages cannot be fragmented\";\n            case error::invalid_continuation:\n                return \"Invalid message continuation\";\n            case error::masking_required:\n                return \"Clients may not send unmasked frames\";\n            case error::masking_forbidden:\n                return \"Servers may not send masked frames\";\n            case error::non_minimal_encoding:\n                return \"Payload length was not minimally encoded\";\n            case error::requires_64bit:\n                return \"64 bit frames are not supported on 32 bit systems\";\n            case error::invalid_utf8:\n                return \"Invalid UTF8 encoding\";\n            case error::not_implemented:\n                return \"Operation required not implemented functionality\";\n            case error::invalid_http_method:\n                return \"Invalid HTTP method.\";\n            case error::invalid_http_version:\n                return \"Invalid HTTP version.\";\n            case error::invalid_http_status:\n                return \"Invalid HTTP status.\";\n            case error::missing_required_header:\n                return \"A required HTTP header is missing\";\n            case error::sha1_library:\n                return \"SHA-1 library error\";\n            case error::no_protocol_support:\n                return \"The WebSocket protocol version in use does not support this feature\";\n            case error::reserved_close_code:\n                return \"Reserved close code used\";\n            case error::invalid_close_code:\n                return \"Invalid close code used\";\n            case error::reason_requires_code:\n                return \"Using a close reason requires a valid close code\";\n            case error::subprotocol_parse_error:\n                return \"Error parsing subprotocol header\";\n            case error::extension_parse_error:\n                return \"Error parsing extension header\";\n            case error::extensions_disabled:\n                return \"Extensions are disabled\";\n            case error::short_key3:\n                return \"Short Hybi00 Key 3 read\";\n            default:\n                return \"Unknown\";\n        }\n    }\n};\n\n/// Get a reference to a static copy of the processor error category\ninline lib::error_category const & get_processor_category() {\n    static processor_category instance;\n    return instance;\n}\n\n/// Create an error code with the given value and the processor category\ninline lib::error_code make_error_code(error::processor_errors e) {\n    return lib::error_code(static_cast<int>(e), get_processor_category());\n}\n\n/// Converts a processor error_code into a websocket close code\n/**\n * Looks up the appropriate WebSocket close code that should be sent after an\n * error of this sort occurred.\n *\n * If the error is not in the processor category close::status::blank is\n * returned.\n *\n * If the error isn't normally associated with reasons to close a connection\n * (such as errors intended to be used internally or delivered to client\n * applications, ex: invalid arguments) then\n * close::status::internal_endpoint_error is returned.\n */\ninline close::status::value to_ws(lib::error_code ec) {\n    if (ec.category() != get_processor_category()) {\n        return close::status::blank;\n    }\n\n    switch (ec.value()) {\n        case error::protocol_violation:\n        case error::control_too_big:\n        case error::invalid_opcode:\n        case error::invalid_rsv_bit:\n        case error::fragmented_control:\n        case error::invalid_continuation:\n        case error::masking_required:\n        case error::masking_forbidden:\n        case error::reserved_close_code:\n        case error::invalid_close_code:\n            return close::status::protocol_error;\n        case error::invalid_payload:\n        case error::invalid_utf8:\n            return close::status::invalid_payload;\n        case error::message_too_big:\n            return close::status::message_too_big;\n        default:\n            return close::status::internal_endpoint_error;\n    }\n}\n\n} // namespace error\n} // namespace processor\n} // namespace websocketpp\n\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_\ntemplate<> struct is_error_code_enum<websocketpp::processor::error::processor_errors>\n{\n    static bool const value = true;\n};\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_\n\n#endif //WEBSOCKETPP_PROCESSOR_BASE_HPP\n"
  },
  {
    "path": "websocketpp/processors/hybi00.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_PROCESSOR_HYBI00_HPP\n#define WEBSOCKETPP_PROCESSOR_HYBI00_HPP\n\n#include <websocketpp/frame.hpp>\n#include <websocketpp/http/constants.hpp>\n\n#include <websocketpp/utf8_validator.hpp>\n#include <websocketpp/common/network.hpp>\n#include <websocketpp/common/md5.hpp>\n#include <websocketpp/common/platforms.hpp>\n\n#include <websocketpp/processors/processor.hpp>\n\n#include <algorithm>\n#include <cstdlib>\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\nnamespace processor {\n\n/// Processor for Hybi Draft version 00\n/**\n * There are many differences between Hybi 00 and Hybi 13\n */\ntemplate <typename config>\nclass hybi00 : public processor<config> {\npublic:\n    typedef processor<config> base;\n\n    typedef typename config::request_type request_type;\n    typedef typename config::response_type response_type;\n\n    typedef typename config::message_type message_type;\n    typedef typename message_type::ptr message_ptr;\n\n    typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;\n\n    explicit hybi00(bool secure, bool p_is_server, msg_manager_ptr manager)\n      : processor<config>(secure, p_is_server)\n      , msg_hdr(0x00)\n      , msg_ftr(0xff)\n      , m_state(HEADER)\n      , m_msg_manager(manager) {}\n\n    int get_version() const {\n        return 0;\n    }\n\n    lib::error_code validate_handshake(request_type const & r) const {\n        if (r.get_method() != \"GET\") {\n            return make_error_code(error::invalid_http_method);\n        }\n\n        if (r.get_version() != \"HTTP/1.1\") {\n            return make_error_code(error::invalid_http_version);\n        }\n\n        // required headers\n        // Host is required by HTTP/1.1\n        // Connection is required by is_websocket_handshake\n        // Upgrade is required by is_websocket_handshake\n        if (r.get_header(\"Sec-WebSocket-Key1\").empty() ||\n            r.get_header(\"Sec-WebSocket-Key2\").empty() ||\n            r.get_header(\"Sec-WebSocket-Key3\").empty())\n        {\n            return make_error_code(error::missing_required_header);\n        }\n\n        return lib::error_code();\n    }\n\n    lib::error_code process_handshake(request_type const & req,\n        std::string const & subprotocol, response_type & res) const\n    {\n        char key_final[16];\n\n        // copy key1 into final key\n        decode_client_key(req.get_header(\"Sec-WebSocket-Key1\"), &key_final[0]);\n\n        // copy key2 into final key\n        decode_client_key(req.get_header(\"Sec-WebSocket-Key2\"), &key_final[4]);\n\n        // copy key3 into final key\n        // key3 should be exactly 8 bytes. If it is more it will be truncated\n        // if it is less the final key will almost certainly be wrong.\n        // TODO: decide if it is best to silently fail here or produce some sort\n        //       of warning or exception.\n        std::string const & key3 = req.get_header(\"Sec-WebSocket-Key3\");\n        std::copy(key3.c_str(),\n                  key3.c_str()+(std::min)(static_cast<size_t>(8), key3.size()),\n                  &key_final[8]);\n\n        res.append_header(\n            \"Sec-WebSocket-Key3\",\n            md5::md5_hash_string(std::string(key_final,16))\n        );\n\n        res.append_header(\"Upgrade\",\"WebSocket\");\n        res.append_header(\"Connection\",\"Upgrade\");\n\n        // Echo back client's origin unless our local application set a\n        // more restrictive one.\n        if (res.get_header(\"Sec-WebSocket-Origin\").empty()) {\n            res.append_header(\"Sec-WebSocket-Origin\",req.get_header(\"Origin\"));\n        }\n\n        // Echo back the client's request host unless our local application\n        // set a different one.\n        if (res.get_header(\"Sec-WebSocket-Location\").empty()) {\n            uri_ptr uri = get_uri(req);\n            res.append_header(\"Sec-WebSocket-Location\",uri->str());\n        }\n\n        if (!subprotocol.empty()) {\n            res.replace_header(\"Sec-WebSocket-Protocol\",subprotocol);\n        }\n\n        return lib::error_code();\n    }\n\n    /// Fill in a set of request headers for a client connection request\n    /**\n     * The Hybi 00 processor only implements incoming connections so this will\n     * always return an error.\n     *\n     * @param [out] req  Set of headers to fill in\n     * @param [in] uri The uri being connected to\n     * @param [in] subprotocols The list of subprotocols to request\n     */\n    lib::error_code client_handshake_request(request_type &, uri_ptr,\n        std::vector<std::string> const &) const\n    {\n        return error::make_error_code(error::no_protocol_support);\n    }\n\n    /// Validate the server's response to an outgoing handshake request\n    /**\n     * The Hybi 00 processor only implements incoming connections so this will\n     * always return an error.\n     *\n     * @param req The original request sent\n     * @param res The reponse to generate\n     * @return An error code, 0 on success, non-zero for other errors\n     */\n    lib::error_code validate_server_handshake_response(request_type const &,\n        response_type &) const\n    {\n        return error::make_error_code(error::no_protocol_support);\n    }\n\n    std::string get_raw(response_type const & res) const {\n        response_type temp = res;\n        temp.remove_header(\"Sec-WebSocket-Key3\");\n        return temp.raw() + res.get_header(\"Sec-WebSocket-Key3\");\n    }\n\n    std::string const & get_origin(request_type const & r) const {\n        return r.get_header(\"Origin\");\n    }\n\n    /// Extracts requested subprotocols from a handshake request\n    /**\n     * hybi00 does support subprotocols\n     * https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#section-1.9\n     *\n     * @param [in] req The request to extract from\n     * @param [out] subprotocol_list A reference to a vector of strings to store\n     * the results in.\n     */\n    lib::error_code extract_subprotocols(request_type const & req,\n        std::vector<std::string> & subprotocol_list)\n    {\n        if (!req.get_header(\"Sec-WebSocket-Protocol\").empty()) {\n            http::parameter_list p;\n\n             if (!req.get_header_as_plist(\"Sec-WebSocket-Protocol\",p)) {\n                 http::parameter_list::const_iterator it;\n\n                 for (it = p.begin(); it != p.end(); ++it) {\n                     subprotocol_list.push_back(it->first);\n                 }\n             } else {\n                 return error::make_error_code(error::subprotocol_parse_error);\n             }\n        }\n        return lib::error_code();\n    }\n\n    uri_ptr get_uri(request_type const & request) const {\n        std::string h = request.get_header(\"Host\");\n\n        size_t last_colon = h.rfind(\":\");\n        size_t last_sbrace = h.rfind(\"]\");\n\n        // no : = hostname with no port\n        // last : before ] = ipv6 literal with no port\n        // : with no ] = hostname with port\n        // : after ] = ipv6 literal with port\n\n        if (last_colon == std::string::npos ||\n            (last_sbrace != std::string::npos && last_sbrace > last_colon))\n        {\n            return lib::make_shared<uri>(base::m_secure, h, request.get_uri());\n        } else {\n            return lib::make_shared<uri>(base::m_secure,\n                                   h.substr(0,last_colon),\n                                   h.substr(last_colon+1),\n                                   request.get_uri());\n        }\n\n        // TODO: check if get_uri is a full uri\n    }\n\n    /// Get hybi00 handshake key3\n    /**\n     * @todo This doesn't appear to be used anymore. It might be able to be\n     * removed\n     */\n    std::string get_key3() const {\n        return \"\";\n    }\n\n    /// Process new websocket connection bytes\n    size_t consume(uint8_t * buf, size_t len, lib::error_code & ec) {\n        // if in state header we are expecting a 0x00 byte, if we don't get one\n        // it is a fatal error\n        size_t p = 0; // bytes processed\n        size_t l = 0;\n\n        ec = lib::error_code();\n\n        while (p < len) {\n            if (m_state == HEADER) {\n                if (buf[p] == msg_hdr) {\n                    p++;\n                    m_msg_ptr = m_msg_manager->get_message(frame::opcode::text,1);\n\n                    if (!m_msg_ptr) {\n                        ec = make_error_code(websocketpp::error::no_incoming_buffers);\n                        m_state = FATAL_ERROR;\n                    } else {\n                        m_state = PAYLOAD;\n                    }\n                } else {\n                    ec = make_error_code(error::protocol_violation);\n                    m_state = FATAL_ERROR;\n                }\n            } else if (m_state == PAYLOAD) {\n                uint8_t *it = std::find(buf+p,buf+len,msg_ftr);\n\n                // 0    1    2    3    4    5\n                // 0x00 0x23 0x23 0x23 0xff 0xXX\n\n                // Copy payload bytes into message\n                l = static_cast<size_t>(it-(buf+p));\n                m_msg_ptr->append_payload(buf+p,l);\n                p += l;\n\n                if (it != buf+len) {\n                    // message is done, copy it and the trailing\n                    p++;\n                    // TODO: validation\n                    m_state = READY;\n                }\n            } else {\n                // TODO\n                break;\n            }\n        }\n        // If we get one, we create a new message and move to application state\n\n        // if in state application we are copying bytes into the output message\n        // and validating them for UTF8 until we hit a 0xff byte. Once we hit\n        // 0x00, the message is complete and is dispatched. Then we go back to\n        // header state.\n\n        //ec = make_error_code(error::not_implemented);\n        return p;\n    }\n\n    bool ready() const {\n        return (m_state == READY);\n    }\n\n    bool get_error() const {\n        return false;\n    }\n\n    message_ptr get_message() {\n        message_ptr ret = m_msg_ptr;\n        m_msg_ptr = message_ptr();\n        m_state = HEADER;\n        return ret;\n    }\n\n    /// Prepare a message for writing\n    /**\n     * Performs validation, masking, compression, etc. will return an error if\n     * there was an error, otherwise msg will be ready to be written\n     */\n    virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out)\n    {\n        if (!in || !out) {\n            return make_error_code(error::invalid_arguments);\n        }\n\n        // TODO: check if the message is prepared already\n\n        // validate opcode\n        if (in->get_opcode() != frame::opcode::text) {\n            return make_error_code(error::invalid_opcode);\n        }\n\n        std::string& i = in->get_raw_payload();\n        //std::string& o = out->get_raw_payload();\n\n        // validate payload utf8\n        if (!utf8_validator::validate(i)) {\n            return make_error_code(error::invalid_payload);\n        }\n\n        // generate header\n        out->set_header(std::string(reinterpret_cast<char const *>(&msg_hdr),1));\n\n        // process payload\n        out->set_payload(i);\n        out->append_payload(std::string(reinterpret_cast<char const *>(&msg_ftr),1));\n\n        // hybi00 doesn't support compression\n        // hybi00 doesn't have masking\n\n        out->set_prepared(true);\n\n        return lib::error_code();\n    }\n\n    /// Prepare a ping frame\n    /**\n     * Hybi 00 doesn't support pings so this will always return an error\n     *\n     * @param in The string to use for the ping payload\n     * @param out The message buffer to prepare the ping in.\n     * @return Status code, zero on success, non-zero on failure\n     */\n    lib::error_code prepare_ping(std::string const &, message_ptr) const\n    {\n        return lib::error_code(error::no_protocol_support);\n    }\n\n    /// Prepare a pong frame\n    /**\n     * Hybi 00 doesn't support pongs so this will always return an error\n     *\n     * @param in The string to use for the pong payload\n     * @param out The message buffer to prepare the pong in.\n     * @return Status code, zero on success, non-zero on failure\n     */\n    lib::error_code prepare_pong(std::string const &, message_ptr) const\n    {\n        return lib::error_code(error::no_protocol_support);\n    }\n\n    /// Prepare a close frame\n    /**\n     * Hybi 00 doesn't support the close code or reason so these parameters are\n     * ignored.\n     *\n     * @param code The close code to send\n     * @param reason The reason string to send\n     * @param out The message buffer to prepare the fame in\n     * @return Status code, zero on success, non-zero on failure\n     */\n    lib::error_code prepare_close(close::status::value, std::string const &, \n        message_ptr out) const\n    {\n        if (!out) {\n            return lib::error_code(error::invalid_arguments);\n        }\n\n        std::string val;\n        val.append(1,'\\xff');\n        val.append(1,'\\x00');\n        out->set_payload(val);\n        out->set_prepared(true);\n\n        return lib::error_code();\n    }\nprivate:\n    void decode_client_key(std::string const & key, char * result) const {\n        unsigned int spaces = 0;\n        std::string digits;\n        uint32_t num;\n\n        // key2\n        for (size_t i = 0; i < key.size(); i++) {\n            if (key[i] == ' ') {\n                spaces++;\n            } else if (key[i] >= '0' && key[i] <= '9') {\n                digits += key[i];\n            }\n        }\n\n        num = static_cast<uint32_t>(strtoul(digits.c_str(), NULL, 10));\n        if (spaces > 0 && num > 0) {\n            num = htonl(num/spaces);\n            std::copy(reinterpret_cast<char*>(&num),\n                      reinterpret_cast<char*>(&num)+4,\n                      result);\n        } else {\n            std::fill(result,result+4,0);\n        }\n    }\n\n    enum state {\n        HEADER = 0,\n        PAYLOAD = 1,\n        READY = 2,\n        FATAL_ERROR = 3\n    };\n\n    uint8_t const msg_hdr;\n    uint8_t const msg_ftr;\n\n    state m_state;\n\n    msg_manager_ptr m_msg_manager;\n    message_ptr m_msg_ptr;\n    utf8_validator::validator m_validator;\n};\n\n} // namespace processor\n} // namespace websocketpp\n\n#endif //WEBSOCKETPP_PROCESSOR_HYBI00_HPP\n"
  },
  {
    "path": "websocketpp/processors/hybi07.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_PROCESSOR_HYBI07_HPP\n#define WEBSOCKETPP_PROCESSOR_HYBI07_HPP\n\n#include <websocketpp/processors/hybi08.hpp>\n\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\nnamespace processor {\n\n/// Processor for Hybi Draft version 07\n/**\n * The primary difference between 07 and 08 is a version number.\n */\ntemplate <typename config>\nclass hybi07 : public hybi08<config> {\npublic:\n    typedef typename config::request_type request_type;\n\n    typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;\n    typedef typename config::rng_type rng_type;\n\n    explicit hybi07(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)\n      : hybi08<config>(secure, p_is_server, manager, rng) {}\n\n    /// Fill in a set of request headers for a client connection request\n    /**\n     * The Hybi 07 processor only implements incoming connections so this will\n     * always return an error.\n     *\n     * @param [out] req  Set of headers to fill in\n     * @param [in] uri The uri being connected to\n     * @param [in] subprotocols The list of subprotocols to request\n     */\n    lib::error_code client_handshake_request(request_type &, uri_ptr,\n        std::vector<std::string> const &) const\n    {\n        return error::make_error_code(error::no_protocol_support);\n    }\n\n    int get_version() const {\n        return 7;\n    }\nprivate:\n};\n\n} // namespace processor\n} // namespace websocketpp\n\n#endif //WEBSOCKETPP_PROCESSOR_HYBI07_HPP\n"
  },
  {
    "path": "websocketpp/processors/hybi08.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_PROCESSOR_HYBI08_HPP\n#define WEBSOCKETPP_PROCESSOR_HYBI08_HPP\n\n#include <websocketpp/processors/hybi13.hpp>\n\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\nnamespace processor {\n\n/// Processor for Hybi Draft version 08\n/**\n * The primary difference between 08 and 13 is a different origin header name\n */\ntemplate <typename config>\nclass hybi08 : public hybi13<config> {\npublic:\n    typedef hybi08<config> type;\n    typedef typename config::request_type request_type;\n\n    typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;\n    typedef typename config::rng_type rng_type;\n\n    explicit hybi08(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)\n      : hybi13<config>(secure, p_is_server, manager, rng) {}\n\n    /// Fill in a set of request headers for a client connection request\n    /**\n     * The Hybi 08 processor only implements incoming connections so this will\n     * always return an error.\n     *\n     * @param [out] req  Set of headers to fill in\n     * @param [in] uri The uri being connected to\n     * @param [in] subprotocols The list of subprotocols to request\n     */\n    lib::error_code client_handshake_request(request_type &, uri_ptr,\n        std::vector<std::string> const &) const\n    {\n        return error::make_error_code(error::no_protocol_support);\n    }\n\n    int get_version() const {\n        return 8;\n    }\n\n    std::string const & get_origin(request_type const & r) const {\n        return r.get_header(\"Sec-WebSocket-Origin\");\n    }\nprivate:\n};\n\n} // namespace processor\n} // namespace websocketpp\n\n#endif //WEBSOCKETPP_PROCESSOR_HYBI08_HPP\n"
  },
  {
    "path": "websocketpp/processors/hybi13.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_PROCESSOR_HYBI13_HPP\n#define WEBSOCKETPP_PROCESSOR_HYBI13_HPP\n\n#include <websocketpp/processors/processor.hpp>\n\n#include <websocketpp/frame.hpp>\n#include <websocketpp/http/constants.hpp>\n\n#include <websocketpp/utf8_validator.hpp>\n#include <websocketpp/sha1/sha1.hpp>\n#include <websocketpp/base64/base64.hpp>\n\n#include <websocketpp/common/network.hpp>\n#include <websocketpp/common/platforms.hpp>\n\n#include <algorithm>\n#include <cassert>\n#include <string>\n#include <vector>\n#include <utility>\n\nnamespace websocketpp {\nnamespace processor {\n\n/// Processor for Hybi version 13 (RFC6455)\ntemplate <typename config>\nclass hybi13 : public processor<config> {\npublic:\n    typedef processor<config> base;\n\n    typedef typename config::request_type request_type;\n    typedef typename config::response_type response_type;\n\n    typedef typename config::message_type message_type;\n    typedef typename message_type::ptr message_ptr;\n\n    typedef typename config::con_msg_manager_type msg_manager_type;\n    typedef typename msg_manager_type::ptr msg_manager_ptr;\n    typedef typename config::rng_type rng_type;\n\n    typedef typename config::permessage_deflate_type permessage_deflate_type;\n\n    typedef std::pair<lib::error_code,std::string> err_str_pair;\n\n    explicit hybi13(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)\n      : processor<config>(secure, p_is_server)\n      , m_msg_manager(manager)\n      , m_rng(rng)\n    {\n        reset_headers();\n    }\n\n    int get_version() const {\n        return 13;\n    }\n\n    bool has_permessage_deflate() const {\n        return m_permessage_deflate.is_implemented();\n    }\n\n    err_str_pair negotiate_extensions(request_type const & request) {\n        return negotiate_extensions_helper(request);\n    }\n    \n    err_str_pair negotiate_extensions(response_type const & response) {\n        return negotiate_extensions_helper(response);\n    }\n    \n    /// Extension negotiation helper function\n    /**\n     * This exists mostly because the code for requests and responses is\n     * identical and I can't have virtual template methods.\n     */\n    template <typename header_type>\n    err_str_pair negotiate_extensions_helper(header_type const & header) {\n        err_str_pair ret;\n\n        // Respect blanket disabling of all extensions and don't even parse\n        // the extension header\n        if (!config::enable_extensions) {\n            ret.first = make_error_code(error::extensions_disabled);\n            return ret;\n        }\n\n        http::parameter_list p;\n\n        bool error = header.get_header_as_plist(\"Sec-WebSocket-Extensions\",p);\n\n        if (error) {\n            ret.first = make_error_code(error::extension_parse_error);\n            return ret;\n        }\n\n        // If there are no extensions parsed then we are done!\n        if (p.size() == 0) {\n            return ret;\n        }\n\n        http::parameter_list::const_iterator it;\n\n        // look through the list of extension requests to find the first\n        // one that we can accept.\n        if (m_permessage_deflate.is_implemented()) {\n            err_str_pair neg_ret;\n            for (it = p.begin(); it != p.end(); ++it) {\n                // not a permessage-deflate extension request, ignore\n                if (it->first != \"permessage-deflate\") {\n                    continue;\n                }\n\n                // if we have already successfully negotiated this extension\n                // then skip any other requests to negotiate the same one\n                // with different parameters \n                if (m_permessage_deflate.is_enabled()) {\n                    continue;\n                }\n                \n                // attempt to negotiate this offer\n                neg_ret = m_permessage_deflate.negotiate(it->second);\n\n                if (neg_ret.first) {\n                    // negotiation offer failed. Do nothing. We will continue\n                    // searching for a permessage-deflate config that succeeds\n                    continue;\n                }\n\n                // Negotiation tentatively succeeded\n\n                // Actually try to initialize the extension before we\n                // deem negotiation complete\n                lib::error_code ec = m_permessage_deflate.init(base::m_server);\n\n                if (ec) {\n                    // Negotiation succeeded but initialization failed this is \n                    // an error that should stop negotiation of permessage \n                    // deflate. Return the reason for the init failure\n\n                    ret.first = ec;\n                    break;\n                } else {\n                    // Successfully initialized, push the negotiated response into\n                    // the reply and stop looking for additional permessage-deflate\n                    // extensions\n                    ret.second += neg_ret.second;\n                    break;\n                }\n            }\n        }\n\n        // support for future extensions would go here. Should check the value of \n        // ret.first before continuing. Might need to consider whether failure of\n        // negotiation of an earlier extension should stop negotiation of subsequent\n        // ones\n\n        return ret;\n    }\n\n    lib::error_code validate_handshake(request_type const & r) const {\n        if (r.get_method() != \"GET\") {\n            return make_error_code(error::invalid_http_method);\n        }\n\n        if (r.get_version() != \"HTTP/1.1\") {\n            return make_error_code(error::invalid_http_version);\n        }\n\n        // required headers\n        // Host is required by HTTP/1.1\n        // Connection is required by is_websocket_handshake\n        // Upgrade is required by is_websocket_handshake\n        if (r.get_header(\"Sec-WebSocket-Key\").empty()) {\n            return make_error_code(error::missing_required_header);\n        }\n\n        return lib::error_code();\n    }\n\n    /* TODO: the 'subprotocol' parameter may need to be expanded into a more\n     * generic struct if other user input parameters to the processed handshake\n     * are found.\n     */\n    lib::error_code process_handshake(request_type const & request, \n        std::string const & subprotocol, response_type & response) const\n    {\n        std::string server_key = request.get_header(\"Sec-WebSocket-Key\");\n\n        lib::error_code ec = process_handshake_key(server_key);\n\n        if (ec) {\n            return ec;\n        }\n\n        response.replace_header(\"Sec-WebSocket-Accept\",server_key);\n        response.append_header(\"Upgrade\",constants::upgrade_token);\n        response.append_header(\"Connection\",constants::connection_token);\n\n        if (!subprotocol.empty()) {\n            response.replace_header(\"Sec-WebSocket-Protocol\",subprotocol);\n        }\n\n        return lib::error_code();\n    }\n\n    /// Fill in a set of request headers for a client connection request\n    /**\n     * @param [out] req  Set of headers to fill in\n     * @param [in] uri The uri being connected to\n     * @param [in] subprotocols The list of subprotocols to request\n     */\n    lib::error_code client_handshake_request(request_type & req, uri_ptr\n        uri, std::vector<std::string> const & subprotocols) const\n    {\n        req.set_method(\"GET\");\n        req.set_uri(uri->get_resource());\n        req.set_version(\"HTTP/1.1\");\n\n        req.append_header(\"Upgrade\",\"websocket\");\n        req.append_header(\"Connection\",\"Upgrade\");\n        req.replace_header(\"Sec-WebSocket-Version\",\"13\");\n        req.replace_header(\"Host\",uri->get_host_port());\n\n        if (!subprotocols.empty()) {\n            std::ostringstream result;\n            std::vector<std::string>::const_iterator it = subprotocols.begin();\n            result << *it++;\n            while (it != subprotocols.end()) {\n                result << \", \" << *it++;\n            }\n\n            req.replace_header(\"Sec-WebSocket-Protocol\",result.str());\n        }\n\n        // Generate handshake key\n        frame::uint32_converter conv;\n        unsigned char raw_key[16];\n\n        for (int i = 0; i < 4; i++) {\n            conv.i = m_rng();\n            std::copy(conv.c,conv.c+4,&raw_key[i*4]);\n        }\n\n        req.replace_header(\"Sec-WebSocket-Key\",base64_encode(raw_key, 16));\n\n        if (m_permessage_deflate.is_implemented()) {\n            std::string offer = m_permessage_deflate.generate_offer();\n            if (!offer.empty()) {\n                req.replace_header(\"Sec-WebSocket-Extensions\",offer);\n            }\n        }\n\n        return lib::error_code();\n    }\n\n    /// Validate the server's response to an outgoing handshake request\n    /**\n     * @param req The original request sent\n     * @param res The reponse to generate\n     * @return An error code, 0 on success, non-zero for other errors\n     */\n    lib::error_code validate_server_handshake_response(request_type const & req,\n        response_type& res) const\n    {\n        // A valid response has an HTTP 101 switching protocols code\n        if (res.get_status_code() != http::status_code::switching_protocols) {\n            return error::make_error_code(error::invalid_http_status);\n        }\n\n        // And the upgrade token in an upgrade header\n        std::string const & upgrade_header = res.get_header(\"Upgrade\");\n        if (utility::ci_find_substr(upgrade_header, constants::upgrade_token,\n            sizeof(constants::upgrade_token)-1) == upgrade_header.end())\n        {\n            return error::make_error_code(error::missing_required_header);\n        }\n\n        // And the websocket token in the connection header\n        std::string const & con_header = res.get_header(\"Connection\");\n        if (utility::ci_find_substr(con_header, constants::connection_token,\n            sizeof(constants::connection_token)-1) == con_header.end())\n        {\n            return error::make_error_code(error::missing_required_header);\n        }\n\n        // And has a valid Sec-WebSocket-Accept value\n        std::string key = req.get_header(\"Sec-WebSocket-Key\");\n        lib::error_code ec = process_handshake_key(key);\n\n        if (ec || key != res.get_header(\"Sec-WebSocket-Accept\")) {\n            return error::make_error_code(error::missing_required_header);\n        }\n\n        // check extensions\n\n        return lib::error_code();\n    }\n\n    std::string get_raw(response_type const & res) const {\n        return res.raw();\n    }\n\n    std::string const & get_origin(request_type const & r) const {\n        return r.get_header(\"Origin\");\n    }\n\n    lib::error_code extract_subprotocols(request_type const & req,\n        std::vector<std::string> & subprotocol_list)\n    {\n        if (!req.get_header(\"Sec-WebSocket-Protocol\").empty()) {\n            http::parameter_list p;\n\n             if (!req.get_header_as_plist(\"Sec-WebSocket-Protocol\",p)) {\n                 http::parameter_list::const_iterator it;\n\n                 for (it = p.begin(); it != p.end(); ++it) {\n                     subprotocol_list.push_back(it->first);\n                 }\n             } else {\n                 return error::make_error_code(error::subprotocol_parse_error);\n             }\n        }\n        return lib::error_code();\n    }\n\n    uri_ptr get_uri(request_type const & request) const {\n        return get_uri_from_host(request,(base::m_secure ? \"wss\" : \"ws\"));\n    }\n\n    /// Process new websocket connection bytes\n    /**\n     *\n     * Hybi 13 data streams represent a series of variable length frames. Each\n     * frame is made up of a series of fixed length fields. The lengths of later\n     * fields are contained in earlier fields. The first field length is fixed\n     * by the spec.\n     *\n     * This processor represents a state machine that keeps track of what field\n     * is presently being read and how many more bytes are needed to complete it\n     *\n     *\n     *\n     *\n     * Read two header bytes\n     *   Extract full frame length.\n     *   Read extra header bytes\n     * Validate frame header (including extension validate)\n     * Read extension data into extension message state object\n     * Read payload data into payload\n     *\n     * @param buf Input buffer\n     *\n     * @param len Length of input buffer\n     *\n     * @return Number of bytes processed or zero on error\n     */\n    size_t consume(uint8_t * buf, size_t len, lib::error_code & ec) {\n        size_t p = 0;\n\n        ec = lib::error_code();\n\n        //std::cout << \"consume: \" << utility::to_hex(buf,len) << std::endl;\n\n        // Loop while we don't have a message ready and we still have bytes\n        // left to process.\n        while (m_state != READY && m_state != FATAL_ERROR &&\n               (p < len || m_bytes_needed == 0))\n        {\n            if (m_state == HEADER_BASIC) {\n                p += this->copy_basic_header_bytes(buf+p,len-p);\n\n                if (m_bytes_needed > 0) {\n                    continue;\n                }\n\n                ec = this->validate_incoming_basic_header(\n                    m_basic_header, base::m_server, !m_data_msg.msg_ptr\n                );\n                if (ec) {break;}\n\n                // extract full header size and adjust consume state accordingly\n                m_state = HEADER_EXTENDED;\n                m_cursor = 0;\n                m_bytes_needed = frame::get_header_len(m_basic_header) -\n                    frame::BASIC_HEADER_LENGTH;\n            } else if (m_state == HEADER_EXTENDED) {\n                p += this->copy_extended_header_bytes(buf+p,len-p);\n\n                if (m_bytes_needed > 0) {\n                    continue;\n                }\n\n                ec = validate_incoming_extended_header(m_basic_header,m_extended_header);\n                if (ec){break;}\n\n                m_state = APPLICATION;\n                m_bytes_needed = static_cast<size_t>(get_payload_size(m_basic_header,m_extended_header));\n\n                // check if this frame is the start of a new message and set up\n                // the appropriate message metadata.\n                frame::opcode::value op = frame::get_opcode(m_basic_header);\n\n                // TODO: get_message failure conditions\n\n                if (frame::opcode::is_control(op)) {\n                    m_control_msg = msg_metadata(\n                        m_msg_manager->get_message(op,m_bytes_needed),\n                        frame::get_masking_key(m_basic_header,m_extended_header)\n                    );\n\n                    m_current_msg = &m_control_msg;\n                } else {\n                    if (!m_data_msg.msg_ptr) {\n                        if (m_bytes_needed > base::m_max_message_size) {\n                            ec = make_error_code(error::message_too_big);\n                            break;\n                        }\n                        \n                        m_data_msg = msg_metadata(\n                            m_msg_manager->get_message(op,m_bytes_needed),\n                            frame::get_masking_key(m_basic_header,m_extended_header)\n                        );\n                        \n                        if (m_permessage_deflate.is_enabled()) {\n                            m_data_msg.msg_ptr->set_compressed(frame::get_rsv1(m_basic_header));\n                        }\n                    } else {\n                        // Fetch the underlying payload buffer from the data message we\n                        // are writing into.\n                        std::string & out = m_data_msg.msg_ptr->get_raw_payload();\n                        \n                        if (out.size() + m_bytes_needed > base::m_max_message_size) {\n                            ec = make_error_code(error::message_too_big);\n                            break;\n                        }\n                        \n                        // Each frame starts a new masking key. All other state\n                        // remains between frames.\n                        m_data_msg.prepared_key = prepare_masking_key(\n                            frame::get_masking_key(\n                                m_basic_header,\n                                m_extended_header\n                            )\n                        );\n                        \n                        out.reserve(out.size() + m_bytes_needed);\n                    }\n                    m_current_msg = &m_data_msg;\n                }\n            } else if (m_state == EXTENSION) {\n                m_state = APPLICATION;\n            } else if (m_state == APPLICATION) {\n                size_t bytes_to_process = (std::min)(m_bytes_needed,len-p);\n\n                if (bytes_to_process > 0) {\n                    p += this->process_payload_bytes(buf+p,bytes_to_process,ec);\n\n                    if (ec) {break;}\n                }\n\n                if (m_bytes_needed > 0) {\n                    continue;\n                }\n\n                // If this was the last frame in the message set the ready flag.\n                // Otherwise, reset processor state to read additional frames.\n                if (frame::get_fin(m_basic_header)) {\n                    ec = finalize_message();\n                    if (ec) {\n                        break;\n                    }\n                } else {\n                    this->reset_headers();\n                }\n            } else {\n                // shouldn't be here\n                ec = make_error_code(error::general);\n                return 0;\n            }\n        }\n\n        return p;\n    }\n\n    /// Perform any finalization actions on an incoming message\n    /**\n     * Called after the full message is received. Provides the opportunity for\n     * extensions to complete any data post processing as well as final UTF8\n     * validation checks for text messages.\n     *\n     * @return A code indicating errors, if any\n     */\n    lib::error_code finalize_message() {\n        std::string & out = m_current_msg->msg_ptr->get_raw_payload();\n\n        // if the frame is compressed, append the compression\n        // trailer and flush the compression buffer.\n        if (m_permessage_deflate.is_enabled()\n            && m_current_msg->msg_ptr->get_compressed())\n        {\n            uint8_t trailer[4] = {0x00, 0x00, 0xff, 0xff};\n\n            // Decompress current buffer into the message buffer\n            lib::error_code ec;\n            ec = m_permessage_deflate.decompress(trailer,4,out);\n            if (ec) {\n                return ec;\n            }\n        }\n\n        // ensure that text messages end on a valid UTF8 code point\n        if (frame::get_opcode(m_basic_header) == frame::opcode::TEXT) {\n            if (!m_current_msg->validator.complete()) {\n                return make_error_code(error::invalid_utf8);\n            }\n        }\n\n        m_state = READY;\n\n        return lib::error_code();\n    }\n\n    void reset_headers() {\n        m_state = HEADER_BASIC;\n        m_bytes_needed = frame::BASIC_HEADER_LENGTH;\n\n        m_basic_header.b0 = 0x00;\n        m_basic_header.b1 = 0x00;\n\n        std::fill_n(\n            m_extended_header.bytes,\n            frame::MAX_EXTENDED_HEADER_LENGTH,\n            0x00\n        );\n    }\n\n    /// Test whether or not the processor has a message ready\n    bool ready() const {\n        return (m_state == READY);\n    }\n\n    message_ptr get_message() {\n        if (!ready()) {\n            return message_ptr();\n        }\n        message_ptr ret = m_current_msg->msg_ptr;\n        m_current_msg->msg_ptr.reset();\n\n        if (frame::opcode::is_control(ret->get_opcode())) {\n            m_control_msg.msg_ptr.reset();\n        } else {\n            m_data_msg.msg_ptr.reset();\n        }\n\n        this->reset_headers();\n\n        return ret;\n    }\n\n    /// Test whether or not the processor is in a fatal error state.\n    bool get_error() const {\n        return m_state == FATAL_ERROR;\n    }\n\n    size_t get_bytes_needed() const {\n        return m_bytes_needed;\n    }\n\n    /// Prepare a user data message for writing\n    /**\n     * Performs validation, masking, compression, etc. will return an error if\n     * there was an error, otherwise msg will be ready to be written\n     *\n     * TODO: tests\n     *\n     * @param in An unprepared message to prepare\n     * @param out A message to be overwritten with the prepared message\n     * @return error code\n     */\n    virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out)\n    {\n        if (!in || !out) {\n            return make_error_code(error::invalid_arguments);\n        }\n\n        frame::opcode::value op = in->get_opcode();\n\n        // validate opcode: only regular data frames\n        if (frame::opcode::is_control(op)) {\n            return make_error_code(error::invalid_opcode);\n        }\n\n        std::string& i = in->get_raw_payload();\n        std::string& o = out->get_raw_payload();\n\n        // validate payload utf8\n        if (op == frame::opcode::TEXT && !utf8_validator::validate(i)) {\n            return make_error_code(error::invalid_payload);\n        }\n\n        frame::masking_key_type key;\n        bool masked = !base::m_server;\n        bool compressed = m_permessage_deflate.is_enabled()\n                          && in->get_compressed();\n        bool fin = in->get_fin();\n\n        if (masked) {\n            // Generate masking key.\n            key.i = m_rng();\n        } else {\n            key.i = 0;\n        }\n\n        // prepare payload\n        if (compressed) {\n            // compress and store in o after header.\n            m_permessage_deflate.compress(i,o);\n\n            if (o.size() < 4) {\n                return make_error_code(error::general);\n            }\n\n            // Strip trailing 4 0x00 0x00 0xff 0xff bytes before writing to the\n            // wire\n            o.resize(o.size()-4);\n\n            // mask in place if necessary\n            if (masked) {\n                this->masked_copy(o,o,key);\n            }\n        } else {\n            // no compression, just copy data into the output buffer\n            o.resize(i.size());\n\n            // if we are masked, have the masking function write to the output\n            // buffer directly to avoid another copy. If not masked, copy\n            // directly without masking.\n            if (masked) {\n                this->masked_copy(i,o,key);\n            } else {\n                std::copy(i.begin(),i.end(),o.begin());\n            }\n        }\n\n        // generate header\n        frame::basic_header h(op,o.size(),fin,masked,compressed);\n\n        if (masked) {\n            frame::extended_header e(o.size(),key.i);\n            out->set_header(frame::prepare_header(h,e));\n        } else {\n            frame::extended_header e(o.size());\n            out->set_header(frame::prepare_header(h,e));\n        }\n\n        out->set_prepared(true);\n        out->set_opcode(op);\n\n        return lib::error_code();\n    }\n\n    /// Get URI\n    lib::error_code prepare_ping(std::string const & in, message_ptr out) const {\n        return this->prepare_control(frame::opcode::PING,in,out);\n    }\n\n    lib::error_code prepare_pong(std::string const & in, message_ptr out) const {\n        return this->prepare_control(frame::opcode::PONG,in,out);\n    }\n\n    virtual lib::error_code prepare_close(close::status::value code,\n        std::string const & reason, message_ptr out) const\n    {\n        if (close::status::reserved(code)) {\n            return make_error_code(error::reserved_close_code);\n        }\n\n        if (close::status::invalid(code) && code != close::status::no_status) {\n            return make_error_code(error::invalid_close_code);\n        }\n\n        if (code == close::status::no_status && reason.size() > 0) {\n            return make_error_code(error::reason_requires_code);\n        }\n\n        if (reason.size() > frame:: limits::payload_size_basic-2) {\n            return make_error_code(error::control_too_big);\n        }\n\n        std::string payload;\n\n        if (code != close::status::no_status) {\n            close::code_converter val;\n            val.i = htons(code);\n\n            payload.resize(reason.size()+2);\n\n            payload[0] = val.c[0];\n            payload[1] = val.c[1];\n\n            std::copy(reason.begin(),reason.end(),payload.begin()+2);\n        }\n\n        return this->prepare_control(frame::opcode::CLOSE,payload,out);\n    }\nprotected:\n    /// Convert a client handshake key into a server response key in place\n    lib::error_code process_handshake_key(std::string & key) const {\n        key.append(constants::handshake_guid);\n\n        unsigned char message_digest[20];\n        sha1::calc(key.c_str(),key.length(),message_digest);\n        key = base64_encode(message_digest,20);\n\n        return lib::error_code();\n    }\n\n    /// Reads bytes from buf into m_basic_header\n    size_t copy_basic_header_bytes(uint8_t const * buf, size_t len) {\n        if (len == 0 || m_bytes_needed == 0) {\n            return 0;\n        }\n\n        if (len > 1) {\n            // have at least two bytes\n            if (m_bytes_needed == 2) {\n                m_basic_header.b0 = buf[0];\n                m_basic_header.b1 = buf[1];\n                m_bytes_needed -= 2;\n                return 2;\n            } else {\n                m_basic_header.b1 = buf[0];\n                m_bytes_needed--;\n                return 1;\n            }\n        } else {\n            // have exactly one byte\n            if (m_bytes_needed == 2) {\n                m_basic_header.b0 = buf[0];\n                m_bytes_needed--;\n                return 1;\n            } else {\n                m_basic_header.b1 = buf[0];\n                m_bytes_needed--;\n                return 1;\n            }\n        }\n    }\n\n    /// Reads bytes from buf into m_extended_header\n    size_t copy_extended_header_bytes(uint8_t const * buf, size_t len) {\n        size_t bytes_to_read = (std::min)(m_bytes_needed,len);\n\n        std::copy(buf,buf+bytes_to_read,m_extended_header.bytes+m_cursor);\n        m_cursor += bytes_to_read;\n        m_bytes_needed -= bytes_to_read;\n\n        return bytes_to_read;\n    }\n\n    /// Reads bytes from buf into message payload\n    /**\n     * This function performs unmasking and uncompression, validates the\n     * decoded bytes, and writes them to the appropriate message buffer.\n     *\n     * This member function will use the input buffer as stratch space for its\n     * work. The raw input bytes will not be preserved. This applies only to the\n     * bytes actually needed. At most min(m_bytes_needed,len) will be processed.\n     *\n     * @param buf Input/working buffer\n     * @param len Length of buf\n     * @return Number of bytes processed or zero in case of an error\n     */\n    size_t process_payload_bytes(uint8_t * buf, size_t len, lib::error_code& ec)\n    {\n        // unmask if masked\n        if (frame::get_masked(m_basic_header)) {\n            m_current_msg->prepared_key = frame::byte_mask_circ(\n                buf, len, m_current_msg->prepared_key);\n            // TODO: SIMD masking\n        }\n\n        std::string & out = m_current_msg->msg_ptr->get_raw_payload();\n        size_t offset = out.size();\n\n        // decompress message if needed.\n        if (m_permessage_deflate.is_enabled()\n            && m_current_msg->msg_ptr->get_compressed())\n        {\n            // Decompress current buffer into the message buffer\n            ec = m_permessage_deflate.decompress(buf,len,out);\n            if (ec) {\n                return 0;\n            }\n        } else {\n            // No compression, straight copy\n            out.append(reinterpret_cast<char *>(buf),len);\n        }\n\n        // validate unmasked, decompressed values\n        if (m_current_msg->msg_ptr->get_opcode() == frame::opcode::TEXT) {\n            if (!m_current_msg->validator.decode(out.begin()+offset,out.end())) {\n                ec = make_error_code(error::invalid_utf8);\n                return 0;\n            }\n        }\n\n        m_bytes_needed -= len;\n\n        return len;\n    }\n\n    /// Validate an incoming basic header\n    /**\n     * Validates an incoming hybi13 basic header.\n     *\n     * @param h The basic header to validate\n     * @param is_server Whether or not the endpoint that received this frame\n     * is a server.\n     * @param new_msg Whether or not this is the first frame of the message\n     * @return 0 on success or a non-zero error code on failure\n     */\n    lib::error_code validate_incoming_basic_header(frame::basic_header const & h,\n        bool is_server, bool new_msg) const\n    {\n        frame::opcode::value op = frame::get_opcode(h);\n\n        // Check control frame size limit\n        if (frame::opcode::is_control(op) &&\n            frame::get_basic_size(h) > frame::limits::payload_size_basic)\n        {\n            return make_error_code(error::control_too_big);\n        }\n\n        // Check that RSV bits are clear\n        // The only RSV bits allowed are rsv1 if the permessage_compress\n        // extension is enabled for this connection and the message is not\n        // a control message.\n        //\n        // TODO: unit tests for this\n        if (frame::get_rsv1(h) && (!m_permessage_deflate.is_enabled()\n                || frame::opcode::is_control(op)))\n        {\n            return make_error_code(error::invalid_rsv_bit);\n        }\n\n        if (frame::get_rsv2(h) || frame::get_rsv3(h)) {\n            return make_error_code(error::invalid_rsv_bit);\n        }\n\n        // Check for reserved opcodes\n        if (frame::opcode::reserved(op)) {\n            return make_error_code(error::invalid_opcode);\n        }\n\n        // Check for invalid opcodes\n        // TODO: unit tests for this?\n        if (frame::opcode::invalid(op)) {\n            return make_error_code(error::invalid_opcode);\n        }\n\n        // Check for fragmented control message\n        if (frame::opcode::is_control(op) && !frame::get_fin(h)) {\n            return make_error_code(error::fragmented_control);\n        }\n\n        // Check for continuation without an active message\n        if (new_msg && op == frame::opcode::CONTINUATION) {\n            return make_error_code(error::invalid_continuation);\n        }\n\n        // Check for new data frame when expecting continuation\n        if (!new_msg && !frame::opcode::is_control(op) &&\n            op != frame::opcode::CONTINUATION)\n        {\n            return make_error_code(error::invalid_continuation);\n        }\n\n        // Servers should reject any unmasked frames from clients.\n        // Clients should reject any masked frames from servers.\n        if (is_server && !frame::get_masked(h)) {\n            return make_error_code(error::masking_required);\n        } else if (!is_server && frame::get_masked(h)) {\n            return make_error_code(error::masking_forbidden);\n        }\n\n        return lib::error_code();\n    }\n\n    /// Validate an incoming extended header\n    /**\n     * Validates an incoming hybi13 full header.\n     *\n     * @todo unit test for the >32 bit frames on 32 bit systems case\n     *\n     * @param h The basic header to validate\n     * @param e The extended header to validate\n     * @return An error_code, non-zero values indicate why the validation\n     * failed\n     */\n    lib::error_code validate_incoming_extended_header(frame::basic_header h,\n        frame::extended_header e) const\n    {\n        uint8_t basic_size = frame::get_basic_size(h);\n        uint64_t payload_size = frame::get_payload_size(h,e);\n\n        // Check for non-minimally encoded payloads\n        if (basic_size == frame::payload_size_code_16bit &&\n            payload_size <= frame::limits::payload_size_basic)\n        {\n            return make_error_code(error::non_minimal_encoding);\n        }\n\n        if (basic_size == frame::payload_size_code_64bit &&\n            payload_size <= frame::limits::payload_size_extended)\n        {\n            return make_error_code(error::non_minimal_encoding);\n        }\n\n        // Check for >32bit frames on 32 bit systems\n        if (sizeof(size_t) == 4 && (payload_size >> 32)) {\n            return make_error_code(error::requires_64bit);\n        }\n\n        return lib::error_code();\n    }\n\n    /// Copy and mask/unmask in one operation\n    /**\n     * Reads input from one string and writes unmasked output to another.\n     *\n     * @param [in] i The input string.\n     * @param [out] o The output string.\n     * @param [in] key The masking key to use for masking/unmasking\n     */\n    void masked_copy (std::string const & i, std::string & o,\n        frame::masking_key_type key) const\n    {\n        frame::byte_mask(i.begin(),i.end(),o.begin(),key);\n        // TODO: SIMD masking\n    }\n\n    /// Generic prepare control frame with opcode and payload.\n    /**\n     * Internal control frame building method. Handles validation, masking, etc\n     *\n     * @param op The control opcode to use\n     * @param payload The payload to use\n     * @param out The message buffer to store the prepared frame in\n     * @return Status code, zero on success, non-zero on error\n     */\n    lib::error_code prepare_control(frame::opcode::value op,\n        std::string const & payload, message_ptr out) const\n    {\n        if (!out) {\n            return make_error_code(error::invalid_arguments);\n        }\n\n        if (!frame::opcode::is_control(op)) {\n            return make_error_code(error::invalid_opcode);\n        }\n\n        if (payload.size() > frame::limits::payload_size_basic) {\n            return make_error_code(error::control_too_big);\n        }\n\n        frame::masking_key_type key;\n        bool masked = !base::m_server;\n\n        frame::basic_header h(op,payload.size(),true,masked);\n\n        std::string & o = out->get_raw_payload();\n        o.resize(payload.size());\n\n        if (masked) {\n            // Generate masking key.\n            key.i = m_rng();\n\n            frame::extended_header e(payload.size(),key.i);\n            out->set_header(frame::prepare_header(h,e));\n            this->masked_copy(payload,o,key);\n        } else {\n            frame::extended_header e(payload.size());\n            out->set_header(frame::prepare_header(h,e));\n            std::copy(payload.begin(),payload.end(),o.begin());\n        }\n    \n        out->set_opcode(op);\n        out->set_prepared(true);\n\n        return lib::error_code();\n    }\n\n    enum state {\n        HEADER_BASIC = 0,\n        HEADER_EXTENDED = 1,\n        EXTENSION = 2,\n        APPLICATION = 3,\n        READY = 4,\n        FATAL_ERROR = 5\n    };\n\n    /// This data structure holds data related to processing a message, such as\n    /// the buffer it is being written to, its masking key, its UTF8 validation\n    /// state, and sometimes its compression state.\n    struct msg_metadata {\n        msg_metadata() {}\n        msg_metadata(message_ptr m, size_t p) : msg_ptr(m),prepared_key(p) {}\n        msg_metadata(message_ptr m, frame::masking_key_type p)\n          : msg_ptr(m)\n          , prepared_key(prepare_masking_key(p)) {}\n\n        message_ptr msg_ptr;        // pointer to the message data buffer\n        size_t      prepared_key;   // prepared masking key\n        utf8_validator::validator validator; // utf8 validation state\n    };\n\n    // Basic header of the frame being read\n    frame::basic_header m_basic_header;\n\n    // Pointer to a manager that can create message buffers for us.\n    msg_manager_ptr m_msg_manager;\n\n    // Number of bytes needed to complete the current operation\n    size_t m_bytes_needed;\n\n    // Number of extended header bytes read\n    size_t m_cursor;\n\n    // Metadata for the current data msg\n    msg_metadata m_data_msg;\n    // Metadata for the current control msg\n    msg_metadata m_control_msg;\n\n    // Pointer to the metadata associated with the frame being read\n    msg_metadata * m_current_msg;\n\n    // Extended header of current frame\n    frame::extended_header m_extended_header;\n\n    rng_type & m_rng;\n\n    // Overall state of the processor\n    state m_state;\n\n    // Extensions\n    permessage_deflate_type m_permessage_deflate;\n};\n\n} // namespace processor\n} // namespace websocketpp\n\n#endif //WEBSOCKETPP_PROCESSOR_HYBI13_HPP\n"
  },
  {
    "path": "websocketpp/processors/processor.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_PROCESSOR_HPP\n#define WEBSOCKETPP_PROCESSOR_HPP\n\n#include <websocketpp/processors/base.hpp>\n#include <websocketpp/common/system_error.hpp>\n\n#include <websocketpp/close.hpp>\n#include <websocketpp/utilities.hpp>\n#include <websocketpp/uri.hpp>\n\n#include <sstream>\n#include <string>\n#include <utility>\n#include <vector>\n\nnamespace websocketpp {\n/// Processors encapsulate the protocol rules specific to each WebSocket version\n/**\n * The processors namespace includes a number of free functions that operate on\n * various WebSocket related data structures and perform processing that is not\n * related to specific versions of the protocol.\n *\n * It also includes the abstract interface for the protocol specific processing\n * engines. These engines wrap all of the logic necessary for parsing and\n * validating WebSocket handshakes and messages of specific protocol version\n * and set of allowed extensions.\n *\n * An instance of a processor represents the state of a single WebSocket\n * connection of the associated version. One processor instance is needed per\n * logical WebSocket connection.\n */\nnamespace processor {\n\n/// Determine whether or not a generic HTTP request is a WebSocket handshake\n/**\n * @param r The HTTP request to read.\n *\n * @return True if the request is a WebSocket handshake, false otherwise\n */\ntemplate <typename request_type>\nbool is_websocket_handshake(request_type& r) {\n    using utility::ci_find_substr;\n\n    std::string const & upgrade_header = r.get_header(\"Upgrade\");\n\n    if (ci_find_substr(upgrade_header, constants::upgrade_token,\n        sizeof(constants::upgrade_token)-1) == upgrade_header.end())\n    {\n        return false;\n    }\n\n    std::string const & con_header = r.get_header(\"Connection\");\n\n    if (ci_find_substr(con_header, constants::connection_token,\n        sizeof(constants::connection_token)-1) == con_header.end())\n    {\n        return false;\n    }\n\n    return true;\n}\n\n/// Extract the version from a WebSocket handshake request\n/**\n * A blank version header indicates a spec before versions were introduced.\n * The only such versions in shipping products are Hixie Draft 75 and Hixie\n * Draft 76. Draft 75 is present in Chrome 4-5 and Safari 5.0.0, Draft 76 (also\n * known as hybi 00 is present in Chrome 6-13 and Safari 5.0.1+. As\n * differentiating between these two sets of browsers is very difficult and\n * Safari 5.0.1+ accounts for the vast majority of cases in the wild this\n * function assumes that all handshakes without a valid version header are\n * Hybi 00.\n *\n * @param r The WebSocket handshake request to read.\n *\n * @return The WebSocket handshake version or -1 if there was an extraction\n * error.\n */\ntemplate <typename request_type>\nint get_websocket_version(request_type& r) {\n    if (!r.ready()) {\n        return -2;\n    }\n    \n    if (r.get_header(\"Sec-WebSocket-Version\").empty()) {\n        return 0;\n    }\n\n    int version;\n    std::istringstream ss(r.get_header(\"Sec-WebSocket-Version\"));\n\n    if ((ss >> version).fail()) {\n        return -1;\n    }\n\n    return version;\n}\n\n/// Extract a URI ptr from the host header of the request\n/**\n * @param request The request to extract the Host header from.\n *\n * @param scheme The scheme under which this request was received (ws, wss,\n * http, https, etc)\n *\n * @return A uri_pointer that encodes the value of the host header.\n */\ntemplate <typename request_type>\nuri_ptr get_uri_from_host(request_type & request, std::string scheme) {\n    std::string h = request.get_header(\"Host\");\n\n    size_t last_colon = h.rfind(\":\");\n    size_t last_sbrace = h.rfind(\"]\");\n\n    // no : = hostname with no port\n    // last : before ] = ipv6 literal with no port\n    // : with no ] = hostname with port\n    // : after ] = ipv6 literal with port\n    if (last_colon == std::string::npos ||\n        (last_sbrace != std::string::npos && last_sbrace > last_colon))\n    {\n        return lib::make_shared<uri>(scheme, h, request.get_uri());\n    } else {\n        return lib::make_shared<uri>(scheme,\n                               h.substr(0,last_colon),\n                               h.substr(last_colon+1),\n                               request.get_uri());\n    }\n}\n\n/// WebSocket protocol processor abstract base class\ntemplate <typename config>\nclass processor {\npublic:\n    typedef processor<config> type;\n    typedef typename config::request_type request_type;\n    typedef typename config::response_type response_type;\n    typedef typename config::message_type::ptr message_ptr;\n    typedef std::pair<lib::error_code,std::string> err_str_pair;\n\n    explicit processor(bool secure, bool p_is_server)\n      : m_secure(secure)\n      , m_server(p_is_server)\n      , m_max_message_size(config::max_message_size)\n    {}\n\n    virtual ~processor() {}\n\n    /// Get the protocol version of this processor\n    virtual int get_version() const = 0;\n\n    /// Get maximum message size\n    /**\n     * Get maximum message size. Maximum message size determines the point at which the\n     * processor will fail a connection with the message_too_big protocol error.\n     *\n     * The default is retrieved from the max_message_size value from the template config\n     *\n     * @since 0.3.0\n     */\n    size_t get_max_message_size() const {\n        return m_max_message_size;\n    }\n    \n    /// Set maximum message size\n    /**\n     * Set maximum message size. Maximum message size determines the point at which the\n     * processor will fail a connection with the message_too_big protocol error.\n     *\n     * The default is retrieved from the max_message_size value from the template config\n     *\n     * @since 0.3.0\n     *\n     * @param new_value The value to set as the maximum message size.\n     */\n    void set_max_message_size(size_t new_value) {\n        m_max_message_size = new_value;\n    }\n\n    /// Returns whether or not the permessage_compress extension is implemented\n    /**\n     * Compile time flag that indicates whether this processor has implemented\n     * the permessage_compress extension. By default this is false.\n     */\n    virtual bool has_permessage_compress() const {\n        return false;\n    }\n\n    /// Initializes extensions based on the Sec-WebSocket-Extensions header\n    /**\n     * Reads the Sec-WebSocket-Extensions header and determines if any of the\n     * requested extensions are supported by this processor. If they are their\n     * settings data is initialized and an extension string to send to the\n     * is returned.\n     *\n     * @param request The request or response headers to look at.\n     */\n    virtual err_str_pair negotiate_extensions(request_type const &) {\n        return err_str_pair();\n    }\n    \n    /// Initializes extensions based on the Sec-WebSocket-Extensions header\n    /**\n     * Reads the Sec-WebSocket-Extensions header and determines if any of the\n     * requested extensions were accepted by the server. If they are their\n     * settings data is initialized. If they are not a list of required\n     * extensions (if any) is returned. This list may be sent back to the server\n     * as a part of the 1010/Extension required close code.\n     *\n     * @param response The request or response headers to look at.\n     */\n    virtual err_str_pair negotiate_extensions(response_type const &) {\n        return err_str_pair();\n    }\n\n    /// validate a WebSocket handshake request for this version\n    /**\n     * @param request The WebSocket handshake request to validate.\n     * is_websocket_handshake(request) must be true and\n     * get_websocket_version(request) must equal this->get_version().\n     *\n     * @return A status code, 0 on success, non-zero for specific sorts of\n     * failure\n     */\n    virtual lib::error_code validate_handshake(request_type const & request) const = 0;\n\n    /// Calculate the appropriate response for this websocket request\n    /**\n     * @param req The request to process\n     *\n     * @param subprotocol The subprotocol in use\n     *\n     * @param res The response to store the processed response in\n     *\n     * @return An error code, 0 on success, non-zero for other errors\n     */\n    virtual lib::error_code process_handshake(request_type const & req,\n        std::string const & subprotocol, response_type& res) const = 0;\n\n    /// Fill in an HTTP request for an outgoing connection handshake\n    /**\n     * @param req The request to process.\n     *\n     * @return An error code, 0 on success, non-zero for other errors\n     */\n    virtual lib::error_code client_handshake_request(request_type & req,\n        uri_ptr uri, std::vector<std::string> const & subprotocols) const = 0;\n\n    /// Validate the server's response to an outgoing handshake request\n    /**\n     * @param req The original request sent\n     * @param res The reponse to generate\n     * @return An error code, 0 on success, non-zero for other errors\n     */\n    virtual lib::error_code validate_server_handshake_response(request_type\n        const & req, response_type & res) const = 0;\n\n    /// Given a completed response, get the raw bytes to put on the wire\n    virtual std::string get_raw(response_type const & request) const = 0;\n\n    /// Return the value of the header containing the CORS origin.\n    virtual std::string const & get_origin(request_type const & request) const = 0;\n\n    /// Extracts requested subprotocols from a handshake request\n    /**\n     * Extracts a list of all subprotocols that the client has requested in the\n     * given opening handshake request.\n     *\n     * @param [in] req The request to extract from\n     * @param [out] subprotocol_list A reference to a vector of strings to store\n     * the results in.\n     */\n    virtual lib::error_code extract_subprotocols(const request_type & req,\n        std::vector<std::string> & subprotocol_list) = 0;\n\n    /// Extracts client uri from a handshake request\n    virtual uri_ptr get_uri(request_type const & request) const = 0;\n\n    /// process new websocket connection bytes\n    /**\n     * WebSocket connections are a continous stream of bytes that must be\n     * interpreted by a protocol processor into discrete frames.\n     *\n     * @param buf Buffer from which bytes should be read.\n     * @param len Length of buffer\n     * @param ec Reference to an error code to return any errors in\n     * @return Number of bytes processed\n     */\n    virtual size_t consume(uint8_t *buf, size_t len, lib::error_code & ec) = 0;\n\n    /// Checks if there is a message ready\n    /**\n     * Checks if the most recent consume operation processed enough bytes to\n     * complete a new WebSocket message. The message can be retrieved by calling\n     * get_message() which will reset the internal state to not-ready and allow\n     * consume to read more bytes.\n     *\n     * @return Whether or not a message is ready.\n     */\n    virtual bool ready() const = 0;\n\n    /// Retrieves the most recently processed message\n    /**\n     * Retrieves a shared pointer to the recently completed message if there is\n     * one. If ready() returns true then there is a message available.\n     * Retrieving the message with get_message will reset the state of ready.\n     * As such, each new message may be retrieved only once. Calling get_message\n     * when there is no message available will result in a null pointer being\n     * returned.\n     *\n     * @return A pointer to the most recently processed message or a null shared\n     *         pointer.\n     */\n    virtual message_ptr get_message() = 0;\n\n    /// Tests whether the processor is in a fatal error state\n    virtual bool get_error() const = 0;\n\n    /// Retrieves the number of bytes presently needed by the processor\n    /// This value may be used as a hint to the transport layer as to how many\n    /// bytes to wait for before running consume again.\n    virtual size_t get_bytes_needed() const {\n        return 1;\n    }\n\n    /// Prepare a data message for writing\n    /**\n     * Performs validation, masking, compression, etc. will return an error if\n     * there was an error, otherwise msg will be ready to be written\n     */\n    virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out) = 0;\n\n    /// Prepare a ping frame\n    /**\n     * Ping preparation is entirely state free. There is no payload validation\n     * other than length. Payload need not be UTF-8.\n     *\n     * @param in The string to use for the ping payload\n     * @param out The message buffer to prepare the ping in.\n     * @return Status code, zero on success, non-zero on failure\n     */\n    virtual lib::error_code prepare_ping(std::string const & in, message_ptr out) const \n        = 0;\n\n    /// Prepare a pong frame\n    /**\n     * Pong preparation is entirely state free. There is no payload validation\n     * other than length. Payload need not be UTF-8.\n     *\n     * @param in The string to use for the pong payload\n     * @param out The message buffer to prepare the pong in.\n     * @return Status code, zero on success, non-zero on failure\n     */\n    virtual lib::error_code prepare_pong(std::string const & in, message_ptr out) const \n        = 0;\n\n    /// Prepare a close frame\n    /**\n     * Close preparation is entirely state free. The code and reason are both\n     * subject to validation. Reason must be valid UTF-8. Code must be a valid\n     * un-reserved WebSocket close code. Use close::status::no_status to\n     * indicate no code. If no code is supplied a reason may not be specified.\n     *\n     * @param code The close code to send\n     * @param reason The reason string to send\n     * @param out The message buffer to prepare the fame in\n     * @return Status code, zero on success, non-zero on failure\n     */\n    virtual lib::error_code prepare_close(close::status::value code,\n        std::string const & reason, message_ptr out) const = 0;\nprotected:\n    bool const m_secure;\n    bool const m_server;\n    size_t m_max_message_size;\n};\n\n} // namespace processor\n} // namespace websocketpp\n\n#endif //WEBSOCKETPP_PROCESSOR_HPP\n"
  },
  {
    "path": "websocketpp/random/none.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_RANDOM_NONE_HPP\n#define WEBSOCKETPP_RANDOM_NONE_HPP\n\nnamespace websocketpp {\n/// Random number generation policies\nnamespace random {\n/// Stub RNG policy that always returns 0\nnamespace none {\n\n/// Thread safe stub \"random\" integer generator.\n/**\n * This template class provides a random integer stub. The interface mimics the\n * WebSocket++ RNG generator classes but the generater function always returns\n * zero. This can be used to stub out the RNG for unit and performance testing.\n *\n * Call operator() to generate the next number\n */\ntemplate <typename int_type>\nclass int_generator {\n    public:\n        int_generator() {}\n\n        /// advances the engine's state and returns the generated value\n        int_type operator()() {\n            return 0;\n        }\n};\n\n} // namespace none\n} // namespace random\n} // namespace websocketpp\n\n#endif //WEBSOCKETPP_RANDOM_NONE_HPP\n"
  },
  {
    "path": "websocketpp/random/random_device.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_RANDOM_RANDOM_DEVICE_HPP\n#define WEBSOCKETPP_RANDOM_RANDOM_DEVICE_HPP\n\n#include <websocketpp/common/random.hpp>\n\nnamespace websocketpp {\nnamespace random {\n/// RNG policy based on std::random_device or boost::random_device\nnamespace random_device {\n\n/// Thread safe non-deterministic random integer generator.\n/**\n * This template class provides thread safe non-deterministic random integer\n * generation. Numbers are produced in a uniformly distributed range from the\n * smallest to largest value that int_type can store.\n *\n * Thread-safety is provided via locking based on the concurrency template\n * parameter.\n *\n * Non-deterministic RNG is provided via websocketpp::lib which uses either\n * C++11 or Boost 1.47+'s random_device class.\n *\n * Call operator() to generate the next number\n */\ntemplate <typename int_type, typename concurrency>\nclass int_generator {\n    public:\n        typedef typename concurrency::scoped_lock_type scoped_lock_type;\n        typedef typename concurrency::mutex_type mutex_type;\n\n        /// constructor\n        //mac TODO: figure out if signed types present a range problem\n        int_generator() {}\n\n        /// advances the engine's state and returns the generated value\n        int_type operator()() {\n            scoped_lock_type guard(m_lock);\n            return m_dis(m_rng);\n        }\n    private:\n\n\n        lib::random_device m_rng;\n        lib::uniform_int_distribution<int_type> m_dis;\n\n        mutex_type m_lock;\n};\n\n} // namespace random_device\n} // namespace random\n} // namespace websocketpp\n\n#endif //WEBSOCKETPP_RANDOM_RANDOM_DEVICE_HPP\n"
  },
  {
    "path": "websocketpp/roles/client_endpoint.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_CLIENT_ENDPOINT_HPP\n#define WEBSOCKETPP_CLIENT_ENDPOINT_HPP\n\n#include <websocketpp/endpoint.hpp>\n#include <websocketpp/uri.hpp>\n\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/common/system_error.hpp>\n\n#include <string>\n\nnamespace websocketpp {\n\n/// Client endpoint role based on the given config\n/**\n *\n */\ntemplate <typename config>\nclass client : public endpoint<connection<config>,config> {\npublic:\n    /// Type of this endpoint\n    typedef client<config> type;\n\n    /// Type of the endpoint concurrency component\n    typedef typename config::concurrency_type concurrency_type;\n    /// Type of the endpoint transport component\n    typedef typename config::transport_type transport_type;\n\n    /// Type of the connections this server will create\n    typedef connection<config> connection_type;\n    /// Type of a shared pointer to the connections this server will create\n    typedef typename connection_type::ptr connection_ptr;\n\n    /// Type of the connection transport component\n    typedef typename transport_type::transport_con_type transport_con_type;\n    /// Type of a shared pointer to the connection transport component\n    typedef typename transport_con_type::ptr transport_con_ptr;\n\n    /// Type of the endpoint component of this server\n    typedef endpoint<connection_type,config> endpoint_type;\n\n    friend class connection<config>;\n\n    explicit client() : endpoint_type(false)\n    {\n        endpoint_type::m_alog->write(log::alevel::devel, \"client constructor\");\n    }\n\n    /// Get a new connection\n    /**\n     * Creates and returns a pointer to a new connection to the given URI\n     * suitable for passing to connect(connection_ptr). This method allows\n     * applying connection specific settings before performing the opening\n     * handshake.\n     *\n     * @param [in] location URI to open the connection to as a uri_ptr\n     * @param [out] ec An status code indicating failure reasons, if any\n     *\n     * @return A connection_ptr to the new connection\n     */\n    connection_ptr get_connection(uri_ptr location, lib::error_code & ec) {\n        if (location->get_secure() && !transport_type::is_secure()) {\n            ec = error::make_error_code(error::endpoint_not_secure);\n            return connection_ptr();\n        }\n\n        connection_ptr con = endpoint_type::create_connection();\n\n        if (!con) {\n            ec = error::make_error_code(error::con_creation_failed);\n            return con;\n        }\n\n        con->set_uri(location);\n\n        ec = lib::error_code();\n        return con;\n    }\n\n    /// Get a new connection (string version)\n    /**\n     * Creates and returns a pointer to a new connection to the given URI\n     * suitable for passing to connect(connection_ptr). This overload allows\n     * default construction of the uri_ptr from a standard string.\n     *\n     * @param [in] u URI to open the connection to as a string\n     * @param [out] ec An status code indicating failure reasons, if any\n     *\n     * @return A connection_ptr to the new connection\n     */\n    connection_ptr get_connection(std::string const & u, lib::error_code & ec) {\n        uri_ptr location = lib::make_shared<uri>(u);\n\n        if (!location->get_valid()) {\n            ec = error::make_error_code(error::invalid_uri);\n            return connection_ptr();\n        }\n\n        return get_connection(location, ec);\n    }\n\n    /// Begin the connection process for the given connection\n    /**\n     * Initiates the opening connection handshake for connection con. Exact\n     * behavior depends on the underlying transport policy.\n     *\n     * @param con The connection to connect\n     *\n     * @return The pointer to the connection originally passed in.\n     */\n    connection_ptr connect(connection_ptr con) {\n        // Ask transport to perform a connection\n        transport_type::async_connect(\n            lib::static_pointer_cast<transport_con_type>(con),\n            con->get_uri(),\n            lib::bind(\n                &type::handle_connect,\n                this,\n                con,\n                lib::placeholders::_1\n            )\n        );\n\n        return con;\n    }\nprivate:\n    // handle_connect\n    void handle_connect(connection_ptr con, lib::error_code const & ec) {\n        if (ec) {\n            con->terminate(ec);\n\n            endpoint_type::m_elog->write(log::elevel::rerror,\n                    \"handle_connect error: \"+ec.message());\n        } else {\n            endpoint_type::m_alog->write(log::alevel::connect,\n                \"Successful connection\");\n\n            con->start();\n        }\n    }\n};\n\n} // namespace websocketpp\n\n#endif //WEBSOCKETPP_CLIENT_ENDPOINT_HPP\n"
  },
  {
    "path": "websocketpp/roles/server_endpoint.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_SERVER_ENDPOINT_HPP\n#define WEBSOCKETPP_SERVER_ENDPOINT_HPP\n\n#include <websocketpp/endpoint.hpp>\n\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/common/system_error.hpp>\n\nnamespace websocketpp {\n\n/// Server endpoint role based on the given config\n/**\n *\n */\ntemplate <typename config>\nclass server : public endpoint<connection<config>,config> {\npublic:\n    /// Type of this endpoint\n    typedef server<config> type;\n\n    /// Type of the endpoint concurrency component\n    typedef typename config::concurrency_type concurrency_type;\n    /// Type of the endpoint transport component\n    typedef typename config::transport_type transport_type;\n\n    /// Type of the connections this server will create\n    typedef connection<config> connection_type;\n    /// Type of a shared pointer to the connections this server will create\n    typedef typename connection_type::ptr connection_ptr;\n\n    /// Type of the connection transport component\n    typedef typename transport_type::transport_con_type transport_con_type;\n    /// Type of a shared pointer to the connection transport component\n    typedef typename transport_con_type::ptr transport_con_ptr;\n\n    /// Type of the endpoint component of this server\n    typedef endpoint<connection_type,config> endpoint_type;\n\n    friend class connection<config>;\n\n    explicit server() : endpoint_type(true)\n    {\n        endpoint_type::m_alog->write(log::alevel::devel, \"server constructor\");\n    }\n\n    /// Destructor\n    ~server<config>() {}\n\n#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n    // no copy constructor because endpoints are not copyable\n    server<config>(server<config> &) = delete;\n\n    // no copy assignment operator because endpoints are not copyable\n    server<config> & operator=(server<config> const &) = delete;\n#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n\n#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_\n    /// Move constructor\n    server<config>(server<config> && o) : endpoint<connection<config>,config>(std::move(o)) {}\n\n#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n    // no move assignment operator because of const member variables\n    server<config> & operator=(server<config> &&) = delete;\n#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n\n#endif // _WEBSOCKETPP_MOVE_SEMANTICS_\n\n    /// Create and initialize a new connection\n    /**\n     * The connection will be initialized and ready to begin. Call its start()\n     * method to begin the processing loop.\n     *\n     * Note: The connection must either be started or terminated using\n     * connection::terminate in order to avoid memory leaks.\n     *\n     * @return A pointer to the new connection.\n     */\n    connection_ptr get_connection() {\n        return endpoint_type::create_connection();\n    }\n\n    /// Starts the server's async connection acceptance loop (exception free)\n    /**\n     * Initiates the server connection acceptance loop. Must be called after\n     * listen. This method will have no effect until the underlying io_service\n     * starts running. It may be called after the io_service is already running.\n     *\n     * Refer to documentation for the transport policy you are using for\n     * instructions on how to stop this acceptance loop.\n     *\n     * @param [out] ec A status code indicating an error, if any.\n     */\n    void start_accept(lib::error_code & ec) {\n        if (!transport_type::is_listening()) {\n            ec = error::make_error_code(error::async_accept_not_listening);\n            return;\n        }\n        \n        ec = lib::error_code();\n        connection_ptr con = get_connection();\n\n        if (!con) {\n          ec = error::make_error_code(error::con_creation_failed);\n          return;\n        }\n\n        transport_type::async_accept(\n            lib::static_pointer_cast<transport_con_type>(con),\n            lib::bind(&type::handle_accept,this,con,lib::placeholders::_1),\n            ec\n        );\n\n        if (ec && con) {\n            // If the connection was constructed but the accept failed,\n            // terminate the connection to prevent memory leaks\n            con->terminate(lib::error_code());\n        }\n    }\n\n    /// Starts the server's async connection acceptance loop\n    /**\n     * Initiates the server connection acceptance loop. Must be called after\n     * listen. This method will have no effect until the underlying io_service\n     * starts running. It may be called after the io_service is already running.\n     *\n     * Refer to documentation for the transport policy you are using for\n     * instructions on how to stop this acceptance loop.\n     */\n    void start_accept() {\n        lib::error_code ec;\n        start_accept(ec);\n        if (ec) {\n            throw exception(ec);\n        }\n    }\n\n    /// Handler callback for start_accept\n    void handle_accept(connection_ptr con, lib::error_code const & ec) {\n        if (ec) {\n            con->terminate(ec);\n\n            if (ec == error::operation_canceled) {\n                endpoint_type::m_elog->write(log::elevel::info,\n                    \"handle_accept error: \"+ec.message());\n            } else {\n                endpoint_type::m_elog->write(log::elevel::rerror,\n                    \"handle_accept error: \"+ec.message());\n            }\n        } else {\n            con->start();\n        }\n\n        lib::error_code start_ec;\n        start_accept(start_ec);\n        if (start_ec == error::async_accept_not_listening) {\n            endpoint_type::m_elog->write(log::elevel::info,\n                \"Stopping acceptance of new connections because the underlying transport is no longer listening.\");\n        } else if (start_ec) {\n            endpoint_type::m_elog->write(log::elevel::rerror,\n                \"Restarting async_accept loop failed: \"+ec.message());\n        }\n    }\n};\n\n} // namespace websocketpp\n\n#endif //WEBSOCKETPP_SERVER_ENDPOINT_HPP\n"
  },
  {
    "path": "websocketpp/server.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_SERVER_HPP\n#define WEBSOCKETPP_SERVER_HPP\n\n#include <websocketpp/roles/server_endpoint.hpp>\n\n#endif //WEBSOCKETPP_SERVER_HPP\n"
  },
  {
    "path": "websocketpp/sha1/sha1.hpp",
    "content": "/*\n*****\nsha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the smallsha1\nlibrary (http://code.google.com/p/smallsha1/) into a single header suitable for\nuse as a header only library. This conversion was done by Peter Thorson\n(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed\nunder the same license as the original, which is listed below.\n*****\n\n Copyright (c) 2011, Micael Hildenborg\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Micael Hildenborg nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY\n EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY\n DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef SHA1_DEFINED\n#define SHA1_DEFINED\n\nnamespace websocketpp {\nnamespace sha1 {\n\nnamespace { // local\n\n// Rotate an integer value to left.\ninline unsigned int rol(unsigned int value, unsigned int steps) {\n    return ((value << steps) | (value >> (32 - steps)));\n}\n\n// Sets the first 16 integers in the buffert to zero.\n// Used for clearing the W buffert.\ninline void clearWBuffert(unsigned int * buffert)\n{\n    for (int pos = 16; --pos >= 0;)\n    {\n        buffert[pos] = 0;\n    }\n}\n\ninline void innerHash(unsigned int * result, unsigned int * w)\n{\n    unsigned int a = result[0];\n    unsigned int b = result[1];\n    unsigned int c = result[2];\n    unsigned int d = result[3];\n    unsigned int e = result[4];\n\n    int round = 0;\n\n    #define sha1macro(func,val) \\\n    { \\\n        const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \\\n        e = d; \\\n        d = c; \\\n        c = rol(b, 30); \\\n        b = a; \\\n        a = t; \\\n    }\n\n    while (round < 16)\n    {\n        sha1macro((b & c) | (~b & d), 0x5a827999)\n        ++round;\n    }\n    while (round < 20)\n    {\n        w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\n        sha1macro((b & c) | (~b & d), 0x5a827999)\n        ++round;\n    }\n    while (round < 40)\n    {\n        w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\n        sha1macro(b ^ c ^ d, 0x6ed9eba1)\n        ++round;\n    }\n    while (round < 60)\n    {\n        w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\n        sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)\n        ++round;\n    }\n    while (round < 80)\n    {\n        w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);\n        sha1macro(b ^ c ^ d, 0xca62c1d6)\n        ++round;\n    }\n\n    #undef sha1macro\n\n    result[0] += a;\n    result[1] += b;\n    result[2] += c;\n    result[3] += d;\n    result[4] += e;\n}\n\n} // namespace\n\n/// Calculate a SHA1 hash\n/**\n * @param src points to any kind of data to be hashed.\n * @param bytelength the number of bytes to hash from the src pointer.\n * @param hash should point to a buffer of at least 20 bytes of size for storing\n * the sha1 result in.\n */\ninline void calc(void const * src, size_t bytelength, unsigned char * hash) {\n    // Init the result array.\n    unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe,\n                               0x10325476, 0xc3d2e1f0 };\n\n    // Cast the void src pointer to be the byte array we can work with.\n    unsigned char const * sarray = (unsigned char const *) src;\n\n    // The reusable round buffer\n    unsigned int w[80];\n\n    // Loop through all complete 64byte blocks.\n\n    size_t endCurrentBlock;\n    size_t currentBlock = 0;\n\n    if (bytelength >= 64) {\n        size_t const endOfFullBlocks = bytelength - 64;\n\n        while (currentBlock <= endOfFullBlocks) {\n            endCurrentBlock = currentBlock + 64;\n\n            // Init the round buffer with the 64 byte block data.\n            for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)\n            {\n                // This line will swap endian on big endian and keep endian on\n                // little endian.\n                w[roundPos++] = (unsigned int) sarray[currentBlock + 3]\n                        | (((unsigned int) sarray[currentBlock + 2]) << 8)\n                        | (((unsigned int) sarray[currentBlock + 1]) << 16)\n                        | (((unsigned int) sarray[currentBlock]) << 24);\n            }\n            innerHash(result, w);\n        }\n    }\n\n    // Handle the last and not full 64 byte block if existing.\n    endCurrentBlock = bytelength - currentBlock;\n    clearWBuffert(w);\n    size_t lastBlockBytes = 0;\n    for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) {\n        w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);\n    }\n\n    w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);\n    if (endCurrentBlock >= 56) {\n        innerHash(result, w);\n        clearWBuffert(w);\n    }\n    w[15] = bytelength << 3;\n    innerHash(result, w);\n\n    // Store hash in result pointer, and make sure we get in in the correct\n    // order on both endian models.\n    for (int hashByte = 20; --hashByte >= 0;) {\n        hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;\n    }\n}\n\n} // namespace sha1\n} // namespace websocketpp\n\n#endif // SHA1_DEFINED\n"
  },
  {
    "path": "websocketpp/transport/asio/base.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP\n#define WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP\n\n#include <websocketpp/common/asio.hpp>\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/functional.hpp>\n#include <websocketpp/common/system_error.hpp>\n#include <websocketpp/common/type_traits.hpp>\n\n#include <string>\n\nnamespace websocketpp {\nnamespace transport {\n/// Transport policy that uses asio\n/**\n * This policy uses a single asio io_service to provide transport\n * services to a WebSocket++ endpoint.\n */\nnamespace asio {\n\n// Class to manage the memory to be used for handler-based custom allocation.\n// It contains a single block of memory which may be returned for allocation\n// requests. If the memory is in use when an allocation request is made, the\n// allocator delegates allocation to the global heap.\nclass handler_allocator {\npublic:\n    static const size_t size = 1024;\n    \n    handler_allocator() : m_in_use(false) {}\n\n#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n\thandler_allocator(handler_allocator const & cpy) = delete;\n\thandler_allocator & operator =(handler_allocator const &) = delete;\n#endif\n\n    void * allocate(std::size_t memsize) {\n        if (!m_in_use && memsize < size) {\n            m_in_use = true;\n            return static_cast<void*>(&m_storage);\n        } else {\n            return ::operator new(memsize);\n        }\n    }\n\n    void deallocate(void * pointer) {\n        if (pointer == &m_storage) {\n            m_in_use = false;\n        } else {\n            ::operator delete(pointer);\n        }\n    }\n\nprivate:\n    // Storage space used for handler-based custom memory allocation.\n    lib::aligned_storage<size>::type m_storage;\n\n    // Whether the handler-based custom allocation storage has been used.\n    bool m_in_use;\n};\n\n// Wrapper class template for handler objects to allow handler memory\n// allocation to be customised. Calls to operator() are forwarded to the\n// encapsulated handler.\ntemplate <typename Handler>\nclass custom_alloc_handler {\npublic:\n    custom_alloc_handler(handler_allocator& a, Handler h)\n      : allocator_(a),\n        handler_(h)\n    {}\n\n    template <typename Arg1>\n    void operator()(Arg1 arg1) {\n        handler_(arg1);\n    }\n\n    template <typename Arg1, typename Arg2>\n    void operator()(Arg1 arg1, Arg2 arg2) {\n        handler_(arg1, arg2);\n    }\n\n    friend void* asio_handler_allocate(std::size_t size,\n        custom_alloc_handler<Handler> * this_handler)\n    {\n        return this_handler->allocator_.allocate(size);\n    }\n\n    friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,\n        custom_alloc_handler<Handler> * this_handler)\n    {\n        this_handler->allocator_.deallocate(pointer);\n    }\n\nprivate:\n    handler_allocator & allocator_;\n    Handler handler_;\n};\n\n// Helper function to wrap a handler object to add custom allocation.\ntemplate <typename Handler>\ninline custom_alloc_handler<Handler> make_custom_alloc_handler(\n    handler_allocator & a, Handler h)\n{\n    return custom_alloc_handler<Handler>(a, h);\n}\n\n\n\n\n\n\n\n// Forward declaration of class endpoint so that it can be friended/referenced\n// before being included.\ntemplate <typename config>\nclass endpoint;\n\ntypedef lib::function<void (lib::asio::error_code const & ec,\n    size_t bytes_transferred)> async_read_handler;\n\ntypedef lib::function<void (lib::asio::error_code const & ec,\n    size_t bytes_transferred)> async_write_handler;\n\ntypedef lib::function<void (lib::error_code const & ec)> pre_init_handler;\n\n// handle_timer: dynamic parameters, multiple copies\n// handle_proxy_write\n// handle_proxy_read\n// handle_async_write\n// handle_pre_init\n\n\n/// Asio transport errors\nnamespace error {\nenum value {\n    /// Catch-all error for transport policy errors that don't fit in other\n    /// categories\n    general = 1,\n\n    /// async_read_at_least call requested more bytes than buffer can store\n    invalid_num_bytes,\n\n    /// there was an error in the underlying transport library\n    pass_through,\n\n    /// The connection to the requested proxy server failed\n    proxy_failed,\n\n    /// Invalid Proxy URI\n    proxy_invalid,\n\n    /// Invalid host or service\n    invalid_host_service\n};\n\n/// Asio transport error category\nclass category : public lib::error_category {\npublic:\n    char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {\n        return \"websocketpp.transport.asio\";\n    }\n\n    std::string message(int value) const {\n        switch(value) {\n            case error::general:\n                return \"Generic asio transport policy error\";\n            case error::invalid_num_bytes:\n                return \"async_read_at_least call requested more bytes than buffer can store\";\n            case error::pass_through:\n                return \"Underlying Transport Error\";\n            case error::proxy_failed:\n                return \"Proxy connection failed\";\n            case error::proxy_invalid:\n                return \"Invalid proxy URI\";\n            case error::invalid_host_service:\n                return \"Invalid host or service\";\n            default:\n                return \"Unknown\";\n        }\n    }\n};\n\n/// Get a reference to a static copy of the asio transport error category\ninline lib::error_category const & get_category() {\n    static category instance;\n    return instance;\n}\n\n/// Create an error code with the given value and the asio transport category\ninline lib::error_code make_error_code(error::value e) {\n    return lib::error_code(static_cast<int>(e), get_category());\n}\n\n} // namespace error\n} // namespace asio\n} // namespace transport\n} // namespace websocketpp\n\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_\ntemplate<> struct is_error_code_enum<websocketpp::transport::asio::error::value>\n{\n    static bool const value = true;\n};\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_\n#endif // WEBSOCKETPP_TRANSPORT_ASIO_HPP\n"
  },
  {
    "path": "websocketpp/transport/asio/connection.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP\n#define WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP\n\n#include <websocketpp/transport/asio/base.hpp>\n\n#include <websocketpp/transport/base/connection.hpp>\n\n#include <websocketpp/logger/levels.hpp>\n#include <websocketpp/http/constants.hpp>\n\n#include <websocketpp/base64/base64.hpp>\n#include <websocketpp/error.hpp>\n#include <websocketpp/uri.hpp>\n\n#include <websocketpp/common/asio.hpp>\n#include <websocketpp/common/chrono.hpp>\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/common/functional.hpp>\n#include <websocketpp/common/connection_hdl.hpp>\n\n#include <istream>\n#include <sstream>\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\nnamespace transport {\nnamespace asio {\n\ntypedef lib::function<void(connection_hdl)> tcp_init_handler;\n\n/// Asio based connection transport component\n/**\n * transport::asio::connection implements a connection transport component using\n * Asio that works with the transport::asio::endpoint endpoint transport\n * component.\n */\ntemplate <typename config>\nclass connection : public config::socket_type::socket_con_type {\npublic:\n    /// Type of this connection transport component\n    typedef connection<config> type;\n    /// Type of a shared pointer to this connection transport component\n    typedef lib::shared_ptr<type> ptr;\n\n    /// Type of the socket connection component\n    typedef typename config::socket_type::socket_con_type socket_con_type;\n    /// Type of a shared pointer to the socket connection component\n    typedef typename socket_con_type::ptr socket_con_ptr;\n    /// Type of this transport's access logging policy\n    typedef typename config::alog_type alog_type;\n    /// Type of this transport's error logging policy\n    typedef typename config::elog_type elog_type;\n\n    typedef typename config::request_type request_type;\n    typedef typename request_type::ptr request_ptr;\n    typedef typename config::response_type response_type;\n    typedef typename response_type::ptr response_ptr;\n\n    /// Type of a pointer to the Asio io_service being used\n    typedef lib::asio::io_service * io_service_ptr;\n    /// Type of a pointer to the Asio io_service::strand being used\n    typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;\n    /// Type of a pointer to the Asio timer class\n    typedef lib::shared_ptr<lib::asio::steady_timer> timer_ptr;\n\n    // connection is friends with its associated endpoint to allow the endpoint\n    // to call private/protected utility methods that we don't want to expose\n    // to the public api.\n    friend class endpoint<config>;\n\n    // generate and manage our own io_service\n    explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)\n      : m_is_server(is_server)\n      , m_alog(alog)\n      , m_elog(elog)\n    {\n        m_alog->write(log::alevel::devel,\"asio con transport constructor\");\n    }\n\n    /// Get a shared pointer to this component\n    ptr get_shared() {\n        return lib::static_pointer_cast<type>(socket_con_type::get_shared());\n    }\n\n    bool is_secure() const {\n        return socket_con_type::is_secure();\n    }\n\n    /// Set uri hook\n    /**\n     * Called by the endpoint as a connection is being established to provide\n     * the uri being connected to to the transport layer.\n     *\n     * This transport policy doesn't use the uri except to forward it to the \n     * socket layer.\n     *\n     * @since 0.6.0\n     *\n     * @param u The uri to set\n     */\n    void set_uri(uri_ptr u) {\n        socket_con_type::set_uri(u);\n    }\n\n    /// Sets the tcp pre init handler\n    /**\n     * The tcp pre init handler is called after the raw tcp connection has been\n     * established but before any additional wrappers (proxy connects, TLS\n     * handshakes, etc) have been performed.\n     *\n     * @since 0.3.0\n     *\n     * @param h The handler to call on tcp pre init.\n     */\n    void set_tcp_pre_init_handler(tcp_init_handler h) {\n        m_tcp_pre_init_handler = h;\n    }\n\n    /// Sets the tcp pre init handler (deprecated)\n    /**\n     * The tcp pre init handler is called after the raw tcp connection has been\n     * established but before any additional wrappers (proxy connects, TLS\n     * handshakes, etc) have been performed.\n     *\n     * @deprecated Use set_tcp_pre_init_handler instead\n     *\n     * @param h The handler to call on tcp pre init.\n     */\n    void set_tcp_init_handler(tcp_init_handler h) {\n        set_tcp_pre_init_handler(h);\n    }\n\n    /// Sets the tcp post init handler\n    /**\n     * The tcp post init handler is called after the tcp connection has been\n     * established and all additional wrappers (proxy connects, TLS handshakes,\n     * etc have been performed. This is fired before any bytes are read or any\n     * WebSocket specific handshake logic has been performed.\n     *\n     * @since 0.3.0\n     *\n     * @param h The handler to call on tcp post init.\n     */\n    void set_tcp_post_init_handler(tcp_init_handler h) {\n        m_tcp_post_init_handler = h;\n    }\n\n    /// Set the proxy to connect through (exception free)\n    /**\n     * The URI passed should be a complete URI including scheme. For example:\n     * http://proxy.example.com:8080/\n     *\n     * The proxy must be set up as an explicit (CONNECT) proxy allowed to\n     * connect to the port you specify. Traffic to the proxy is not encrypted.\n     *\n     * @param uri The full URI of the proxy to connect to.\n     *\n     * @param ec A status value\n     */\n    void set_proxy(std::string const & uri, lib::error_code & ec) {\n        // TODO: return errors for illegal URIs here?\n        // TODO: should https urls be illegal for the moment?\n        m_proxy = uri;\n        m_proxy_data = lib::make_shared<proxy_data>();\n        ec = lib::error_code();\n    }\n\n    /// Set the proxy to connect through (exception)\n    void set_proxy(std::string const & uri) {\n        lib::error_code ec;\n        set_proxy(uri,ec);\n        if (ec) { throw exception(ec); }\n    }\n\n    /// Set the basic auth credentials to use (exception free)\n    /**\n     * The URI passed should be a complete URI including scheme. For example:\n     * http://proxy.example.com:8080/\n     *\n     * The proxy must be set up as an explicit proxy\n     *\n     * @param username The username to send\n     *\n     * @param password The password to send\n     *\n     * @param ec A status value\n     */\n    void set_proxy_basic_auth(std::string const & username, std::string const &\n        password, lib::error_code & ec)\n    {\n        if (!m_proxy_data) {\n            ec = make_error_code(websocketpp::error::invalid_state);\n            return;\n        }\n\n        // TODO: username can't contain ':'\n        std::string val = \"Basic \"+base64_encode(username + \":\" + password);\n        m_proxy_data->req.replace_header(\"Proxy-Authorization\",val);\n        ec = lib::error_code();\n    }\n\n    /// Set the basic auth credentials to use (exception)\n    void set_proxy_basic_auth(std::string const & username, std::string const &\n        password)\n    {\n        lib::error_code ec;\n        set_proxy_basic_auth(username,password,ec);\n        if (ec) { throw exception(ec); }\n    }\n\n    /// Set the proxy timeout duration (exception free)\n    /**\n     * Duration is in milliseconds. Default value is based on the transport\n     * config\n     *\n     * @param duration The number of milliseconds to wait before aborting the\n     * proxy connection.\n     *\n     * @param ec A status value\n     */\n    void set_proxy_timeout(long duration, lib::error_code & ec) {\n        if (!m_proxy_data) {\n            ec = make_error_code(websocketpp::error::invalid_state);\n            return;\n        }\n\n        m_proxy_data->timeout_proxy = duration;\n        ec = lib::error_code();\n    }\n\n    /// Set the proxy timeout duration (exception)\n    void set_proxy_timeout(long duration) {\n        lib::error_code ec;\n        set_proxy_timeout(duration,ec);\n        if (ec) { throw exception(ec); }\n    }\n\n    std::string const & get_proxy() const {\n        return m_proxy;\n    }\n\n    /// Get the remote endpoint address\n    /**\n     * The iostream transport has no information about the ultimate remote\n     * endpoint. It will return the string \"iostream transport\". To indicate\n     * this.\n     *\n     * TODO: allow user settable remote endpoint addresses if this seems useful\n     *\n     * @return A string identifying the address of the remote endpoint\n     */\n    std::string get_remote_endpoint() const {\n        lib::error_code ec;\n\n        std::string ret = socket_con_type::get_remote_endpoint(ec);\n\n        if (ec) {\n            m_elog->write(log::elevel::info,ret);\n            return \"Unknown\";\n        } else {\n            return ret;\n        }\n    }\n\n    /// Get the connection handle\n    connection_hdl get_handle() const {\n        return m_connection_hdl;\n    }\n\n    /// Call back a function after a period of time.\n    /**\n     * Sets a timer that calls back a function after the specified period of\n     * milliseconds. Returns a handle that can be used to cancel the timer.\n     * A cancelled timer will return the error code error::operation_aborted\n     * A timer that expired will return no error.\n     *\n     * @param duration Length of time to wait in milliseconds\n     *\n     * @param callback The function to call back when the timer has expired\n     *\n     * @return A handle that can be used to cancel the timer if it is no longer\n     * needed.\n     */\n    timer_ptr set_timer(long duration, timer_handler callback) {\n        timer_ptr new_timer(\n            new lib::asio::steady_timer(\n                *m_io_service,\n                lib::asio::milliseconds(duration))\n        );\n\n        if (config::enable_multithreading) {\n            new_timer->async_wait(m_strand->wrap(lib::bind(\n                &type::handle_timer, get_shared(),\n                new_timer,\n                callback,\n                lib::placeholders::_1\n            )));\n        } else {\n            new_timer->async_wait(lib::bind(\n                &type::handle_timer, get_shared(),\n                new_timer,\n                callback,\n                lib::placeholders::_1\n            ));\n        }\n\n        return new_timer;\n    }\n\n    /// Timer callback\n    /**\n     * The timer pointer is included to ensure the timer isn't destroyed until\n     * after it has expired.\n     *\n     * TODO: candidate for protected status\n     *\n     * @param post_timer Pointer to the timer in question\n     * @param callback The function to call back\n     * @param ec The status code\n     */\n    void handle_timer(timer_ptr, timer_handler callback,\n        lib::asio::error_code const & ec)\n    {\n        if (ec) {\n            if (ec == lib::asio::error::operation_aborted) {\n                callback(make_error_code(transport::error::operation_aborted));\n            } else {\n                log_err(log::elevel::info,\"asio handle_timer\",ec);\n                callback(make_error_code(error::pass_through));\n            }\n        } else {\n            callback(lib::error_code());\n        }\n    }\n\n    /// Get a pointer to this connection's strand\n    strand_ptr get_strand() {\n        return m_strand;\n    }\n\n    /// Get the internal transport error code for a closed/failed connection\n    /**\n     * Retrieves a machine readable detailed error code indicating the reason\n     * that the connection was closed or failed. Valid only after the close or\n     * fail handler is called.\n     *\n     * Primarily used if you are using mismatched asio / system_error\n     * implementations such as `boost::asio` with `std::system_error`. In these\n     * cases the transport error type is different than the library error type\n     * and some WebSocket++ functions that return transport errors via the \n     * library error code type will be coerced into a catch all `pass_through`\n     * or `tls_error` error. This method will return the original machine \n     * readable transport error in the native type.\n     *\n     * @since 0.7.0\n     *\n     * @return Error code indicating the reason the connection was closed or \n     * failed\n     */\n    lib::asio::error_code get_transport_ec() const {\n        return m_tec;\n    }\n\n    /// Initialize transport for reading\n    /**\n     * init_asio is called once immediately after construction to initialize\n     * Asio components to the io_service\n     *\n     * The transport initialization sequence consists of the following steps:\n     * - Pre-init: the underlying socket is initialized to the point where\n     * bytes may be written. No bytes are actually written in this stage\n     * - Proxy negotiation: if a proxy is set, a request is made to it to start\n     * a tunnel to the final destination. This stage ends when the proxy is\n     * ready to forward the\n     * next byte to the remote endpoint.\n     * - Post-init: Perform any i/o with the remote endpoint, such as setting up\n     * tunnels for encryption. This stage ends when the connection is ready to\n     * read or write the WebSocket handshakes. At this point the original\n     * callback function is called.\n     */\nprotected:\n    void init(init_handler callback) {\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\"asio connection init\");\n        }\n\n        // TODO: pre-init timeout. Right now no implemented socket policies\n        // actually have an asyncronous pre-init\n\n        socket_con_type::pre_init(\n            lib::bind(\n                &type::handle_pre_init,\n                get_shared(),\n                callback,\n                lib::placeholders::_1\n            )\n        );\n    }\n\n    /// initialize the proxy buffers and http parsers\n    /**\n     *\n     * @param authority The address of the server we want the proxy to tunnel to\n     * in the format of a URI authority (host:port)\n     *\n     * @return Status code indicating what errors occurred, if any\n     */\n    lib::error_code proxy_init(std::string const & authority) {\n        if (!m_proxy_data) {\n            return websocketpp::error::make_error_code(\n                websocketpp::error::invalid_state);\n        }\n        m_proxy_data->req.set_version(\"HTTP/1.1\");\n        m_proxy_data->req.set_method(\"CONNECT\");\n\n        m_proxy_data->req.set_uri(authority);\n        m_proxy_data->req.replace_header(\"Host\",authority);\n\n        return lib::error_code();\n    }\n\n    /// Finish constructing the transport\n    /**\n     * init_asio is called once immediately after construction to initialize\n     * Asio components to the io_service.\n     *\n     * @param io_service A pointer to the io_service to register with this\n     * connection\n     *\n     * @return Status code for the success or failure of the initialization\n     */\n    lib::error_code init_asio (io_service_ptr io_service) {\n        m_io_service = io_service;\n\n        if (config::enable_multithreading) {\n            m_strand.reset(new lib::asio::io_service::strand(*io_service));\n        }\n\n        lib::error_code ec = socket_con_type::init_asio(io_service, m_strand,\n            m_is_server);\n\n        return ec;\n    }\n\n    void handle_pre_init(init_handler callback, lib::error_code const & ec) {\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\"asio connection handle pre_init\");\n        }\n\n        if (m_tcp_pre_init_handler) {\n            m_tcp_pre_init_handler(m_connection_hdl);\n        }\n\n        if (ec) {\n            callback(ec);\n        }\n\n        // If we have a proxy set issue a proxy connect, otherwise skip to\n        // post_init\n        if (!m_proxy.empty()) {\n            proxy_write(callback);\n        } else {\n            post_init(callback);\n        }\n    }\n\n    void post_init(init_handler callback) {\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\"asio connection post_init\");\n        }\n\n        timer_ptr post_timer;\n        \n        if (config::timeout_socket_post_init > 0) {\n            post_timer = set_timer(\n                config::timeout_socket_post_init,\n                lib::bind(\n                    &type::handle_post_init_timeout,\n                    get_shared(),\n                    post_timer,\n                    callback,\n                    lib::placeholders::_1\n                )\n            );\n        }\n\n        socket_con_type::post_init(\n            lib::bind(\n                &type::handle_post_init,\n                get_shared(),\n                post_timer,\n                callback,\n                lib::placeholders::_1\n            )\n        );\n    }\n\n    /// Post init timeout callback\n    /**\n     * The timer pointer is included to ensure the timer isn't destroyed until\n     * after it has expired.\n     *\n     * @param post_timer Pointer to the timer in question\n     * @param callback The function to call back\n     * @param ec The status code\n     */\n    void handle_post_init_timeout(timer_ptr, init_handler callback,\n        lib::error_code const & ec)\n    {\n        lib::error_code ret_ec;\n\n        if (ec) {\n            if (ec == transport::error::operation_aborted) {\n                m_alog->write(log::alevel::devel,\n                    \"asio post init timer cancelled\");\n                return;\n            }\n\n            log_err(log::elevel::devel,\"asio handle_post_init_timeout\",ec);\n            ret_ec = ec;\n        } else {\n            if (socket_con_type::get_ec()) {\n                ret_ec = socket_con_type::get_ec();\n            } else {\n                ret_ec = make_error_code(transport::error::timeout);\n            }\n        }\n\n        m_alog->write(log::alevel::devel, \"Asio transport post-init timed out\");\n        cancel_socket_checked();\n        callback(ret_ec);\n    }\n\n    /// Post init timeout callback\n    /**\n     * The timer pointer is included to ensure the timer isn't destroyed until\n     * after it has expired.\n     *\n     * @param post_timer Pointer to the timer in question\n     * @param callback The function to call back\n     * @param ec The status code\n     */\n    void handle_post_init(timer_ptr post_timer, init_handler callback,\n        lib::error_code const & ec)\n    {\n        if (ec == transport::error::operation_aborted ||\n            (post_timer && lib::asio::is_neg(post_timer->expires_from_now())))\n        {\n            m_alog->write(log::alevel::devel,\"post_init cancelled\");\n            return;\n        }\n\n        if (post_timer) {\n            post_timer->cancel();\n        }\n\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\"asio connection handle_post_init\");\n        }\n\n        if (m_tcp_post_init_handler) {\n            m_tcp_post_init_handler(m_connection_hdl);\n        }\n\n        callback(ec);\n    }\n\n    void proxy_write(init_handler callback) {\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\"asio connection proxy_write\");\n        }\n\n        if (!m_proxy_data) {\n            m_elog->write(log::elevel::library,\n                \"assertion failed: !m_proxy_data in asio::connection::proxy_write\");\n            callback(make_error_code(error::general));\n            return;\n        }\n\n        m_proxy_data->write_buf = m_proxy_data->req.raw();\n\n        m_bufs.push_back(lib::asio::buffer(m_proxy_data->write_buf.data(),\n                                           m_proxy_data->write_buf.size()));\n\n        m_alog->write(log::alevel::devel,m_proxy_data->write_buf);\n\n        // Set a timer so we don't wait forever for the proxy to respond\n        m_proxy_data->timer = this->set_timer(\n            m_proxy_data->timeout_proxy,\n            lib::bind(\n                &type::handle_proxy_timeout,\n                get_shared(),\n                callback,\n                lib::placeholders::_1\n            )\n        );\n\n        // Send proxy request\n        if (config::enable_multithreading) {\n            lib::asio::async_write(\n                socket_con_type::get_next_layer(),\n                m_bufs,\n                m_strand->wrap(lib::bind(\n                    &type::handle_proxy_write, get_shared(),\n                    callback,\n                    lib::placeholders::_1\n                ))\n            );\n        } else {\n            lib::asio::async_write(\n                socket_con_type::get_next_layer(),\n                m_bufs,\n                lib::bind(\n                    &type::handle_proxy_write, get_shared(),\n                    callback,\n                    lib::placeholders::_1\n                )\n            );\n        }\n    }\n\n    void handle_proxy_timeout(init_handler callback, lib::error_code const & ec)\n    {\n        if (ec == transport::error::operation_aborted) {\n            m_alog->write(log::alevel::devel,\n                \"asio handle_proxy_write timer cancelled\");\n            return;\n        } else if (ec) {\n            log_err(log::elevel::devel,\"asio handle_proxy_write\",ec);\n            callback(ec);\n        } else {\n            m_alog->write(log::alevel::devel,\n                \"asio handle_proxy_write timer expired\");\n            cancel_socket_checked();\n            callback(make_error_code(transport::error::timeout));\n        }\n    }\n\n    void handle_proxy_write(init_handler callback,\n        lib::asio::error_code const & ec)\n    {\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\n                \"asio connection handle_proxy_write\");\n        }\n\n        m_bufs.clear();\n\n        // Timer expired or the operation was aborted for some reason.\n        // Whatever aborted it will be issuing the callback so we are safe to\n        // return\n        if (ec == lib::asio::error::operation_aborted ||\n            lib::asio::is_neg(m_proxy_data->timer->expires_from_now()))\n        {\n            m_elog->write(log::elevel::devel,\"write operation aborted\");\n            return;\n        }\n\n        if (ec) {\n            log_err(log::elevel::info,\"asio handle_proxy_write\",ec);\n            m_proxy_data->timer->cancel();\n            callback(make_error_code(error::pass_through));\n            return;\n        }\n\n        proxy_read(callback);\n    }\n\n    void proxy_read(init_handler callback) {\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\"asio connection proxy_read\");\n        }\n\n        if (!m_proxy_data) {\n            m_elog->write(log::elevel::library,\n                \"assertion failed: !m_proxy_data in asio::connection::proxy_read\");\n            m_proxy_data->timer->cancel();\n            callback(make_error_code(error::general));\n            return;\n        }\n\n        if (config::enable_multithreading) {\n            lib::asio::async_read_until(\n                socket_con_type::get_next_layer(),\n                m_proxy_data->read_buf,\n                \"\\r\\n\\r\\n\",\n                m_strand->wrap(lib::bind(\n                    &type::handle_proxy_read, get_shared(),\n                    callback,\n                    lib::placeholders::_1, lib::placeholders::_2\n                ))\n            );\n        } else {\n            lib::asio::async_read_until(\n                socket_con_type::get_next_layer(),\n                m_proxy_data->read_buf,\n                \"\\r\\n\\r\\n\",\n                lib::bind(\n                    &type::handle_proxy_read, get_shared(),\n                    callback,\n                    lib::placeholders::_1, lib::placeholders::_2\n                )\n            );\n        }\n    }\n\n    /// Proxy read callback\n    /**\n     * @param init_handler The function to call back\n     * @param ec The status code\n     * @param bytes_transferred The number of bytes read\n     */\n    void handle_proxy_read(init_handler callback,\n        lib::asio::error_code const & ec, size_t)\n    {\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\n                \"asio connection handle_proxy_read\");\n        }\n\n        // Timer expired or the operation was aborted for some reason.\n        // Whatever aborted it will be issuing the callback so we are safe to\n        // return\n        if (ec == lib::asio::error::operation_aborted ||\n            lib::asio::is_neg(m_proxy_data->timer->expires_from_now()))\n        {\n            m_elog->write(log::elevel::devel,\"read operation aborted\");\n            return;\n        }\n\n        // At this point there is no need to wait for the timer anymore\n        m_proxy_data->timer->cancel();\n\n        if (ec) {\n            m_elog->write(log::elevel::info,\n                \"asio handle_proxy_read error: \"+ec.message());\n            callback(make_error_code(error::pass_through));\n        } else {\n            if (!m_proxy_data) {\n                m_elog->write(log::elevel::library,\n                    \"assertion failed: !m_proxy_data in asio::connection::handle_proxy_read\");\n                callback(make_error_code(error::general));\n                return;\n            }\n\n            std::istream input(&m_proxy_data->read_buf);\n\n            m_proxy_data->res.consume(input);\n\n            if (!m_proxy_data->res.headers_ready()) {\n                // we read until the headers were done in theory but apparently\n                // they aren't. Internal endpoint error.\n                callback(make_error_code(error::general));\n                return;\n            }\n\n            m_alog->write(log::alevel::devel,m_proxy_data->res.raw());\n\n            if (m_proxy_data->res.get_status_code() != http::status_code::ok) {\n                // got an error response back\n                // TODO: expose this error in a programmatically accessible way?\n                // if so, see below for an option on how to do this.\n                std::stringstream s;\n                s << \"Proxy connection error: \"\n                  << m_proxy_data->res.get_status_code()\n                  << \" (\"\n                  << m_proxy_data->res.get_status_msg()\n                  << \")\";\n                m_elog->write(log::elevel::info,s.str());\n                callback(make_error_code(error::proxy_failed));\n                return;\n            }\n\n            // we have successfully established a connection to the proxy, now\n            // we can continue and the proxy will transparently forward the\n            // WebSocket connection.\n\n            // TODO: decide if we want an on_proxy callback that would allow\n            // access to the proxy response.\n\n            // free the proxy buffers and req/res objects as they aren't needed\n            // anymore\n            m_proxy_data.reset();\n\n            // Continue with post proxy initialization\n            post_init(callback);\n        }\n    }\n\n    /// read at least num_bytes bytes into buf and then call handler.\n    void async_read_at_least(size_t num_bytes, char *buf, size_t len,\n        read_handler handler)\n    {\n        if (m_alog->static_test(log::alevel::devel)) {\n            std::stringstream s;\n            s << \"asio async_read_at_least: \" << num_bytes;\n            m_alog->write(log::alevel::devel,s.str());\n        }\n\n        // TODO: safety vs speed ?\n        // maybe move into an if devel block\n        /*if (num_bytes > len) {\n            m_elog->write(log::elevel::devel,\n                \"asio async_read_at_least error::invalid_num_bytes\");\n            handler(make_error_code(transport::error::invalid_num_bytes),\n                size_t(0));\n            return;\n        }*/\n\n        if (config::enable_multithreading) {\n            lib::asio::async_read(\n                socket_con_type::get_socket(),\n                lib::asio::buffer(buf,len),\n                lib::asio::transfer_at_least(num_bytes),\n                m_strand->wrap(make_custom_alloc_handler(\n                    m_read_handler_allocator,\n                    lib::bind(\n                        &type::handle_async_read, get_shared(),\n                        handler,\n                        lib::placeholders::_1, lib::placeholders::_2\n                    )\n                ))\n            );\n        } else {\n            lib::asio::async_read(\n                socket_con_type::get_socket(),\n                lib::asio::buffer(buf,len),\n                lib::asio::transfer_at_least(num_bytes),\n                make_custom_alloc_handler(\n                    m_read_handler_allocator,\n                    lib::bind(\n                        &type::handle_async_read, get_shared(),\n                        handler,\n                        lib::placeholders::_1, lib::placeholders::_2\n                    )\n                )\n            );    \n        }\n        \n    }\n\n    void handle_async_read(read_handler handler, lib::asio::error_code const & ec,\n        size_t bytes_transferred)\n    {\n        m_alog->write(log::alevel::devel, \"asio con handle_async_read\");\n\n        // translate asio error codes into more lib::error_codes\n        lib::error_code tec;\n        if (ec == lib::asio::error::eof) {\n            tec = make_error_code(transport::error::eof);\n        } else if (ec) {\n            // We don't know much more about the error at this point. As our\n            // socket/security policy if it knows more:\n            tec = socket_con_type::translate_ec(ec);\n            m_tec = ec;\n\n            if (tec == transport::error::tls_error ||\n                tec == transport::error::pass_through)\n            {\n                // These are aggregate/catch all errors. Log some human readable\n                // information to the info channel to give library users some\n                // more details about why the upstream method may have failed.\n                log_err(log::elevel::info,\"asio async_read_at_least\",ec);\n            }\n        }\n        if (handler) {\n            handler(tec,bytes_transferred);\n        } else {\n            // This can happen in cases where the connection is terminated while\n            // the transport is waiting on a read.\n            m_alog->write(log::alevel::devel,\n                \"handle_async_read called with null read handler\");\n        }\n    }\n\n    /// Initiate a potentially asyncronous write of the given buffer\n    void async_write(const char* buf, size_t len, write_handler handler) {\n        m_bufs.push_back(lib::asio::buffer(buf,len));\n\n        if (config::enable_multithreading) {\n            lib::asio::async_write(\n                socket_con_type::get_socket(),\n                m_bufs,\n                m_strand->wrap(make_custom_alloc_handler(\n                    m_write_handler_allocator,\n                    lib::bind(\n                        &type::handle_async_write, get_shared(),\n                        handler,\n                        lib::placeholders::_1, lib::placeholders::_2\n                    )\n                ))\n            );\n        } else {\n            lib::asio::async_write(\n                socket_con_type::get_socket(),\n                m_bufs,\n                make_custom_alloc_handler(\n                    m_write_handler_allocator,\n                    lib::bind(\n                        &type::handle_async_write, get_shared(),\n                        handler,\n                        lib::placeholders::_1, lib::placeholders::_2\n                    )\n                )\n            );\n        }\n    }\n\n    /// Initiate a potentially asyncronous write of the given buffers\n    void async_write(std::vector<buffer> const & bufs, write_handler handler) {\n        std::vector<buffer>::const_iterator it;\n\n        for (it = bufs.begin(); it != bufs.end(); ++it) {\n            m_bufs.push_back(lib::asio::buffer((*it).buf,(*it).len));\n        }\n\n        if (config::enable_multithreading) {\n            lib::asio::async_write(\n                socket_con_type::get_socket(),\n                m_bufs,\n                m_strand->wrap(make_custom_alloc_handler(\n                    m_write_handler_allocator,\n                    lib::bind(\n                        &type::handle_async_write, get_shared(),\n                        handler,\n                        lib::placeholders::_1, lib::placeholders::_2\n                    )\n                ))\n            );\n        } else {\n            lib::asio::async_write(\n                socket_con_type::get_socket(),\n                m_bufs,\n                make_custom_alloc_handler(\n                    m_write_handler_allocator,\n                    lib::bind(\n                        &type::handle_async_write, get_shared(),\n                        handler,\n                        lib::placeholders::_1, lib::placeholders::_2\n                    )\n                )\n            );\n        }\n    }\n\n    /// Async write callback\n    /**\n     * @param ec The status code\n     * @param bytes_transferred The number of bytes read\n     */\n    void handle_async_write(write_handler handler, lib::asio::error_code const & ec, size_t) {\n        m_bufs.clear();\n        lib::error_code tec;\n        if (ec) {\n            log_err(log::elevel::info,\"asio async_write\",ec);\n            tec = make_error_code(transport::error::pass_through);\n        }\n        if (handler) {\n            handler(tec);\n        } else {\n            // This can happen in cases where the connection is terminated while\n            // the transport is waiting on a read.\n            m_alog->write(log::alevel::devel,\n                \"handle_async_write called with null write handler\");\n        }\n    }\n\n    /// Set Connection Handle\n    /**\n     * See common/connection_hdl.hpp for information\n     *\n     * @param hdl A connection_hdl that the transport will use to refer\n     * to itself\n     */\n    void set_handle(connection_hdl hdl) {\n        m_connection_hdl = hdl;\n        socket_con_type::set_handle(hdl);\n    }\n\n    /// Trigger the on_interrupt handler\n    /**\n     * This needs to be thread safe\n     */\n    lib::error_code interrupt(interrupt_handler handler) {\n        if (config::enable_multithreading) {\n            m_io_service->post(m_strand->wrap(handler));\n        } else {\n            m_io_service->post(handler);\n        }\n        return lib::error_code();\n    }\n\n    lib::error_code dispatch(dispatch_handler handler) {\n        if (config::enable_multithreading) {\n            m_io_service->post(m_strand->wrap(handler));\n        } else {\n            m_io_service->post(handler);\n        }\n        return lib::error_code();\n    }\n\n    /*void handle_interrupt(interrupt_handler handler) {\n        handler();\n    }*/\n\n    /// close and clean up the underlying socket\n    void async_shutdown(shutdown_handler callback) {\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\"asio connection async_shutdown\");\n        }\n\n        timer_ptr shutdown_timer;\n        shutdown_timer = set_timer(\n            config::timeout_socket_shutdown,\n            lib::bind(\n                &type::handle_async_shutdown_timeout,\n                get_shared(),\n                shutdown_timer,\n                callback,\n                lib::placeholders::_1\n            )\n        );\n\n        socket_con_type::async_shutdown(\n            lib::bind(\n                &type::handle_async_shutdown,\n                get_shared(),\n                shutdown_timer,\n                callback,\n                lib::placeholders::_1\n            )\n        );\n    }\n\n    /// Async shutdown timeout handler\n    /**\n     * @param shutdown_timer A pointer to the timer to keep it in scope\n     * @param callback The function to call back\n     * @param ec The status code\n     */\n    void handle_async_shutdown_timeout(timer_ptr, init_handler callback, \n        lib::error_code const & ec)\n    {\n        lib::error_code ret_ec;\n\n        if (ec) {\n            if (ec == transport::error::operation_aborted) {\n                m_alog->write(log::alevel::devel,\n                    \"asio socket shutdown timer cancelled\");\n                return;\n            }\n\n            log_err(log::elevel::devel,\"asio handle_async_shutdown_timeout\",ec);\n            ret_ec = ec;\n        } else {\n            ret_ec = make_error_code(transport::error::timeout);\n        }\n\n        m_alog->write(log::alevel::devel,\n            \"Asio transport socket shutdown timed out\");\n        cancel_socket_checked();\n        callback(ret_ec);\n    }\n\n    void handle_async_shutdown(timer_ptr shutdown_timer, shutdown_handler\n        callback, lib::asio::error_code const & ec)\n    {\n        if (ec == lib::asio::error::operation_aborted ||\n            lib::asio::is_neg(shutdown_timer->expires_from_now()))\n        {\n            m_alog->write(log::alevel::devel,\"async_shutdown cancelled\");\n            return;\n        }\n\n        shutdown_timer->cancel();\n\n        lib::error_code tec;\n        if (ec) {\n            if (ec == lib::asio::error::not_connected) {\n                // The socket was already closed when we tried to close it. This\n                // happens periodically (usually if a read or write fails\n                // earlier and if it is a real error will be caught at another\n                // level of the stack.\n            } else {\n                // We don't know anything more about this error, give our\n                // socket/security policy a crack at it.\n                tec = socket_con_type::translate_ec(ec);\n                m_tec = ec;\n\n                // all other errors are effectively pass through errors of\n\t\t\t\t// some sort so print some detail on the info channel for\n\t\t\t\t// library users to look up if needed.\n\t\t\t\tlog_err(log::elevel::info,\"asio async_shutdown\",ec);\n            }\n        } else {\n            if (m_alog->static_test(log::alevel::devel)) {\n                m_alog->write(log::alevel::devel,\n                    \"asio con handle_async_shutdown\");\n            }\n        }\n        callback(tec);\n    }\n\n    /// Cancel the underlying socket and log any errors\n    void cancel_socket_checked() {\n        lib::asio::error_code cec = socket_con_type::cancel_socket();\n        if (cec) {\n            if (cec == lib::asio::error::operation_not_supported) {\n                // cancel not supported on this OS, ignore and log at dev level\n                m_alog->write(log::alevel::devel, \"socket cancel not supported\");\n            } else {\n                log_err(log::elevel::warn, \"socket cancel failed\", cec);\n            }\n        }\n    }\n\nprivate:\n    /// Convenience method for logging the code and message for an error_code\n    template <typename error_type>\n    void log_err(log::level l, const char * msg, const error_type & ec) {\n        std::stringstream s;\n        s << msg << \" error: \" << ec << \" (\" << ec.message() << \")\";\n        m_elog->write(l,s.str());\n    }\n\n    // static settings\n    const bool m_is_server;\n    lib::shared_ptr<alog_type> m_alog;\n    lib::shared_ptr<elog_type> m_elog;\n\n    struct proxy_data {\n        proxy_data() : timeout_proxy(config::timeout_proxy) {}\n\n        request_type req;\n        response_type res;\n        std::string write_buf;\n        lib::asio::streambuf read_buf;\n        long timeout_proxy;\n        timer_ptr timer;\n    };\n\n    std::string m_proxy;\n    lib::shared_ptr<proxy_data> m_proxy_data;\n\n    // transport resources\n    io_service_ptr  m_io_service;\n    strand_ptr      m_strand;\n    connection_hdl  m_connection_hdl;\n\n    std::vector<lib::asio::const_buffer> m_bufs;\n\n    /// Detailed internal error code\n    lib::asio::error_code m_tec;\n\n    // Handlers\n    tcp_init_handler    m_tcp_pre_init_handler;\n    tcp_init_handler    m_tcp_post_init_handler;\n\n    handler_allocator   m_read_handler_allocator;\n    handler_allocator   m_write_handler_allocator;\n};\n\n\n} // namespace asio\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP\n"
  },
  {
    "path": "websocketpp/transport/asio/endpoint.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_ASIO_HPP\n#define WEBSOCKETPP_TRANSPORT_ASIO_HPP\n\n#include <websocketpp/transport/base/endpoint.hpp>\n#include <websocketpp/transport/asio/connection.hpp>\n#include <websocketpp/transport/asio/security/none.hpp>\n\n#include <websocketpp/uri.hpp>\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/common/asio.hpp>\n#include <websocketpp/common/functional.hpp>\n\n#include <sstream>\n#include <string>\n\nnamespace websocketpp {\nnamespace transport {\nnamespace asio {\n\n/// Asio based endpoint transport component\n/**\n * transport::asio::endpoint implements an endpoint transport component using\n * Asio.\n */\ntemplate <typename config>\nclass endpoint : public config::socket_type {\npublic:\n    /// Type of this endpoint transport component\n    typedef endpoint<config> type;\n\n    /// Type of the concurrency policy\n    typedef typename config::concurrency_type concurrency_type;\n    /// Type of the socket policy\n    typedef typename config::socket_type socket_type;\n    /// Type of the error logging policy\n    typedef typename config::elog_type elog_type;\n    /// Type of the access logging policy\n    typedef typename config::alog_type alog_type;\n\n    /// Type of the socket connection component\n    typedef typename socket_type::socket_con_type socket_con_type;\n    /// Type of a shared pointer to the socket connection component\n    typedef typename socket_con_type::ptr socket_con_ptr;\n\n    /// Type of the connection transport component associated with this\n    /// endpoint transport component\n    typedef asio::connection<config> transport_con_type;\n    /// Type of a shared pointer to the connection transport component\n    /// associated with this endpoint transport component\n    typedef typename transport_con_type::ptr transport_con_ptr;\n\n    /// Type of a pointer to the ASIO io_service being used\n    typedef lib::asio::io_service * io_service_ptr;\n    /// Type of a shared pointer to the acceptor being used\n    typedef lib::shared_ptr<lib::asio::ip::tcp::acceptor> acceptor_ptr;\n    /// Type of a shared pointer to the resolver being used\n    typedef lib::shared_ptr<lib::asio::ip::tcp::resolver> resolver_ptr;\n    /// Type of timer handle\n    typedef lib::shared_ptr<lib::asio::steady_timer> timer_ptr;\n    /// Type of a shared pointer to an io_service work object\n    typedef lib::shared_ptr<lib::asio::io_service::work> work_ptr;\n\n    /// Type of socket pre-bind handler\n    typedef lib::function<lib::error_code(acceptor_ptr)> tcp_pre_bind_handler;\n\n    // generate and manage our own io_service\n    explicit endpoint()\n      : m_io_service(NULL)\n      , m_external_io_service(false)\n      , m_listen_backlog(lib::asio::socket_base::max_connections)\n      , m_reuse_addr(false)\n      , m_state(UNINITIALIZED)\n    {\n        //std::cout << \"transport::asio::endpoint constructor\" << std::endl;\n    }\n\n    ~endpoint() {\n        // clean up our io_service if we were initialized with an internal one.\n\n        // Explicitly destroy local objects\n        m_acceptor.reset();\n        m_resolver.reset();\n        m_work.reset();\n        if (m_state != UNINITIALIZED && !m_external_io_service) {\n            delete m_io_service;\n        }\n    }\n\n    /// transport::asio objects are moveable but not copyable or assignable.\n    /// The following code sets this situation up based on whether or not we\n    /// have C++11 support or not\n#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n    endpoint(const endpoint & src) = delete;\n    endpoint& operator= (const endpoint & rhs) = delete;\n#else\nprivate:\n    endpoint(const endpoint & src);\n    endpoint & operator= (const endpoint & rhs);\npublic:\n#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_\n\n#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_\n    endpoint (endpoint && src)\n      : config::socket_type(std::move(src))\n      , m_tcp_pre_init_handler(src.m_tcp_pre_init_handler)\n      , m_tcp_post_init_handler(src.m_tcp_post_init_handler)\n      , m_io_service(src.m_io_service)\n      , m_external_io_service(src.m_external_io_service)\n      , m_acceptor(src.m_acceptor)\n      , m_listen_backlog(lib::asio::socket_base::max_connections)\n      , m_reuse_addr(src.m_reuse_addr)\n      , m_elog(src.m_elog)\n      , m_alog(src.m_alog)\n      , m_state(src.m_state)\n    {\n        src.m_io_service = NULL;\n        src.m_external_io_service = false;\n        src.m_acceptor = NULL;\n        src.m_state = UNINITIALIZED;\n    }\n\n    /*endpoint & operator= (const endpoint && rhs) {\n        if (this != &rhs) {\n            m_io_service = rhs.m_io_service;\n            m_external_io_service = rhs.m_external_io_service;\n            m_acceptor = rhs.m_acceptor;\n            m_listen_backlog = rhs.m_listen_backlog;\n            m_reuse_addr = rhs.m_reuse_addr;\n            m_state = rhs.m_state;\n\n            rhs.m_io_service = NULL;\n            rhs.m_external_io_service = false;\n            rhs.m_acceptor = NULL;\n            rhs.m_listen_backlog = lib::asio::socket_base::max_connections;\n            rhs.m_state = UNINITIALIZED;\n            \n            // TODO: this needs to be updated\n        }\n        return *this;\n    }*/\n#endif // _WEBSOCKETPP_MOVE_SEMANTICS_\n\n    /// Return whether or not the endpoint produces secure connections.\n    bool is_secure() const {\n        return socket_type::is_secure();\n    }\n\n    /// initialize asio transport with external io_service (exception free)\n    /**\n     * Initialize the ASIO transport policy for this endpoint using the provided\n     * io_service object. asio_init must be called exactly once on any endpoint\n     * that uses transport::asio before it can be used.\n     *\n     * @param ptr A pointer to the io_service to use for asio events\n     * @param ec Set to indicate what error occurred, if any.\n     */\n    void init_asio(io_service_ptr ptr, lib::error_code & ec) {\n        if (m_state != UNINITIALIZED) {\n            m_elog->write(log::elevel::library,\n                \"asio::init_asio called from the wrong state\");\n            using websocketpp::error::make_error_code;\n            ec = make_error_code(websocketpp::error::invalid_state);\n            return;\n        }\n\n        m_alog->write(log::alevel::devel,\"asio::init_asio\");\n\n        m_io_service = ptr;\n        m_external_io_service = true;\n        m_acceptor.reset(new lib::asio::ip::tcp::acceptor(*m_io_service));\n\n        m_state = READY;\n        ec = lib::error_code();\n    }\n\n    /// initialize asio transport with external io_service\n    /**\n     * Initialize the ASIO transport policy for this endpoint using the provided\n     * io_service object. asio_init must be called exactly once on any endpoint\n     * that uses transport::asio before it can be used.\n     *\n     * @param ptr A pointer to the io_service to use for asio events\n     */\n    void init_asio(io_service_ptr ptr) {\n        lib::error_code ec;\n        init_asio(ptr,ec);\n        if (ec) { throw exception(ec); }\n    }\n\n    /// Initialize asio transport with internal io_service (exception free)\n    /**\n     * This method of initialization will allocate and use an internally managed\n     * io_service.\n     *\n     * @see init_asio(io_service_ptr ptr)\n     *\n     * @param ec Set to indicate what error occurred, if any.\n     */\n    void init_asio(lib::error_code & ec) {\n        // Use a smart pointer until the call is successful and ownership has \n        // successfully been taken. Use unique_ptr when available.\n        // TODO: remove the use of auto_ptr when C++98/03 support is no longer\n        //       necessary.\n#ifdef _WEBSOCKETPP_CPP11_MEMORY_\n        lib::unique_ptr<lib::asio::io_service> service(new lib::asio::io_service());\n#else\n        lib::auto_ptr<lib::asio::io_service> service(new lib::asio::io_service());\n#endif\n        init_asio(service.get(), ec);\n        if( !ec ) service.release(); // Call was successful, transfer ownership\n        m_external_io_service = false;\n    }\n\n    /// Initialize asio transport with internal io_service\n    /**\n     * This method of initialization will allocate and use an internally managed\n     * io_service.\n     *\n     * @see init_asio(io_service_ptr ptr)\n     */\n    void init_asio() {\n        // Use a smart pointer until the call is successful and ownership has \n        // successfully been taken. Use unique_ptr when available.\n        // TODO: remove the use of auto_ptr when C++98/03 support is no longer\n        //       necessary.\n#ifdef _WEBSOCKETPP_CPP11_MEMORY_\n        lib::unique_ptr<lib::asio::io_service> service(new lib::asio::io_service());\n#else\n        lib::auto_ptr<lib::asio::io_service> service(new lib::asio::io_service());\n#endif\n        init_asio( service.get() );\n        // If control got this far without an exception, then ownership has successfully been taken\n        service.release();\n        m_external_io_service = false;\n    }\n\n    /// Sets the tcp pre bind handler\n    /**\n     * The tcp pre bind handler is called after the listen acceptor has\n     * been created but before the socket bind is performed.\n     *\n     * @since 0.8.0\n     *\n     * @param h The handler to call on tcp pre bind init.\n     */\n    void set_tcp_pre_bind_handler(tcp_pre_bind_handler h) {\n        m_tcp_pre_bind_handler = h;\n    }\n\n    /// Sets the tcp pre init handler\n    /**\n     * The tcp pre init handler is called after the raw tcp connection has been\n     * established but before any additional wrappers (proxy connects, TLS\n     * handshakes, etc) have been performed.\n     *\n     * @since 0.3.0\n     *\n     * @param h The handler to call on tcp pre init.\n     */\n    void set_tcp_pre_init_handler(tcp_init_handler h) {\n        m_tcp_pre_init_handler = h;\n    }\n\n    /// Sets the tcp pre init handler (deprecated)\n    /**\n     * The tcp pre init handler is called after the raw tcp connection has been\n     * established but before any additional wrappers (proxy connects, TLS\n     * handshakes, etc) have been performed.\n     *\n     * @deprecated Use set_tcp_pre_init_handler instead\n     *\n     * @param h The handler to call on tcp pre init.\n     */\n    void set_tcp_init_handler(tcp_init_handler h) {\n        set_tcp_pre_init_handler(h);\n    }\n\n    /// Sets the tcp post init handler\n    /**\n     * The tcp post init handler is called after the tcp connection has been\n     * established and all additional wrappers (proxy connects, TLS handshakes,\n     * etc have been performed. This is fired before any bytes are read or any\n     * WebSocket specific handshake logic has been performed.\n     *\n     * @since 0.3.0\n     *\n     * @param h The handler to call on tcp post init.\n     */\n    void set_tcp_post_init_handler(tcp_init_handler h) {\n        m_tcp_post_init_handler = h;\n    }\n\n    /// Sets the maximum length of the queue of pending connections.\n    /**\n     * Sets the maximum length of the queue of pending connections. Increasing\n     * this will allow WebSocket++ to queue additional incoming connections.\n     * Setting it higher may prevent failed connections at high connection rates\n     * but may cause additional latency.\n     *\n     * For this value to take effect you may need to adjust operating system\n     * settings.\n     *\n     * New values affect future calls to listen only.\n     *\n     * The default value is specified as *::asio::socket_base::max_connections\n     * which uses the operating system defined maximum queue length. Your OS\n     * may restrict or silently lower this value. A value of zero may cause\n     * all connections to be rejected.\n     *\n     * @since 0.3.0\n     *\n     * @param backlog The maximum length of the queue of pending connections\n     */\n    void set_listen_backlog(int backlog) {\n        m_listen_backlog = backlog;\n    }\n\n    /// Sets whether to use the SO_REUSEADDR flag when opening listening sockets\n    /**\n     * Specifies whether or not to use the SO_REUSEADDR TCP socket option. What\n     * this flag does depends on your operating system.\n     *\n     * Please consult operating system documentation for more details. There\n     * may be security consequences to enabling this option.\n     *\n     * New values affect future calls to listen only so set this value prior to\n     * calling listen.\n     *\n     * The default is false.\n     *\n     * @since 0.3.0\n     *\n     * @param value Whether or not to use the SO_REUSEADDR option\n     */\n    void set_reuse_addr(bool value) {\n        m_reuse_addr = value;\n    }\n\n    /// Retrieve a reference to the endpoint's io_service\n    /**\n     * The io_service may be an internal or external one. This may be used to\n     * call methods of the io_service that are not explicitly wrapped by the\n     * endpoint.\n     *\n     * This method is only valid after the endpoint has been initialized with\n     * `init_asio`. No error will be returned if it isn't.\n     *\n     * @return A reference to the endpoint's io_service\n     */\n    lib::asio::io_service & get_io_service() {\n        return *m_io_service;\n    }\n    \n    /// Get local TCP endpoint\n    /**\n     * Extracts the local endpoint from the acceptor. This represents the\n     * address that WebSocket++ is listening on.\n     *\n     * Sets a bad_descriptor error if the acceptor is not currently listening\n     * or otherwise unavailable.\n     * \n     * @since 0.7.0\n     *\n     * @param ec Set to indicate what error occurred, if any.\n     * @return The local endpoint\n     */\n    lib::asio::ip::tcp::endpoint get_local_endpoint(lib::asio::error_code & ec) {\n        if (m_acceptor) {\n            return m_acceptor->local_endpoint(ec);\n        } else {\n            ec = lib::asio::error::make_error_code(lib::asio::error::bad_descriptor);\n            return lib::asio::ip::tcp::endpoint();\n        }\n    }\n\n    /// Set up endpoint for listening manually (exception free)\n    /**\n     * Bind the internal acceptor using the specified settings. The endpoint\n     * must have been initialized by calling init_asio before listening.\n     *\n     * @param ep An endpoint to read settings from\n     * @param ec Set to indicate what error occurred, if any.\n     */\n    void listen(lib::asio::ip::tcp::endpoint const & ep, lib::error_code & ec)\n    {\n        if (m_state != READY) {\n            m_elog->write(log::elevel::library,\n                \"asio::listen called from the wrong state\");\n            using websocketpp::error::make_error_code;\n            ec = make_error_code(websocketpp::error::invalid_state);\n            return;\n        }\n\n        m_alog->write(log::alevel::devel,\"asio::listen\");\n\n        lib::asio::error_code bec;\n\n        m_acceptor->open(ep.protocol(),bec);\n        if (bec) {ec = clean_up_listen_after_error(bec);return;}\n        \n        m_acceptor->set_option(lib::asio::socket_base::reuse_address(m_reuse_addr),bec);\n        if (bec) {ec = clean_up_listen_after_error(bec);return;}\n        \n        // if a TCP pre-bind handler is present, run it\n        if (m_tcp_pre_bind_handler) {\n            ec = m_tcp_pre_bind_handler(m_acceptor);\n            if (ec) {\n                ec = clean_up_listen_after_error(ec);\n                return;\n            }\n        }\n        \n        m_acceptor->bind(ep,bec);\n        if (bec) {ec = clean_up_listen_after_error(bec);return;}\n        \n        m_acceptor->listen(m_listen_backlog,bec);\n        if (bec) {ec = clean_up_listen_after_error(bec);return;}\n        \n        // Success\n        m_state = LISTENING;\n        ec = lib::error_code();\n    }\n\n\n\n    /// Set up endpoint for listening manually\n    /**\n     * Bind the internal acceptor using the settings specified by the endpoint e\n     *\n     * @param ep An endpoint to read settings from\n     */\n    void listen(lib::asio::ip::tcp::endpoint const & ep) {\n        lib::error_code ec;\n        listen(ep,ec);\n        if (ec) { throw exception(ec); }\n    }\n\n    /// Set up endpoint for listening with protocol and port (exception free)\n    /**\n     * Bind the internal acceptor using the given internet protocol and port.\n     * The endpoint must have been initialized by calling init_asio before\n     * listening.\n     *\n     * Common options include:\n     * - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6()\n     * - IPv4 only: lib::asio::ip::tcp::v4()\n     *\n     * @param internet_protocol The internet protocol to use.\n     * @param port The port to listen on.\n     * @param ec Set to indicate what error occurred, if any.\n     */\n    template <typename InternetProtocol>\n    void listen(InternetProtocol const & internet_protocol, uint16_t port,\n        lib::error_code & ec)\n    {\n        lib::asio::ip::tcp::endpoint ep(internet_protocol, port);\n        listen(ep,ec);\n    }\n\n    /// Set up endpoint for listening with protocol and port\n    /**\n     * Bind the internal acceptor using the given internet protocol and port.\n     * The endpoint must have been initialized by calling init_asio before\n     * listening.\n     *\n     * Common options include:\n     * - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6()\n     * - IPv4 only: lib::asio::ip::tcp::v4()\n     *\n     * @param internet_protocol The internet protocol to use.\n     * @param port The port to listen on.\n     */\n    template <typename InternetProtocol>\n    void listen(InternetProtocol const & internet_protocol, uint16_t port)\n    {\n        lib::asio::ip::tcp::endpoint ep(internet_protocol, port);\n        listen(ep);\n    }\n\n    /// Set up endpoint for listening on a port (exception free)\n    /**\n     * Bind the internal acceptor using the given port. The IPv6 protocol with\n     * mapped IPv4 for dual stack hosts will be used. If you need IPv4 only use\n     * the overload that allows specifying the protocol explicitly.\n     *\n     * The endpoint must have been initialized by calling init_asio before\n     * listening.\n     *\n     * @param port The port to listen on.\n     * @param ec Set to indicate what error occurred, if any.\n     */\n    void listen(uint16_t port, lib::error_code & ec) {\n        listen(lib::asio::ip::tcp::v6(), port, ec);\n    }\n\n    /// Set up endpoint for listening on a port\n    /**\n     * Bind the internal acceptor using the given port. The IPv6 protocol with\n     * mapped IPv4 for dual stack hosts will be used. If you need IPv4 only use\n     * the overload that allows specifying the protocol explicitly.\n     *\n     * The endpoint must have been initialized by calling init_asio before\n     * listening.\n     *\n     * @param port The port to listen on.\n     * @param ec Set to indicate what error occurred, if any.\n     */\n    void listen(uint16_t port) {\n        listen(lib::asio::ip::tcp::v6(), port);\n    }\n\n    /// Set up endpoint for listening on a host and service (exception free)\n    /**\n     * Bind the internal acceptor using the given host and service. More details\n     * about what host and service can be are available in the Asio\n     * documentation for ip::basic_resolver_query::basic_resolver_query's\n     * constructors.\n     *\n     * The endpoint must have been initialized by calling init_asio before\n     * listening.\n     *\n     * @param host A string identifying a location. May be a descriptive name or\n     * a numeric address string.\n     * @param service A string identifying the requested service. This may be a\n     * descriptive name or a numeric string corresponding to a port number.\n     * @param ec Set to indicate what error occurred, if any.\n     */\n    void listen(std::string const & host, std::string const & service,\n        lib::error_code & ec)\n    {\n        using lib::asio::ip::tcp;\n        tcp::resolver r(*m_io_service);\n        tcp::resolver::query query(host, service);\n        tcp::resolver::iterator endpoint_iterator = r.resolve(query);\n        tcp::resolver::iterator end;\n        if (endpoint_iterator == end) {\n            m_elog->write(log::elevel::library,\n                \"asio::listen could not resolve the supplied host or service\");\n            ec = make_error_code(error::invalid_host_service);\n            return;\n        }\n        listen(*endpoint_iterator,ec);\n    }\n\n    /// Set up endpoint for listening on a host and service\n    /**\n     * Bind the internal acceptor using the given host and service. More details\n     * about what host and service can be are available in the Asio\n     * documentation for ip::basic_resolver_query::basic_resolver_query's\n     * constructors.\n     *\n     * The endpoint must have been initialized by calling init_asio before\n     * listening.\n     *\n     * @param host A string identifying a location. May be a descriptive name or\n     * a numeric address string.\n     * @param service A string identifying the requested service. This may be a\n     * descriptive name or a numeric string corresponding to a port number.\n     * @param ec Set to indicate what error occurred, if any.\n     */\n    void listen(std::string const & host, std::string const & service)\n    {\n        lib::error_code ec;\n        listen(host,service,ec);\n        if (ec) { throw exception(ec); }\n    }\n\n    /// Stop listening (exception free)\n    /**\n     * Stop listening and accepting new connections. This will not end any\n     * existing connections.\n     *\n     * @since 0.3.0-alpha4\n     * @param ec A status code indicating an error, if any.\n     */\n    void stop_listening(lib::error_code & ec) {\n        if (m_state != LISTENING) {\n            m_elog->write(log::elevel::library,\n                \"asio::listen called from the wrong state\");\n            using websocketpp::error::make_error_code;\n            ec = make_error_code(websocketpp::error::invalid_state);\n            return;\n        }\n\n        m_acceptor->close();\n        m_state = READY;\n        ec = lib::error_code();\n    }\n\n    /// Stop listening\n    /**\n     * Stop listening and accepting new connections. This will not end any\n     * existing connections.\n     *\n     * @since 0.3.0-alpha4\n     */\n    void stop_listening() {\n        lib::error_code ec;\n        stop_listening(ec);\n        if (ec) { throw exception(ec); }\n    }\n\n    /// Check if the endpoint is listening\n    /**\n     * @return Whether or not the endpoint is listening.\n     */\n    bool is_listening() const {\n        return (m_state == LISTENING);\n    }\n\n    /// wraps the run method of the internal io_service object\n    std::size_t run() {\n        return m_io_service->run();\n    }\n\n    /// wraps the run_one method of the internal io_service object\n    /**\n     * @since 0.3.0-alpha4\n     */\n    std::size_t run_one() {\n        return m_io_service->run_one();\n    }\n\n    /// wraps the stop method of the internal io_service object\n    void stop() {\n        m_io_service->stop();\n    }\n\n    /// wraps the poll method of the internal io_service object\n    std::size_t poll() {\n        return m_io_service->poll();\n    }\n\n    /// wraps the poll_one method of the internal io_service object\n    std::size_t poll_one() {\n        return m_io_service->poll_one();\n    }\n\n    /// wraps the reset method of the internal io_service object\n    void reset() {\n        m_io_service->reset();\n    }\n\n    /// wraps the stopped method of the internal io_service object\n    bool stopped() const {\n        return m_io_service->stopped();\n    }\n\n    /// Marks the endpoint as perpetual, stopping it from exiting when empty\n    /**\n     * Marks the endpoint as perpetual. Perpetual endpoints will not\n     * automatically exit when they run out of connections to process. To stop\n     * a perpetual endpoint call `end_perpetual`.\n     *\n     * An endpoint may be marked perpetual at any time by any thread. It must be\n     * called either before the endpoint has run out of work or before it was\n     * started\n     *\n     * @since 0.3.0\n     */\n    void start_perpetual() {\n        m_work.reset(new lib::asio::io_service::work(*m_io_service));\n    }\n\n    /// Clears the endpoint's perpetual flag, allowing it to exit when empty\n    /**\n     * Clears the endpoint's perpetual flag. This will cause the endpoint's run\n     * method to exit normally when it runs out of connections. If there are\n     * currently active connections it will not end until they are complete.\n     *\n     * @since 0.3.0\n     */\n    void stop_perpetual() {\n        m_work.reset();\n    }\n\n    /// Call back a function after a period of time.\n    /**\n     * Sets a timer that calls back a function after the specified period of\n     * milliseconds. Returns a handle that can be used to cancel the timer.\n     * A cancelled timer will return the error code error::operation_aborted\n     * A timer that expired will return no error.\n     *\n     * @param duration Length of time to wait in milliseconds\n     * @param callback The function to call back when the timer has expired\n     * @return A handle that can be used to cancel the timer if it is no longer\n     * needed.\n     */\n    timer_ptr set_timer(long duration, timer_handler callback) {\n        timer_ptr new_timer = lib::make_shared<lib::asio::steady_timer>(\n            *m_io_service,\n             lib::asio::milliseconds(duration)\n        );\n\n        new_timer->async_wait(\n            lib::bind(\n                &type::handle_timer,\n                this,\n                new_timer,\n                callback,\n                lib::placeholders::_1\n            )\n        );\n\n        return new_timer;\n    }\n\n    /// Timer handler\n    /**\n     * The timer pointer is included to ensure the timer isn't destroyed until\n     * after it has expired.\n     *\n     * @param t Pointer to the timer in question\n     * @param callback The function to call back\n     * @param ec A status code indicating an error, if any.\n     */\n    void handle_timer(timer_ptr, timer_handler callback,\n        lib::asio::error_code const & ec)\n    {\n        if (ec) {\n            if (ec == lib::asio::error::operation_aborted) {\n                callback(make_error_code(transport::error::operation_aborted));\n            } else {\n                m_elog->write(log::elevel::info,\n                    \"asio handle_timer error: \"+ec.message());\n                log_err(log::elevel::info,\"asio handle_timer\",ec);\n                callback(socket_con_type::translate_ec(ec));\n            }\n        } else {\n            callback(lib::error_code());\n        }\n    }\n\n    /// Accept the next connection attempt and assign it to con (exception free)\n    /**\n     * @param tcon The connection to accept into.\n     * @param callback The function to call when the operation is complete.\n     * @param ec A status code indicating an error, if any.\n     */\n    void async_accept(transport_con_ptr tcon, accept_handler callback,\n        lib::error_code & ec)\n    {\n        if (m_state != LISTENING || !m_acceptor) {\n            using websocketpp::error::make_error_code;\n            ec = make_error_code(websocketpp::error::async_accept_not_listening);\n            return;\n        }\n\n        m_alog->write(log::alevel::devel, \"asio::async_accept\");\n\n        if (config::enable_multithreading) {\n            m_acceptor->async_accept(\n                tcon->get_raw_socket(),\n                tcon->get_strand()->wrap(lib::bind(\n                    &type::handle_accept,\n                    this,\n                    callback,\n                    lib::placeholders::_1\n                ))\n            );\n        } else {\n            m_acceptor->async_accept(\n                tcon->get_raw_socket(),\n                lib::bind(\n                    &type::handle_accept,\n                    this,\n                    callback,\n                    lib::placeholders::_1\n                )\n            );\n        }\n    }\n\n    /// Accept the next connection attempt and assign it to con.\n    /**\n     * @param tcon The connection to accept into.\n     * @param callback The function to call when the operation is complete.\n     */\n    void async_accept(transport_con_ptr tcon, accept_handler callback) {\n        lib::error_code ec;\n        async_accept(tcon,callback,ec);\n        if (ec) { throw exception(ec); }\n    }\nprotected:\n    /// Initialize logging\n    /**\n     * The loggers are located in the main endpoint class. As such, the\n     * transport doesn't have direct access to them. This method is called\n     * by the endpoint constructor to allow shared logging from the transport\n     * component. These are raw pointers to member variables of the endpoint.\n     * In particular, they cannot be used in the transport constructor as they\n     * haven't been constructed yet, and cannot be used in the transport\n     * destructor as they will have been destroyed by then.\n     */\n    void init_logging(const lib::shared_ptr<alog_type>& a, const lib::shared_ptr<elog_type>& e) {\n        m_alog = a;\n        m_elog = e;\n    }\n\n    void handle_accept(accept_handler callback, lib::asio::error_code const & \n        asio_ec)\n    {\n        lib::error_code ret_ec;\n\n        m_alog->write(log::alevel::devel, \"asio::handle_accept\");\n\n        if (asio_ec) {\n            if (asio_ec == lib::asio::errc::operation_canceled) {\n                ret_ec = make_error_code(websocketpp::error::operation_canceled);\n            } else {\n                log_err(log::elevel::info,\"asio handle_accept\",asio_ec);\n                ret_ec = socket_con_type::translate_ec(asio_ec);\n            }\n        }\n\n        callback(ret_ec);\n    }\n\n    /// Initiate a new connection\n    // TODO: there have to be some more failure conditions here\n    void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) {\n        using namespace lib::asio::ip;\n\n        // Create a resolver\n        if (!m_resolver) {\n            m_resolver.reset(new lib::asio::ip::tcp::resolver(*m_io_service));\n        }\n\n        tcon->set_uri(u);\n\n        std::string proxy = tcon->get_proxy();\n        std::string host;\n        std::string port;\n\n        if (proxy.empty()) {\n            host = u->get_host();\n            port = u->get_port_str();\n        } else {\n            lib::error_code ec;\n\n            uri_ptr pu = lib::make_shared<uri>(proxy);\n\n            if (!pu->get_valid()) {\n                cb(make_error_code(error::proxy_invalid));\n                return;\n            }\n\n            ec = tcon->proxy_init(u->get_authority());\n            if (ec) {\n                cb(ec);\n                return;\n            }\n\n            host = pu->get_host();\n            port = pu->get_port_str();\n        }\n\n        tcp::resolver::query query(host,port);\n\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\n                \"starting async DNS resolve for \"+host+\":\"+port);\n        }\n\n        timer_ptr dns_timer;\n\n        dns_timer = tcon->set_timer(\n            config::timeout_dns_resolve,\n            lib::bind(\n                &type::handle_resolve_timeout,\n                this,\n                dns_timer,\n                cb,\n                lib::placeholders::_1\n            )\n        );\n\n        if (config::enable_multithreading) {\n            m_resolver->async_resolve(\n                query,\n                tcon->get_strand()->wrap(lib::bind(\n                    &type::handle_resolve,\n                    this,\n                    tcon,\n                    dns_timer,\n                    cb,\n                    lib::placeholders::_1,\n                    lib::placeholders::_2\n                ))\n            );\n        } else {\n            m_resolver->async_resolve(\n                query,\n                lib::bind(\n                    &type::handle_resolve,\n                    this,\n                    tcon,\n                    dns_timer,\n                    cb,\n                    lib::placeholders::_1,\n                    lib::placeholders::_2\n                )\n            );\n        }\n    }\n\n    /// DNS resolution timeout handler\n    /**\n     * The timer pointer is included to ensure the timer isn't destroyed until\n     * after it has expired.\n     *\n     * @param dns_timer Pointer to the timer in question\n     * @param callback The function to call back\n     * @param ec A status code indicating an error, if any.\n     */\n    void handle_resolve_timeout(timer_ptr, connect_handler callback,\n        lib::error_code const & ec)\n    {\n        lib::error_code ret_ec;\n\n        if (ec) {\n            if (ec == transport::error::operation_aborted) {\n                m_alog->write(log::alevel::devel,\n                    \"asio handle_resolve_timeout timer cancelled\");\n                return;\n            }\n\n            log_err(log::elevel::devel,\"asio handle_resolve_timeout\",ec);\n            ret_ec = ec;\n        } else {\n            ret_ec = make_error_code(transport::error::timeout);\n        }\n\n        m_alog->write(log::alevel::devel,\"DNS resolution timed out\");\n        m_resolver->cancel();\n        callback(ret_ec);\n    }\n\n    void handle_resolve(transport_con_ptr tcon, timer_ptr dns_timer,\n        connect_handler callback, lib::asio::error_code const & ec,\n        lib::asio::ip::tcp::resolver::iterator iterator)\n    {\n        if (ec == lib::asio::error::operation_aborted ||\n            lib::asio::is_neg(dns_timer->expires_from_now()))\n        {\n            m_alog->write(log::alevel::devel,\"async_resolve cancelled\");\n            return;\n        }\n\n        dns_timer->cancel();\n\n        if (ec) {\n            log_err(log::elevel::info,\"asio async_resolve\",ec);\n            callback(socket_con_type::translate_ec(ec));\n            return;\n        }\n\n        if (m_alog->static_test(log::alevel::devel)) {\n            std::stringstream s;\n            s << \"Async DNS resolve successful. Results: \";\n\n            lib::asio::ip::tcp::resolver::iterator it, end;\n            for (it = iterator; it != end; ++it) {\n                s << (*it).endpoint() << \" \";\n            }\n\n            m_alog->write(log::alevel::devel,s.str());\n        }\n\n        m_alog->write(log::alevel::devel,\"Starting async connect\");\n\n        timer_ptr con_timer;\n\n        con_timer = tcon->set_timer(\n            config::timeout_connect,\n            lib::bind(\n                &type::handle_connect_timeout,\n                this,\n                tcon,\n                con_timer,\n                callback,\n                lib::placeholders::_1\n            )\n        );\n\n        if (config::enable_multithreading) {\n            lib::asio::async_connect(\n                tcon->get_raw_socket(),\n                iterator,\n                tcon->get_strand()->wrap(lib::bind(\n                    &type::handle_connect,\n                    this,\n                    tcon,\n                    con_timer,\n                    callback,\n                    lib::placeholders::_1\n                ))\n            );\n        } else {\n            lib::asio::async_connect(\n                tcon->get_raw_socket(),\n                iterator,\n                lib::bind(\n                    &type::handle_connect,\n                    this,\n                    tcon,\n                    con_timer,\n                    callback,\n                    lib::placeholders::_1\n                )\n            );\n        }\n    }\n\n    /// Asio connect timeout handler\n    /**\n     * The timer pointer is included to ensure the timer isn't destroyed until\n     * after it has expired.\n     *\n     * @param tcon Pointer to the transport connection that is being connected\n     * @param con_timer Pointer to the timer in question\n     * @param callback The function to call back\n     * @param ec A status code indicating an error, if any.\n     */\n    void handle_connect_timeout(transport_con_ptr tcon, timer_ptr,\n        connect_handler callback, lib::error_code const & ec)\n    {\n        lib::error_code ret_ec;\n\n        if (ec) {\n            if (ec == transport::error::operation_aborted) {\n                m_alog->write(log::alevel::devel,\n                    \"asio handle_connect_timeout timer cancelled\");\n                return;\n            }\n\n            log_err(log::elevel::devel,\"asio handle_connect_timeout\",ec);\n            ret_ec = ec;\n        } else {\n            ret_ec = make_error_code(transport::error::timeout);\n        }\n\n        m_alog->write(log::alevel::devel,\"TCP connect timed out\");\n        tcon->cancel_socket_checked();\n        callback(ret_ec);\n    }\n\n    void handle_connect(transport_con_ptr tcon, timer_ptr con_timer,\n        connect_handler callback, lib::asio::error_code const & ec)\n    {\n        if (ec == lib::asio::error::operation_aborted ||\n            lib::asio::is_neg(con_timer->expires_from_now()))\n        {\n            m_alog->write(log::alevel::devel,\"async_connect cancelled\");\n            return;\n        }\n\n        con_timer->cancel();\n\n        if (ec) {\n            log_err(log::elevel::info,\"asio async_connect\",ec);\n            callback(socket_con_type::translate_ec(ec));\n            return;\n        }\n\n        if (m_alog->static_test(log::alevel::devel)) {\n            m_alog->write(log::alevel::devel,\n                \"Async connect to \"+tcon->get_remote_endpoint()+\" successful.\");\n        }\n\n        callback(lib::error_code());\n    }\n\n    /// Initialize a connection\n    /**\n     * init is called by an endpoint once for each newly created connection.\n     * It's purpose is to give the transport policy the chance to perform any\n     * transport specific initialization that couldn't be done via the default\n     * constructor.\n     *\n     * @param tcon A pointer to the transport portion of the connection.\n     *\n     * @return A status code indicating the success or failure of the operation\n     */\n    lib::error_code init(transport_con_ptr tcon) {\n        m_alog->write(log::alevel::devel, \"transport::asio::init\");\n\n        // Initialize the connection socket component\n        socket_type::init(lib::static_pointer_cast<socket_con_type,\n            transport_con_type>(tcon));\n\n        lib::error_code ec;\n\n        ec = tcon->init_asio(m_io_service);\n        if (ec) {return ec;}\n\n        tcon->set_tcp_pre_init_handler(m_tcp_pre_init_handler);\n        tcon->set_tcp_post_init_handler(m_tcp_post_init_handler);\n\n        return lib::error_code();\n    }\nprivate:\n    /// Convenience method for logging the code and message for an error_code\n    template <typename error_type>\n    void log_err(log::level l, char const * msg, error_type const & ec) {\n        std::stringstream s;\n        s << msg << \" error: \" << ec << \" (\" << ec.message() << \")\";\n        m_elog->write(l,s.str());\n    }\n\n    /// Helper for cleaning up in the listen method after an error\n    template <typename error_type>\n    lib::error_code clean_up_listen_after_error(error_type const & ec) {\n        if (m_acceptor->is_open()) {\n            m_acceptor->close();\n        }\n        log_err(log::elevel::info,\"asio listen\",ec);\n        return socket_con_type::translate_ec(ec);\n    }\n\n    enum state {\n        UNINITIALIZED = 0,\n        READY = 1,\n        LISTENING = 2\n    };\n\n    // Handlers\n    tcp_pre_bind_handler    m_tcp_pre_bind_handler;\n    tcp_init_handler    m_tcp_pre_init_handler;\n    tcp_init_handler    m_tcp_post_init_handler;\n\n    // Network Resources\n    io_service_ptr      m_io_service;\n    bool                m_external_io_service;\n    acceptor_ptr        m_acceptor;\n    resolver_ptr        m_resolver;\n    work_ptr            m_work;\n\n    // Network constants\n    int                 m_listen_backlog;\n    bool                m_reuse_addr;\n\n    lib::shared_ptr<elog_type> m_elog;\n    lib::shared_ptr<alog_type> m_alog;\n\n    // Transport state\n    state               m_state;\n};\n\n} // namespace asio\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_ASIO_HPP\n"
  },
  {
    "path": "websocketpp/transport/asio/security/base.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP\n#define WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP\n\n#include <websocketpp/common/asio.hpp>\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/common/functional.hpp>\n#include <websocketpp/common/system_error.hpp>\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/connection_hdl.hpp>\n\n#include <string>\n\n// Interface that sockets/security policies must implement\n\n/*\n * Endpoint Interface\n *\n * bool is_secure() const;\n * @return Whether or not the endpoint creates secure connections\n *\n * lib::error_code init(socket_con_ptr scon);\n * Called by the transport after a new connection is created to initialize\n * the socket component of the connection.\n * @param scon Pointer to the socket component of the connection\n * @return Error code (empty on success)\n */\n\n\n// Connection\n// TODO\n// set_hostname(std::string hostname)\n// pre_init(init_handler);\n// post_init(init_handler);\n\nnamespace websocketpp {\nnamespace transport {\nnamespace asio {\nnamespace socket {\n\ntypedef lib::function<void(lib::asio::error_code const &)> shutdown_handler;\n\n/**\n * The transport::asio::socket::* classes are a set of security/socket related\n * policies and support code for the ASIO transport types.\n */\n\n/// Errors related to asio transport sockets\nnamespace error {\n    enum value {\n        /// Catch-all error for security policy errors that don't fit in other\n        /// categories\n        security = 1,\n\n        /// Catch-all error for socket component errors that don't fit in other\n        /// categories\n        socket,\n\n        /// A function was called in a state that it was illegal to do so.\n        invalid_state,\n\n        /// The application was prompted to provide a TLS context and it was\n        /// empty or otherwise invalid\n        invalid_tls_context,\n\n        /// TLS Handshake Timeout\n        tls_handshake_timeout,\n\n        /// pass_through from underlying library\n        pass_through,\n\n        /// Required tls_init handler not present\n        missing_tls_init_handler,\n\n        /// TLS Handshake Failed\n        tls_handshake_failed,\n        \n        /// Failed to set TLS SNI hostname\n        tls_failed_sni_hostname\n    };\n} // namespace error\n\n/// Error category related to asio transport socket policies\nclass socket_category : public lib::error_category {\npublic:\n    char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {\n        return \"websocketpp.transport.asio.socket\";\n    }\n\n    std::string message(int value) const {\n        switch(value) {\n            case error::security:\n                return \"Security policy error\";\n            case error::socket:\n                return \"Socket component error\";\n            case error::invalid_state:\n                return \"Invalid state\";\n            case error::invalid_tls_context:\n                return \"Invalid or empty TLS context supplied\";\n            case error::tls_handshake_timeout:\n                return \"TLS handshake timed out\";\n            case error::pass_through:\n                return \"Pass through from socket policy\";\n            case error::missing_tls_init_handler:\n                return \"Required tls_init handler not present.\";\n            case error::tls_handshake_failed:\n                return \"TLS handshake failed\";\n            case error::tls_failed_sni_hostname:\n                return \"Failed to set TLS SNI hostname\";\n            default:\n                return \"Unknown\";\n        }\n    }\n};\n\ninline lib::error_category const & get_socket_category() {\n    static socket_category instance;\n    return instance;\n}\n\ninline lib::error_code make_error_code(error::value e) {\n    return lib::error_code(static_cast<int>(e), get_socket_category());\n}\n\n/// Type of asio transport socket policy initialization handlers\ntypedef lib::function<void(const lib::error_code&)> init_handler;\n\n} // namespace socket\n} // namespace asio\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP\n"
  },
  {
    "path": "websocketpp/transport/asio/security/none.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP\n#define WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP\n\n#include <websocketpp/uri.hpp>\n\n#include <websocketpp/transport/base/connection.hpp>\n#include <websocketpp/transport/asio/security/base.hpp>\n\n#include <websocketpp/common/asio.hpp>\n#include <websocketpp/common/memory.hpp>\n\n#include <sstream>\n#include <string>\n\nnamespace websocketpp {\nnamespace transport {\nnamespace asio {\n/// A socket policy for the asio transport that implements a plain, unencrypted\n/// socket\nnamespace basic_socket {\n\n/// The signature of the socket init handler for this socket policy\ntypedef lib::function<void(connection_hdl,lib::asio::ip::tcp::socket&)>\n    socket_init_handler;\n\n/// Basic Asio connection socket component\n/**\n * transport::asio::basic_socket::connection implements a connection socket\n * component using Asio ip::tcp::socket.\n */\nclass connection : public lib::enable_shared_from_this<connection> {\npublic:\n    /// Type of this connection socket component\n    typedef connection type;\n    /// Type of a shared pointer to this connection socket component\n    typedef lib::shared_ptr<type> ptr;\n\n    /// Type of a pointer to the Asio io_service being used\n    typedef lib::asio::io_service* io_service_ptr;\n    /// Type of a pointer to the Asio io_service strand being used\n    typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;\n    /// Type of the ASIO socket being used\n    typedef lib::asio::ip::tcp::socket socket_type;\n    /// Type of a shared pointer to the socket being used.\n    typedef lib::shared_ptr<socket_type> socket_ptr;\n\n    explicit connection() : m_state(UNINITIALIZED) {\n        //std::cout << \"transport::asio::basic_socket::connection constructor\"\n        //          << std::endl;\n    }\n\n    /// Get a shared pointer to this component\n    ptr get_shared() {\n        return shared_from_this();\n    }\n\n    /// Check whether or not this connection is secure\n    /**\n     * @return Whether or not this connection is secure\n     */\n    bool is_secure() const {\n        return false;\n    }\n\n    /// Set the socket initialization handler\n    /**\n     * The socket initialization handler is called after the socket object is\n     * created but before it is used. This gives the application a chance to\n     * set any Asio socket options it needs.\n     *\n     * @param h The new socket_init_handler\n     */\n    void set_socket_init_handler(socket_init_handler h) {\n        m_socket_init_handler = h;\n    }\n\n    /// Retrieve a pointer to the underlying socket\n    /**\n     * This is used internally. It can also be used to set socket options, etc\n     */\n    lib::asio::ip::tcp::socket & get_socket() {\n        return *m_socket;\n    }\n\n    /// Retrieve a pointer to the underlying socket\n    /**\n     * This is used internally.\n     */\n    lib::asio::ip::tcp::socket & get_next_layer() {\n        return *m_socket;\n    }\n\n    /// Retrieve a pointer to the underlying socket\n    /**\n     * This is used internally. It can also be used to set socket options, etc\n     */\n    lib::asio::ip::tcp::socket & get_raw_socket() {\n        return *m_socket;\n    }\n\n    /// Get the remote endpoint address\n    /**\n     * The iostream transport has no information about the ultimate remote\n     * endpoint. It will return the string \"iostream transport\". To indicate\n     * this.\n     *\n     * TODO: allow user settable remote endpoint addresses if this seems useful\n     *\n     * @return A string identifying the address of the remote endpoint\n     */\n    std::string get_remote_endpoint(lib::error_code & ec) const {\n        std::stringstream s;\n\n        lib::asio::error_code aec;\n        lib::asio::ip::tcp::endpoint ep = m_socket->remote_endpoint(aec);\n\n        if (aec) {\n            ec = error::make_error_code(error::pass_through);\n            s << \"Error getting remote endpoint: \" << aec\n               << \" (\" << aec.message() << \")\";\n            return s.str();\n        } else {\n            ec = lib::error_code();\n            s << ep;\n            return s.str();\n        }\n    }\nprotected:\n    /// Perform one time initializations\n    /**\n     * init_asio is called once immediately after construction to initialize\n     * Asio components to the io_service\n     *\n     * @param service A pointer to the endpoint's io_service\n     * @param strand A shared pointer to the connection's asio strand\n     * @param is_server Whether or not the endpoint is a server or not.\n     */\n    lib::error_code init_asio (io_service_ptr service, strand_ptr, bool)\n    {\n        if (m_state != UNINITIALIZED) {\n            return socket::make_error_code(socket::error::invalid_state);\n        }\n\n        m_socket.reset(new lib::asio::ip::tcp::socket(*service));\n\n        if (m_socket_init_handler) {\n            m_socket_init_handler(m_hdl, *m_socket);\n        }\n\n        m_state = READY;\n\n        return lib::error_code();\n    }\n\n    /// Set uri hook\n    /**\n     * Called by the transport as a connection is being established to provide\n     * the uri being connected to to the security/socket layer.\n     *\n     * This socket policy doesn't use the uri so it is ignored.\n     *\n     * @since 0.6.0\n     *\n     * @param u The uri to set\n     */\n    void set_uri(uri_ptr) {}\n\n    /// Pre-initialize security policy\n    /**\n     * Called by the transport after a new connection is created to initialize\n     * the socket component of the connection. This method is not allowed to\n     * write any bytes to the wire. This initialization happens before any\n     * proxies or other intermediate wrappers are negotiated.\n     *\n     * @param callback Handler to call back with completion information\n     */\n    void pre_init(init_handler callback) {\n        if (m_state != READY) {\n            callback(socket::make_error_code(socket::error::invalid_state));\n            return;\n        }\n\n        m_state = READING;\n\n        callback(lib::error_code());\n    }\n\n    /// Post-initialize security policy\n    /**\n     * Called by the transport after all intermediate proxies have been\n     * negotiated. This gives the security policy the chance to talk with the\n     * real remote endpoint for a bit before the websocket handshake.\n     *\n     * @param callback Handler to call back with completion information\n     */\n    void post_init(init_handler callback) {\n        callback(lib::error_code());\n    }\n\n    /// Sets the connection handle\n    /**\n     * The connection handle is passed to any handlers to identify the\n     * connection\n     *\n     * @param hdl The new handle\n     */\n    void set_handle(connection_hdl hdl) {\n        m_hdl = hdl;\n    }\n\n    /// Cancel all async operations on this socket\n    /**\n     * Attempts to cancel all async operations on this socket and reports any\n     * failures.\n     *\n     * NOTE: Windows XP and earlier do not support socket cancellation.\n     *\n     * @return The error that occurred, if any.\n     */\n    lib::asio::error_code cancel_socket() {\n        lib::asio::error_code ec;\n        m_socket->cancel(ec);\n        return ec;\n    }\n\n    void async_shutdown(socket::shutdown_handler h) {\n        lib::asio::error_code ec;\n        m_socket->shutdown(lib::asio::ip::tcp::socket::shutdown_both, ec);\n        h(ec);\n    }\n\n    lib::error_code get_ec() const {\n        return lib::error_code();\n    }\n\npublic:\n    /// Translate any security policy specific information about an error code\n    /**\n     * Translate_ec takes an Asio error code and attempts to convert its value \n     * to an appropriate websocketpp error code. In the case that the Asio and\n     * Websocketpp error types are the same (such as using boost::asio and\n     * boost::system_error or using standalone asio and std::system_error the\n     * code will be passed through natively.\n     *\n     * In the case of a mismatch (boost::asio with std::system_error) a\n     * translated code will be returned. The plain socket policy does not have \n     * any additional information so all such errors will be reported as the\n     * generic transport pass_through error.\n     *\n     * @since 0.3.0\n     *\n     * @param ec The error code to translate_ec\n     * @return The translated error code\n     */\n    template <typename ErrorCodeType>\n    static\n    lib::error_code translate_ec(ErrorCodeType) {\n        // We don't know any more information about this error so pass through\n        return make_error_code(transport::error::pass_through);\n    }\n\n    static\n    /// Overload of translate_ec to catch cases where lib::error_code is the \n    /// same type as lib::asio::error_code\n    lib::error_code translate_ec(lib::error_code ec) {\n        // We don't know any more information about this error, but the error is\n        // the same type as the one we are translating to, so pass through\n        // untranslated.\n        return ec;\n    }\nprivate:\n    enum state {\n        UNINITIALIZED = 0,\n        READY = 1,\n        READING = 2\n    };\n\n    socket_ptr          m_socket;\n    state               m_state;\n\n    connection_hdl      m_hdl;\n    socket_init_handler m_socket_init_handler;\n};\n\n/// Basic ASIO endpoint socket component\n/**\n * transport::asio::basic_socket::endpoint implements an endpoint socket\n * component that uses Boost ASIO's ip::tcp::socket.\n */\nclass endpoint {\npublic:\n    /// The type of this endpoint socket component\n    typedef endpoint type;\n\n    /// The type of the corresponding connection socket component\n    typedef connection socket_con_type;\n    /// The type of a shared pointer to the corresponding connection socket\n    /// component.\n    typedef socket_con_type::ptr socket_con_ptr;\n\n    explicit endpoint() {}\n\n    /// Checks whether the endpoint creates secure connections\n    /**\n     * @return Whether or not the endpoint creates secure connections\n     */\n    bool is_secure() const {\n        return false;\n    }\n\n    /// Set socket init handler\n    /**\n     * The socket init handler is called after a connection's socket is created\n     * but before it is used. This gives the end application an opportunity to\n     * set asio socket specific parameters.\n     *\n     * @param h The new socket_init_handler\n     */\n    void set_socket_init_handler(socket_init_handler h) {\n        m_socket_init_handler = h;\n    }\nprotected:\n    /// Initialize a connection\n    /**\n     * Called by the transport after a new connection is created to initialize\n     * the socket component of the connection.\n     *\n     * @param scon Pointer to the socket component of the connection\n     *\n     * @return Error code (empty on success)\n     */\n    lib::error_code init(socket_con_ptr scon) {\n        scon->set_socket_init_handler(m_socket_init_handler);\n        return lib::error_code();\n    }\nprivate:\n    socket_init_handler m_socket_init_handler;\n};\n\n} // namespace basic_socket\n} // namespace asio\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP\n"
  },
  {
    "path": "websocketpp/transport/asio/security/tls.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP\n#define WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP\n\n#include <websocketpp/transport/asio/security/base.hpp>\n\n#include <websocketpp/uri.hpp>\n\n#include <websocketpp/common/asio_ssl.hpp>\n#include <websocketpp/common/asio.hpp>\n#include <websocketpp/common/connection_hdl.hpp>\n#include <websocketpp/common/functional.hpp>\n#include <websocketpp/common/memory.hpp>\n\n#include <sstream>\n#include <string>\n\nnamespace websocketpp {\nnamespace transport {\nnamespace asio {\n/// A socket policy for the asio transport that implements a TLS encrypted\n/// socket by wrapping with an asio::ssl::stream\nnamespace tls_socket {\n\n/// The signature of the socket_init_handler for this socket policy\ntypedef lib::function<void(connection_hdl,lib::asio::ssl::stream<\n    lib::asio::ip::tcp::socket>&)> socket_init_handler;\n/// The signature of the tls_init_handler for this socket policy\ntypedef lib::function<lib::shared_ptr<lib::asio::ssl::context>(connection_hdl)>\n    tls_init_handler;\n\n/// TLS enabled Asio connection socket component\n/**\n * transport::asio::tls_socket::connection implements a secure connection socket\n * component that uses Asio's ssl::stream to wrap an ip::tcp::socket.\n */\nclass connection : public lib::enable_shared_from_this<connection> {\npublic:\n    /// Type of this connection socket component\n    typedef connection type;\n    /// Type of a shared pointer to this connection socket component\n    typedef lib::shared_ptr<type> ptr;\n\n    /// Type of the ASIO socket being used\n    typedef lib::asio::ssl::stream<lib::asio::ip::tcp::socket> socket_type;\n    /// Type of a shared pointer to the ASIO socket being used\n    typedef lib::shared_ptr<socket_type> socket_ptr;\n    /// Type of a pointer to the ASIO io_service being used\n    typedef lib::asio::io_service * io_service_ptr;\n    /// Type of a pointer to the ASIO io_service strand being used\n    typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;\n    /// Type of a shared pointer to the ASIO TLS context being used\n    typedef lib::shared_ptr<lib::asio::ssl::context> context_ptr;\n\n    explicit connection() {\n        //std::cout << \"transport::asio::tls_socket::connection constructor\"\n        //          << std::endl;\n    }\n\n    /// Get a shared pointer to this component\n    ptr get_shared() {\n        return shared_from_this();\n    }\n\n    /// Check whether or not this connection is secure\n    /**\n     * @return Whether or not this connection is secure\n     */\n    bool is_secure() const {\n        return true;\n    }\n\n    /// Retrieve a pointer to the underlying socket\n    /**\n     * This is used internally. It can also be used to set socket options, etc\n     */\n    socket_type::lowest_layer_type & get_raw_socket() {\n        return m_socket->lowest_layer();\n    }\n\n    /// Retrieve a pointer to the layer below the ssl stream\n    /**\n     * This is used internally.\n     */\n    socket_type::next_layer_type & get_next_layer() {\n        return m_socket->next_layer();\n    }\n\n    /// Retrieve a pointer to the wrapped socket\n    /**\n     * This is used internally.\n     */\n    socket_type & get_socket() {\n        return *m_socket;\n    }\n\n    /// Set the socket initialization handler\n    /**\n     * The socket initialization handler is called after the socket object is\n     * created but before it is used. This gives the application a chance to\n     * set any ASIO socket options it needs.\n     *\n     * @param h The new socket_init_handler\n     */\n    void set_socket_init_handler(socket_init_handler h) {\n        m_socket_init_handler = h;\n    }\n\n    /// Set TLS init handler\n    /**\n     * The tls init handler is called when needed to request a TLS context for\n     * the library to use. A TLS init handler must be set and it must return a\n     * valid TLS context in order for this endpoint to be able to initialize\n     * TLS connections\n     *\n     * @param h The new tls_init_handler\n     */\n    void set_tls_init_handler(tls_init_handler h) {\n        m_tls_init_handler = h;\n    }\n\n    /// Get the remote endpoint address\n    /**\n     * The iostream transport has no information about the ultimate remote\n     * endpoint. It will return the string \"iostream transport\". To indicate\n     * this.\n     *\n     * TODO: allow user settable remote endpoint addresses if this seems useful\n     *\n     * @return A string identifying the address of the remote endpoint\n     */\n    std::string get_remote_endpoint(lib::error_code & ec) const {\n        std::stringstream s;\n\n        lib::asio::error_code aec;\n        lib::asio::ip::tcp::endpoint ep = m_socket->lowest_layer().remote_endpoint(aec);\n\n        if (aec) {\n            ec = error::make_error_code(error::pass_through);\n            s << \"Error getting remote endpoint: \" << aec\n               << \" (\" << aec.message() << \")\";\n            return s.str();\n        } else {\n            ec = lib::error_code();\n            s << ep;\n            return s.str();\n        }\n    }\nprotected:\n    /// Perform one time initializations\n    /**\n     * init_asio is called once immediately after construction to initialize\n     * Asio components to the io_service\n     *\n     * @param service A pointer to the endpoint's io_service\n     * @param strand A pointer to the connection's strand\n     * @param is_server Whether or not the endpoint is a server or not.\n     */\n    lib::error_code init_asio (io_service_ptr service, strand_ptr strand,\n        bool is_server)\n    {\n        if (!m_tls_init_handler) {\n            return socket::make_error_code(socket::error::missing_tls_init_handler);\n        }\n        m_context = m_tls_init_handler(m_hdl);\n\n        if (!m_context) {\n            return socket::make_error_code(socket::error::invalid_tls_context);\n        }\n        m_socket.reset(new socket_type(*service, *m_context));\n\n        if (m_socket_init_handler) {\n            m_socket_init_handler(m_hdl, get_socket());\n        }\n\n        m_io_service = service;\n        m_strand = strand;\n        m_is_server = is_server;\n\n        return lib::error_code();\n    }\n\n    /// Set hostname hook\n    /**\n     * Called by the transport as a connection is being established to provide\n     * the hostname being connected to to the security/socket layer.\n     *\n     * This socket policy uses the hostname to set the appropriate TLS SNI\n     * header.\n     *\n     * @since 0.6.0\n     *\n     * @param u The uri to set\n     */\n    void set_uri(uri_ptr u) {\n        m_uri = u;\n    }\n\n    /// Pre-initialize security policy\n    /**\n     * Called by the transport after a new connection is created to initialize\n     * the socket component of the connection. This method is not allowed to\n     * write any bytes to the wire. This initialization happens before any\n     * proxies or other intermediate wrappers are negotiated.\n     *\n     * @param callback Handler to call back with completion information\n     */\n    void pre_init(init_handler callback) {\n        // TODO: is this the best way to check whether this function is \n        //       available in the version of OpenSSL being used?\n        // TODO: consider case where host is an IP address\n#if OPENSSL_VERSION_NUMBER >= 0x90812f\n        if (!m_is_server) {\n            // For clients on systems with a suitable OpenSSL version, set the\n            // TLS SNI hostname header so connecting to TLS servers using SNI\n            // will work.\n            long res = SSL_set_tlsext_host_name(\n                get_socket().native_handle(), m_uri->get_host().c_str());\n            if (!(1 == res)) {\n                callback(socket::make_error_code(socket::error::tls_failed_sni_hostname));\n            }\n        }\n#endif\n\n        callback(lib::error_code());\n    }\n\n    /// Post-initialize security policy\n    /**\n     * Called by the transport after all intermediate proxies have been\n     * negotiated. This gives the security policy the chance to talk with the\n     * real remote endpoint for a bit before the websocket handshake.\n     *\n     * @param callback Handler to call back with completion information\n     */\n    void post_init(init_handler callback) {\n        m_ec = socket::make_error_code(socket::error::tls_handshake_timeout);\n\n        // TLS handshake\n        if (m_strand) {\n            m_socket->async_handshake(\n                get_handshake_type(),\n                m_strand->wrap(lib::bind(\n                    &type::handle_init, get_shared(),\n                    callback,\n                    lib::placeholders::_1\n                ))\n            );\n        } else {\n            m_socket->async_handshake(\n                get_handshake_type(),\n                lib::bind(\n                    &type::handle_init, get_shared(),\n                    callback,\n                    lib::placeholders::_1\n                )\n            );\n        }\n    }\n\n    /// Sets the connection handle\n    /**\n     * The connection handle is passed to any handlers to identify the\n     * connection\n     *\n     * @param hdl The new handle\n     */\n    void set_handle(connection_hdl hdl) {\n        m_hdl = hdl;\n    }\n\n    void handle_init(init_handler callback,lib::asio::error_code const & ec) {\n        if (ec) {\n            m_ec = socket::make_error_code(socket::error::tls_handshake_failed);\n        } else {\n            m_ec = lib::error_code();\n        }\n\n        callback(m_ec);\n    }\n\n    lib::error_code get_ec() const {\n        return m_ec;\n    }\n\n    /// Cancel all async operations on this socket\n    /**\n     * Attempts to cancel all async operations on this socket and reports any\n     * failures.\n     *\n     * NOTE: Windows XP and earlier do not support socket cancellation.\n     *\n     * @return The error that occurred, if any.\n     */\n    lib::asio::error_code cancel_socket() {\n        lib::asio::error_code ec;\n        get_raw_socket().cancel(ec);\n        return ec;\n    }\n\n    void async_shutdown(socket::shutdown_handler callback) {\n        if (m_strand) {\n            m_socket->async_shutdown(m_strand->wrap(callback));\n        } else {\n            m_socket->async_shutdown(callback);\n        }\n    }\n\npublic:\n    /// Translate any security policy specific information about an error code\n    /**\n     * Translate_ec takes an Asio error code and attempts to convert its value\n     * to an appropriate websocketpp error code. In the case that the Asio and\n     * Websocketpp error types are the same (such as using boost::asio and\n     * boost::system_error or using standalone asio and std::system_error the\n     * code will be passed through natively.\n     *\n     * In the case of a mismatch (boost::asio with std::system_error) a\n     * translated code will be returned. Any error that is determined to be\n     * related to TLS but does not have a more specific websocketpp error code\n     * is returned under the catch all error `tls_error`. Non-TLS related errors\n     * are returned as the transport generic error `pass_through`\n     *\n     * @since 0.3.0\n     *\n     * @param ec The error code to translate_ec\n     * @return The translated error code\n     */\n    template <typename ErrorCodeType>\n    static\n    lib::error_code translate_ec(ErrorCodeType ec) {\n        if (ec.category() == lib::asio::error::get_ssl_category()) {\n            // We know it is a TLS related error, but otherwise don't know more.\n            // Pass through as TLS generic.\n            return make_error_code(transport::error::tls_error);\n        } else {\n            // We don't know any more information about this error so pass\n            // through\n            return make_error_code(transport::error::pass_through);\n        }\n    }\n\n    static\n    /// Overload of translate_ec to catch cases where lib::error_code is the\n    /// same type as lib::asio::error_code\n    lib::error_code translate_ec(lib::error_code ec) {\n        return ec;\n    }\nprivate:\n    socket_type::handshake_type get_handshake_type() {\n        if (m_is_server) {\n            return lib::asio::ssl::stream_base::server;\n        } else {\n            return lib::asio::ssl::stream_base::client;\n        }\n    }\n\n    io_service_ptr      m_io_service;\n    strand_ptr          m_strand;\n    context_ptr         m_context;\n    socket_ptr          m_socket;\n    uri_ptr             m_uri;\n    bool                m_is_server;\n\n    lib::error_code     m_ec;\n\n    connection_hdl      m_hdl;\n    socket_init_handler m_socket_init_handler;\n    tls_init_handler    m_tls_init_handler;\n};\n\n/// TLS enabled Asio endpoint socket component\n/**\n * transport::asio::tls_socket::endpoint implements a secure endpoint socket\n * component that uses Asio's ssl::stream to wrap an ip::tcp::socket.\n */\nclass endpoint {\npublic:\n    /// The type of this endpoint socket component\n    typedef endpoint type;\n\n    /// The type of the corresponding connection socket component\n    typedef connection socket_con_type;\n    /// The type of a shared pointer to the corresponding connection socket\n    /// component.\n    typedef socket_con_type::ptr socket_con_ptr;\n\n    explicit endpoint() {}\n\n    /// Checks whether the endpoint creates secure connections\n    /**\n     * @return Whether or not the endpoint creates secure connections\n     */\n    bool is_secure() const {\n        return true;\n    }\n\n    /// Set socket init handler\n    /**\n     * The socket init handler is called after a connection's socket is created\n     * but before it is used. This gives the end application an opportunity to\n     * set asio socket specific parameters.\n     *\n     * @param h The new socket_init_handler\n     */\n    void set_socket_init_handler(socket_init_handler h) {\n        m_socket_init_handler = h;\n    }\n\n    /// Set TLS init handler\n    /**\n     * The tls init handler is called when needed to request a TLS context for\n     * the library to use. A TLS init handler must be set and it must return a\n     * valid TLS context in order for this endpoint to be able to initialize\n     * TLS connections\n     *\n     * @param h The new tls_init_handler\n     */\n    void set_tls_init_handler(tls_init_handler h) {\n        m_tls_init_handler = h;\n    }\nprotected:\n    /// Initialize a connection\n    /**\n     * Called by the transport after a new connection is created to initialize\n     * the socket component of the connection.\n     *\n     * @param scon Pointer to the socket component of the connection\n     *\n     * @return Error code (empty on success)\n     */\n    lib::error_code init(socket_con_ptr scon) {\n        scon->set_socket_init_handler(m_socket_init_handler);\n        scon->set_tls_init_handler(m_tls_init_handler);\n        return lib::error_code();\n    }\n\nprivate:\n    socket_init_handler m_socket_init_handler;\n    tls_init_handler m_tls_init_handler;\n};\n\n} // namespace tls_socket\n} // namespace asio\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP\n"
  },
  {
    "path": "websocketpp/transport/base/connection.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_BASE_CON_HPP\n#define WEBSOCKETPP_TRANSPORT_BASE_CON_HPP\n\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/connection_hdl.hpp>\n#include <websocketpp/common/functional.hpp>\n#include <websocketpp/common/system_error.hpp>\n\n#include <string>\n\nnamespace websocketpp {\n/// Transport policies provide network connectivity and timers\n/**\n * ### Connection Interface\n *\n * Transport connection components needs to provide:\n *\n * **init**\\n\n * `void init(init_handler handler)`\\n\n * Called once shortly after construction to give the policy the chance to\n * perform one time initialization. When complete, the policy must call the\n * supplied `init_handler` to continue setup. The handler takes one argument\n * with the error code if any. If an error is returned here setup will fail and\n * the connection will be aborted or terminated.\n *\n * WebSocket++ will call init only once. The transport must call `handler`\n * exactly once.\n *\n * **async_read_at_least**\\n\n * `void async_read_at_least(size_t num_bytes, char *buf, size_t len,\n * read_handler handler)`\\n\n * start an async read for at least num_bytes and at most len\n * bytes into buf. Call handler when done with number of bytes read.\n *\n * WebSocket++ promises to have only one async_read_at_least in flight at a\n * time. The transport must promise to only call read_handler once per async\n * read.\n *\n * **async_write**\\n\n * `void async_write(const char* buf, size_t len, write_handler handler)`\\n\n * `void async_write(std::vector<buffer> & bufs, write_handler handler)`\\n\n * Start a write of all of the data in buf or bufs. In second case data is\n * written sequentially and in place without copying anything to a temporary\n * location.\n *\n * Websocket++ promises to have only one async_write in flight at a time.\n * The transport must promise to only call the write_handler once per async\n * write\n *\n * **set_handle**\\n\n * `void set_handle(connection_hdl hdl)`\\n\n * Called by WebSocket++ to let this policy know the hdl to the connection. It\n * may be stored for later use or ignored/discarded. This handle should be used\n * if the policy adds any connection handlers. Connection handlers must be\n * called with the handle as the first argument so that the handler code knows\n * which connection generated the callback.\n *\n * **set_timer**\\n\n * `timer_ptr set_timer(long duration, timer_handler handler)`\\n\n * WebSocket++ uses the timers provided by the transport policy as the\n * implementation of timers is often highly coupled with the implementation of\n * the networking event loops.\n *\n * Transport timer support is an optional feature. A transport method may elect\n * to implement a dummy timer object and have this method return an empty\n * pointer. If so, all timer related features of WebSocket++ core will be\n * disabled. This includes many security features designed to prevent denial of\n * service attacks. Use timer-free transport policies with caution.\n *\n * **get_remote_endpoint**\\n\n * `std::string get_remote_endpoint()`\\n\n * retrieve address of remote endpoint\n *\n * **is_secure**\\n\n * `void is_secure()`\\n\n * whether or not the connection to the remote endpoint is secure\n *\n * **dispatch**\\n\n * `lib::error_code dispatch(dispatch_handler handler)`: invoke handler within\n * the transport's event system if it uses one. Otherwise, this method should\n * simply call `handler` immediately.\n *\n * **async_shutdown**\\n\n * `void async_shutdown(shutdown_handler handler)`\\n\n * Perform any cleanup necessary (if any). Call `handler` when complete.\n */\nnamespace transport {\n\n/// The type and signature of the callback passed to the init hook\ntypedef lib::function<void(lib::error_code const &)> init_handler;\n\n/// The type and signature of the callback passed to the read method\ntypedef lib::function<void(lib::error_code const &,size_t)> read_handler;\n\n/// The type and signature of the callback passed to the write method\ntypedef lib::function<void(lib::error_code const &)> write_handler;\n\n/// The type and signature of the callback passed to the read method\ntypedef lib::function<void(lib::error_code const &)> timer_handler;\n\n/// The type and signature of the callback passed to the shutdown method\ntypedef lib::function<void(lib::error_code const &)> shutdown_handler;\n\n/// The type and signature of the callback passed to the interrupt method\ntypedef lib::function<void()> interrupt_handler;\n\n/// The type and signature of the callback passed to the dispatch method\ntypedef lib::function<void()> dispatch_handler;\n\n/// A simple utility buffer class\nstruct buffer {\n    buffer(char const * b, size_t l) : buf(b),len(l) {}\n\n    char const * buf;\n    size_t len;\n};\n\n/// Generic transport related errors\nnamespace error {\nenum value {\n    /// Catch-all error for transport policy errors that don't fit in other\n    /// categories\n    general = 1,\n\n    /// underlying transport pass through\n    pass_through,\n\n    /// async_read_at_least call requested more bytes than buffer can store\n    invalid_num_bytes,\n\n    /// async_read called while another async_read was in progress\n    double_read,\n\n    /// Operation aborted\n    operation_aborted,\n\n    /// Operation not supported\n    operation_not_supported,\n\n    /// End of file\n    eof,\n\n    /// TLS short read\n    tls_short_read,\n\n    /// Timer expired\n    timeout,\n\n    /// read or write after shutdown\n    action_after_shutdown,\n\n    /// Other TLS error\n    tls_error\n};\n\nclass category : public lib::error_category {\n    public:\n    category() {}\n\n    char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {\n        return \"websocketpp.transport\";\n    }\n\n    std::string message(int value) const {\n        switch(value) {\n            case general:\n                return \"Generic transport policy error\";\n            case pass_through:\n                return \"Underlying Transport Error\";\n            case invalid_num_bytes:\n                return \"async_read_at_least call requested more bytes than buffer can store\";\n            case operation_aborted:\n                return \"The operation was aborted\";\n            case operation_not_supported:\n                return \"The operation is not supported by this transport\";\n            case eof:\n                return \"End of File\";\n            case tls_short_read:\n                return \"TLS Short Read\";\n            case timeout:\n                return \"Timer Expired\";\n            case action_after_shutdown:\n                return \"A transport action was requested after shutdown\";\n            case tls_error:\n                return \"Generic TLS related error\";\n            default:\n                return \"Unknown\";\n        }\n    }\n};\n\ninline lib::error_category const & get_category() {\n    static category instance;\n    return instance;\n}\n\ninline lib::error_code make_error_code(error::value e) {\n    return lib::error_code(static_cast<int>(e), get_category());\n}\n\n} // namespace error\n} // namespace transport\n} // namespace websocketpp\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_\ntemplate<> struct is_error_code_enum<websocketpp::transport::error::value>\n{\n    static bool const value = true;\n};\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_\n\n#endif // WEBSOCKETPP_TRANSPORT_BASE_CON_HPP\n"
  },
  {
    "path": "websocketpp/transport/base/endpoint.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_BASE_HPP\n#define WEBSOCKETPP_TRANSPORT_BASE_HPP\n\n#include <websocketpp/common/functional.hpp>\n#include <websocketpp/common/system_error.hpp>\n\nnamespace websocketpp {\n/// Transport policies provide network connectivity and timers\n/**\n * ### Endpoint Interface\n *\n * Transport endpoint components needs to provide:\n *\n * **init**\\n\n * `lib::error_code init(transport_con_ptr tcon)`\\n\n * init is called by an endpoint once for each newly created connection.\n * It's purpose is to give the transport policy the chance to perform any\n * transport specific initialization that couldn't be done via the default\n * constructor.\n *\n * **is_secure**\\n\n * `bool is_secure() const`\\n\n * Test whether the transport component of this endpoint is capable of secure\n * connections.\n *\n * **async_connect**\\n\n * `void async_connect(transport_con_ptr tcon, uri_ptr location,\n *  connect_handler handler)`\\n\n * Initiate a connection to `location` using the given connection `tcon`. `tcon`\n * is a pointer to the transport connection component of the connection. When\n * complete, `handler` should be called with the the connection's\n * `connection_hdl` and any error that occurred.\n *\n * **init_logging**\n * `void init_logging(const lib::shared_ptr<alog_type>& a, const lib::shared_ptr<elog_type>& e)`\\n\n * Called once after construction to provide pointers to the endpoint's access\n * and error loggers. These may be stored and used to log messages or ignored.\n */\nnamespace transport {\n\n/// The type and signature of the callback passed to the accept method\ntypedef lib::function<void(lib::error_code const &)> accept_handler;\n\n/// The type and signature of the callback passed to the connect method\ntypedef lib::function<void(lib::error_code const &)> connect_handler;\n\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_BASE_HPP\n"
  },
  {
    "path": "websocketpp/transport/debug/base.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP\n#define WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP\n\n#include <websocketpp/common/system_error.hpp>\n#include <websocketpp/common/cpp11.hpp>\n\n#include <string>\n\nnamespace websocketpp {\nnamespace transport {\n/// Debug transport policy that is used for various mocking and stubbing duties\n/// in unit tests.\nnamespace debug {\n\n/// debug transport errors\nnamespace error {\nenum value {\n    /// Catch-all error for transport policy errors that don't fit in other\n    /// categories\n    general = 1,\n\n    /// not implemented\n    not_implemented,\n    \n    invalid_num_bytes,\n    \n    double_read\n};\n\n/// debug transport error category\nclass category : public lib::error_category {\n    public:\n    category() {}\n\n    char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {\n        return \"websocketpp.transport.debug\";\n    }\n\n    std::string message(int value) const {\n        switch(value) {\n            case general:\n                return \"Generic stub transport policy error\";\n            case not_implemented:\n                return \"feature not implemented\";\n            case invalid_num_bytes:\n                return \"Invalid number of bytes\";\n            case double_read:\n                return \"Read while another read was outstanding\";\n            default:\n                return \"Unknown\";\n        }\n    }\n};\n\n/// Get a reference to a static copy of the debug transport error category\ninline lib::error_category const & get_category() {\n    static category instance;\n    return instance;\n}\n\n/// Get an error code with the given value and the debug transport category\ninline lib::error_code make_error_code(error::value e) {\n    return lib::error_code(static_cast<int>(e), get_category());\n}\n\n} // namespace error\n} // namespace debug\n} // namespace transport\n} // namespace websocketpp\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_\ntemplate<> struct is_error_code_enum<websocketpp::transport::debug::error::value>\n{\n    static bool const value = true;\n};\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_\n\n#endif // WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP\n"
  },
  {
    "path": "websocketpp/transport/debug/connection.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP\n#define WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP\n\n#include <websocketpp/transport/debug/base.hpp>\n\n#include <websocketpp/transport/base/connection.hpp>\n\n#include <websocketpp/uri.hpp>\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/common/connection_hdl.hpp>\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/common/platforms.hpp>\n\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\nnamespace transport {\nnamespace debug {\n\n/// Empty timer class to stub out for timer functionality that stub\n/// transport doesn't support\nstruct timer {\n    void cancel() {}\n};\n\ntemplate <typename config>\nclass connection : public lib::enable_shared_from_this< connection<config> > {\npublic:\n    /// Type of this connection transport component\n    typedef connection<config> type;\n    /// Type of a shared pointer to this connection transport component\n    typedef lib::shared_ptr<type> ptr;\n\n    /// transport concurrency policy\n    typedef typename config::concurrency_type concurrency_type;\n    /// Type of this transport's access logging policy\n    typedef typename config::alog_type alog_type;\n    /// Type of this transport's error logging policy\n    typedef typename config::elog_type elog_type;\n\n    // Concurrency policy types\n    typedef typename concurrency_type::scoped_lock_type scoped_lock_type;\n    typedef typename concurrency_type::mutex_type mutex_type;\n\n    typedef lib::shared_ptr<timer> timer_ptr;\n\n    explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)\n      : m_reading(false), m_is_server(is_server), m_alog(alog), m_elog(elog)\n    {\n        m_alog->write(log::alevel::devel,\"debug con transport constructor\");\n    }\n\n    /// Get a shared pointer to this component\n    ptr get_shared() {\n        return type::shared_from_this();\n    }\n\n    /// Set whether or not this connection is secure\n    /**\n     * Todo: docs\n     *\n     * @since 0.3.0-alpha4\n     *\n     * @param value Whether or not this connection is secure.\n     */\n    void set_secure(bool) {}\n\n    /// Tests whether or not the underlying transport is secure\n    /**\n     * TODO: docs\n     *\n     * @return Whether or not the underlying transport is secure\n     */\n    bool is_secure() const {\n        return false;\n    }\n\n    /// Set uri hook\n    /**\n     * Called by the endpoint as a connection is being established to provide\n     * the uri being connected to to the transport layer.\n     *\n     * Implementation is optional and can be ignored if the transport has no\n     * need for this information.\n     *\n     * @since 0.6.0\n     *\n     * @param u The uri to set\n     */\n    void set_uri(uri_ptr) {}\n\n    /// Set human readable remote endpoint address\n    /**\n     * Sets the remote endpoint address returned by `get_remote_endpoint`. This\n     * value should be a human readable string that describes the remote\n     * endpoint. Typically an IP address or hostname, perhaps with a port. But\n     * may be something else depending on the nature of the underlying\n     * transport.\n     *\n     * If none is set a default is returned.\n     *\n     * @since 0.3.0-alpha4\n     *\n     * @param value The remote endpoint address to set.\n     */\n    void set_remote_endpoint(std::string) {}\n\n    /// Get human readable remote endpoint address\n    /**\n     * TODO: docs\n     *\n     * This value is used in access and error logs and is available to the end\n     * application for including in user facing interfaces and messages.\n     *\n     * @return A string identifying the address of the remote endpoint\n     */\n    std::string get_remote_endpoint() const {\n        return \"unknown (debug transport)\";\n    }\n\n    /// Get the connection handle\n    /**\n     * @return The handle for this connection.\n     */\n    connection_hdl get_handle() const {\n        return connection_hdl();\n    }\n\n    /// Call back a function after a period of time.\n    /**\n     * Timers are not implemented in this transport. The timer pointer will\n     * always be empty. The handler will never be called.\n     *\n     * @param duration Length of time to wait in milliseconds\n     * @param callback The function to call back when the timer has expired\n     * @return A handle that can be used to cancel the timer if it is no longer\n     * needed.\n     */\n    timer_ptr set_timer(long, timer_handler handler) {\n        m_alog->write(log::alevel::devel,\"debug connection set timer\");\n        m_timer_handler = handler;\n        return timer_ptr();\n    }\n    \n    /// Manual input supply (read all)\n    /**\n     * Similar to read_some, but continues to read until all bytes in the\n     * supplied buffer have been read or the connection runs out of read\n     * requests.\n     *\n     * This method still may not read all of the bytes in the input buffer. if\n     * it doesn't it indicates that the connection was most likely closed or\n     * is in an error state where it is no longer accepting new input.\n     *\n     * @since 0.3.0\n     *\n     * @param buf Char buffer to read into the websocket\n     * @param len Length of buf\n     * @return The number of characters from buf actually read.\n     */\n    size_t read_all(char const * buf, size_t len) {        \n        size_t total_read = 0;\n        size_t temp_read = 0;\n\n        do {\n            temp_read = this->read_some_impl(buf+total_read,len-total_read);\n            total_read += temp_read;\n        } while (temp_read != 0 && total_read < len);\n\n        return total_read;\n    }\n    \n    // debug stuff to invoke the async handlers\n    void expire_timer(lib::error_code const & ec) {\n        m_timer_handler(ec);\n    }\n    \n    void fullfil_write() {\n        m_write_handler(lib::error_code());\n    }\nprotected:\n    /// Initialize the connection transport\n    /**\n     * Initialize the connection's transport component.\n     *\n     * @param handler The `init_handler` to call when initialization is done\n     */\n    void init(init_handler handler) {\n        m_alog->write(log::alevel::devel,\"debug connection init\");\n        handler(lib::error_code());\n    }\n\n    /// Initiate an async_read for at least num_bytes bytes into buf\n    /**\n     * Initiates an async_read request for at least num_bytes bytes. The input\n     * will be read into buf. A maximum of len bytes will be input. When the\n     * operation is complete, handler will be called with the status and number\n     * of bytes read.\n     *\n     * This method may or may not call handler from within the initial call. The\n     * application should be prepared to accept either.\n     *\n     * The application should never call this method a second time before it has\n     * been called back for the first read. If this is done, the second read\n     * will be called back immediately with a double_read error.\n     *\n     * If num_bytes or len are zero handler will be called back immediately\n     * indicating success.\n     *\n     * @param num_bytes Don't call handler until at least this many bytes have\n     * been read.\n     * @param buf The buffer to read bytes into\n     * @param len The size of buf. At maximum, this many bytes will be read.\n     * @param handler The callback to invoke when the operation is complete or\n     * ends in an error\n     */\n    void async_read_at_least(size_t num_bytes, char * buf, size_t len,\n        read_handler handler)\n    {\n        std::stringstream s;\n        s << \"debug_con async_read_at_least: \" << num_bytes;\n        m_alog->write(log::alevel::devel,s.str());\n\n        if (num_bytes > len) {\n            handler(make_error_code(error::invalid_num_bytes),size_t(0));\n            return;\n        }\n\n        if (m_reading == true) {\n            handler(make_error_code(error::double_read),size_t(0));\n            return;\n        }\n\n        if (num_bytes == 0 || len == 0) {\n            handler(lib::error_code(),size_t(0));\n            return;\n        }\n\n        m_buf = buf;\n        m_len = len;\n        m_bytes_needed = num_bytes;\n        m_read_handler = handler;\n        m_cursor = 0;\n        m_reading = true;\n    }\n\n    /// Asyncronous Transport Write\n    /**\n     * Write len bytes in buf to the output stream. Call handler to report\n     * success or failure. handler may or may not be called during async_write,\n     * but it must be safe for this to happen.\n     *\n     * Will return 0 on success.\n     *\n     * @param buf buffer to read bytes from\n     * @param len number of bytes to write\n     * @param handler Callback to invoke with operation status.\n     */\n    void async_write(char const *, size_t, write_handler handler) {\n        m_alog->write(log::alevel::devel,\"debug_con async_write\");\n        m_write_handler = handler;\n    }\n\n    /// Asyncronous Transport Write (scatter-gather)\n    /**\n     * Write a sequence of buffers to the output stream. Call handler to report\n     * success or failure. handler may or may not be called during async_write,\n     * but it must be safe for this to happen.\n     *\n     * Will return 0 on success.\n     *\n     * @param bufs vector of buffers to write\n     * @param handler Callback to invoke with operation status.\n     */\n    void async_write(std::vector<buffer> const &, write_handler handler) {\n        m_alog->write(log::alevel::devel,\"debug_con async_write buffer list\");\n        m_write_handler = handler;\n    }\n\n    /// Set Connection Handle\n    /**\n     * @param hdl The new handle\n     */\n    void set_handle(connection_hdl) {}\n\n    /// Call given handler back within the transport's event system (if present)\n    /**\n     * Invoke a callback within the transport's event system if it has one. If\n     * it doesn't, the handler will be invoked immediately before this function\n     * returns.\n     *\n     * @param handler The callback to invoke\n     *\n     * @return Whether or not the transport was able to register the handler for\n     * callback.\n     */\n    lib::error_code dispatch(dispatch_handler handler) {\n        handler();\n        return lib::error_code();\n    }\n\n    /// Perform cleanup on socket shutdown_handler\n    /**\n     * @param h The `shutdown_handler` to call back when complete\n     */\n    void async_shutdown(shutdown_handler handler) {\n        handler(lib::error_code());\n    }\n    \n    size_t read_some_impl(char const * buf, size_t len) {\n        m_alog->write(log::alevel::devel,\"debug_con read_some\");\n\n        if (!m_reading) {\n            m_elog->write(log::elevel::devel,\"write while not reading\");\n            return 0;\n        }\n\n        size_t bytes_to_copy = (std::min)(len,m_len-m_cursor);\n\n        std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor);\n\n        m_cursor += bytes_to_copy;\n\n        if (m_cursor >= m_bytes_needed) {\n            complete_read(lib::error_code());\n        }\n\n        return bytes_to_copy;\n    }\n\n    /// Signal that a requested read is complete\n    /**\n     * Sets the reading flag to false and returns the handler that should be\n     * called back with the result of the read. The cursor position that is sent\n     * is whatever the value of m_cursor is.\n     *\n     * It MUST NOT be called when m_reading is false.\n     * it MUST be called while holding the read lock\n     *\n     * It is important to use this method rather than directly setting/calling\n     * m_read_handler back because this function makes sure to delete the\n     * locally stored handler which contains shared pointers that will otherwise\n     * cause circular reference based memory leaks.\n     *\n     * @param ec The error code to forward to the read handler\n     */\n    void complete_read(lib::error_code const & ec) {\n        m_reading = false;\n\n        read_handler handler = m_read_handler;\n        m_read_handler = read_handler();\n\n        handler(ec,m_cursor);\n    }\nprivate:\n    timer_handler m_timer_handler;\n    \n    // Read space (Protected by m_read_mutex)\n    char *          m_buf;\n    size_t          m_len;\n    size_t          m_bytes_needed;\n    read_handler    m_read_handler;\n    size_t          m_cursor;\n\n    // transport resources\n    connection_hdl  m_connection_hdl;\n    write_handler   m_write_handler;\n    shutdown_handler    m_shutdown_handler;\n\n    bool            m_reading;\n    bool const      m_is_server;\n    bool            m_is_secure;\n    lib::shared_ptr<alog_type>     m_alog;\n    lib::shared_ptr<elog_type>     m_elog;\n    std::string     m_remote_endpoint;\n};\n\n\n} // namespace debug\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP\n"
  },
  {
    "path": "websocketpp/transport/debug/endpoint.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_DEBUG_HPP\n#define WEBSOCKETPP_TRANSPORT_DEBUG_HPP\n\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/transport/base/endpoint.hpp>\n#include <websocketpp/transport/debug/connection.hpp>\n\nnamespace websocketpp {\nnamespace transport {\nnamespace debug {\n\ntemplate <typename config>\nclass endpoint {\npublic:\n    /// Type of this endpoint transport component\n    typedef endpoint type;\n    /// Type of a pointer to this endpoint transport component\n    typedef lib::shared_ptr<type> ptr;\n\n    /// Type of this endpoint's concurrency policy\n    typedef typename config::concurrency_type concurrency_type;\n    /// Type of this endpoint's error logging policy\n    typedef typename config::elog_type elog_type;\n    /// Type of this endpoint's access logging policy\n    typedef typename config::alog_type alog_type;\n\n    /// Type of this endpoint transport component's associated connection\n    /// transport component.\n    typedef debug::connection<config> transport_con_type;\n    /// Type of a shared pointer to this endpoint transport component's\n    /// associated connection transport component\n    typedef typename transport_con_type::ptr transport_con_ptr;\n\n    // generate and manage our own io_service\n    explicit endpoint()\n    {\n        //std::cout << \"transport::iostream::endpoint constructor\" << std::endl;\n    }\n\n    /// Set whether or not endpoint can create secure connections\n    /**\n     * TODO: docs\n     *\n     * Setting this value only indicates whether or not the endpoint is capable\n     * of producing and managing secure connections. Connections produced by\n     * this endpoint must also be individually flagged as secure if they are.\n     *\n     * @since 0.3.0-alpha4\n     *\n     * @param value Whether or not the endpoint can create secure connections.\n     */\n    void set_secure(bool) {}\n\n    /// Tests whether or not the underlying transport is secure\n    /**\n     * TODO: docs\n     *\n     * @return Whether or not the underlying transport is secure\n     */\n    bool is_secure() const {\n        return false;\n    }\nprotected:\n    /// Initialize logging\n    /**\n     * The loggers are located in the main endpoint class. As such, the\n     * transport doesn't have direct access to them. This method is called\n     * by the endpoint constructor to allow shared logging from the transport\n     * component. These are raw pointers to member variables of the endpoint.\n     * In particular, they cannot be used in the transport constructor as they\n     * haven't been constructed yet, and cannot be used in the transport\n     * destructor as they will have been destroyed by then.\n     *\n     * @param a A pointer to the access logger to use.\n     * @param e A pointer to the error logger to use.\n     */\n    void init_logging(lib::shared_ptr<alog_type>, lib::shared_ptr<elog_type>) {}\n\n    /// Initiate a new connection\n    /**\n     * @param tcon A pointer to the transport connection component of the\n     * connection to connect.\n     * @param u A URI pointer to the URI to connect to.\n     * @param cb The function to call back with the results when complete.\n     */\n    void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) {\n        cb(lib::error_code());\n    }\n\n    /// Initialize a connection\n    /**\n     * Init is called by an endpoint once for each newly created connection.\n     * It's purpose is to give the transport policy the chance to perform any\n     * transport specific initialization that couldn't be done via the default\n     * constructor.\n     *\n     * @param tcon A pointer to the transport portion of the connection.\n     * @return A status code indicating the success or failure of the operation\n     */\n    lib::error_code init(transport_con_ptr) {\n        return lib::error_code();\n    }\nprivate:\n\n};\n\n} // namespace debug\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_DEBUG_HPP\n"
  },
  {
    "path": "websocketpp/transport/iostream/base.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_IOSTREAM_BASE_HPP\n#define WEBSOCKETPP_TRANSPORT_IOSTREAM_BASE_HPP\n\n#include <websocketpp/common/system_error.hpp>\n#include <websocketpp/common/cpp11.hpp>\n#include <websocketpp/common/functional.hpp>\n#include <websocketpp/common/connection_hdl.hpp>\n\n#include <websocketpp/transport/base/connection.hpp>\n\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\nnamespace transport {\n/// Transport policy that uses STL iostream for I/O and does not support timers\nnamespace iostream {\n\n/// The type and signature of the callback used by iostream transport to write\ntypedef lib::function<lib::error_code(connection_hdl, char const *, size_t)>\n    write_handler;\n\n/// The type and signature of the callback used by iostream transport to perform\n/// vectored writes.\n/**\n * If a vectored write handler is not set the standard write handler will be\n * called multiple times.\n */\ntypedef lib::function<lib::error_code(connection_hdl, std::vector<transport::buffer> const\n    & bufs)> vector_write_handler;\n\n/// The type and signature of the callback used by iostream transport to signal\n/// a transport shutdown.\ntypedef lib::function<lib::error_code(connection_hdl)> shutdown_handler;\n\n/// iostream transport errors\nnamespace error {\nenum value {\n    /// Catch-all error for transport policy errors that don't fit in other\n    /// categories\n    general = 1,\n\n    /// async_read_at_least call requested more bytes than buffer can store\n    invalid_num_bytes,\n\n    /// async_read called while another async_read was in progress\n    double_read,\n\n    /// An operation that requires an output stream was attempted before\n    /// setting one.\n    output_stream_required,\n\n    /// stream error\n    bad_stream\n};\n\n/// iostream transport error category\nclass category : public lib::error_category {\n    public:\n    category() {}\n\n    char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {\n        return \"websocketpp.transport.iostream\";\n    }\n\n    std::string message(int value) const {\n        switch(value) {\n            case general:\n                return \"Generic iostream transport policy error\";\n            case invalid_num_bytes:\n                return \"async_read_at_least call requested more bytes than buffer can store\";\n            case double_read:\n                return \"Async read already in progress\";\n            case output_stream_required:\n                return \"An output stream to be set before async_write can be used\";\n            case bad_stream:\n                return \"A stream operation returned ios::bad\";\n            default:\n                return \"Unknown\";\n        }\n    }\n};\n\n/// Get a reference to a static copy of the iostream transport error category\ninline lib::error_category const & get_category() {\n    static category instance;\n    return instance;\n}\n\n/// Get an error code with the given value and the iostream transport category\ninline lib::error_code make_error_code(error::value e) {\n    return lib::error_code(static_cast<int>(e), get_category());\n}\n\n} // namespace error\n} // namespace iostream\n} // namespace transport\n} // namespace websocketpp\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_\ntemplate<> struct is_error_code_enum<websocketpp::transport::iostream::error::value>\n{\n    static bool const value = true;\n};\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_\n\n#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_BASE_HPP\n"
  },
  {
    "path": "websocketpp/transport/iostream/connection.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP\n#define WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP\n\n#include <websocketpp/transport/iostream/base.hpp>\n\n#include <websocketpp/transport/base/connection.hpp>\n\n#include <websocketpp/uri.hpp>\n\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/common/connection_hdl.hpp>\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/common/platforms.hpp>\n\n#include <algorithm>\n#include <iostream>\n#include <sstream>\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\nnamespace transport {\nnamespace iostream {\n\n/// Empty timer class to stub out for timer functionality that iostream\n/// transport doesn't support\nstruct timer {\n    void cancel() {}\n};\n\ntemplate <typename config>\nclass connection : public lib::enable_shared_from_this< connection<config> > {\npublic:\n    /// Type of this connection transport component\n    typedef connection<config> type;\n    /// Type of a shared pointer to this connection transport component\n    typedef lib::shared_ptr<type> ptr;\n\n    /// transport concurrency policy\n    typedef typename config::concurrency_type concurrency_type;\n    /// Type of this transport's access logging policy\n    typedef typename config::alog_type alog_type;\n    /// Type of this transport's error logging policy\n    typedef typename config::elog_type elog_type;\n\n    // Concurrency policy types\n    typedef typename concurrency_type::scoped_lock_type scoped_lock_type;\n    typedef typename concurrency_type::mutex_type mutex_type;\n\n    typedef lib::shared_ptr<timer> timer_ptr;\n\n    explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)\n      : m_output_stream(NULL)\n      , m_reading(false)\n      , m_is_server(is_server)\n      , m_is_secure(false)\n      , m_alog(alog)\n      , m_elog(elog)\n      , m_remote_endpoint(\"iostream transport\")\n    {\n        m_alog->write(log::alevel::devel,\"iostream con transport constructor\");\n    }\n\n    /// Get a shared pointer to this component\n    ptr get_shared() {\n        return type::shared_from_this();\n    }\n\n    /// Register a std::ostream with the transport for writing output\n    /**\n     * Register a std::ostream with the transport. All future writes will be\n     * done to this output stream.\n     *\n     * @param o A pointer to the ostream to use for output.\n     */\n    void register_ostream(std::ostream * o) {\n        // TODO: lock transport state?\n        scoped_lock_type lock(m_read_mutex);\n        m_output_stream = o;\n    }\n\n    /// Set uri hook\n    /**\n     * Called by the endpoint as a connection is being established to provide\n     * the uri being connected to to the transport layer.\n     *\n     * This transport policy doesn't use the uri so it is ignored.\n     *\n     * @since 0.6.0\n     *\n     * @param u The uri to set\n     */\n    void set_uri(uri_ptr) {}\n\n    /// Overloaded stream input operator\n    /**\n     * Attempts to read input from the given stream into the transport. Bytes\n     * will be extracted from the input stream to fulfill any pending reads.\n     * Input in this manner will only read until the current read buffer has\n     * been filled. Then it will signal the library to process the input. If the\n     * library's input handler adds a new async_read, additional bytes will be\n     * read, otherwise the input operation will end.\n     *\n     * When this function returns one of the following conditions is true:\n     * - There is no outstanding read operation\n     * - There are no more bytes available in the input stream\n     *\n     * You can use tellg() on the input stream to determine if all of the input\n     * bytes were read or not.\n     *\n     * If there is no pending read operation when the input method is called, it\n     * will return immediately and tellg() will not have changed.\n     */\n    friend std::istream & operator>> (std::istream & in, type & t) {\n        // this serializes calls to external read.\n        scoped_lock_type lock(t.m_read_mutex);\n\n        t.read(in);\n\n        return in;\n    }\n\n    /// Manual input supply (read some)\n    /**\n     * Copies bytes from buf into WebSocket++'s input buffers. Bytes will be\n     * copied from the supplied buffer to fulfill any pending library reads. It\n     * will return the number of bytes successfully processed. If there are no\n     * pending reads read_some will return immediately. Not all of the bytes may\n     * be able to be read in one call.\n     *\n     * @since 0.3.0-alpha4\n     *\n     * @param buf Char buffer to read into the websocket\n     * @param len Length of buf\n     * @return The number of characters from buf actually read.\n     */\n    size_t read_some(char const * buf, size_t len) {\n        // this serializes calls to external read.\n        scoped_lock_type lock(m_read_mutex);\n\n        return this->read_some_impl(buf,len);\n    }\n\n    /// Manual input supply (read all)\n    /**\n     * Similar to read_some, but continues to read until all bytes in the\n     * supplied buffer have been read or the connection runs out of read\n     * requests.\n     *\n     * This method still may not read all of the bytes in the input buffer. if\n     * it doesn't it indicates that the connection was most likely closed or\n     * is in an error state where it is no longer accepting new input.\n     *\n     * @since 0.3.0\n     *\n     * @param buf Char buffer to read into the websocket\n     * @param len Length of buf\n     * @return The number of characters from buf actually read.\n     */\n    size_t read_all(char const * buf, size_t len) {\n        // this serializes calls to external read.\n        scoped_lock_type lock(m_read_mutex);\n\n        size_t total_read = 0;\n        size_t temp_read = 0;\n\n        do {\n            temp_read = this->read_some_impl(buf+total_read,len-total_read);\n            total_read += temp_read;\n        } while (temp_read != 0 && total_read < len);\n\n        return total_read;\n    }\n\n    /// Manual input supply (DEPRECATED)\n    /**\n     * @deprecated DEPRECATED in favor of read_some()\n     * @see read_some()\n     */\n    size_t readsome(char const * buf, size_t len) {\n        return this->read_some(buf,len);\n    }\n\n    /// Signal EOF\n    /**\n     * Signals to the transport that data stream being read has reached EOF and\n     * that no more bytes may be read or written to/from the transport.\n     *\n     * @since 0.3.0-alpha4\n     */\n    void eof() {\n        // this serializes calls to external read.\n        scoped_lock_type lock(m_read_mutex);\n\n        if (m_reading) {\n            complete_read(make_error_code(transport::error::eof));\n        }\n    }\n\n    /// Signal transport error\n    /**\n     * Signals to the transport that a fatal data stream error has occurred and\n     * that no more bytes may be read or written to/from the transport.\n     *\n     * @since 0.3.0-alpha4\n     */\n    void fatal_error() {\n        // this serializes calls to external read.\n        scoped_lock_type lock(m_read_mutex);\n\n        if (m_reading) {\n            complete_read(make_error_code(transport::error::pass_through));\n        }\n    }\n\n    /// Set whether or not this connection is secure\n    /**\n     * The iostream transport does not provide any security features. As such\n     * it defaults to returning false when `is_secure` is called. However, the\n     * iostream transport may be used to wrap an external socket API that may\n     * provide secure transport. This method allows that external API to flag\n     * whether or not this connection is secure so that users of the WebSocket++\n     * API will get more accurate information.\n     *\n     * @since 0.3.0-alpha4\n     *\n     * @param value Whether or not this connection is secure.\n     */\n    void set_secure(bool value) {\n        m_is_secure = value;\n    }\n\n    /// Tests whether or not the underlying transport is secure\n    /**\n     * iostream transport will return false always because it has no information\n     * about the ultimate remote endpoint. This may or may not be accurate\n     * depending on the real source of bytes being input. The `set_secure`\n     * method may be used to flag connections that are secured by an external\n     * API\n     *\n     * @return Whether or not the underlying transport is secure\n     */\n    bool is_secure() const {\n        return m_is_secure;\n    }\n\n    /// Set human readable remote endpoint address\n    /**\n     * Sets the remote endpoint address returned by `get_remote_endpoint`. This\n     * value should be a human readable string that describes the remote\n     * endpoint. Typically an IP address or hostname, perhaps with a port. But\n     * may be something else depending on the nature of the underlying\n     * transport.\n     *\n     * If none is set the default is \"iostream transport\".\n     *\n     * @since 0.3.0-alpha4\n     *\n     * @param value The remote endpoint address to set.\n     */\n    void set_remote_endpoint(std::string value) {\n        m_remote_endpoint = value;\n    }\n\n    /// Get human readable remote endpoint address\n    /**\n     * The iostream transport has no information about the ultimate remote\n     * endpoint. It will return the string \"iostream transport\". The\n     * `set_remote_endpoint` method may be used by external network code to set\n     * a more accurate value.\n     *\n     * This value is used in access and error logs and is available to the end\n     * application for including in user facing interfaces and messages.\n     *\n     * @return A string identifying the address of the remote endpoint\n     */\n    std::string get_remote_endpoint() const {\n        return m_remote_endpoint;\n    }\n\n    /// Get the connection handle\n    /**\n     * @return The handle for this connection.\n     */\n    connection_hdl get_handle() const {\n        return m_connection_hdl;\n    }\n\n    /// Call back a function after a period of time.\n    /**\n     * Timers are not implemented in this transport. The timer pointer will\n     * always be empty. The handler will never be called.\n     *\n     * @param duration Length of time to wait in milliseconds\n     * @param callback The function to call back when the timer has expired\n     * @return A handle that can be used to cancel the timer if it is no longer\n     * needed.\n     */\n    timer_ptr set_timer(long, timer_handler) {\n        return timer_ptr();\n    }\n\n    /// Sets the write handler\n    /**\n     * The write handler is called when the iostream transport receives data\n     * that needs to be written to the appropriate output location. This handler\n     * can be used in place of registering an ostream for output.\n     *\n     * The signature of the handler is\n     * `lib::error_code (connection_hdl, char const *, size_t)` The\n     * code returned will be reported and logged by the core library.\n     *\n     * See also, set_vector_write_handler, for an optional write handler that\n     * allows more efficient handling of multiple writes at once.\n     *\n     * @see set_vector_write_handler\n     *\n     * @since 0.5.0\n     *\n     * @param h The handler to call when data is to be written.\n     */\n    void set_write_handler(write_handler h) {\n        m_write_handler = h;\n    }\n\n    /// Sets the vectored write handler\n    /**\n     * The vectored write handler is called when the iostream transport receives\n     * multiple chunks of data that need to be written to the appropriate output\n     * location. This handler can be used in conjunction with the write_handler\n     * in place of registering an ostream for output.\n     *\n     * The sequence of buffers represents bytes that should be written\n     * consecutively and it is suggested to group the buffers into as few next\n     * layer packets as possible. Vector write is used to allow implementations\n     * that support it to coalesce writes into a single TCP packet or TLS\n     * segment for improved efficiency.\n     *\n     * This is an optional handler. If it is not defined then multiple calls\n     * will be made to the standard write handler.\n     *\n     * The signature of the handler is\n     * `lib::error_code (connection_hdl, std::vector<websocketpp::transport::buffer>\n     * const & bufs)`. The code returned will be reported and logged by the core\n     * library. The `websocketpp::transport::buffer` type is a struct with two\n     * data members. buf (char const *) and len (size_t).\n     *\n     * @since 0.6.0\n     *\n     * @param h The handler to call when vectored data is to be written.\n     */\n    void set_vector_write_handler(vector_write_handler h) {\n        m_vector_write_handler = h;\n    }\n\n    /// Sets the shutdown handler\n    /**\n     * The shutdown handler is called when the iostream transport receives a\n     * notification from the core library that it is finished with all read and\n     * write operations and that the underlying transport can be cleaned up.\n     *\n     * If you are using iostream transport with another socket library, this is\n     * a good time to close/shutdown the socket for this connection.\n     *\n     * The signature of the handler is `lib::error_code (connection_hdl)`. The\n     * code returned will be reported and logged by the core library.\n     *\n     * @since 0.5.0\n     *\n     * @param h The handler to call on connection shutdown.\n     */\n    void set_shutdown_handler(shutdown_handler h) {\n        m_shutdown_handler = h;\n    }\nprotected:\n    /// Initialize the connection transport\n    /**\n     * Initialize the connection's transport component.\n     *\n     * @param handler The `init_handler` to call when initialization is done\n     */\n    void init(init_handler handler) {\n        m_alog->write(log::alevel::devel,\"iostream connection init\");\n        handler(lib::error_code());\n    }\n\n    /// Initiate an async_read for at least num_bytes bytes into buf\n    /**\n     * Initiates an async_read request for at least num_bytes bytes. The input\n     * will be read into buf. A maximum of len bytes will be input. When the\n     * operation is complete, handler will be called with the status and number\n     * of bytes read.\n     *\n     * This method may or may not call handler from within the initial call. The\n     * application should be prepared to accept either.\n     *\n     * The application should never call this method a second time before it has\n     * been called back for the first read. If this is done, the second read\n     * will be called back immediately with a double_read error.\n     *\n     * If num_bytes or len are zero handler will be called back immediately\n     * indicating success.\n     *\n     * @param num_bytes Don't call handler until at least this many bytes have\n     * been read.\n     * @param buf The buffer to read bytes into\n     * @param len The size of buf. At maximum, this many bytes will be read.\n     * @param handler The callback to invoke when the operation is complete or\n     * ends in an error\n     */\n    void async_read_at_least(size_t num_bytes, char *buf, size_t len,\n        read_handler handler)\n    {\n        std::stringstream s;\n        s << \"iostream_con async_read_at_least: \" << num_bytes;\n        m_alog->write(log::alevel::devel,s.str());\n\n        if (num_bytes > len) {\n            handler(make_error_code(error::invalid_num_bytes),size_t(0));\n            return;\n        }\n\n        if (m_reading == true) {\n            handler(make_error_code(error::double_read),size_t(0));\n            return;\n        }\n\n        if (num_bytes == 0 || len == 0) {\n            handler(lib::error_code(),size_t(0));\n            return;\n        }\n\n        m_buf = buf;\n        m_len = len;\n        m_bytes_needed = num_bytes;\n        m_read_handler = handler;\n        m_cursor = 0;\n        m_reading = true;\n    }\n\n    /// Asyncronous Transport Write\n    /**\n     * Write len bytes in buf to the output method. Call handler to report\n     * success or failure. handler may or may not be called during async_write,\n     * but it must be safe for this to happen.\n     *\n     * Will return 0 on success. Other possible errors (not exhaustive)\n     * output_stream_required: No output stream was registered to write to\n     * bad_stream: a ostream pass through error\n     *\n     * This method will attempt to write to the registered ostream first. If an\n     * ostream is not registered it will use the write handler. If neither are\n     * registered then an error is passed up to the connection.\n     *\n     * @param buf buffer to read bytes from\n     * @param len number of bytes to write\n     * @param handler Callback to invoke with operation status.\n     */\n    void async_write(char const * buf, size_t len, transport::write_handler\n        handler)\n    {\n        m_alog->write(log::alevel::devel,\"iostream_con async_write\");\n        // TODO: lock transport state?\n\n        lib::error_code ec;\n\n        if (m_output_stream) {\n            m_output_stream->write(buf,len);\n\n            if (m_output_stream->bad()) {\n                ec = make_error_code(error::bad_stream);\n            }\n        } else if (m_write_handler) {\n            ec = m_write_handler(m_connection_hdl, buf, len);\n        } else {\n            ec = make_error_code(error::output_stream_required);\n        }\n\n        handler(ec);\n    }\n\n    /// Asyncronous Transport Write (scatter-gather)\n    /**\n     * Write a sequence of buffers to the output method. Call handler to report\n     * success or failure. handler may or may not be called during async_write,\n     * but it must be safe for this to happen.\n     *\n     * Will return 0 on success. Other possible errors (not exhaustive)\n     * output_stream_required: No output stream was registered to write to\n     * bad_stream: a ostream pass through error\n     *\n     * This method will attempt to write to the registered ostream first. If an\n     * ostream is not registered it will use the write handler. If neither are\n     * registered then an error is passed up to the connection.\n     *\n     * @param bufs vector of buffers to write\n     * @param handler Callback to invoke with operation status.\n     */\n    void async_write(std::vector<buffer> const & bufs, transport::write_handler\n        handler)\n    {\n        m_alog->write(log::alevel::devel,\"iostream_con async_write buffer list\");\n        // TODO: lock transport state?\n\n        lib::error_code ec;\n\n        if (m_output_stream) {\n            std::vector<buffer>::const_iterator it;\n            for (it = bufs.begin(); it != bufs.end(); it++) {\n                m_output_stream->write((*it).buf,(*it).len);\n\n                if (m_output_stream->bad()) {\n                    ec = make_error_code(error::bad_stream);\n                    break;\n                }\n            }\n        } else if (m_vector_write_handler) {\n            ec = m_vector_write_handler(m_connection_hdl, bufs);\n        } else if (m_write_handler) {\n            std::vector<buffer>::const_iterator it;\n            for (it = bufs.begin(); it != bufs.end(); it++) {\n                ec = m_write_handler(m_connection_hdl, (*it).buf, (*it).len);\n                if (ec) {break;}\n            }\n\n        } else {\n            ec = make_error_code(error::output_stream_required);\n        }\n\n        handler(ec);\n    }\n\n    /// Set Connection Handle\n    /**\n     * @param hdl The new handle\n     */\n    void set_handle(connection_hdl hdl) {\n        m_connection_hdl = hdl;\n    }\n\n    /// Call given handler back within the transport's event system (if present)\n    /**\n     * Invoke a callback within the transport's event system if it has one. If\n     * it doesn't, the handler will be invoked immediately before this function\n     * returns.\n     *\n     * @param handler The callback to invoke\n     *\n     * @return Whether or not the transport was able to register the handler for\n     * callback.\n     */\n    lib::error_code dispatch(dispatch_handler handler) {\n        handler();\n        return lib::error_code();\n    }\n\n    /// Perform cleanup on socket shutdown_handler\n    /**\n     * If a shutdown handler is set, call it and pass through its return error\n     * code. Otherwise assume there is nothing to do and pass through a success\n     * code.\n     *\n     * @param handler The `shutdown_handler` to call back when complete\n     */\n    void async_shutdown(transport::shutdown_handler handler) {\n        lib::error_code ec;\n\n        if (m_shutdown_handler) {\n            ec = m_shutdown_handler(m_connection_hdl);\n        }\n\n        handler(ec);\n    }\nprivate:\n    void read(std::istream &in) {\n        m_alog->write(log::alevel::devel,\"iostream_con read\");\n\n        while (in.good()) {\n            if (!m_reading) {\n                m_elog->write(log::elevel::devel,\"write while not reading\");\n                break;\n            }\n\n            in.read(m_buf+m_cursor,static_cast<std::streamsize>(m_len-m_cursor));\n\n            if (in.gcount() == 0) {\n                m_elog->write(log::elevel::devel,\"read zero bytes\");\n                break;\n            }\n\n            m_cursor += static_cast<size_t>(in.gcount());\n\n            // TODO: error handling\n            if (in.bad()) {\n                m_reading = false;\n                complete_read(make_error_code(error::bad_stream));\n            }\n\n            if (m_cursor >= m_bytes_needed) {\n                m_reading = false;\n                complete_read(lib::error_code());\n            }\n        }\n    }\n\n    size_t read_some_impl(char const * buf, size_t len) {\n        m_alog->write(log::alevel::devel,\"iostream_con read_some\");\n\n        if (!m_reading) {\n            m_elog->write(log::elevel::devel,\"write while not reading\");\n            return 0;\n        }\n\n        size_t bytes_to_copy = (std::min)(len,m_len-m_cursor);\n\n        std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor);\n\n        m_cursor += bytes_to_copy;\n\n        if (m_cursor >= m_bytes_needed) {\n            complete_read(lib::error_code());\n        }\n\n        return bytes_to_copy;\n    }\n\n    /// Signal that a requested read is complete\n    /**\n     * Sets the reading flag to false and returns the handler that should be\n     * called back with the result of the read. The cursor position that is sent\n     * is whatever the value of m_cursor is.\n     *\n     * It MUST NOT be called when m_reading is false.\n     * it MUST be called while holding the read lock\n     *\n     * It is important to use this method rather than directly setting/calling\n     * m_read_handler back because this function makes sure to delete the\n     * locally stored handler which contains shared pointers that will otherwise\n     * cause circular reference based memory leaks.\n     *\n     * @param ec The error code to forward to the read handler\n     */\n    void complete_read(lib::error_code const & ec) {\n        m_reading = false;\n\n        read_handler handler = m_read_handler;\n        m_read_handler = read_handler();\n\n        handler(ec,m_cursor);\n    }\n\n    // Read space (Protected by m_read_mutex)\n    char *          m_buf;\n    size_t          m_len;\n    size_t          m_bytes_needed;\n    read_handler    m_read_handler;\n    size_t          m_cursor;\n\n    // transport resources\n    std::ostream *  m_output_stream;\n    connection_hdl  m_connection_hdl;\n    write_handler   m_write_handler;\n    vector_write_handler m_vector_write_handler;\n    shutdown_handler    m_shutdown_handler;\n\n    bool            m_reading;\n    bool const      m_is_server;\n    bool            m_is_secure;\n    lib::shared_ptr<alog_type>     m_alog;\n    lib::shared_ptr<elog_type>     m_elog;\n    std::string     m_remote_endpoint;\n\n    // This lock ensures that only one thread can edit read data for this\n    // connection. This is a very coarse lock that is basically locked all the\n    // time. The nature of the connection is such that it cannot be\n    // parallelized, the locking is here to prevent intra-connection concurrency\n    // in order to allow inter-connection concurrency.\n    mutex_type      m_read_mutex;\n};\n\n\n} // namespace iostream\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP\n"
  },
  {
    "path": "websocketpp/transport/iostream/endpoint.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP\n#define WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP\n\n#include <websocketpp/transport/base/endpoint.hpp>\n#include <websocketpp/transport/iostream/connection.hpp>\n\n#include <websocketpp/uri.hpp>\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/common/memory.hpp>\n\n#include <ostream>\n\nnamespace websocketpp {\nnamespace transport {\nnamespace iostream {\n\ntemplate <typename config>\nclass endpoint {\npublic:\n    /// Type of this endpoint transport component\n    typedef endpoint type;\n    /// Type of a pointer to this endpoint transport component\n    typedef lib::shared_ptr<type> ptr;\n\n    /// Type of this endpoint's concurrency policy\n    typedef typename config::concurrency_type concurrency_type;\n    /// Type of this endpoint's error logging policy\n    typedef typename config::elog_type elog_type;\n    /// Type of this endpoint's access logging policy\n    typedef typename config::alog_type alog_type;\n\n    /// Type of this endpoint transport component's associated connection\n    /// transport component.\n    typedef iostream::connection<config> transport_con_type;\n    /// Type of a shared pointer to this endpoint transport component's\n    /// associated connection transport component\n    typedef typename transport_con_type::ptr transport_con_ptr;\n\n    // generate and manage our own io_service\n    explicit endpoint() : m_output_stream(NULL), m_is_secure(false)\n    {\n        //std::cout << \"transport::iostream::endpoint constructor\" << std::endl;\n    }\n\n    /// Register a default output stream\n    /**\n     * The specified output stream will be assigned to future connections as the\n     * default output stream.\n     *\n     * @param o The ostream to use as the default output stream.\n     */\n    void register_ostream(std::ostream * o) {\n        m_alog->write(log::alevel::devel,\"register_ostream\");\n        m_output_stream = o;\n    }\n\n    /// Set whether or not endpoint can create secure connections\n    /**\n     * The iostream transport does not provide any security features. As such\n     * it defaults to returning false when `is_secure` is called. However, the\n     * iostream transport may be used to wrap an external socket API that may\n     * provide secure transport. This method allows that external API to flag\n     * whether or not it can create secure connections so that users of the\n     * WebSocket++ API will get more accurate information.\n     *\n     * Setting this value only indicates whether or not the endpoint is capable\n     * of producing and managing secure connections. Connections produced by\n     * this endpoint must also be individually flagged as secure if they are.\n     *\n     * @since 0.3.0-alpha4\n     *\n     * @param value Whether or not the endpoint can create secure connections.\n     */\n    void set_secure(bool value) {\n        m_is_secure = value;\n    }\n\n    /// Tests whether or not the underlying transport is secure\n    /**\n     * iostream transport will return false by default because it has no\n     * information about the ultimate remote endpoint. This may or may not be\n     * accurate depending on the real source of bytes being input. `set_secure`\n     * may be used by a wrapper API to correct the return value in the case that\n     * secure connections are in fact possible.\n     *\n     * @return Whether or not the underlying transport is secure\n     */\n    bool is_secure() const {\n        return m_is_secure;\n    }\n    \n    /// Sets the write handler\n    /**\n     * The write handler is called when the iostream transport receives data\n     * that needs to be written to the appropriate output location. This handler\n     * can be used in place of registering an ostream for output.\n     *\n     * The signature of the handler is \n     * `lib::error_code (connection_hdl, char const *, size_t)` The\n     * code returned will be reported and logged by the core library.\n     *\n     * @since 0.5.0\n     *\n     * @param h The handler to call on connection shutdown.\n     */\n    void set_write_handler(write_handler h) {\n        m_write_handler = h;\n    }\n    \n    /// Sets the shutdown handler\n    /**\n     * The shutdown handler is called when the iostream transport receives a\n     * notification from the core library that it is finished with all read and\n     * write operations and that the underlying transport can be cleaned up.\n     *\n     * If you are using iostream transport with another socket library, this is\n     * a good time to close/shutdown the socket for this connection.\n     *\n     * The signature of the handler is lib::error_code (connection_hdl). The\n     * code returned will be reported and logged by the core library.\n     *\n     * @since 0.5.0\n     *\n     * @param h The handler to call on connection shutdown.\n     */\n    void set_shutdown_handler(shutdown_handler h) {\n        m_shutdown_handler = h;\n    }\nprotected:\n    /// Initialize logging\n    /**\n     * The loggers are located in the main endpoint class. As such, the\n     * transport doesn't have direct access to them. This method is called\n     * by the endpoint constructor to allow shared logging from the transport\n     * component. These are raw pointers to member variables of the endpoint.\n     * In particular, they cannot be used in the transport constructor as they\n     * haven't been constructed yet, and cannot be used in the transport\n     * destructor as they will have been destroyed by then.\n     *\n     * @param a A pointer to the access logger to use.\n     * @param e A pointer to the error logger to use.\n     */\n    void init_logging(lib::shared_ptr<alog_type> a, lib::shared_ptr<elog_type> e) {\n        m_elog = e;\n        m_alog = a;\n    }\n\n    /// Initiate a new connection\n    /**\n     * @param tcon A pointer to the transport connection component of the\n     * connection to connect.\n     * @param u A URI pointer to the URI to connect to.\n     * @param cb The function to call back with the results when complete.\n     */\n    void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) {\n        cb(lib::error_code());\n    }\n\n    /// Initialize a connection\n    /**\n     * Init is called by an endpoint once for each newly created connection.\n     * It's purpose is to give the transport policy the chance to perform any\n     * transport specific initialization that couldn't be done via the default\n     * constructor.\n     *\n     * @param tcon A pointer to the transport portion of the connection.\n     * @return A status code indicating the success or failure of the operation\n     */\n    lib::error_code init(transport_con_ptr tcon) {\n        tcon->register_ostream(m_output_stream);\n        if (m_shutdown_handler) {\n            tcon->set_shutdown_handler(m_shutdown_handler);\n        }\n        if (m_write_handler) {\n            tcon->set_write_handler(m_write_handler);\n        }\n        return lib::error_code();\n    }\nprivate:\n    std::ostream *  m_output_stream;\n    shutdown_handler m_shutdown_handler;\n    write_handler   m_write_handler;\n    \n    lib::shared_ptr<elog_type>     m_elog;\n    lib::shared_ptr<alog_type>     m_alog;\n    bool            m_is_secure;\n};\n\n\n} // namespace iostream\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP\n"
  },
  {
    "path": "websocketpp/transport/stub/base.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP\n#define WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP\n\n#include <websocketpp/common/system_error.hpp>\n#include <websocketpp/common/cpp11.hpp>\n\n#include <string>\n\nnamespace websocketpp {\nnamespace transport {\n/// Stub transport policy that has no input or output.\nnamespace stub {\n\n/// stub transport errors\nnamespace error {\nenum value {\n    /// Catch-all error for transport policy errors that don't fit in other\n    /// categories\n    general = 1,\n\n    /// not implemented\n    not_implemented\n};\n\n/// stub transport error category\nclass category : public lib::error_category {\n    public:\n    category() {}\n\n    char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {\n        return \"websocketpp.transport.stub\";\n    }\n\n    std::string message(int value) const {\n        switch(value) {\n            case general:\n                return \"Generic stub transport policy error\";\n            case not_implemented:\n                return \"feature not implemented\";\n            default:\n                return \"Unknown\";\n        }\n    }\n};\n\n/// Get a reference to a static copy of the stub transport error category\ninline lib::error_category const & get_category() {\n    static category instance;\n    return instance;\n}\n\n/// Get an error code with the given value and the stub transport category\ninline lib::error_code make_error_code(error::value e) {\n    return lib::error_code(static_cast<int>(e), get_category());\n}\n\n} // namespace error\n} // namespace stub\n} // namespace transport\n} // namespace websocketpp\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_\ntemplate<> struct is_error_code_enum<websocketpp::transport::stub::error::value>\n{\n    static bool const value = true;\n};\n_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_\n\n#endif // WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP\n"
  },
  {
    "path": "websocketpp/transport/stub/connection.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_STUB_CON_HPP\n#define WEBSOCKETPP_TRANSPORT_STUB_CON_HPP\n\n#include <websocketpp/transport/stub/base.hpp>\n\n#include <websocketpp/transport/base/connection.hpp>\n\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/common/connection_hdl.hpp>\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/common/platforms.hpp>\n\n#include <string>\n#include <vector>\n\nnamespace websocketpp {\nnamespace transport {\nnamespace stub {\n\n/// Empty timer class to stub out for timer functionality that stub\n/// transport doesn't support\nstruct timer {\n    void cancel() {}\n};\n\ntemplate <typename config>\nclass connection : public lib::enable_shared_from_this< connection<config> > {\npublic:\n    /// Type of this connection transport component\n    typedef connection<config> type;\n    /// Type of a shared pointer to this connection transport component\n    typedef lib::shared_ptr<type> ptr;\n\n    /// transport concurrency policy\n    typedef typename config::concurrency_type concurrency_type;\n    /// Type of this transport's access logging policy\n    typedef typename config::alog_type alog_type;\n    /// Type of this transport's error logging policy\n    typedef typename config::elog_type elog_type;\n\n    // Concurrency policy types\n    typedef typename concurrency_type::scoped_lock_type scoped_lock_type;\n    typedef typename concurrency_type::mutex_type mutex_type;\n\n    typedef lib::shared_ptr<timer> timer_ptr;\n\n    explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)\n      : m_alog(alog), m_elog(elog)\n    {\n        m_alog->write(log::alevel::devel,\"stub con transport constructor\");\n    }\n\n    /// Get a shared pointer to this component\n    ptr get_shared() {\n        return type::shared_from_this();\n    }\n\n    /// Set whether or not this connection is secure\n    /**\n     * Todo: docs\n     *\n     * @since 0.3.0-alpha4\n     *\n     * @param value Whether or not this connection is secure.\n     */\n    void set_secure(bool value) {}\n\n    /// Tests whether or not the underlying transport is secure\n    /**\n     * TODO: docs\n     *\n     * @return Whether or not the underlying transport is secure\n     */\n    bool is_secure() const {\n        return false;\n    }\n\n    /// Set uri hook\n    /**\n     * Called by the endpoint as a connection is being established to provide\n     * the uri being connected to to the transport layer.\n     *\n     * Implementation is optional and can be ignored if the transport has no\n     * need for this information.\n     *\n     * @since 0.6.0\n     *\n     * @param u The uri to set\n     */\n    void set_uri(uri_ptr) {}\n\n    /// Set human readable remote endpoint address\n    /**\n     * Sets the remote endpoint address returned by `get_remote_endpoint`. This\n     * value should be a human readable string that describes the remote\n     * endpoint. Typically an IP address or hostname, perhaps with a port. But\n     * may be something else depending on the nature of the underlying\n     * transport.\n     *\n     * If none is set a default is returned.\n     *\n     * @since 0.3.0-alpha4\n     *\n     * @param value The remote endpoint address to set.\n     */\n    void set_remote_endpoint(std::string value) {}\n\n    /// Get human readable remote endpoint address\n    /**\n     * TODO: docs\n     *\n     * This value is used in access and error logs and is available to the end\n     * application for including in user facing interfaces and messages.\n     *\n     * @return A string identifying the address of the remote endpoint\n     */\n    std::string get_remote_endpoint() const {\n        return \"unknown (stub transport)\";\n    }\n\n    /// Get the connection handle\n    /**\n     * @return The handle for this connection.\n     */\n    connection_hdl get_handle() const {\n        return connection_hdl();\n    }\n\n    /// Call back a function after a period of time.\n    /**\n     * Timers are not implemented in this transport. The timer pointer will\n     * always be empty. The handler will never be called.\n     *\n     * @param duration Length of time to wait in milliseconds\n     * @param callback The function to call back when the timer has expired\n     * @return A handle that can be used to cancel the timer if it is no longer\n     * needed.\n     */\n    timer_ptr set_timer(long duration, timer_handler handler) {\n        return timer_ptr();\n    }\nprotected:\n    /// Initialize the connection transport\n    /**\n     * Initialize the connection's transport component.\n     *\n     * @param handler The `init_handler` to call when initialization is done\n     */\n    void init(init_handler handler) {\n        m_alog->write(log::alevel::devel,\"stub connection init\");\n        handler(make_error_code(error::not_implemented));\n    }\n\n    /// Initiate an async_read for at least num_bytes bytes into buf\n    /**\n     * Initiates an async_read request for at least num_bytes bytes. The input\n     * will be read into buf. A maximum of len bytes will be input. When the\n     * operation is complete, handler will be called with the status and number\n     * of bytes read.\n     *\n     * This method may or may not call handler from within the initial call. The\n     * application should be prepared to accept either.\n     *\n     * The application should never call this method a second time before it has\n     * been called back for the first read. If this is done, the second read\n     * will be called back immediately with a double_read error.\n     *\n     * If num_bytes or len are zero handler will be called back immediately\n     * indicating success.\n     *\n     * @param num_bytes Don't call handler until at least this many bytes have\n     * been read.\n     * @param buf The buffer to read bytes into\n     * @param len The size of buf. At maximum, this many bytes will be read.\n     * @param handler The callback to invoke when the operation is complete or\n     * ends in an error\n     */\n    void async_read_at_least(size_t num_bytes, char * buf, size_t len,\n        read_handler handler)\n    {\n        m_alog->write(log::alevel::devel, \"stub_con async_read_at_least\");\n        handler(make_error_code(error::not_implemented), 0);\n    }\n\n    /// Asyncronous Transport Write\n    /**\n     * Write len bytes in buf to the output stream. Call handler to report\n     * success or failure. handler may or may not be called during async_write,\n     * but it must be safe for this to happen.\n     *\n     * Will return 0 on success.\n     *\n     * @param buf buffer to read bytes from\n     * @param len number of bytes to write\n     * @param handler Callback to invoke with operation status.\n     */\n    void async_write(char const * buf, size_t len, write_handler handler) {\n        m_alog->write(log::alevel::devel,\"stub_con async_write\");\n        handler(make_error_code(error::not_implemented));\n    }\n\n    /// Asyncronous Transport Write (scatter-gather)\n    /**\n     * Write a sequence of buffers to the output stream. Call handler to report\n     * success or failure. handler may or may not be called during async_write,\n     * but it must be safe for this to happen.\n     *\n     * Will return 0 on success.\n     *\n     * @param bufs vector of buffers to write\n     * @param handler Callback to invoke with operation status.\n     */\n    void async_write(std::vector<buffer> const & bufs, write_handler handler) {\n        m_alog->write(log::alevel::devel,\"stub_con async_write buffer list\");\n        handler(make_error_code(error::not_implemented));\n    }\n\n    /// Set Connection Handle\n    /**\n     * @param hdl The new handle\n     */\n    void set_handle(connection_hdl hdl) {}\n\n    /// Call given handler back within the transport's event system (if present)\n    /**\n     * Invoke a callback within the transport's event system if it has one. If\n     * it doesn't, the handler will be invoked immediately before this function\n     * returns.\n     *\n     * @param handler The callback to invoke\n     *\n     * @return Whether or not the transport was able to register the handler for\n     * callback.\n     */\n    lib::error_code dispatch(dispatch_handler handler) {\n        handler();\n        return lib::error_code();\n    }\n\n    /// Perform cleanup on socket shutdown_handler\n    /**\n     * @param h The `shutdown_handler` to call back when complete\n     */\n    void async_shutdown(shutdown_handler handler) {\n        handler(lib::error_code());\n    }\nprivate:\n    // member variables!\n    lib::shared_ptr<alog_type> m_alog;\n    lib::shared_ptr<elog_type> m_elog;\n};\n\n\n} // namespace stub\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_STUB_CON_HPP\n"
  },
  {
    "path": "websocketpp/transport/stub/endpoint.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_TRANSPORT_STUB_HPP\n#define WEBSOCKETPP_TRANSPORT_STUB_HPP\n\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/logger/levels.hpp>\n\n#include <websocketpp/transport/base/endpoint.hpp>\n#include <websocketpp/transport/stub/connection.hpp>\n\nnamespace websocketpp {\nnamespace transport {\nnamespace stub {\n\ntemplate <typename config>\nclass endpoint {\npublic:\n    /// Type of this endpoint transport component\n    typedef endpoint type;\n    /// Type of a pointer to this endpoint transport component\n    typedef lib::shared_ptr<type> ptr;\n\n    /// Type of this endpoint's concurrency policy\n    typedef typename config::concurrency_type concurrency_type;\n    /// Type of this endpoint's error logging policy\n    typedef typename config::elog_type elog_type;\n    /// Type of this endpoint's access logging policy\n    typedef typename config::alog_type alog_type;\n\n    /// Type of this endpoint transport component's associated connection\n    /// transport component.\n    typedef stub::connection<config> transport_con_type;\n    /// Type of a shared pointer to this endpoint transport component's\n    /// associated connection transport component\n    typedef typename transport_con_type::ptr transport_con_ptr;\n\n    // generate and manage our own io_service\n    explicit endpoint()\n    {\n        //std::cout << \"transport::iostream::endpoint constructor\" << std::endl;\n    }\n\n    /// Set whether or not endpoint can create secure connections\n    /**\n     * TODO: docs\n     *\n     * Setting this value only indicates whether or not the endpoint is capable\n     * of producing and managing secure connections. Connections produced by\n     * this endpoint must also be individually flagged as secure if they are.\n     *\n     * @since 0.3.0-alpha4\n     *\n     * @param value Whether or not the endpoint can create secure connections.\n     */\n    void set_secure(bool value) {}\n\n    /// Tests whether or not the underlying transport is secure\n    /**\n     * TODO: docs\n     *\n     * @return Whether or not the underlying transport is secure\n     */\n    bool is_secure() const {\n        return false;\n    }\nprotected:\n    /// Initialize logging\n    /**\n     * The loggers are located in the main endpoint class. As such, the\n     * transport doesn't have direct access to them. This method is called\n     * by the endpoint constructor to allow shared logging from the transport\n     * component. These are raw pointers to member variables of the endpoint.\n     * In particular, they cannot be used in the transport constructor as they\n     * haven't been constructed yet, and cannot be used in the transport\n     * destructor as they will have been destroyed by then.\n     *\n     * @param a A pointer to the access logger to use.\n     * @param e A pointer to the error logger to use.\n     */\n    void init_logging(alog_type * a, elog_type * e) {}\n\n    /// Initiate a new connection\n    /**\n     * @param tcon A pointer to the transport connection component of the\n     * connection to connect.\n     * @param u A URI pointer to the URI to connect to.\n     * @param cb The function to call back with the results when complete.\n     */\n    void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) {\n        cb(make_error_code(error::not_implemented));\n    }\n\n    /// Initialize a connection\n    /**\n     * Init is called by an endpoint once for each newly created connection.\n     * It's purpose is to give the transport policy the chance to perform any\n     * transport specific initialization that couldn't be done via the default\n     * constructor.\n     *\n     * @param tcon A pointer to the transport portion of the connection.\n     * @return A status code indicating the success or failure of the operation\n     */\n    lib::error_code init(transport_con_ptr tcon) {\n        return make_error_code(error::not_implemented);\n    }\nprivate:\n\n};\n\n} // namespace stub\n} // namespace transport\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_TRANSPORT_STUB_HPP\n"
  },
  {
    "path": "websocketpp/uri.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_URI_HPP\n#define WEBSOCKETPP_URI_HPP\n\n#include <websocketpp/error.hpp>\n\n#include <websocketpp/common/memory.hpp>\n#include <websocketpp/common/stdint.hpp>\n\n#include <algorithm>\n#include <sstream>\n#include <string>\n\nnamespace websocketpp {\n\n// TODO: figure out why this fixes horrible linking errors.\n\n/// Default port for ws://\nstatic uint16_t const uri_default_port = 80;\n/// Default port for wss://\nstatic uint16_t const uri_default_secure_port = 443;\n\nclass uri {\npublic:\n    explicit uri(std::string const & uri_string) : m_valid(false) {\n        std::string::const_iterator it;\n        std::string::const_iterator temp;\n\n        int state = 0;\n\n        it = uri_string.begin();\n        size_t uri_len = uri_string.length();\n\n        if (uri_len >= 7 && std::equal(it,it+6,\"wss://\")) {\n            m_secure = true;\n            m_scheme = \"wss\";\n            it += 6;\n        } else if (uri_len >= 6 && std::equal(it,it+5,\"ws://\")) {\n            m_secure = false;\n            m_scheme = \"ws\";\n            it += 5;\n        } else if (uri_len >= 8 && std::equal(it,it+7,\"http://\")) {\n            m_secure = false;\n            m_scheme = \"http\";\n            it += 7;\n        } else if (uri_len >= 9 && std::equal(it,it+8,\"https://\")) {\n            m_secure = true;\n            m_scheme = \"https\";\n            it += 8;\n        } else {\n            return;\n        }\n\n        // extract host.\n        // either a host string\n        // an IPv4 address\n        // or an IPv6 address\n        if (*it == '[') {\n            ++it;\n            // IPv6 literal\n            // extract IPv6 digits until ]\n\n            // TODO: this doesn't work on g++... not sure why\n            //temp = std::find(it,it2,']');\n\n            temp = it;\n            while (temp != uri_string.end()) {\n                if (*temp == ']') {\n                    break;\n                }\n                ++temp;\n            }\n\n            if (temp == uri_string.end()) {\n                return;\n            } else {\n                // validate IPv6 literal parts\n                // can contain numbers, a-f and A-F\n                m_host.append(it,temp);\n            }\n            it = temp+1;\n            if (it == uri_string.end()) {\n                state = 2;\n            } else if (*it == '/') {\n                state = 2;\n                ++it;\n            } else if (*it == ':') {\n                state = 1;\n                ++it;\n            } else {\n                // problem\n                return;\n            }\n        } else {\n            // IPv4 or hostname\n            // extract until : or /\n            while (state == 0) {\n                if (it == uri_string.end()) {\n                    state = 2;\n                    break;\n                } else if (*it == '/') {\n                    state = 2;\n                } else if (*it == ':') {\n                    // end hostname start port\n                    state = 1;\n                } else {\n                    m_host += *it;\n                }\n                ++it;\n            }\n        }\n\n        // parse port\n        std::string port;\n        while (state == 1) {\n            if (it == uri_string.end()) {\n                // state is not used after this point presently.\n                // this should be re-enabled if it ever is needed in a future\n                // refactoring\n                //state = 3;\n                break;\n            } else if (*it == '/') {\n                state = 3;\n            } else {\n                port += *it;\n            }\n            ++it;\n        }\n\n        lib::error_code ec;\n        m_port = get_port_from_string(port, ec);\n\n        if (ec) {\n            return;\n        }\n\n        m_resource = \"/\";\n        m_resource.append(it,uri_string.end());\n\n\n        m_valid = true;\n    }\n\n    uri(bool secure, std::string const & host, uint16_t port,\n        std::string const & resource)\n      : m_scheme(secure ? \"wss\" : \"ws\")\n      , m_host(host)\n      , m_resource(resource.empty() ? \"/\" : resource)\n      , m_port(port)\n      , m_secure(secure)\n      , m_valid(true) {}\n\n    uri(bool secure, std::string const & host, std::string const & resource)\n      : m_scheme(secure ? \"wss\" : \"ws\")\n      , m_host(host)\n      , m_resource(resource.empty() ? \"/\" : resource)\n      , m_port(secure ? uri_default_secure_port : uri_default_port)\n      , m_secure(secure)\n      , m_valid(true) {}\n\n    uri(bool secure, std::string const & host, std::string const & port,\n        std::string const & resource)\n      : m_scheme(secure ? \"wss\" : \"ws\")\n      , m_host(host)\n      , m_resource(resource.empty() ? \"/\" : resource)\n      , m_secure(secure)\n    {\n        lib::error_code ec;\n        m_port = get_port_from_string(port,ec);\n        m_valid = !ec;\n    }\n\n    uri(std::string const & scheme, std::string const & host, uint16_t port,\n        std::string const & resource)\n      : m_scheme(scheme)\n      , m_host(host)\n      , m_resource(resource.empty() ? \"/\" : resource)\n      , m_port(port)\n      , m_secure(scheme == \"wss\" || scheme == \"https\")\n      , m_valid(true) {}\n\n    uri(std::string scheme, std::string const & host, std::string const & resource)\n      : m_scheme(scheme)\n      , m_host(host)\n      , m_resource(resource.empty() ? \"/\" : resource)\n      , m_port((scheme == \"wss\" || scheme == \"https\") ? uri_default_secure_port : uri_default_port)\n      , m_secure(scheme == \"wss\" || scheme == \"https\")\n      , m_valid(true) {}\n\n    uri(std::string const & scheme, std::string const & host,\n        std::string const & port, std::string const & resource)\n      : m_scheme(scheme)\n      , m_host(host)\n      , m_resource(resource.empty() ? \"/\" : resource)\n      , m_secure(scheme == \"wss\" || scheme == \"https\")\n    {\n        lib::error_code ec;\n        m_port = get_port_from_string(port,ec);\n        m_valid = !ec;\n    }\n\n    bool get_valid() const {\n        return m_valid;\n    }\n\n    bool get_secure() const {\n        return m_secure;\n    }\n\n    std::string const & get_scheme() const {\n        return m_scheme;\n    }\n\n    std::string const & get_host() const {\n        return m_host;\n    }\n\n    std::string get_host_port() const {\n        if (m_port == (m_secure ? uri_default_secure_port : uri_default_port)) {\n            return m_host;\n        } else {\n            std::stringstream p;\n            p << m_host << \":\" << m_port;\n            return p.str();\n        }\n    }\n\n    std::string get_authority() const {\n        std::stringstream p;\n        p << m_host << \":\" << m_port;\n        return p.str();\n    }\n\n    uint16_t get_port() const {\n        return m_port;\n    }\n\n    std::string get_port_str() const {\n        std::stringstream p;\n        p << m_port;\n        return p.str();\n    }\n\n    std::string const & get_resource() const {\n        return m_resource;\n    }\n\n    std::string str() const {\n        std::stringstream s;\n\n        s << m_scheme << \"://\" << m_host;\n\n        if (m_port != (m_secure ? uri_default_secure_port : uri_default_port)) {\n            s << \":\" << m_port;\n        }\n\n        s << m_resource;\n        return s.str();\n    }\n\n    /// Return the query portion\n    /**\n     * Returns the query portion (after the ?) of the URI or an empty string if\n     * there is none.\n     *\n     * @return query portion of the URI.\n     */\n    std::string get_query() const {\n        std::size_t found = m_resource.find('?');\n        if (found != std::string::npos) {\n            return m_resource.substr(found + 1);\n        } else {\n            return \"\";\n        }\n    }\n\n    // get fragment\n\n    // hi <3\n\n    // get the string representation of this URI\n\n    //std::string base() const; // is this still needed?\n\n    // setter methods set some or all (in the case of parse) based on the input.\n    // These functions throw a uri_exception on failure.\n    /*void set_uri(const std::string& uri);\n\n    void set_secure(bool secure);\n    void set_host(const std::string& host);\n    void set_port(uint16_t port);\n    void set_port(const std::string& port);\n    void set_resource(const std::string& resource);*/\nprivate:\n    uint16_t get_port_from_string(std::string const & port, lib::error_code &\n        ec) const\n    {\n        ec = lib::error_code();\n\n        if (port.empty()) {\n            return (m_secure ? uri_default_secure_port : uri_default_port);\n        }\n\n        unsigned int t_port = static_cast<unsigned int>(atoi(port.c_str()));\n\n        if (t_port > 65535) {\n            ec = error::make_error_code(error::invalid_port);\n        }\n\n        if (t_port == 0) {\n            ec = error::make_error_code(error::invalid_port);\n        }\n\n        return static_cast<uint16_t>(t_port);\n    }\n\n    std::string m_scheme;\n    std::string m_host;\n    std::string m_resource;\n    uint16_t    m_port;\n    bool        m_secure;\n    bool        m_valid;\n};\n\n/// Pointer to a URI\ntypedef lib::shared_ptr<uri> uri_ptr;\n\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_URI_HPP\n"
  },
  {
    "path": "websocketpp/utf8_validator.hpp",
    "content": "/*\n * The following code is adapted from code originally written by Bjoern\n * Hoehrmann <bjoern@hoehrmann.de>. See\n * http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.\n *\n * The original license:\n *\n * Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n*/\n\n#ifndef UTF8_VALIDATOR_HPP\n#define UTF8_VALIDATOR_HPP\n\n#include <websocketpp/common/stdint.hpp>\n\n#include <string>\n\nnamespace websocketpp {\nnamespace utf8_validator {\n\n/// State that represents a valid utf8 input sequence\nstatic unsigned int const utf8_accept = 0;\n/// State that represents an invalid utf8 input sequence\nstatic unsigned int const utf8_reject = 1;\n\n/// Lookup table for the UTF8 decode state machine\nstatic uint8_t const utf8d[] = {\n  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f\n  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f\n  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f\n  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f\n  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f\n  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf\n  8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df\n  0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef\n  0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff\n  0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0\n  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2\n  1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4\n  1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6\n  1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8\n};\n\n/// Decode the next byte of a UTF8 sequence\n/**\n * @param [out] state The decoder state to advance\n * @param [out] codep The codepoint to fill in\n * @param [in] byte The byte to input\n * @return The ending state of the decode operation\n */\ninline uint32_t decode(uint32_t * state, uint32_t * codep, uint8_t byte) {\n  uint32_t type = utf8d[byte];\n\n  *codep = (*state != utf8_accept) ?\n    (byte & 0x3fu) | (*codep << 6) :\n    (0xff >> type) & (byte);\n\n  *state = utf8d[256 + *state*16 + type];\n  return *state;\n}\n\n/// Provides streaming UTF8 validation functionality\nclass validator {\npublic:\n    /// Construct and initialize the validator\n    validator() : m_state(utf8_accept),m_codepoint(0) {}\n\n    /// Advance the state of the validator with the next input byte\n    /**\n     * @param byte The byte to advance the validation state with\n     * @return Whether or not the byte resulted in a validation error.\n     */\n    bool consume (uint8_t byte) {\n        if (utf8_validator::decode(&m_state,&m_codepoint,byte) == utf8_reject) {\n            return false;\n        }\n        return true;\n    }\n\n    /// Advance validator state with input from an iterator pair\n    /**\n     * @param begin Input iterator to the start of the input range\n     * @param end Input iterator to the end of the input range\n     * @return Whether or not decoding the bytes resulted in a validation error.\n     */\n    template <typename iterator_type>\n    bool decode (iterator_type begin, iterator_type end) {\n        for (iterator_type it = begin; it != end; ++it) {\n            unsigned int result = utf8_validator::decode(\n                &m_state,\n                &m_codepoint,\n                static_cast<uint8_t>(*it)\n            );\n\n            if (result == utf8_reject) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /// Return whether the input sequence ended on a valid utf8 codepoint\n    /**\n     * @return Whether or not the input sequence ended on a valid codepoint.\n     */\n    bool complete() {\n        return m_state == utf8_accept;\n    }\n\n    /// Reset the validator to decode another message\n    void reset() {\n        m_state = utf8_accept;\n        m_codepoint = 0;\n    }\nprivate:\n    uint32_t    m_state;\n    uint32_t    m_codepoint;\n};\n\n/// Validate a UTF8 string\n/**\n * convenience function that creates a validator, validates a complete string\n * and returns the result.\n */\ninline bool validate(std::string const & s) {\n    validator v;\n    if (!v.decode(s.begin(),s.end())) {\n        return false;\n    }\n    return v.complete();\n}\n\n} // namespace utf8_validator\n} // namespace websocketpp\n\n#endif // UTF8_VALIDATOR_HPP\n"
  },
  {
    "path": "websocketpp/utilities.hpp",
    "content": "/*\n * Copyright (c) 2014, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_UTILITIES_HPP\n#define WEBSOCKETPP_UTILITIES_HPP\n\n#include <websocketpp/common/stdint.hpp>\n\n#include <algorithm>\n#include <string>\n#include <locale>\n\nnamespace websocketpp {\n/// Generic non-websocket specific utility functions and data structures\nnamespace utility {\n\n/// Helper functor for case insensitive find\n/**\n * Based on code from\n * http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find\n *\n * templated version of my_equal so it could work with both char and wchar_t\n */\ntemplate<typename charT>\nstruct my_equal {\n    /// Construct the functor with the given locale\n    /**\n     * @param [in] loc The locale to use for determining the case of values\n     */\n    my_equal(std::locale const & loc ) : m_loc(loc) {}\n\n    /// Perform a case insensitive comparison\n    /**\n     * @param ch1 The first value to compare\n     * @param ch2 The second value to compare\n     * @return Whether or not the two values are equal when both are converted\n     *         to uppercase using the given locale.\n     */\n    bool operator()(charT ch1, charT ch2) {\n        return std::toupper(ch1, m_loc) == std::toupper(ch2, m_loc);\n    }\nprivate:\n    std::locale const & m_loc;\n};\n\n/// Helper less than functor for case insensitive find\n/**\n * Based on code from\n * http://stackoverflow.com/questions/3152241/case-insensitive-stdstring-find\n */\nstruct ci_less {\n    // case-independent (ci) compare_less binary function\n    struct nocase_compare {\n        bool operator() (unsigned char const & c1, unsigned char const & c2) const {\n            return tolower (c1) < tolower (c2);\n        }\n    };\n    bool operator() (std::string const & s1, std::string const & s2) const {\n        return std::lexicographical_compare\n            (s1.begin (), s1.end (),   // source range\n            s2.begin (), s2.end (),   // dest range\n            nocase_compare ());  // comparison\n    }\n};\n\n/// Find substring (case insensitive)\n/**\n * @param [in] haystack The string to search in\n * @param [in] needle The string to search for\n * @param [in] loc The locale to use for determining the case of values.\n *             Defaults to the current locale.\n * @return An iterator to the first element of the first occurrance of needle in\n *         haystack. If the sequence is not found, the function returns\n *         haystack.end()\n */\ntemplate<typename T>\ntypename T::const_iterator ci_find_substr(T const & haystack, T const & needle,\n    std::locale const & loc = std::locale())\n{\n    return std::search( haystack.begin(), haystack.end(),\n        needle.begin(), needle.end(), my_equal<typename T::value_type>(loc) );\n}\n\n/// Find substring (case insensitive)\n/**\n * @todo Is this still used? This method may not make sense.. should use\n * iterators or be less generic. As is it is too tightly coupled to std::string\n *\n * @param [in] haystack The string to search in\n * @param [in] needle The string to search for as a char array of values\n * @param [in] size Length of needle\n * @param [in] loc The locale to use for determining the case of values.\n *             Defaults to the current locale.\n * @return An iterator to the first element of the first occurrance of needle in\n *         haystack. If the sequence is not found, the function returns\n *         haystack.end()\n */\ntemplate<typename T>\ntypename T::const_iterator ci_find_substr(T const & haystack,\n    typename T::value_type const * needle, typename T::size_type size,\n    std::locale const & loc = std::locale())\n{\n    return std::search( haystack.begin(), haystack.end(),\n        needle, needle+size, my_equal<typename T::value_type>(loc) );\n}\n\n/// Convert a string to lowercase\n/**\n * @param [in] in The string to convert\n * @return The converted string\n */\nstd::string to_lower(std::string const & in);\n\n/// Replace all occurrances of a substring with another\n/**\n * @param [in] subject The string to search in\n * @param [in] search The string to search for\n * @param [in] replace The string to replace with\n * @return A copy of `subject` with all occurances of `search` replaced with\n *         `replace`\n */\nstd::string string_replace_all(std::string subject, std::string const & search,\n                               std::string const & replace);\n\n/// Convert std::string to ascii printed string of hex digits\n/**\n * @param [in] input The string to print\n * @return A copy of `input` converted to the printable representation of the\n *         hex values of its data.\n */\nstd::string to_hex(std::string const & input);\n\n/// Convert byte array (uint8_t) to ascii printed string of hex digits\n/**\n * @param [in] input The byte array to print\n * @param [in] length The length of input\n * @return A copy of `input` converted to the printable representation of the\n *         hex values of its data.\n */\nstd::string to_hex(uint8_t const * input, size_t length);\n\n/// Convert char array to ascii printed string of hex digits\n/**\n * @param [in] input The char array to print\n * @param [in] length The length of input\n * @return A copy of `input` converted to the printable representation of the\n *         hex values of its data.\n */\nstd::string to_hex(char const * input, size_t length);\n\n} // namespace utility\n} // namespace websocketpp\n\n#include <websocketpp/impl/utilities_impl.hpp>\n\n#endif // WEBSOCKETPP_UTILITIES_HPP\n"
  },
  {
    "path": "websocketpp/version.hpp",
    "content": "/*\n * Copyright (c) 2015, Peter Thorson. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of the WebSocket++ Project nor the\n *       names of its contributors may be used to endorse or promote products\n *       derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n\n#ifndef WEBSOCKETPP_VERSION_HPP\n#define WEBSOCKETPP_VERSION_HPP\n\n/// Namespace for the WebSocket++ project\nnamespace websocketpp {\n\n/*\n other places where version information is kept\n - readme.md\n - changelog.md\n - Doxyfile\n - CMakeLists.txt\n*/\n\n/// Library major version number\nstatic int const major_version = 0;\n/// Library minor version number\nstatic int const minor_version = 8;\n/// Library patch version number\nstatic int const patch_version = 2;\n/// Library pre-release flag\n/**\n * This is a textual flag indicating the type and number for pre-release\n * versions (dev, alpha, beta, rc). This will be blank for release versions.\n */\n\nstatic char const prerelease_flag[] = \"\";\n\n/// Default user agent string\nstatic char const user_agent[] = \"WebSocket++/0.8.2\";\n\n} // namespace websocketpp\n\n#endif // WEBSOCKETPP_VERSION_HPP\n"
  },
  {
    "path": "websocketpp-config.cmake.in",
    "content": "# - Config file for the websocketpp package\n# It defines the following variables\n#  WEBSOCKETPP_FOUND - indicates that the module was found\n#  WEBSOCKETPP_INCLUDE_DIR - include directories\n\n@PACKAGE_INIT@\nset_and_check(WEBSOCKETPP_INCLUDE_DIR \"@PACKAGE_INSTALL_INCLUDE_DIR@\")\nset(WEBSOCKETPP_FOUND TRUE)\n\n#This is a bit of a hack, but it works well. It also allows continued support of CMake 2.8\nif(${CMAKE_VERSION} VERSION_GREATER 3.0.0 OR ${CMAKE_VERSION} VERSION_EQUAL 3.0.0)\n  add_library(websocketpp::websocketpp INTERFACE IMPORTED)\n  set_target_properties(websocketpp::websocketpp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES \"${WEBSOCKETPP_INCLUDE_DIR}\")\nendif()\n"
  }
]